260224:1606 20260224:1600 V1.8.0
All checks were successful
Build and Deploy / deploy (push) Successful in 6m25s
All checks were successful
Build and Deploy / deploy (push) Successful in 6m25s
This commit is contained in:
@@ -4,64 +4,72 @@ trigger: always_on
|
||||
|
||||
# Project Specifications & Context Protocol
|
||||
|
||||
Description: Enforces strict adherence to the project's documentation structure (specs/00-06) for all agent activities.
|
||||
Globs: *
|
||||
Description: Enforces strict adherence to the project's documentation structure for all agent activities.
|
||||
Globs: \*
|
||||
|
||||
---
|
||||
|
||||
## Agent Role
|
||||
|
||||
You are a Principal Engineer and Architect strictly bound by the project's documentation. You do not improvise outside of the defined specifications.
|
||||
|
||||
## The Context Loading Protocol
|
||||
|
||||
Before generating code or planning a solution, you MUST conceptually load the context in this specific order:
|
||||
|
||||
1. **🎯 ACTIVE TASK (`specs/06-tasks/`)**
|
||||
- Identify the current active task file.
|
||||
- *Action:* Determine the immediate scope. Do NOT implement features not listed here.
|
||||
1. **📖 PROJECT CONTEXT (`specs/00-Overview/`)**
|
||||
- _Action:_ Align with the high-level goals and domain language described here.
|
||||
|
||||
2. **📖 PROJECT CONTEXT (`specs/00-overview/`)**
|
||||
- *Action:* Align with the high-level goals and domain language described here.
|
||||
2. **✅ REQUIREMENTS (`specs/01-Requirements/`)**
|
||||
- _Action:_ Verify that your plan satisfies the functional requirements and user stories.
|
||||
- _Constraint:_ If a requirement is ambiguous, stop and ask.
|
||||
|
||||
3. **✅ REQUIREMENTS (`specs/01-requirements/`)**
|
||||
- *Action:* Verify that your plan satisfies the functional requirements and user stories.
|
||||
- *Constraint:* If a requirement is ambiguous, stop and ask.
|
||||
3. **🏗 ARCHITECTURE & DECISIONS (`specs/02-Architecture/` & `specs/06-Decision-Records/`)**
|
||||
- _Action:_ Adhere to the defined system design.
|
||||
- _Crucial:_ Check `specs/06-Decision-Records/` (ADRs) to ensure you do not violate previously agreed-upon technical decisions.
|
||||
|
||||
4. **🏗 ARCHITECTURE & DECISIONS (`specs/02-architecture/` & `specs/05-decisions/`)**
|
||||
- *Action:* Adhere to the defined system design.
|
||||
- *Crucial:* Check `specs/05-decisions/` (ADRs) to ensure you do not violate previously agreed-upon technical decisions.
|
||||
4. **💾 DATABASE & SCHEMA (`specs/03-Data-and-Storage/`)**
|
||||
- _Action:_
|
||||
- **Read `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`** for exact table structures and constraints.
|
||||
- **Consult `specs/03-Data-and-Storage/03-01-data-dictionary.md`** for field meanings and business rules.
|
||||
- **Check `specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-basic.sql`** to understand initial data states.
|
||||
- **Check `specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-permissions.sql`** to understand initial permissions states.
|
||||
- _Constraint:_ NEVER invent table names or columns. Use ONLY what is defined here.
|
||||
|
||||
5. **💾 DATABASE & SCHEMA (`specs/07-database/`)**
|
||||
- *Action:* - **Read `specs/07-database/lcbp3-v1.7.0-schema.sql`** (or relevant `.sql` files) for exact table structures and constraints.
|
||||
- **Consult `specs/07-database/data-dictionary-v1.7.0.md`** for field meanings and business rules.
|
||||
- **Check `specs/07-database/lcbp3-v1.7.0-seed-basic.sql`** to understand initial data states.
|
||||
- **Check `specs/07-database/lcbp3-v1.7.0-seed-permissions.sql`** to understand initial permissions states.
|
||||
- *Constraint:* NEVER invent table names or columns. Use ONLY what is defined here.
|
||||
5. **⚙️ IMPLEMENTATION DETAILS (`specs/05-Engineering-Guidelines/`)**
|
||||
- _Action:_ Follow Tech Stack, Naming Conventions, and Code Patterns.
|
||||
|
||||
6. **⚙️ IMPLEMENTATION DETAILS (`specs/03-implementation/`)**
|
||||
- *Action:* Follow Tech Stack, Naming Conventions, and Code Patterns.
|
||||
|
||||
7. **🚀 OPERATIONS (`specs/04-operations/`)**
|
||||
- *Action:* Ensure deployability and configuration compliance.
|
||||
|
||||
8. **🏗️ INFRASTRUCTURE (`specs/08-infrastructure/`)**
|
||||
- *Action:* Review Docker Compose configurations, network diagrams, monitoring setup, and security zones.
|
||||
- *Constraint:* Ensure deployment paths, port mappings, and volume mounts are consistent with this documentation.
|
||||
6. **🚀 OPERATIONS & INFRASTRUCTURE (`specs/04-Infrastructure-OPS/`)**
|
||||
- _Action:_ Ensure deployability and configuration compliance.
|
||||
- _Constraint:_ Ensure deployment paths, port mappings, and volume mounts are consistent with this documentation.
|
||||
|
||||
## Execution Rules
|
||||
|
||||
### 1. Citation Requirement
|
||||
|
||||
When proposing a change or writing code, you must explicitly reference the source of truth:
|
||||
> "Implementing feature X per `specs/01-requirements/README.md` and `specs/01-requirements/**.md` using pattern defined in `specs/03-implementation/**.md`."
|
||||
|
||||
> "Implementing feature X per `specs/01-Requirements/` using pattern defined in `specs/05-Engineering-Guidelines/`."
|
||||
|
||||
### 2. Conflict Resolution
|
||||
|
||||
- **Spec vs. Training Data:** The `specs/` folder ALWAYS supersedes your general training data.
|
||||
- **Spec vs. User Prompt:** If a user prompt contradicts `specs/05-decisions/`, warn the user before proceeding.
|
||||
- **Spec vs. User Prompt:** If a user prompt contradicts `specs/06-Decision-Records/`, warn the user before proceeding.
|
||||
|
||||
### 3. File Generation
|
||||
- Do not create new files outside of the structure defined.
|
||||
- Keep the code style consistent with `specs/03-implementation/`.
|
||||
|
||||
### 4. Data Migration
|
||||
- Do not migrate. The schema can be modified directly.
|
||||
- Do not create new files outside of the established project structure:
|
||||
- Backend: `backend/src/modules/<name>/`, `backend/src/common/`
|
||||
- Frontend: `frontend/app/`, `frontend/components/`, `frontend/hooks/`, `frontend/lib/`
|
||||
- Specs: `specs/` subdirectories only
|
||||
- Keep the code style consistent with `specs/05-Engineering-Guidelines/`.
|
||||
- New modules MUST follow the workflow in `.agents/workflows/create-backend-module.md` or `.agents/workflows/create-frontend-page.md`.
|
||||
|
||||
### 4. Schema Changes
|
||||
|
||||
- **DO NOT** create or run TypeORM migration files.
|
||||
- Modify the schema directly in `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`.
|
||||
- Update `specs/03-Data-and-Storage/03-01-data-dictionary.md` if adding/changing columns.
|
||||
- Notify the user so they can apply the SQL change to the live database manually.
|
||||
|
||||
---
|
||||
@@ -1,15 +1,38 @@
|
||||
---
|
||||
trigger: always_on
|
||||
description: Control which shell commands the agent may run automatically.
|
||||
allowAuto: ["pnpm test:watch", "pnpm test:debug", "pnpm test:e2e", "git status"]
|
||||
denyAuto: ["rm -rf", "Remove-Item", "git push --force", "curl | bash"]
|
||||
allowAuto:
|
||||
- 'pnpm test:watch'
|
||||
- 'pnpm test:debug'
|
||||
- 'pnpm test:e2e'
|
||||
- 'git status'
|
||||
- 'git log --oneline'
|
||||
- 'git diff'
|
||||
- 'git branch'
|
||||
- 'tsc --noEmit'
|
||||
denyAuto:
|
||||
- 'rm -rf'
|
||||
- 'Remove-Item'
|
||||
- 'git push --force'
|
||||
- 'git reset --hard'
|
||||
- 'git clean -fd'
|
||||
- 'curl | bash'
|
||||
- 'docker compose down'
|
||||
- 'DROP TABLE'
|
||||
- 'TRUNCATE'
|
||||
- 'DELETE FROM'
|
||||
alwaysReview: true
|
||||
scopes: ["backend/src/**", "backend/test/**", "frontend/app/**"]
|
||||
scopes:
|
||||
- 'backend/src/**'
|
||||
- 'backend/test/**'
|
||||
- 'frontend/app/**'
|
||||
---
|
||||
|
||||
# Execution Rules
|
||||
|
||||
- Only auto-execute commands that are explicitly listed in `allowAuto`.
|
||||
- Commands in denyAuto must always be blocked, even if manually requested.
|
||||
- All shell operations that create, modify, or delete files in `backend/src/` or `backend/test/` or `frontend/app/` require human review.
|
||||
- Alert if environment variables related to DB connection or secrets would be displayed or logged.
|
||||
- Commands in `denyAuto` must always be blocked, even if manually requested.
|
||||
- All shell operations that create, modify, or delete files in `backend/src/`, `backend/test/`, or `frontend/app/` require human review.
|
||||
- Alert before running any SQL that modifies data (INSERT/UPDATE/DELETE/DROP/TRUNCATE).
|
||||
- Alert if environment variables related to DB connection or secrets (DATABASE_URL, JWT_SECRET, passwords) would be displayed or logged.
|
||||
- Never auto-execute commands that expose sensitive credentials via MCP tools or shell output.
|
||||
|
||||
206
.agents/README.md
Normal file
206
.agents/README.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# 🚀 Spec-Kit: Antigravity Skills & Workflows
|
||||
|
||||
> **The Event Horizon of Software Quality.**
|
||||
> *Adapted for Google Antigravity IDE from [github/spec-kit](https://github.com/github/spec-kit).*
|
||||
> *Version: 1.1.0*
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Overview
|
||||
|
||||
Welcome to the **Antigravity Edition** of Spec-Kit. This system is architected to empower your AI pair programmer (Antigravity) to drive the entire Software Development Life Cycle (SDLC) using two powerful mechanisms: **Workflows** and **Skills**.
|
||||
|
||||
### 🔄 Dual-Mode Intelligence
|
||||
In this edition, Spec-Kit commands have been split into two interactive layers:
|
||||
|
||||
1. **Workflows (`/command`)**: High-level orchestrations that guide the agent through a series of logical steps. **The easiest way to run a skill is by typing its corresponding workflow command.**
|
||||
2. **Skills (`@speckit.name`)**: Packaged agentic capabilities. Mentions of a skill give the agent immediate context and autonomous "know-how" to execute the specific toolset associated with that phase.
|
||||
|
||||
> **To understand the power of Skills in Antigravity, read the docs here:**
|
||||
> [https://antigravity.google/docs/skills](https://antigravity.google/docs/skills)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Installation
|
||||
|
||||
To enable these agent capabilities in your project:
|
||||
|
||||
1. **Add the folder**: Drop the `.agent/` folder into the root of your project workspace.
|
||||
2. **That's it!** Antigravity automatically detects the `.agent/skills` and `.agent/workflows` directories. It will instantly gain the ability to perform Spec-Driven Development.
|
||||
|
||||
> **💡 Compatibility Note:** This toolkit is fully compatible with **Claude Code**. To use it with Claude, simply rename the `.agent` folder to `.claude`. The skills and workflows will function identically.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ The Architecture
|
||||
|
||||
The toolkit is organized into modular components that provide both the logic (Scripts) and the structure (Templates) for the agent.
|
||||
|
||||
```text
|
||||
.agent/
|
||||
├── skills/ # @ Mentions (Agent Intelligence)
|
||||
│ ├── speckit.analyze # Consistency Checker
|
||||
│ ├── speckit.checker # Static Analysis Aggregator
|
||||
│ ├── speckit.checklist # Requirements Validator
|
||||
│ ├── speckit.clarify # Ambiguity Resolver
|
||||
│ ├── speckit.constitution # Governance Manager
|
||||
│ ├── speckit.diff # Artifact Comparator
|
||||
│ ├── speckit.implement # Code Builder (Anti-Regression)
|
||||
│ ├── speckit.migrate # Legacy Code Migrator
|
||||
│ ├── speckit.plan # Technical Planner
|
||||
│ ├── speckit.quizme # Logic Challenger (Red Team)
|
||||
│ ├── speckit.reviewer # Code Reviewer
|
||||
│ ├── speckit.specify # Feature Definer
|
||||
│ ├── speckit.status # Progress Dashboard
|
||||
│ ├── speckit.tasks # Task Breaker
|
||||
│ ├── speckit.taskstoissues# Issue Tracker Syncer
|
||||
│ ├── speckit.tester # Test Runner & Coverage
|
||||
│ └── speckit.validate # Implementation Validator
|
||||
│
|
||||
├── workflows/ # / Slash Commands (Orchestration)
|
||||
│ ├── 00-speckit.all.md # Full Pipeline
|
||||
│ ├── 01-speckit.constitution.md # Governance
|
||||
│ ├── 02-speckit.specify.md # Feature Spec
|
||||
│ ├── ... (Numbered 00-11)
|
||||
│ ├── speckit.prepare.md # Prep Pipeline
|
||||
│ └── util-speckit.*.md # Utilities
|
||||
│
|
||||
└── scripts/ # Shared Bash Core (Kinetic logic)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Mapping: Commands to Capabilities
|
||||
|
||||
| Phase | Workflow Trigger | Antigravity Skill | Role |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Pipeline** | `/00-speckit.all` | N/A | Runs the full SDLC pipeline. |
|
||||
| **Governance** | `/01-speckit.constitution` | `@speckit.constitution` | Establishes project rules & principles. |
|
||||
| **Definition** | `/02-speckit.specify` | `@speckit.specify` | Drafts structured `spec.md`. |
|
||||
| **Ambiguity** | `/03-speckit.clarify` | `@speckit.clarify` | Resolves gaps post-spec. |
|
||||
| **Architecture** | `/04-speckit.plan` | `@speckit.plan` | Generates technical `plan.md`. |
|
||||
| **Decomposition** | `/05-speckit.tasks` | `@speckit.tasks` | Breaks plans into atomic tasks. |
|
||||
| **Consistency** | `/06-speckit.analyze` | `@speckit.analyze` | Cross-checks Spec vs Plan vs Tasks. |
|
||||
| **Execution** | `/07-speckit.implement` | `@speckit.implement` | Builds implementation with safety protocols. |
|
||||
| **Quality** | `/08-speckit.checker` | `@speckit.checker` | Runs static analysis (Linting, Security, Types). |
|
||||
| **Testing** | `/09-speckit.tester` | `@speckit.tester` | Runs test suite & reports coverage. |
|
||||
| **Review** | `/10-speckit.reviewer` | `@speckit.reviewer` | Performs code review (Logic, Perf, Style). |
|
||||
| **Validation** | `/11-speckit.validate` | `@speckit.validate` | Verifies implementation matches Spec requirements. |
|
||||
| **Preparation** | `/speckit.prepare` | N/A | Runs Specify -> Analyze sequence. |
|
||||
| **Checklist** | `/util-speckit.checklist` | `@speckit.checklist` | Generates feature checklists. |
|
||||
| **Diff** | `/util-speckit.diff` | `@speckit.diff` | Compares artifact versions. |
|
||||
| **Migration** | `/util-speckit.migrate` | `@speckit.migrate` | Port existing code to Spec-Kit. |
|
||||
| **Red Team** | `/util-speckit.quizme` | `@speckit.quizme` | Challenges logical flaws. |
|
||||
| **Status** | `/util-speckit.status` | `@speckit.status` | Shows feature completion status. |
|
||||
| **Tracking** | `/util-speckit.taskstoissues`| `@speckit.taskstoissues`| Syncs tasks to GitHub/Jira/etc. |
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ The Quality Assurance Pipeline
|
||||
|
||||
The following skills are designed to work together as a comprehensive defense against regression and poor quality. Run them in this order:
|
||||
|
||||
| Step | Skill | Core Question | Focus |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **1. Checker** | `@speckit.checker` | *"Is the code compliant?"* | **Syntax & Security**. Runs compilation, linting (ESLint/GolangCI), and vulnerability scans (npm audit/govulncheck). Catches low-level errors first. |
|
||||
| **2. Tester** | `@speckit.tester` | *"Does it work?"* | **Functionality**. Executes your test suite (Jest/Pytest/Go Test) to ensure logic performs as expected and tests pass. |
|
||||
| **3. Reviewer** | `@speckit.reviewer` | *"Is the code written well?"* | **Quality & Maintainability**. Analyzes code structure for complexity, performance bottlenecks, and best practices, acting as a senior peer reviewer. |
|
||||
| **4. Validate** | `@speckit.validate` | *"Did we build the right thing?"* | **Requirements**. Semantically compares the implementation against the defined `spec.md` and `plan.md` to ensure all feature requirements are met. |
|
||||
|
||||
> **🤖 Power User Tip:** You can amplify this pipeline by creating a custom **Claude Code (MCP) Server** or subagent that delegates heavy reasoning to **Gemini Pro 3** via the `gemini` CLI.
|
||||
>
|
||||
> * **Use Case:** Bind the `@speckit.validate` and `@speckit.reviewer` steps to Gemini Pro 3.
|
||||
> * **Benefit:** Gemini's 1M+ token context and reasoning capabilities excel at analyzing the full project context against the Spec, finding subtle logical flaws that smaller models miss.
|
||||
> * **How:** Create a wrapper script `scripts/gemini-reviewer.sh` that pipes the `tasks.md` and codebase to `gemini chat`, then expose this as a tool to Claude.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ The Design & Management Pipeline
|
||||
|
||||
These workflows function as the "Control Plane" of the project, managing everything from idea inception to status tracking.
|
||||
|
||||
| Step | Workflow | Core Question | Focus |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **1. Preparation** | `/speckit.prepare` | *"Are we ready?"* | **The Macro-Workflow**. Runs Skills 02–06 (Specify $\to$ Clarify $\to$ Plan $\to$ Tasks $\to$ Analyze) in one sequence to go from "Idea" to "Ready to Code". |
|
||||
| **2. Migration** | `/util-speckit.migrate` | *"Can we import?"* | **Onboarding**. Reverse-engineers existing code into `spec.md`, `plan.md`, and `tasks.md`. |
|
||||
| **3. Red Team** | `/util-speckit.quizme` | *"What did we miss?"* | **Hardening**. Socratic questioning to find logical gaps in your specification before you plan. |
|
||||
| **4. Export** | `/util-speckit.taskstoissues` | *"Who does what?"* | **Handoff**. Converts your `tasks.md` into real GitHub/Jira issues for the team. |
|
||||
| **5. Status** | `/util-speckit.status` | *"Are we there yet?"* | **Tracking**. Scans all artifacts to report feature completion percentage. |
|
||||
| **6. Utilities** | `/util-speckit.diff` <br> `/util-speckit.checklist` | *"What changed?"* | **Support**. View artifact diffs or generate quick acceptance checklists. |
|
||||
|
||||
### 🔄 The Design Sequence
|
||||
|
||||
**Stage 1: Inception**
|
||||
* *Legacy Project?* $\to$ Run **`/util-speckit.migrate`**.
|
||||
* *New Feature?* $\to$ Run **`/speckit.prepare`**.
|
||||
|
||||
**Stage 2: Hardening**
|
||||
* Run **`/util-speckit.quizme`** to catch edge cases.
|
||||
* Run **`/speckit.prepare`** again to regenerate the Plan based on restricted specs.
|
||||
|
||||
**Stage 3: Handoff**
|
||||
* Run **`/util-speckit.taskstoissues`** to sync with your board.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Getting Started in Antigravity
|
||||
|
||||
Once the `.agent` folder is present, you can talk to your agent as a partner. You can trigger a full process using a slash command or reference a specific capability using a skill mention.
|
||||
|
||||
**Example Conversation:**
|
||||
|
||||
> **Developer**: "**/02-speckit.specify** Add a real-time notification system using WebSockets."
|
||||
>
|
||||
> **Antigravity**: "Understood. Executing the **@speckit.specify** skill. Creating feature branch `005-notifications` and drafting the initial specification..."
|
||||
> *(Antigravity creates branch, drafts spec.md)*
|
||||
>
|
||||
> **Antigravity**: "Specification ready. I've identified some ambiguity in the reconnection strategy. Should I use **@speckit.clarify** to resolve this?"
|
||||
>
|
||||
> **Developer**: "Yes, use **@speckit.clarify**."
|
||||
> *(Antigravity executes the skill logic, interviewing the developer and updating the spec)*
|
||||
>
|
||||
> **Antigravity**: "The spec is now robust. I'm ready to trigger **/04-speckit.plan** and **/05-speckit.tasks** to prepare for implementation."
|
||||
|
||||
---
|
||||
|
||||
## 🏆 Best Practices for Antigravity
|
||||
|
||||
To get the most out of this system, follow these **Spec-Driven Development (SDD)** rules:
|
||||
|
||||
### 1. The Constitution is King 👑
|
||||
**Never skip `/01-speckit.constitution`.**
|
||||
* This file is the "Context Window Anchor" for the AI.
|
||||
* It prevents hallucinations about tech stack (e.g., "Don't use jQuery" or "Always use TypeScript strict mode").
|
||||
* **Tip:** If Antigravity makes a style mistake, don't just fix the code—update the Constitution so it never happens again.
|
||||
|
||||
### 2. The Layered Defense 🛡️
|
||||
Don't rush to code. The workflow exists to catch errors *cheaply* before they become expensive bugs.
|
||||
* **Ambiguity Layer**: `/03-speckit.clarify` catches misunderstandings.
|
||||
* **Logic Layer**: `/util-speckit.quizme` catches edge cases.
|
||||
* **Consistency Layer**: `/06-speckit.analyze` catches gaps between Spec and Plan.
|
||||
|
||||
### 3. The 15-Minute Rule ⏱️
|
||||
When generating `tasks.md` (Skill 05), ensure tasks are **atomic**.
|
||||
* **Bad Task**: "Implement User Auth" (Too big, AI will get lost).
|
||||
* **Good Task**: "Create `User` Mongoose schema with email validation" (Perfect).
|
||||
* **Rule of Thumb**: If a task takes Antigravity more than 3 tool calls to finish, it's too big. Break it down.
|
||||
|
||||
### 4. "Refine, Don't Rewind" ⏩
|
||||
If you change your mind mid-project:
|
||||
1. Don't just edit the code.
|
||||
2. Edit the `spec.md` to reflect the new requirement.
|
||||
3. Run `/util-speckit.diff` to see the drift.
|
||||
4. This keeps your documentation alive and truthful.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Adaptation Notes
|
||||
|
||||
* **Skill-Based Autonomy**: Mentions like `@speckit.plan` trigger the agent's internalized understanding of how to perform that role.
|
||||
* **Shared Script Core**: All logic resides in `.agent/scripts/bash` for consistent file and git operations.
|
||||
* **Agent-Native**: Designed to be invoked via Antigravity tool calls and reasoning rather than just terminal strings.
|
||||
|
||||
---
|
||||
*Built with logic from [Spec-Kit](https://github.com/github/spec-kit). Powered by Antigravity.*
|
||||
166
.agents/scripts/bash/check-prerequisites.sh
Normal file
166
.agents/scripts/bash/check-prerequisites.sh
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Consolidated prerequisite checking script
|
||||
#
|
||||
# This script provides unified prerequisite checking for Spec-Driven Development workflow.
|
||||
# It replaces the functionality previously spread across multiple scripts.
|
||||
#
|
||||
# Usage: ./check-prerequisites.sh [OPTIONS]
|
||||
#
|
||||
# OPTIONS:
|
||||
# --json Output in JSON format
|
||||
# --require-tasks Require tasks.md to exist (for implementation phase)
|
||||
# --include-tasks Include tasks.md in AVAILABLE_DOCS list
|
||||
# --paths-only Only output path variables (no validation)
|
||||
# --help, -h Show help message
|
||||
#
|
||||
# OUTPUTS:
|
||||
# JSON mode: {"FEATURE_DIR":"...", "AVAILABLE_DOCS":["..."]}
|
||||
# Text mode: FEATURE_DIR:... \n AVAILABLE_DOCS: \n ✓/✗ file.md
|
||||
# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... etc.
|
||||
|
||||
set -e
|
||||
|
||||
# Parse command line arguments
|
||||
JSON_MODE=false
|
||||
REQUIRE_TASKS=false
|
||||
INCLUDE_TASKS=false
|
||||
PATHS_ONLY=false
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--json)
|
||||
JSON_MODE=true
|
||||
;;
|
||||
--require-tasks)
|
||||
REQUIRE_TASKS=true
|
||||
;;
|
||||
--include-tasks)
|
||||
INCLUDE_TASKS=true
|
||||
;;
|
||||
--paths-only)
|
||||
PATHS_ONLY=true
|
||||
;;
|
||||
--help|-h)
|
||||
cat << 'EOF'
|
||||
Usage: check-prerequisites.sh [OPTIONS]
|
||||
|
||||
Consolidated prerequisite checking for Spec-Driven Development workflow.
|
||||
|
||||
OPTIONS:
|
||||
--json Output in JSON format
|
||||
--require-tasks Require tasks.md to exist (for implementation phase)
|
||||
--include-tasks Include tasks.md in AVAILABLE_DOCS list
|
||||
--paths-only Only output path variables (no prerequisite validation)
|
||||
--help, -h Show this help message
|
||||
|
||||
EXAMPLES:
|
||||
# Check task prerequisites (plan.md required)
|
||||
./check-prerequisites.sh --json
|
||||
|
||||
# Check implementation prerequisites (plan.md + tasks.md required)
|
||||
./check-prerequisites.sh --json --require-tasks --include-tasks
|
||||
|
||||
# Get feature paths only (no validation)
|
||||
./check-prerequisites.sh --paths-only
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown option '$arg'. Use --help for usage information." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Source common functions
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
# Get feature paths and validate branch
|
||||
eval $(get_feature_paths)
|
||||
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1
|
||||
|
||||
# If paths-only mode, output paths and exit (support JSON + paths-only combined)
|
||||
if $PATHS_ONLY; then
|
||||
if $JSON_MODE; then
|
||||
# Minimal JSON paths payload (no validation performed)
|
||||
printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \
|
||||
"$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS"
|
||||
else
|
||||
echo "REPO_ROOT: $REPO_ROOT"
|
||||
echo "BRANCH: $CURRENT_BRANCH"
|
||||
echo "FEATURE_DIR: $FEATURE_DIR"
|
||||
echo "FEATURE_SPEC: $FEATURE_SPEC"
|
||||
echo "IMPL_PLAN: $IMPL_PLAN"
|
||||
echo "TASKS: $TASKS"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate required directories and files
|
||||
if [[ ! -d "$FEATURE_DIR" ]]; then
|
||||
echo "ERROR: Feature directory not found: $FEATURE_DIR" >&2
|
||||
echo "Run /speckit.specify first to create the feature structure." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$IMPL_PLAN" ]]; then
|
||||
echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
|
||||
echo "Run /speckit.plan first to create the implementation plan." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for tasks.md if required
|
||||
if $REQUIRE_TASKS && [[ ! -f "$TASKS" ]]; then
|
||||
echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2
|
||||
echo "Run /speckit.tasks first to create the task list." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build list of available documents
|
||||
docs=()
|
||||
|
||||
# Always check these optional docs
|
||||
[[ -f "$RESEARCH" ]] && docs+=("research.md")
|
||||
[[ -f "$DATA_MODEL" ]] && docs+=("data-model.md")
|
||||
|
||||
# Check contracts directory (only if it exists and has files)
|
||||
if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then
|
||||
docs+=("contracts/")
|
||||
fi
|
||||
|
||||
[[ -f "$QUICKSTART" ]] && docs+=("quickstart.md")
|
||||
|
||||
# Include tasks.md if requested and it exists
|
||||
if $INCLUDE_TASKS && [[ -f "$TASKS" ]]; then
|
||||
docs+=("tasks.md")
|
||||
fi
|
||||
|
||||
# Output results
|
||||
if $JSON_MODE; then
|
||||
# Build JSON array of documents
|
||||
if [[ ${#docs[@]} -eq 0 ]]; then
|
||||
json_docs="[]"
|
||||
else
|
||||
json_docs=$(printf '"%s",' "${docs[@]}")
|
||||
json_docs="[${json_docs%,}]"
|
||||
fi
|
||||
|
||||
printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$FEATURE_DIR" "$json_docs"
|
||||
else
|
||||
# Text output
|
||||
echo "FEATURE_DIR:$FEATURE_DIR"
|
||||
echo "AVAILABLE_DOCS:"
|
||||
|
||||
# Show status of each potential document
|
||||
check_file "$RESEARCH" "research.md"
|
||||
check_file "$DATA_MODEL" "data-model.md"
|
||||
check_dir "$CONTRACTS_DIR" "contracts/"
|
||||
check_file "$QUICKSTART" "quickstart.md"
|
||||
|
||||
if $INCLUDE_TASKS; then
|
||||
check_file "$TASKS" "tasks.md"
|
||||
fi
|
||||
fi
|
||||
156
.agents/scripts/bash/common.sh
Normal file
156
.agents/scripts/bash/common.sh
Normal file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common functions and variables for all scripts
|
||||
|
||||
# Get repository root, with fallback for non-git repositories
|
||||
get_repo_root() {
|
||||
if git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
git rev-parse --show-toplevel
|
||||
else
|
||||
# Fall back to script location for non-git repos
|
||||
local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
(cd "$script_dir/../../.." && pwd)
|
||||
fi
|
||||
}
|
||||
|
||||
# Get current branch, with fallback for non-git repositories
|
||||
get_current_branch() {
|
||||
# First check if SPECIFY_FEATURE environment variable is set
|
||||
if [[ -n "${SPECIFY_FEATURE:-}" ]]; then
|
||||
echo "$SPECIFY_FEATURE"
|
||||
return
|
||||
fi
|
||||
|
||||
# Then check git if available
|
||||
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
return
|
||||
fi
|
||||
|
||||
# For non-git repos, try to find the latest feature directory
|
||||
local repo_root=$(get_repo_root)
|
||||
local specs_dir="$repo_root/specs"
|
||||
|
||||
if [[ -d "$specs_dir" ]]; then
|
||||
local latest_feature=""
|
||||
local highest=0
|
||||
|
||||
for dir in "$specs_dir"/*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
local dirname=$(basename "$dir")
|
||||
if [[ "$dirname" =~ ^([0-9]{3})- ]]; then
|
||||
local number=${BASH_REMATCH[1]}
|
||||
number=$((10#$number))
|
||||
if [[ "$number" -gt "$highest" ]]; then
|
||||
highest=$number
|
||||
latest_feature=$dirname
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$latest_feature" ]]; then
|
||||
echo "$latest_feature"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "main" # Final fallback
|
||||
}
|
||||
|
||||
# Check if we have git available
|
||||
has_git() {
|
||||
git rev-parse --show-toplevel >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_feature_branch() {
|
||||
local branch="$1"
|
||||
local has_git_repo="$2"
|
||||
|
||||
# For non-git repos, we can't enforce branch naming but still provide output
|
||||
if [[ "$has_git_repo" != "true" ]]; then
|
||||
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then
|
||||
echo "ERROR: Not on a feature branch. Current branch: $branch" >&2
|
||||
echo "Feature branches should be named like: 001-feature-name" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
get_feature_dir() { echo "$1/specs/$2"; }
|
||||
|
||||
# Find feature directory by numeric prefix instead of exact branch match
|
||||
# This allows multiple branches to work on the same spec (e.g., 004-fix-bug, 004-add-feature)
|
||||
find_feature_dir_by_prefix() {
|
||||
local repo_root="$1"
|
||||
local branch_name="$2"
|
||||
local specs_dir="$repo_root/specs"
|
||||
|
||||
# Extract numeric prefix from branch (e.g., "004" from "004-whatever")
|
||||
if [[ ! "$branch_name" =~ ^([0-9]{3})- ]]; then
|
||||
# If branch doesn't have numeric prefix, fall back to exact match
|
||||
echo "$specs_dir/$branch_name"
|
||||
return
|
||||
fi
|
||||
|
||||
local prefix="${BASH_REMATCH[1]}"
|
||||
|
||||
# Search for directories in specs/ that start with this prefix
|
||||
local matches=()
|
||||
if [[ -d "$specs_dir" ]]; then
|
||||
for dir in "$specs_dir"/"$prefix"-*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
matches+=("$(basename "$dir")")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Handle results
|
||||
if [[ ${#matches[@]} -eq 0 ]]; then
|
||||
# No match found - return the branch name path (will fail later with clear error)
|
||||
echo "$specs_dir/$branch_name"
|
||||
elif [[ ${#matches[@]} -eq 1 ]]; then
|
||||
# Exactly one match - perfect!
|
||||
echo "$specs_dir/${matches[0]}"
|
||||
else
|
||||
# Multiple matches - this shouldn't happen with proper naming convention
|
||||
echo "ERROR: Multiple spec directories found with prefix '$prefix': ${matches[*]}" >&2
|
||||
echo "Please ensure only one spec directory exists per numeric prefix." >&2
|
||||
echo "$specs_dir/$branch_name" # Return something to avoid breaking the script
|
||||
fi
|
||||
}
|
||||
|
||||
get_feature_paths() {
|
||||
local repo_root=$(get_repo_root)
|
||||
local current_branch=$(get_current_branch)
|
||||
local has_git_repo="false"
|
||||
|
||||
if has_git; then
|
||||
has_git_repo="true"
|
||||
fi
|
||||
|
||||
# Use prefix-based lookup to support multiple branches per spec
|
||||
local feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch")
|
||||
|
||||
cat <<EOF
|
||||
REPO_ROOT='$repo_root'
|
||||
CURRENT_BRANCH='$current_branch'
|
||||
HAS_GIT='$has_git_repo'
|
||||
FEATURE_DIR='$feature_dir'
|
||||
FEATURE_SPEC='$feature_dir/spec.md'
|
||||
IMPL_PLAN='$feature_dir/plan.md'
|
||||
TASKS='$feature_dir/tasks.md'
|
||||
RESEARCH='$feature_dir/research.md'
|
||||
DATA_MODEL='$feature_dir/data-model.md'
|
||||
QUICKSTART='$feature_dir/quickstart.md'
|
||||
CONTRACTS_DIR='$feature_dir/contracts'
|
||||
EOF
|
||||
}
|
||||
|
||||
check_file() { [[ -f "$1" ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
||||
check_dir() { [[ -d "$1" && -n $(ls -A "$1" 2>/dev/null) ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
||||
|
||||
297
.agents/scripts/bash/create-new-feature.sh
Normal file
297
.agents/scripts/bash/create-new-feature.sh
Normal file
@@ -0,0 +1,297 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
JSON_MODE=false
|
||||
SHORT_NAME=""
|
||||
BRANCH_NUMBER=""
|
||||
ARGS=()
|
||||
i=1
|
||||
while [ $i -le $# ]; do
|
||||
arg="${!i}"
|
||||
case "$arg" in
|
||||
--json)
|
||||
JSON_MODE=true
|
||||
;;
|
||||
--short-name)
|
||||
if [ $((i + 1)) -gt $# ]; then
|
||||
echo 'Error: --short-name requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
i=$((i + 1))
|
||||
next_arg="${!i}"
|
||||
# Check if the next argument is another option (starts with --)
|
||||
if [[ "$next_arg" == --* ]]; then
|
||||
echo 'Error: --short-name requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
SHORT_NAME="$next_arg"
|
||||
;;
|
||||
--number)
|
||||
if [ $((i + 1)) -gt $# ]; then
|
||||
echo 'Error: --number requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
i=$((i + 1))
|
||||
next_arg="${!i}"
|
||||
if [[ "$next_arg" == --* ]]; then
|
||||
echo 'Error: --number requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
BRANCH_NUMBER="$next_arg"
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --json Output in JSON format"
|
||||
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
|
||||
echo " --number N Specify branch number manually (overrides auto-detection)"
|
||||
echo " --help, -h Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 'Add user authentication system' --short-name 'user-auth'"
|
||||
echo " $0 'Implement OAuth2 integration for API' --number 5"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
ARGS+=("$arg")
|
||||
;;
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
FEATURE_DESCRIPTION="${ARGS[*]}"
|
||||
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
||||
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to find the repository root by searching for existing project markers
|
||||
find_repo_root() {
|
||||
local dir="$1"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -d "$dir/.git" ] || [ -d "$dir/.specify" ]; then
|
||||
echo "$dir"
|
||||
return 0
|
||||
fi
|
||||
dir="$(dirname "$dir")"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to get highest number from specs directory
|
||||
get_highest_from_specs() {
|
||||
local specs_dir="$1"
|
||||
local highest=0
|
||||
|
||||
if [ -d "$specs_dir" ]; then
|
||||
for dir in "$specs_dir"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
dirname=$(basename "$dir")
|
||||
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$highest" ]; then
|
||||
highest=$number
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$highest"
|
||||
}
|
||||
|
||||
# Function to get highest number from git branches
|
||||
get_highest_from_branches() {
|
||||
local highest=0
|
||||
|
||||
# Get all branches (local and remote)
|
||||
branches=$(git branch -a 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$branches" ]; then
|
||||
while IFS= read -r branch; do
|
||||
# Clean branch name: remove leading markers and remote prefixes
|
||||
clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||')
|
||||
|
||||
# Extract feature number if branch matches pattern ###-*
|
||||
if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then
|
||||
number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0")
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$highest" ]; then
|
||||
highest=$number
|
||||
fi
|
||||
fi
|
||||
done <<< "$branches"
|
||||
fi
|
||||
|
||||
echo "$highest"
|
||||
}
|
||||
|
||||
# Function to check existing branches (local and remote) and return next available number
|
||||
check_existing_branches() {
|
||||
local specs_dir="$1"
|
||||
|
||||
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
|
||||
git fetch --all --prune 2>/dev/null || true
|
||||
|
||||
# Get highest number from ALL branches (not just matching short name)
|
||||
local highest_branch=$(get_highest_from_branches)
|
||||
|
||||
# Get highest number from ALL specs (not just matching short name)
|
||||
local highest_spec=$(get_highest_from_specs "$specs_dir")
|
||||
|
||||
# Take the maximum of both
|
||||
local max_num=$highest_branch
|
||||
if [ "$highest_spec" -gt "$max_num" ]; then
|
||||
max_num=$highest_spec
|
||||
fi
|
||||
|
||||
# Return next number
|
||||
echo $((max_num + 1))
|
||||
}
|
||||
|
||||
# Function to clean and format a branch name
|
||||
clean_branch_name() {
|
||||
local name="$1"
|
||||
echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//'
|
||||
}
|
||||
|
||||
# Resolve repository root. Prefer git information when available, but fall back
|
||||
# to searching for repository markers so the workflow still functions in repositories that
|
||||
# were initialised with --no-git.
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
HAS_GIT=true
|
||||
else
|
||||
REPO_ROOT="$(find_repo_root "$SCRIPT_DIR")"
|
||||
if [ -z "$REPO_ROOT" ]; then
|
||||
echo "Error: Could not determine repository root. Please run this script from within the repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
HAS_GIT=false
|
||||
fi
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
SPECS_DIR="$REPO_ROOT/specs"
|
||||
mkdir -p "$SPECS_DIR"
|
||||
|
||||
# Function to generate branch name with stop word filtering and length filtering
|
||||
generate_branch_name() {
|
||||
local description="$1"
|
||||
|
||||
# Common stop words to filter out
|
||||
local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
|
||||
|
||||
# Convert to lowercase and split into words
|
||||
local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
|
||||
|
||||
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
|
||||
local meaningful_words=()
|
||||
for word in $clean_name; do
|
||||
# Skip empty words
|
||||
[ -z "$word" ] && continue
|
||||
|
||||
# Keep words that are NOT stop words AND (length >= 3 OR are potential acronyms)
|
||||
if ! echo "$word" | grep -qiE "$stop_words"; then
|
||||
if [ ${#word} -ge 3 ]; then
|
||||
meaningful_words+=("$word")
|
||||
elif echo "$description" | grep -q "\b${word^^}\b"; then
|
||||
# Keep short words if they appear as uppercase in original (likely acronyms)
|
||||
meaningful_words+=("$word")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# If we have meaningful words, use first 3-4 of them
|
||||
if [ ${#meaningful_words[@]} -gt 0 ]; then
|
||||
local max_words=3
|
||||
if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
|
||||
|
||||
local result=""
|
||||
local count=0
|
||||
for word in "${meaningful_words[@]}"; do
|
||||
if [ $count -ge $max_words ]; then break; fi
|
||||
if [ -n "$result" ]; then result="$result-"; fi
|
||||
result="$result$word"
|
||||
count=$((count + 1))
|
||||
done
|
||||
echo "$result"
|
||||
else
|
||||
# Fallback to original logic if no meaningful words found
|
||||
local cleaned=$(clean_branch_name "$description")
|
||||
echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate branch name
|
||||
if [ -n "$SHORT_NAME" ]; then
|
||||
# Use provided short name, just clean it up
|
||||
BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME")
|
||||
else
|
||||
# Generate from description with smart filtering
|
||||
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
|
||||
fi
|
||||
|
||||
# Determine branch number
|
||||
if [ -z "$BRANCH_NUMBER" ]; then
|
||||
if [ "$HAS_GIT" = true ]; then
|
||||
# Check existing branches on remotes
|
||||
BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR")
|
||||
else
|
||||
# Fall back to local directory check
|
||||
HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
|
||||
BRANCH_NUMBER=$((HIGHEST + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
# Force base-10 interpretation to prevent octal conversion (e.g., 010 → 8 in octal, but should be 10 in decimal)
|
||||
FEATURE_NUM=$(printf "%03d" "$((10#$BRANCH_NUMBER))")
|
||||
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
|
||||
|
||||
# GitHub enforces a 244-byte limit on branch names
|
||||
# Validate and truncate if necessary
|
||||
MAX_BRANCH_LENGTH=244
|
||||
if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
|
||||
# Calculate how much we need to trim from suffix
|
||||
# Account for: feature number (3) + hyphen (1) = 4 chars
|
||||
MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - 4))
|
||||
|
||||
# Truncate suffix at word boundary if possible
|
||||
TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
|
||||
# Remove trailing hyphen if truncation created one
|
||||
TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
|
||||
|
||||
ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
|
||||
BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
|
||||
|
||||
>&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
|
||||
>&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
|
||||
>&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
|
||||
fi
|
||||
|
||||
if [ "$HAS_GIT" = true ]; then
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
else
|
||||
>&2 echo "[specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME"
|
||||
fi
|
||||
|
||||
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
|
||||
mkdir -p "$FEATURE_DIR"
|
||||
|
||||
TEMPLATE="$REPO_ROOT/.specify/templates/spec-template.md"
|
||||
SPEC_FILE="$FEATURE_DIR/spec.md"
|
||||
if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi
|
||||
|
||||
# Set the SPECIFY_FEATURE environment variable for the current session
|
||||
export SPECIFY_FEATURE="$BRANCH_NAME"
|
||||
|
||||
if $JSON_MODE; then
|
||||
printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM"
|
||||
else
|
||||
echo "BRANCH_NAME: $BRANCH_NAME"
|
||||
echo "SPEC_FILE: $SPEC_FILE"
|
||||
echo "FEATURE_NUM: $FEATURE_NUM"
|
||||
echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME"
|
||||
fi
|
||||
61
.agents/scripts/bash/setup-plan.sh
Normal file
61
.agents/scripts/bash/setup-plan.sh
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# Parse command line arguments
|
||||
JSON_MODE=false
|
||||
ARGS=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--json)
|
||||
JSON_MODE=true
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--json]"
|
||||
echo " --json Output results in JSON format"
|
||||
echo " --help Show this help message"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
ARGS+=("$arg")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get script directory and load common functions
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
# Get all paths and variables from common functions
|
||||
eval $(get_feature_paths)
|
||||
|
||||
# Check if we're on a proper feature branch (only for git repos)
|
||||
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1
|
||||
|
||||
# Ensure the feature directory exists
|
||||
mkdir -p "$FEATURE_DIR"
|
||||
|
||||
# Copy plan template if it exists
|
||||
TEMPLATE="$REPO_ROOT/.specify/templates/plan-template.md"
|
||||
if [[ -f "$TEMPLATE" ]]; then
|
||||
cp "$TEMPLATE" "$IMPL_PLAN"
|
||||
echo "Copied plan template to $IMPL_PLAN"
|
||||
else
|
||||
echo "Warning: Plan template not found at $TEMPLATE"
|
||||
# Create a basic plan file if template doesn't exist
|
||||
touch "$IMPL_PLAN"
|
||||
fi
|
||||
|
||||
# Output results
|
||||
if $JSON_MODE; then
|
||||
printf '{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s","HAS_GIT":"%s"}\n' \
|
||||
"$FEATURE_SPEC" "$IMPL_PLAN" "$FEATURE_DIR" "$CURRENT_BRANCH" "$HAS_GIT"
|
||||
else
|
||||
echo "FEATURE_SPEC: $FEATURE_SPEC"
|
||||
echo "IMPL_PLAN: $IMPL_PLAN"
|
||||
echo "SPECS_DIR: $FEATURE_DIR"
|
||||
echo "BRANCH: $CURRENT_BRANCH"
|
||||
echo "HAS_GIT: $HAS_GIT"
|
||||
fi
|
||||
|
||||
799
.agents/scripts/bash/update-agent-context.sh
Normal file
799
.agents/scripts/bash/update-agent-context.sh
Normal file
@@ -0,0 +1,799 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Update agent context files with information from plan.md
|
||||
#
|
||||
# This script maintains AI agent context files by parsing feature specifications
|
||||
# and updating agent-specific configuration files with project information.
|
||||
#
|
||||
# MAIN FUNCTIONS:
|
||||
# 1. Environment Validation
|
||||
# - Verifies git repository structure and branch information
|
||||
# - Checks for required plan.md files and templates
|
||||
# - Validates file permissions and accessibility
|
||||
#
|
||||
# 2. Plan Data Extraction
|
||||
# - Parses plan.md files to extract project metadata
|
||||
# - Identifies language/version, frameworks, databases, and project types
|
||||
# - Handles missing or incomplete specification data gracefully
|
||||
#
|
||||
# 3. Agent File Management
|
||||
# - Creates new agent context files from templates when needed
|
||||
# - Updates existing agent files with new project information
|
||||
# - Preserves manual additions and custom configurations
|
||||
# - Supports multiple AI agent formats and directory structures
|
||||
#
|
||||
# 4. Content Generation
|
||||
# - Generates language-specific build/test commands
|
||||
# - Creates appropriate project directory structures
|
||||
# - Updates technology stacks and recent changes sections
|
||||
# - Maintains consistent formatting and timestamps
|
||||
#
|
||||
# 5. Multi-Agent Support
|
||||
# - Handles agent-specific file paths and naming conventions
|
||||
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, or Amazon Q Developer CLI
|
||||
# - Can update single agents or all existing agent files
|
||||
# - Creates default Claude file if no agent files exist
|
||||
#
|
||||
# Usage: ./update-agent-context.sh [agent_type]
|
||||
# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|shai|q|bob|qoder
|
||||
# Leave empty to update all existing agent files
|
||||
|
||||
set -e
|
||||
|
||||
# Enable strict error handling
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
#==============================================================================
|
||||
# Configuration and Global Variables
|
||||
#==============================================================================
|
||||
|
||||
# Get script directory and load common functions
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
# Get all paths and variables from common functions
|
||||
eval $(get_feature_paths)
|
||||
|
||||
NEW_PLAN="$IMPL_PLAN" # Alias for compatibility with existing code
|
||||
AGENT_TYPE="${1:-}"
|
||||
|
||||
# Agent-specific file paths
|
||||
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"
|
||||
GEMINI_FILE="$REPO_ROOT/GEMINI.md"
|
||||
COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md"
|
||||
CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"
|
||||
QWEN_FILE="$REPO_ROOT/QWEN.md"
|
||||
AGENTS_FILE="$REPO_ROOT/AGENTS.md"
|
||||
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
|
||||
KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md"
|
||||
AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md"
|
||||
ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md"
|
||||
CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md"
|
||||
QODER_FILE="$REPO_ROOT/QODER.md"
|
||||
AMP_FILE="$REPO_ROOT/AGENTS.md"
|
||||
SHAI_FILE="$REPO_ROOT/SHAI.md"
|
||||
Q_FILE="$REPO_ROOT/AGENTS.md"
|
||||
BOB_FILE="$REPO_ROOT/AGENTS.md"
|
||||
|
||||
# Template file
|
||||
TEMPLATE_FILE="$REPO_ROOT/.specify/templates/agent-file-template.md"
|
||||
|
||||
# Global variables for parsed plan data
|
||||
NEW_LANG=""
|
||||
NEW_FRAMEWORK=""
|
||||
NEW_DB=""
|
||||
NEW_PROJECT_TYPE=""
|
||||
|
||||
#==============================================================================
|
||||
# Utility Functions
|
||||
#==============================================================================
|
||||
|
||||
log_info() {
|
||||
echo "INFO: $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo "✓ $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "ERROR: $1" >&2
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo "WARNING: $1" >&2
|
||||
}
|
||||
|
||||
# Cleanup function for temporary files
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
rm -f /tmp/agent_update_*_$$
|
||||
rm -f /tmp/manual_additions_$$
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Set up cleanup trap
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
#==============================================================================
|
||||
# Validation Functions
|
||||
#==============================================================================
|
||||
|
||||
validate_environment() {
|
||||
# Check if we have a current branch/feature (git or non-git)
|
||||
if [[ -z "$CURRENT_BRANCH" ]]; then
|
||||
log_error "Unable to determine current feature"
|
||||
if [[ "$HAS_GIT" == "true" ]]; then
|
||||
log_info "Make sure you're on a feature branch"
|
||||
else
|
||||
log_info "Set SPECIFY_FEATURE environment variable or create a feature first"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if plan.md exists
|
||||
if [[ ! -f "$NEW_PLAN" ]]; then
|
||||
log_error "No plan.md found at $NEW_PLAN"
|
||||
log_info "Make sure you're working on a feature with a corresponding spec directory"
|
||||
if [[ "$HAS_GIT" != "true" ]]; then
|
||||
log_info "Use: export SPECIFY_FEATURE=your-feature-name or create a new feature first"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if template exists (needed for new files)
|
||||
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||
log_warning "Template file not found at $TEMPLATE_FILE"
|
||||
log_warning "Creating new agent files will fail"
|
||||
fi
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Plan Parsing Functions
|
||||
#==============================================================================
|
||||
|
||||
extract_plan_field() {
|
||||
local field_pattern="$1"
|
||||
local plan_file="$2"
|
||||
|
||||
grep "^\*\*${field_pattern}\*\*: " "$plan_file" 2>/dev/null | \
|
||||
head -1 | \
|
||||
sed "s|^\*\*${field_pattern}\*\*: ||" | \
|
||||
sed 's/^[ \t]*//;s/[ \t]*$//' | \
|
||||
grep -v "NEEDS CLARIFICATION" | \
|
||||
grep -v "^N/A$" || echo ""
|
||||
}
|
||||
|
||||
parse_plan_data() {
|
||||
local plan_file="$1"
|
||||
|
||||
if [[ ! -f "$plan_file" ]]; then
|
||||
log_error "Plan file not found: $plan_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -r "$plan_file" ]]; then
|
||||
log_error "Plan file is not readable: $plan_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Parsing plan data from $plan_file"
|
||||
|
||||
NEW_LANG=$(extract_plan_field "Language/Version" "$plan_file")
|
||||
NEW_FRAMEWORK=$(extract_plan_field "Primary Dependencies" "$plan_file")
|
||||
NEW_DB=$(extract_plan_field "Storage" "$plan_file")
|
||||
NEW_PROJECT_TYPE=$(extract_plan_field "Project Type" "$plan_file")
|
||||
|
||||
# Log what we found
|
||||
if [[ -n "$NEW_LANG" ]]; then
|
||||
log_info "Found language: $NEW_LANG"
|
||||
else
|
||||
log_warning "No language information found in plan"
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_FRAMEWORK" ]]; then
|
||||
log_info "Found framework: $NEW_FRAMEWORK"
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
|
||||
log_info "Found database: $NEW_DB"
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_PROJECT_TYPE" ]]; then
|
||||
log_info "Found project type: $NEW_PROJECT_TYPE"
|
||||
fi
|
||||
}
|
||||
|
||||
format_technology_stack() {
|
||||
local lang="$1"
|
||||
local framework="$2"
|
||||
local parts=()
|
||||
|
||||
# Add non-empty parts
|
||||
[[ -n "$lang" && "$lang" != "NEEDS CLARIFICATION" ]] && parts+=("$lang")
|
||||
[[ -n "$framework" && "$framework" != "NEEDS CLARIFICATION" && "$framework" != "N/A" ]] && parts+=("$framework")
|
||||
|
||||
# Join with proper formatting
|
||||
if [[ ${#parts[@]} -eq 0 ]]; then
|
||||
echo ""
|
||||
elif [[ ${#parts[@]} -eq 1 ]]; then
|
||||
echo "${parts[0]}"
|
||||
else
|
||||
# Join multiple parts with " + "
|
||||
local result="${parts[0]}"
|
||||
for ((i=1; i<${#parts[@]}; i++)); do
|
||||
result="$result + ${parts[i]}"
|
||||
done
|
||||
echo "$result"
|
||||
fi
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Template and Content Generation Functions
|
||||
#==============================================================================
|
||||
|
||||
get_project_structure() {
|
||||
local project_type="$1"
|
||||
|
||||
if [[ "$project_type" == *"web"* ]]; then
|
||||
echo "backend/\\nfrontend/\\ntests/"
|
||||
else
|
||||
echo "src/\\ntests/"
|
||||
fi
|
||||
}
|
||||
|
||||
get_commands_for_language() {
|
||||
local lang="$1"
|
||||
|
||||
case "$lang" in
|
||||
*"Python"*)
|
||||
echo "cd src && pytest && ruff check ."
|
||||
;;
|
||||
*"Rust"*)
|
||||
echo "cargo test && cargo clippy"
|
||||
;;
|
||||
*"JavaScript"*|*"TypeScript"*)
|
||||
echo "npm test \\&\\& npm run lint"
|
||||
;;
|
||||
*)
|
||||
echo "# Add commands for $lang"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_language_conventions() {
|
||||
local lang="$1"
|
||||
echo "$lang: Follow standard conventions"
|
||||
}
|
||||
|
||||
create_new_agent_file() {
|
||||
local target_file="$1"
|
||||
local temp_file="$2"
|
||||
local project_name="$3"
|
||||
local current_date="$4"
|
||||
|
||||
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||
log_error "Template not found at $TEMPLATE_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -r "$TEMPLATE_FILE" ]]; then
|
||||
log_error "Template file is not readable: $TEMPLATE_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Creating new agent context file from template..."
|
||||
|
||||
if ! cp "$TEMPLATE_FILE" "$temp_file"; then
|
||||
log_error "Failed to copy template file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Replace template placeholders
|
||||
local project_structure
|
||||
project_structure=$(get_project_structure "$NEW_PROJECT_TYPE")
|
||||
|
||||
local commands
|
||||
commands=$(get_commands_for_language "$NEW_LANG")
|
||||
|
||||
local language_conventions
|
||||
language_conventions=$(get_language_conventions "$NEW_LANG")
|
||||
|
||||
# Perform substitutions with error checking using safer approach
|
||||
# Escape special characters for sed by using a different delimiter or escaping
|
||||
local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\[\.*^$()+{}|]/\\&/g')
|
||||
local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\[\.*^$()+{}|]/\\&/g')
|
||||
local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\[\.*^$()+{}|]/\\&/g')
|
||||
|
||||
# Build technology stack and recent change strings conditionally
|
||||
local tech_stack
|
||||
if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
|
||||
tech_stack="- $escaped_lang + $escaped_framework ($escaped_branch)"
|
||||
elif [[ -n "$escaped_lang" ]]; then
|
||||
tech_stack="- $escaped_lang ($escaped_branch)"
|
||||
elif [[ -n "$escaped_framework" ]]; then
|
||||
tech_stack="- $escaped_framework ($escaped_branch)"
|
||||
else
|
||||
tech_stack="- ($escaped_branch)"
|
||||
fi
|
||||
|
||||
local recent_change
|
||||
if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
|
||||
recent_change="- $escaped_branch: Added $escaped_lang + $escaped_framework"
|
||||
elif [[ -n "$escaped_lang" ]]; then
|
||||
recent_change="- $escaped_branch: Added $escaped_lang"
|
||||
elif [[ -n "$escaped_framework" ]]; then
|
||||
recent_change="- $escaped_branch: Added $escaped_framework"
|
||||
else
|
||||
recent_change="- $escaped_branch: Added"
|
||||
fi
|
||||
|
||||
local substitutions=(
|
||||
"s|\[PROJECT NAME\]|$project_name|"
|
||||
"s|\[DATE\]|$current_date|"
|
||||
"s|\[EXTRACTED FROM ALL PLAN.MD FILES\]|$tech_stack|"
|
||||
"s|\[ACTUAL STRUCTURE FROM PLANS\]|$project_structure|g"
|
||||
"s|\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]|$commands|"
|
||||
"s|\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]|$language_conventions|"
|
||||
"s|\[LAST 3 FEATURES AND WHAT THEY ADDED\]|$recent_change|"
|
||||
)
|
||||
|
||||
for substitution in "${substitutions[@]}"; do
|
||||
if ! sed -i.bak -e "$substitution" "$temp_file"; then
|
||||
log_error "Failed to perform substitution: $substitution"
|
||||
rm -f "$temp_file" "$temp_file.bak"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Convert \n sequences to actual newlines
|
||||
newline=$(printf '\n')
|
||||
sed -i.bak2 "s/\\\\n/${newline}/g" "$temp_file"
|
||||
|
||||
# Clean up backup files
|
||||
rm -f "$temp_file.bak" "$temp_file.bak2"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
update_existing_agent_file() {
|
||||
local target_file="$1"
|
||||
local current_date="$2"
|
||||
|
||||
log_info "Updating existing agent context file..."
|
||||
|
||||
# Use a single temporary file for atomic update
|
||||
local temp_file
|
||||
temp_file=$(mktemp) || {
|
||||
log_error "Failed to create temporary file"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Process the file in one pass
|
||||
local tech_stack=$(format_technology_stack "$NEW_LANG" "$NEW_FRAMEWORK")
|
||||
local new_tech_entries=()
|
||||
local new_change_entry=""
|
||||
|
||||
# Prepare new technology entries
|
||||
if [[ -n "$tech_stack" ]] && ! grep -q "$tech_stack" "$target_file"; then
|
||||
new_tech_entries+=("- $tech_stack ($CURRENT_BRANCH)")
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]] && ! grep -q "$NEW_DB" "$target_file"; then
|
||||
new_tech_entries+=("- $NEW_DB ($CURRENT_BRANCH)")
|
||||
fi
|
||||
|
||||
# Prepare new change entry
|
||||
if [[ -n "$tech_stack" ]]; then
|
||||
new_change_entry="- $CURRENT_BRANCH: Added $tech_stack"
|
||||
elif [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]]; then
|
||||
new_change_entry="- $CURRENT_BRANCH: Added $NEW_DB"
|
||||
fi
|
||||
|
||||
# Check if sections exist in the file
|
||||
local has_active_technologies=0
|
||||
local has_recent_changes=0
|
||||
|
||||
if grep -q "^## Active Technologies" "$target_file" 2>/dev/null; then
|
||||
has_active_technologies=1
|
||||
fi
|
||||
|
||||
if grep -q "^## Recent Changes" "$target_file" 2>/dev/null; then
|
||||
has_recent_changes=1
|
||||
fi
|
||||
|
||||
# Process file line by line
|
||||
local in_tech_section=false
|
||||
local in_changes_section=false
|
||||
local tech_entries_added=false
|
||||
local changes_entries_added=false
|
||||
local existing_changes_count=0
|
||||
local file_ended=false
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# Handle Active Technologies section
|
||||
if [[ "$line" == "## Active Technologies" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
in_tech_section=true
|
||||
continue
|
||||
elif [[ $in_tech_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
|
||||
# Add new tech entries before closing the section
|
||||
if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||
tech_entries_added=true
|
||||
fi
|
||||
echo "$line" >> "$temp_file"
|
||||
in_tech_section=false
|
||||
continue
|
||||
elif [[ $in_tech_section == true ]] && [[ -z "$line" ]]; then
|
||||
# Add new tech entries before empty line in tech section
|
||||
if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||
tech_entries_added=true
|
||||
fi
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Handle Recent Changes section
|
||||
if [[ "$line" == "## Recent Changes" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
# Add new change entry right after the heading
|
||||
if [[ -n "$new_change_entry" ]]; then
|
||||
echo "$new_change_entry" >> "$temp_file"
|
||||
fi
|
||||
in_changes_section=true
|
||||
changes_entries_added=true
|
||||
continue
|
||||
elif [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
in_changes_section=false
|
||||
continue
|
||||
elif [[ $in_changes_section == true ]] && [[ "$line" == "- "* ]]; then
|
||||
# Keep only first 2 existing changes
|
||||
if [[ $existing_changes_count -lt 2 ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
((existing_changes_count++))
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# Update timestamp
|
||||
if [[ "$line" =~ \*\*Last\ updated\*\*:.*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] ]]; then
|
||||
echo "$line" | sed "s/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/$current_date/" >> "$temp_file"
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$target_file"
|
||||
|
||||
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
||||
if [[ $in_tech_section == true ]] && [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||
tech_entries_added=true
|
||||
fi
|
||||
|
||||
# If sections don't exist, add them at the end of the file
|
||||
if [[ $has_active_technologies -eq 0 ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||
echo "" >> "$temp_file"
|
||||
echo "## Active Technologies" >> "$temp_file"
|
||||
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||
tech_entries_added=true
|
||||
fi
|
||||
|
||||
if [[ $has_recent_changes -eq 0 ]] && [[ -n "$new_change_entry" ]]; then
|
||||
echo "" >> "$temp_file"
|
||||
echo "## Recent Changes" >> "$temp_file"
|
||||
echo "$new_change_entry" >> "$temp_file"
|
||||
changes_entries_added=true
|
||||
fi
|
||||
|
||||
# Move temp file to target atomically
|
||||
if ! mv "$temp_file" "$target_file"; then
|
||||
log_error "Failed to update target file"
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
#==============================================================================
|
||||
# Main Agent File Update Function
|
||||
#==============================================================================
|
||||
|
||||
update_agent_file() {
|
||||
local target_file="$1"
|
||||
local agent_name="$2"
|
||||
|
||||
if [[ -z "$target_file" ]] || [[ -z "$agent_name" ]]; then
|
||||
log_error "update_agent_file requires target_file and agent_name parameters"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Updating $agent_name context file: $target_file"
|
||||
|
||||
local project_name
|
||||
project_name=$(basename "$REPO_ROOT")
|
||||
local current_date
|
||||
current_date=$(date +%Y-%m-%d)
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
local target_dir
|
||||
target_dir=$(dirname "$target_file")
|
||||
if [[ ! -d "$target_dir" ]]; then
|
||||
if ! mkdir -p "$target_dir"; then
|
||||
log_error "Failed to create directory: $target_dir"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -f "$target_file" ]]; then
|
||||
# Create new file from template
|
||||
local temp_file
|
||||
temp_file=$(mktemp) || {
|
||||
log_error "Failed to create temporary file"
|
||||
return 1
|
||||
}
|
||||
|
||||
if create_new_agent_file "$target_file" "$temp_file" "$project_name" "$current_date"; then
|
||||
if mv "$temp_file" "$target_file"; then
|
||||
log_success "Created new $agent_name context file"
|
||||
else
|
||||
log_error "Failed to move temporary file to $target_file"
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "Failed to create new agent file"
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Update existing file
|
||||
if [[ ! -r "$target_file" ]]; then
|
||||
log_error "Cannot read existing file: $target_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -w "$target_file" ]]; then
|
||||
log_error "Cannot write to existing file: $target_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if update_existing_agent_file "$target_file" "$current_date"; then
|
||||
log_success "Updated existing $agent_name context file"
|
||||
else
|
||||
log_error "Failed to update existing agent file"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Agent Selection and Processing
|
||||
#==============================================================================
|
||||
|
||||
update_specific_agent() {
|
||||
local agent_type="$1"
|
||||
|
||||
case "$agent_type" in
|
||||
claude)
|
||||
update_agent_file "$CLAUDE_FILE" "Claude Code"
|
||||
;;
|
||||
gemini)
|
||||
update_agent_file "$GEMINI_FILE" "Gemini CLI"
|
||||
;;
|
||||
copilot)
|
||||
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
|
||||
;;
|
||||
cursor-agent)
|
||||
update_agent_file "$CURSOR_FILE" "Cursor IDE"
|
||||
;;
|
||||
qwen)
|
||||
update_agent_file "$QWEN_FILE" "Qwen Code"
|
||||
;;
|
||||
opencode)
|
||||
update_agent_file "$AGENTS_FILE" "opencode"
|
||||
;;
|
||||
codex)
|
||||
update_agent_file "$AGENTS_FILE" "Codex CLI"
|
||||
;;
|
||||
windsurf)
|
||||
update_agent_file "$WINDSURF_FILE" "Windsurf"
|
||||
;;
|
||||
kilocode)
|
||||
update_agent_file "$KILOCODE_FILE" "Kilo Code"
|
||||
;;
|
||||
auggie)
|
||||
update_agent_file "$AUGGIE_FILE" "Auggie CLI"
|
||||
;;
|
||||
roo)
|
||||
update_agent_file "$ROO_FILE" "Roo Code"
|
||||
;;
|
||||
codebuddy)
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||
;;
|
||||
qoder)
|
||||
update_agent_file "$QODER_FILE" "Qoder CLI"
|
||||
;;
|
||||
amp)
|
||||
update_agent_file "$AMP_FILE" "Amp"
|
||||
;;
|
||||
shai)
|
||||
update_agent_file "$SHAI_FILE" "SHAI"
|
||||
;;
|
||||
q)
|
||||
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
||||
;;
|
||||
bob)
|
||||
update_agent_file "$BOB_FILE" "IBM Bob"
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown agent type '$agent_type'"
|
||||
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q|bob|qoder"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
update_all_existing_agents() {
|
||||
local found_agent=false
|
||||
|
||||
# Check each possible agent file and update if it exists
|
||||
if [[ -f "$CLAUDE_FILE" ]]; then
|
||||
update_agent_file "$CLAUDE_FILE" "Claude Code"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$GEMINI_FILE" ]]; then
|
||||
update_agent_file "$GEMINI_FILE" "Gemini CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$COPILOT_FILE" ]]; then
|
||||
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$CURSOR_FILE" ]]; then
|
||||
update_agent_file "$CURSOR_FILE" "Cursor IDE"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$QWEN_FILE" ]]; then
|
||||
update_agent_file "$QWEN_FILE" "Qwen Code"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$AGENTS_FILE" ]]; then
|
||||
update_agent_file "$AGENTS_FILE" "Codex/opencode"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$WINDSURF_FILE" ]]; then
|
||||
update_agent_file "$WINDSURF_FILE" "Windsurf"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$KILOCODE_FILE" ]]; then
|
||||
update_agent_file "$KILOCODE_FILE" "Kilo Code"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$AUGGIE_FILE" ]]; then
|
||||
update_agent_file "$AUGGIE_FILE" "Auggie CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$ROO_FILE" ]]; then
|
||||
update_agent_file "$ROO_FILE" "Roo Code"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$CODEBUDDY_FILE" ]]; then
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$SHAI_FILE" ]]; then
|
||||
update_agent_file "$SHAI_FILE" "SHAI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$QODER_FILE" ]]; then
|
||||
update_agent_file "$QODER_FILE" "Qoder CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$Q_FILE" ]]; then
|
||||
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
if [[ -f "$BOB_FILE" ]]; then
|
||||
update_agent_file "$BOB_FILE" "IBM Bob"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
# If no agent files exist, create a default Claude file
|
||||
if [[ "$found_agent" == false ]]; then
|
||||
log_info "No existing agent files found, creating default Claude file..."
|
||||
update_agent_file "$CLAUDE_FILE" "Claude Code"
|
||||
fi
|
||||
}
|
||||
print_summary() {
|
||||
echo
|
||||
log_info "Summary of changes:"
|
||||
|
||||
if [[ -n "$NEW_LANG" ]]; then
|
||||
echo " - Added language: $NEW_LANG"
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_FRAMEWORK" ]]; then
|
||||
echo " - Added framework: $NEW_FRAMEWORK"
|
||||
fi
|
||||
|
||||
if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
|
||||
echo " - Added database: $NEW_DB"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|shai|q|bob|qoder]"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Main Execution
|
||||
#==============================================================================
|
||||
|
||||
main() {
|
||||
# Validate environment before proceeding
|
||||
validate_environment
|
||||
|
||||
log_info "=== Updating agent context files for feature $CURRENT_BRANCH ==="
|
||||
|
||||
# Parse the plan file to extract project information
|
||||
if ! parse_plan_data "$NEW_PLAN"; then
|
||||
log_error "Failed to parse plan data"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Process based on agent type argument
|
||||
local success=true
|
||||
|
||||
if [[ -z "$AGENT_TYPE" ]]; then
|
||||
# No specific agent provided - update all existing agent files
|
||||
log_info "No agent specified, updating all existing agent files..."
|
||||
if ! update_all_existing_agents; then
|
||||
success=false
|
||||
fi
|
||||
else
|
||||
# Specific agent provided - update only that agent
|
||||
log_info "Updating specific agent: $AGENT_TYPE"
|
||||
if ! update_specific_agent "$AGENT_TYPE"; then
|
||||
success=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Print summary
|
||||
print_summary
|
||||
|
||||
if [[ "$success" == true ]]; then
|
||||
log_success "Agent context update completed successfully"
|
||||
exit 0
|
||||
else
|
||||
log_error "Agent context update completed with errors"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute main function if script is run directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
main "$@"
|
||||
fi
|
||||
|
||||
18
.agents/skills/VERSION
Normal file
18
.agents/skills/VERSION
Normal file
@@ -0,0 +1,18 @@
|
||||
# Speckit Skills Version
|
||||
|
||||
version: 1.1.0
|
||||
release_date: 2026-01-24
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.1.0 (2026-01-24)
|
||||
- New QA skills: tester, reviewer, checker
|
||||
- tester: Execute tests, measure coverage, report results
|
||||
- reviewer: Code review with severity levels and suggestions
|
||||
- checker: Static analysis aggregation (lint, types, security)
|
||||
|
||||
### 1.0.0 (2026-01-24)
|
||||
- Initial versioned release
|
||||
- Core skills: specify, clarify, plan, tasks, implement, analyze, checklist, constitution, quizme, taskstoissues
|
||||
- New skills: diff, validate, migrate, status
|
||||
- All workflows enhanced with error handling and relative paths
|
||||
@@ -1,8 +1,9 @@
|
||||
description = "Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.analyze
|
||||
description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.tasks
|
||||
---
|
||||
|
||||
## User Input
|
||||
@@ -13,8 +14,13 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Goal
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Consistency Analyst**. Your role is to identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. You act with strict adherence to the project constitution.
|
||||
|
||||
## Task
|
||||
|
||||
### Goal
|
||||
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/speckit.tasks` has successfully produced a complete `tasks.md`.
|
||||
|
||||
## Operating Constraints
|
||||
@@ -23,11 +29,11 @@ Identify inconsistencies, duplications, ambiguities, and underspecified items ac
|
||||
|
||||
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
|
||||
|
||||
## Execution Steps
|
||||
### Steps
|
||||
|
||||
### 1. Initialize Analysis Context
|
||||
|
||||
Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
|
||||
Run `../scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
|
||||
|
||||
- SPEC = FEATURE_DIR/spec.md
|
||||
- PLAN = FEATURE_DIR/plan.md
|
||||
@@ -185,4 +191,3 @@ Ask the user: "Would you like me to suggest concrete remediation edits for the t
|
||||
## Context
|
||||
|
||||
{{args}}
|
||||
"""
|
||||
154
.agents/skills/speckit.checker/SKILL.md
Normal file
154
.agents/skills/speckit.checker/SKILL.md
Normal file
@@ -0,0 +1,154 @@
|
||||
---
|
||||
name: speckit.checker
|
||||
description: Run static analysis tools and aggregate results.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Static Analyzer**. Your role is to run all applicable static analysis tools and provide a unified report of issues.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Auto-detect available tools, run them, and aggregate results into a prioritized report.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Detect Project Type and Tools**:
|
||||
```bash
|
||||
# Check for config files
|
||||
ls -la | grep -E "(package.json|pyproject.toml|go.mod|Cargo.toml|pom.xml)"
|
||||
|
||||
# Check for linter configs
|
||||
ls -la | grep -E "(eslint|prettier|pylint|golangci|rustfmt)"
|
||||
```
|
||||
|
||||
| Config | Tools to Run |
|
||||
|--------|-------------|
|
||||
| `package.json` | ESLint, TypeScript, npm audit |
|
||||
| `pyproject.toml` | Pylint/Ruff, mypy, bandit |
|
||||
| `go.mod` | golangci-lint, go vet |
|
||||
| `Cargo.toml` | clippy, cargo audit |
|
||||
| `pom.xml` | SpotBugs, PMD |
|
||||
|
||||
2. **Run Linting**:
|
||||
|
||||
| Stack | Command |
|
||||
|-------|---------|
|
||||
| Node/TS | `npx eslint . --format json 2>/dev/null` |
|
||||
| Python | `ruff check . --output-format json 2>/dev/null || pylint --output-format=json **/*.py` |
|
||||
| Go | `golangci-lint run --out-format json` |
|
||||
| Rust | `cargo clippy --message-format=json` |
|
||||
|
||||
3. **Run Type Checking**:
|
||||
|
||||
| Stack | Command |
|
||||
|-------|---------|
|
||||
| TypeScript | `npx tsc --noEmit 2>&1` |
|
||||
| Python | `mypy . --no-error-summary 2>&1` |
|
||||
| Go | `go build ./... 2>&1` (types are built-in) |
|
||||
|
||||
4. **Run Security Scanning**:
|
||||
|
||||
| Stack | Command |
|
||||
|-------|---------|
|
||||
| Node | `npm audit --json` |
|
||||
| Python | `bandit -r . -f json 2>/dev/null || safety check --json` |
|
||||
| Go | `govulncheck ./... 2>&1` |
|
||||
| Rust | `cargo audit --json` |
|
||||
|
||||
5. **Aggregate and Prioritize**:
|
||||
|
||||
| Category | Priority |
|
||||
|----------|----------|
|
||||
| Security (Critical/High) | 🔴 P1 |
|
||||
| Type Errors | 🟠 P2 |
|
||||
| Security (Medium/Low) | 🟡 P3 |
|
||||
| Lint Errors | 🟡 P3 |
|
||||
| Lint Warnings | 🟢 P4 |
|
||||
| Style Issues | ⚪ P5 |
|
||||
|
||||
6. **Generate Report**:
|
||||
```markdown
|
||||
# Static Analysis Report
|
||||
|
||||
**Date**: [timestamp]
|
||||
**Project**: [name from package.json/pyproject.toml]
|
||||
**Status**: CLEAN | ISSUES FOUND
|
||||
|
||||
## Tools Run
|
||||
|
||||
| Tool | Status | Issues |
|
||||
|------|--------|--------|
|
||||
| ESLint | ✅ | 12 |
|
||||
| TypeScript | ✅ | 3 |
|
||||
| npm audit | ⚠️ | 2 vulnerabilities |
|
||||
|
||||
## Summary by Priority
|
||||
|
||||
| Priority | Count |
|
||||
|----------|-------|
|
||||
| 🔴 P1 Critical | X |
|
||||
| 🟠 P2 High | X |
|
||||
| 🟡 P3 Medium | X |
|
||||
| 🟢 P4 Low | X |
|
||||
|
||||
## Issues
|
||||
|
||||
### 🔴 P1: Security Vulnerabilities
|
||||
|
||||
| Package | Severity | Issue | Fix |
|
||||
|---------|----------|-------|-----|
|
||||
| lodash | HIGH | Prototype Pollution | Upgrade to 4.17.21 |
|
||||
|
||||
### 🟠 P2: Type Errors
|
||||
|
||||
| File | Line | Error |
|
||||
|------|------|-------|
|
||||
| src/api.ts | 45 | Type 'string' is not assignable to type 'number' |
|
||||
|
||||
### 🟡 P3: Lint Issues
|
||||
|
||||
| File | Line | Rule | Message |
|
||||
|------|------|------|---------|
|
||||
| src/utils.ts | 12 | no-unused-vars | 'foo' is defined but never used |
|
||||
|
||||
## Quick Fixes
|
||||
|
||||
```bash
|
||||
# Fix security issues
|
||||
npm audit fix
|
||||
|
||||
# Auto-fix lint issues
|
||||
npx eslint . --fix
|
||||
```
|
||||
|
||||
## Recommendations
|
||||
|
||||
1. **Immediate**: Fix P1 security issues
|
||||
2. **Before merge**: Fix P2 type errors
|
||||
3. **Tech debt**: Address P3/P4 lint issues
|
||||
```
|
||||
|
||||
7. **Output**:
|
||||
- Display report
|
||||
- Exit with non-zero if P1 or P2 issues exist
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Run Everything**: Don't skip tools, aggregate all results
|
||||
- **Be Fast**: Run tools in parallel when possible
|
||||
- **Be Actionable**: Every issue should have a clear fix path
|
||||
- **Don't Duplicate**: Dedupe issues found by multiple tools
|
||||
- **Respect Configs**: Honor project's existing linter configs
|
||||
@@ -1,7 +1,5 @@
|
||||
description = "Generate a custom checklist for the current feature based on user requirements."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.checklist
|
||||
description: Generate a custom checklist for the current feature based on user requirements.
|
||||
---
|
||||
|
||||
@@ -34,9 +32,15 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Execution Steps
|
||||
## Role
|
||||
|
||||
1. **Setup**: Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS list.
|
||||
You are the **Antigravity Quality Gatekeeper**. Your role is to validate the quality of requirements by generating "Unit Tests for English"—checklists that ensure specifications are complete, clear, consistent, and measurable. You don't test the code; you test the documentation that defines it.
|
||||
|
||||
## Task
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS list.
|
||||
- All file paths must be absolute.
|
||||
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
@@ -178,7 +182,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- If no ID system exists: "Is a requirement & acceptance criteria ID scheme established? [Traceability]"
|
||||
|
||||
**Surface & Resolve Issues** (Requirements Quality Problems):
|
||||
Ask questions about the requirements themselves:
|
||||
- Ask questions about the requirements themselves:
|
||||
- Ambiguities: "Is the term 'fast' quantified with specific metrics? [Ambiguity, Spec §NFR-1]"
|
||||
- Conflicts: "Do navigation requirements conflict between §FR-10 and §FR-10a? [Conflict]"
|
||||
- Assumptions: "Is the assumption of 'always available podcast API' validated? [Assumption]"
|
||||
@@ -206,7 +210,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- ✅ "Are [edge cases/scenarios] addressed in requirements?"
|
||||
- ✅ "Does the spec define [missing aspect]?"
|
||||
|
||||
6. **Structure Reference**: Generate the checklist following the canonical template in `.specify/templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### <requirement item>` lines with globally incrementing IDs starting at CHK001.
|
||||
b. **Structure Reference**: Generate the checklist following the canonical template in `templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### <requirement item>` lines with globally incrementing IDs starting at CHK001.
|
||||
|
||||
7. **Report**: Output full path to created checklist, item count, and remind user that each run creates a new file. Summarize:
|
||||
- Focus areas selected
|
||||
@@ -295,4 +299,3 @@ Sample items:
|
||||
- Correct: Validation of requirement quality
|
||||
- Wrong: "Does it do X?"
|
||||
- Correct: "Is X clearly specified?"
|
||||
"""
|
||||
@@ -0,0 +1,40 @@
|
||||
# [CHECKLIST TYPE] Checklist: [FEATURE NAME]
|
||||
|
||||
**Purpose**: [Brief description of what this checklist covers]
|
||||
**Created**: [DATE]
|
||||
**Feature**: [Link to spec.md or relevant documentation]
|
||||
|
||||
**Note**: This checklist is generated by the `/speckit.checklist` command based on feature context and requirements.
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
IMPORTANT: The checklist items below are SAMPLE ITEMS for illustration only.
|
||||
|
||||
The /speckit.checklist command MUST replace these with actual items based on:
|
||||
- User's specific checklist request
|
||||
- Feature requirements from spec.md
|
||||
- Technical context from plan.md
|
||||
- Implementation details from tasks.md
|
||||
|
||||
DO NOT keep these sample items in the generated checklist file.
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
## [Category 1]
|
||||
|
||||
- [ ] CHK001 First checklist item with clear action
|
||||
- [ ] CHK002 Second checklist item
|
||||
- [ ] CHK003 Third checklist item
|
||||
|
||||
## [Category 2]
|
||||
|
||||
- [ ] CHK004 Another category item
|
||||
- [ ] CHK005 Item with specific criteria
|
||||
- [ ] CHK006 Final item in this category
|
||||
|
||||
## Notes
|
||||
|
||||
- Check items off as completed: `[x]`
|
||||
- Add comments or findings inline
|
||||
- Link to relevant resources or documentation
|
||||
- Items are numbered sequentially for easy reference
|
||||
@@ -1,8 +1,9 @@
|
||||
description = "Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.clarify
|
||||
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.specify
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
agent: speckit.plan
|
||||
@@ -17,7 +18,13 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Ambiguity Buster**. Your role is to interrogate specifications for logical gaps, missing constraints, or vague requirements. You resolve these via structured questioning to minimize rework risk.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Goal: Detect and reduce ambiguity or missing decision points in the active feature specification and record the clarifications directly in the spec file.
|
||||
|
||||
@@ -25,7 +32,7 @@ Note: This clarification workflow is expected to run (and be completed) BEFORE i
|
||||
|
||||
Execution steps:
|
||||
|
||||
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields:
|
||||
1. Run `../scripts/bash/check-prerequisites.sh --json --paths-only` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields:
|
||||
- `FEATURE_DIR`
|
||||
- `FEATURE_SPEC`
|
||||
- (Optionally capture `IMPL_PLAN`, `TASKS` for future chained flows.)
|
||||
@@ -182,4 +189,3 @@ Behavior rules:
|
||||
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
|
||||
|
||||
Context for prioritization: {{args}}
|
||||
"""
|
||||
@@ -1,7 +1,5 @@
|
||||
description = "Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.constitution
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
|
||||
handoffs:
|
||||
- label: Build Specification
|
||||
@@ -17,13 +15,19 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Governance Architect**. Your role is to establish and maintain the project's "Source of Law"—the constitution. You ensure that all project principles, standards, and non-negotiables are clearly documented and kept in sync across all templates and workflows.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
|
||||
|
||||
Follow this execution flow:
|
||||
|
||||
1. Load the existing constitution template at `.specify/memory/constitution.md`.
|
||||
1. Load the existing constitution template at `memory/constitution.md`.
|
||||
- Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`.
|
||||
**IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly.
|
||||
|
||||
@@ -83,4 +87,3 @@ If the user supplies partial updates (e.g., only one principle revision), still
|
||||
If critical info missing (e.g., ratification date truly unknown), insert `TODO(<FIELD_NAME>): explanation` and include in the Sync Impact Report under deferred items.
|
||||
|
||||
Do not create a new template; always operate on the existing `.specify/memory/constitution.md` file.
|
||||
"""
|
||||
81
.agents/skills/speckit.diff/SKILL.md
Normal file
81
.agents/skills/speckit.diff/SKILL.md
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: speckit.diff
|
||||
description: Compare two versions of a spec or plan to highlight changes.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Diff Analyst**. Your role is to compare specification/plan versions and produce clear, actionable change summaries.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Compare two versions of a specification artifact and produce a structured diff report.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Parse Arguments**:
|
||||
- If user provides two file paths: Compare those files directly
|
||||
- If user provides one file path: Compare current version with git HEAD
|
||||
- If no arguments: Use `check-prerequisites.sh` to find current feature's spec.md and compare with HEAD
|
||||
|
||||
2. **Load Files**:
|
||||
```bash
|
||||
# For git comparison
|
||||
git show HEAD:<relative-path> > /tmp/old_version.md
|
||||
```
|
||||
- Read both versions into memory
|
||||
|
||||
3. **Semantic Diff Analysis**:
|
||||
Analyze changes by section:
|
||||
- **Added**: New sections, requirements, or criteria
|
||||
- **Removed**: Deleted content
|
||||
- **Modified**: Changed wording or values
|
||||
- **Moved**: Reorganized content (same meaning, different location)
|
||||
|
||||
4. **Generate Report**:
|
||||
```markdown
|
||||
# Diff Report: [filename]
|
||||
|
||||
**Compared**: [version A] → [version B]
|
||||
**Date**: [timestamp]
|
||||
|
||||
## Summary
|
||||
- X additions, Y removals, Z modifications
|
||||
|
||||
## Changes by Section
|
||||
|
||||
### [Section Name]
|
||||
|
||||
| Type | Content | Impact |
|
||||
|------|---------|--------|
|
||||
| + Added | [new text] | [what this means] |
|
||||
| - Removed | [old text] | [what this means] |
|
||||
| ~ Modified | [before] → [after] | [what this means] |
|
||||
|
||||
## Risk Assessment
|
||||
- Breaking changes: [list any]
|
||||
- Scope changes: [list any]
|
||||
```
|
||||
|
||||
5. **Output**:
|
||||
- Display report in terminal (do NOT write to file unless requested)
|
||||
- Offer to save report to `FEATURE_DIR/diffs/[timestamp].md`
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Be Precise**: Quote exact text changes
|
||||
- **Highlight Impact**: Explain what each change means for implementation
|
||||
- **Flag Breaking Changes**: Any change that invalidates existing work
|
||||
- **Ignore Whitespace**: Focus on semantic changes, not formatting
|
||||
248
.agents/skills/speckit.implement/SKILL.md
Normal file
248
.agents/skills/speckit.implement/SKILL.md
Normal file
@@ -0,0 +1,248 @@
|
||||
---
|
||||
name: speckit.implement
|
||||
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md (with Ironclad Anti-Regression Protocols)
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.tasks
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Master Builder**. Your role is to execute the implementation plan with precision, processing tasks from `tasks.md` and ensuring that the final codebase aligns perfectly with the specification, plan, and quality standards.
|
||||
|
||||
**CORE OBJECTIVE:** Fix bugs and implement features with **ZERO REGRESSION**.
|
||||
**YOUR MOTTO:** "Measure twice, cut once. If you can't prove it's broken, don't fix it."
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ IRONCLAD PROTOCOLS (Non-Negotiable)
|
||||
|
||||
These protocols MUST be followed for EVERY task before any production code modification:
|
||||
|
||||
### Protocol 1: Blast Radius Analysis
|
||||
|
||||
**BEFORE** writing a single line of production code modification, you MUST:
|
||||
|
||||
1. **Read**: Read the target file(s) to understand current implementation.
|
||||
2. **Trace**: Use `grep` or search tools to find ALL other files importing or using the function/class you intend to modify.
|
||||
3. **Report**: Output a precise list:
|
||||
```
|
||||
🔍 BLAST RADIUS ANALYSIS
|
||||
─────────────────────────
|
||||
Modifying: `[Function/Class X]` in `[file.ts]`
|
||||
Affected files: [A.ts, B.ts, C.ts]
|
||||
Risk Level: [LOW (<3 files) | MEDIUM (3-5 files) | HIGH (>5 files)]
|
||||
```
|
||||
4. **Decide**: If > 2 files are affected, **DO NOT MODIFY inline**. Trigger **Protocol 2 (Strangler Pattern)**.
|
||||
|
||||
### Protocol 2: Strangler Pattern (Immutable Core)
|
||||
|
||||
If a file is critical, complex, or has high dependencies (>2 affected files):
|
||||
|
||||
1. **DO NOT EDIT** the existing function inside the old file.
|
||||
2. **CREATE** a new file/module (e.g., `feature_v2.ts` or `utils_patch.ts`).
|
||||
3. **IMPLEMENT** the improved logic there.
|
||||
4. **SWITCH** the imports in the consuming files one by one.
|
||||
5. **ANNOUNCE**: "Applying Strangler Pattern to avoid regression."
|
||||
|
||||
*Benefit: If it breaks, we simply revert the import, not the whole logic.*
|
||||
|
||||
### Protocol 3: Reproduction Script First (TDD)
|
||||
|
||||
You are **FORBIDDEN** from fixing a bug or implementing a feature without evidence:
|
||||
|
||||
1. Create a temporary script `repro_task_[id].ts` (or .js/.py/.go based on stack).
|
||||
2. This script MUST:
|
||||
- For bugs: **FAIL** when run against the current code (demonstrating the bug).
|
||||
- For features: **FAIL** when run against current code (feature doesn't exist).
|
||||
3. Run it and show the failure output.
|
||||
4. **ONLY THEN**, implement the fix/feature.
|
||||
5. Run the script again to prove it passes.
|
||||
6. Delete the temporary script OR convert it to a permanent test.
|
||||
|
||||
### Protocol 4: Context Anchoring
|
||||
|
||||
At the start of execution and after every 3 modifications:
|
||||
|
||||
1. Run `tree -L 2` (or equivalent) to visualize the file structure.
|
||||
2. Update `ARCHITECTURE.md` if it exists, or create it to reflect the current reality.
|
||||
|
||||
---
|
||||
|
||||
## Task Execution
|
||||
|
||||
### Outline
|
||||
|
||||
1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
|
||||
- Scan all checklist files in the checklists/ directory
|
||||
- For each checklist, count:
|
||||
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
|
||||
- Completed items: Lines matching `- [X]` or `- [x]`
|
||||
- Incomplete items: Lines matching `- [ ]`
|
||||
- Create a status table:
|
||||
|
||||
```text
|
||||
| Checklist | Total | Completed | Incomplete | Status |
|
||||
|-----------|-------|-----------|------------|--------|
|
||||
| ux.md | 12 | 12 | 0 | ✓ PASS |
|
||||
| test.md | 8 | 5 | 3 | ✗ FAIL |
|
||||
| security.md | 6 | 6 | 0 | ✓ PASS |
|
||||
```
|
||||
|
||||
- Calculate overall status:
|
||||
- **PASS**: All checklists have 0 incomplete items
|
||||
- **FAIL**: One or more checklists have incomplete items
|
||||
|
||||
- **If any checklist is incomplete**:
|
||||
- Display the table with incomplete item counts
|
||||
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
|
||||
- Wait for user response before continuing
|
||||
- If user says "no" or "wait" or "stop", halt execution
|
||||
- If user says "yes" or "proceed" or "continue", proceed to step 3
|
||||
|
||||
- **If all checklists are complete**:
|
||||
- Display the table showing all checklists passed
|
||||
- Automatically proceed to step 3
|
||||
|
||||
3. Load and analyze the implementation context:
|
||||
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
|
||||
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
|
||||
- **IF EXISTS**: Read data-model.md for entities and relationships
|
||||
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
|
||||
- **IF EXISTS**: Read research.md for technical decisions and constraints
|
||||
- **IF EXISTS**: Read quickstart.md for integration scenarios
|
||||
|
||||
4. **Context Anchoring (Protocol 4)**:
|
||||
- Run `tree -L 2` to visualize the current file structure
|
||||
- Document the initial state before any modifications
|
||||
|
||||
5. **Project Setup Verification**:
|
||||
- **REQUIRED**: Create/verify ignore files based on actual project setup:
|
||||
|
||||
**Detection & Creation Logic**:
|
||||
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
|
||||
|
||||
```sh
|
||||
git rev-parse --git-dir 2>/dev/null
|
||||
```
|
||||
|
||||
- Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore
|
||||
- Check if .eslintrc* exists → create/verify .eslintignore
|
||||
- Check if eslint.config.* exists → ensure the config's `ignores` entries cover required patterns
|
||||
- Check if .prettierrc* exists → create/verify .prettierignore
|
||||
- Check if .npmrc or package.json exists → create/verify .npmignore (if publishing)
|
||||
- Check if terraform files (*.tf) exist → create/verify .terraformignore
|
||||
- Check if .helmignore needed (helm charts present) → create/verify .helmignore
|
||||
|
||||
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
|
||||
**If ignore file missing**: Create with full pattern set for detected technology
|
||||
|
||||
**Common Patterns by Technology** (from plan.md tech stack):
|
||||
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
|
||||
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
|
||||
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
|
||||
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
|
||||
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
|
||||
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
|
||||
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
|
||||
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
|
||||
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
|
||||
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
|
||||
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
|
||||
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
|
||||
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
|
||||
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
|
||||
|
||||
**Tool-Specific Patterns**:
|
||||
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
|
||||
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
|
||||
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
|
||||
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
|
||||
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
|
||||
|
||||
6. Parse tasks.md structure and extract:
|
||||
- **Task phases**: Setup, Tests, Core, Integration, Polish
|
||||
- **Task dependencies**: Sequential vs parallel execution rules
|
||||
- **Task details**: ID, description, file paths, parallel markers [P]
|
||||
- **Execution flow**: Order and dependency requirements
|
||||
|
||||
7. **Execute implementation following the task plan with Ironclad Protocols**:
|
||||
|
||||
**For EACH task**, follow this sequence:
|
||||
|
||||
a. **Blast Radius Analysis (Protocol 1)**:
|
||||
- Identify all files that will be modified
|
||||
- Run `grep` to find all dependents
|
||||
- Report the blast radius
|
||||
|
||||
b. **Strategy Decision**:
|
||||
- If LOW risk (≤2 affected files): Proceed with inline modification
|
||||
- If MEDIUM/HIGH risk (>2 files): Apply Strangler Pattern (Protocol 2)
|
||||
|
||||
c. **Reproduction Script (Protocol 3)**:
|
||||
- Create `repro_task_[ID].ts` that demonstrates expected behavior
|
||||
- Run it to confirm current state (should fail for new features, or fail for bugs)
|
||||
|
||||
d. **Implementation**:
|
||||
- Execute the task according to plan
|
||||
- **Phase-by-phase execution**: Complete each phase before moving to the next
|
||||
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
|
||||
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
|
||||
- **File-based coordination**: Tasks affecting the same files must run sequentially
|
||||
|
||||
e. **Verification**:
|
||||
- Run the reproduction script again (should now pass)
|
||||
- Run existing tests to ensure no regression
|
||||
- If any test fails: **STOP** and report the regression
|
||||
|
||||
f. **Cleanup**:
|
||||
- Delete temporary repro scripts OR convert to permanent tests
|
||||
- Mark task as complete `[X]` in tasks.md
|
||||
|
||||
8. **Progress tracking and error handling**:
|
||||
- Report progress after each completed task with this format:
|
||||
```
|
||||
✅ TASK [ID] COMPLETE
|
||||
─────────────────────
|
||||
Modified files: [list]
|
||||
Tests passed: [count]
|
||||
Blast radius: [LOW/MEDIUM/HIGH]
|
||||
```
|
||||
- Halt execution if any non-parallel task fails
|
||||
- For parallel tasks [P], continue with successful tasks, report failed ones
|
||||
- Provide clear error messages with context for debugging
|
||||
- Suggest next steps if implementation cannot proceed
|
||||
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
|
||||
|
||||
9. **Context Re-anchoring (every 3 tasks)**:
|
||||
- Run `tree -L 2` to verify file structure
|
||||
- Update ARCHITECTURE.md if structure has changed
|
||||
|
||||
10. **Completion validation**:
|
||||
- Verify all required tasks are completed
|
||||
- Check that implemented features match the original specification
|
||||
- Validate that tests pass and coverage meets requirements
|
||||
- Confirm the implementation follows the technical plan
|
||||
- Report final status with summary of completed work
|
||||
|
||||
---
|
||||
|
||||
## 🚫 Anti-Hallucination Rules
|
||||
|
||||
1. **No Magic Imports:** Never import a library or file without checking `ls` or `package.json` first.
|
||||
2. **Strict Diff-Only:** When modifying existing files, use minimal edits.
|
||||
3. **Stop & Ask:** If you find yourself editing more than 3 files for a "simple fix," **STOP**. You are likely cascading a regression. Ask for strategic guidance.
|
||||
|
||||
---
|
||||
|
||||
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.
|
||||
106
.agents/skills/speckit.migrate/SKILL.md
Normal file
106
.agents/skills/speckit.migrate/SKILL.md
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
name: speckit.migrate
|
||||
description: Migrate existing projects into the speckit structure by generating spec.md, plan.md, and tasks.md from existing code.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Migration Specialist**. Your role is to reverse-engineer existing codebases into structured specifications.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Analyze an existing codebase and generate speckit artifacts (spec.md, plan.md, tasks.md) that document what currently exists.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Parse Arguments**:
|
||||
- `--path <dir>`: Directory to analyze (default: current repo root)
|
||||
- `--feature <name>`: Feature name for output directory
|
||||
- `--depth <n>`: Analysis depth (1=overview, 2=detailed, 3=exhaustive)
|
||||
|
||||
2. **Codebase Discovery**:
|
||||
```bash
|
||||
# Get project structure
|
||||
tree -L 3 --dirsfirst -I 'node_modules|.git|dist|build' > /tmp/structure.txt
|
||||
|
||||
# Find key files
|
||||
find . -name "*.md" -o -name "package.json" -o -name "*.config.*" | head -50
|
||||
```
|
||||
|
||||
3. **Analyze Architecture**:
|
||||
- Identify framework/stack from config files
|
||||
- Map directory structure to components
|
||||
- Find entry points (main, index, app)
|
||||
- Identify data models/entities
|
||||
- Map API endpoints (if applicable)
|
||||
|
||||
4. **Generate spec.md** (reverse-engineered):
|
||||
```markdown
|
||||
# [Feature Name] - Specification (Migrated)
|
||||
|
||||
> This specification was auto-generated from existing code.
|
||||
> Review and refine before using for future development.
|
||||
|
||||
## Overview
|
||||
[Inferred from README, comments, and code structure]
|
||||
|
||||
## Functional Requirements
|
||||
[Extracted from existing functionality]
|
||||
|
||||
## Key Entities
|
||||
[From data models, schemas, types]
|
||||
```
|
||||
|
||||
5. **Generate plan.md** (reverse-engineered):
|
||||
```markdown
|
||||
# [Feature Name] - Technical Plan (Migrated)
|
||||
|
||||
## Current Architecture
|
||||
[Documented from codebase analysis]
|
||||
|
||||
## Technology Stack
|
||||
[From package.json, imports, configs]
|
||||
|
||||
## Component Map
|
||||
[Directory → responsibility mapping]
|
||||
```
|
||||
|
||||
6. **Generate tasks.md** (completion status):
|
||||
```markdown
|
||||
# [Feature Name] - Tasks (Migrated)
|
||||
|
||||
All tasks marked [x] represent existing implemented functionality.
|
||||
Tasks marked [ ] are inferred gaps or TODOs found in code.
|
||||
|
||||
## Existing Implementation
|
||||
- [x] [Component A] - Implemented in `src/componentA/`
|
||||
- [x] [Component B] - Implemented in `src/componentB/`
|
||||
|
||||
## Identified Gaps
|
||||
- [ ] [Missing tests for X]
|
||||
- [ ] [TODO comment at Y]
|
||||
```
|
||||
|
||||
7. **Output**:
|
||||
- Create feature directory: `.specify/features/[feature-name]/`
|
||||
- Write all three files
|
||||
- Report summary with confidence scores
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Don't Invent**: Only document what exists, mark uncertainties as [INFERRED]
|
||||
- **Preserve Intent**: Use code comments and naming to understand purpose
|
||||
- **Flag TODOs**: Any TODO/FIXME/HACK in code becomes an open task
|
||||
- **Be Conservative**: When unsure, ask rather than assume
|
||||
@@ -1,8 +1,9 @@
|
||||
description = "Execute the implementation planning workflow using the plan template to generate design artifacts."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.plan
|
||||
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.specify
|
||||
handoffs:
|
||||
- label: Create Tasks
|
||||
agent: speckit.tasks
|
||||
@@ -21,11 +22,17 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
1. **Setup**: Run `.specify/scripts/powershell/setup-plan.ps1 -Json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
You are the **Antigravity System Architect**. Your role is to bridge the gap between functional specifications and technical implementation. You design data models, define API contracts, and perform technical research to ensure a robust and scalable architecture.
|
||||
|
||||
2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied).
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
1. **Setup**: Run `../scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template from `templates/plan-template.md`.
|
||||
|
||||
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
|
||||
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
|
||||
@@ -78,7 +85,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- Output OpenAPI/GraphQL schema to `/contracts/`
|
||||
|
||||
3. **Agent context update**:
|
||||
- Run `.specify/scripts/powershell/update-agent-context.ps1 -AgentType gemini`
|
||||
- Run `../scripts/bash/update-agent-context.sh gemini`
|
||||
- These scripts detect which AI agent is in use
|
||||
- Update the appropriate agent-specific context file
|
||||
- Add only new technology from current plan
|
||||
@@ -90,4 +97,3 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
- Use absolute paths
|
||||
- ERROR on gate failures or unresolved clarifications
|
||||
"""
|
||||
28
.agents/skills/speckit.plan/templates/agent-file-template.md
Normal file
28
.agents/skills/speckit.plan/templates/agent-file-template.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# [PROJECT NAME] Development Guidelines
|
||||
|
||||
Auto-generated from all feature plans. Last updated: [DATE]
|
||||
|
||||
## Active Technologies
|
||||
|
||||
[EXTRACTED FROM ALL PLAN.MD FILES]
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
[ACTUAL STRUCTURE FROM PLANS]
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
|
||||
|
||||
## Code Style
|
||||
|
||||
[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
|
||||
|
||||
## Recent Changes
|
||||
|
||||
[LAST 3 FEATURES AND WHAT THEY ADDED]
|
||||
|
||||
<!-- MANUAL ADDITIONS START -->
|
||||
<!-- MANUAL ADDITIONS END -->
|
||||
104
.agents/skills/speckit.plan/templates/plan-template.md
Normal file
104
.agents/skills/speckit.plan/templates/plan-template.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Implementation Plan: [FEATURE]
|
||||
|
||||
**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
|
||||
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
[Extract from feature spec: primary requirement + technical approach from research]
|
||||
|
||||
## Technical Context
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the content in this section with the technical details
|
||||
for the project. The structure here is presented in advisory capacity to guide
|
||||
the iteration process.
|
||||
-->
|
||||
|
||||
**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
|
||||
**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
|
||||
**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
|
||||
**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
|
||||
**Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
|
||||
**Project Type**: [single/web/mobile - determines source structure]
|
||||
**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
|
||||
**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
|
||||
**Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
[Gates determined based on constitution file]
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
|
||||
```text
|
||||
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
|
||||
src/
|
||||
├── models/
|
||||
├── services/
|
||||
├── cli/
|
||||
└── lib/
|
||||
|
||||
tests/
|
||||
├── contract/
|
||||
├── integration/
|
||||
└── unit/
|
||||
|
||||
# [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
│ ├── services/
|
||||
│ └── api/
|
||||
└── tests/
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ ├── pages/
|
||||
│ └── services/
|
||||
└── tests/
|
||||
|
||||
# [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
|
||||
api/
|
||||
└── [same as backend above]
|
||||
|
||||
ios/ or android/
|
||||
└── [platform-specific structure: feature modules, UI flows, platform tests]
|
||||
```
|
||||
|
||||
**Structure Decision**: [Document the selected structure and reference the real
|
||||
directories captured above]
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
65
.agents/skills/speckit.quizme/SKILL.md
Normal file
65
.agents/skills/speckit.quizme/SKILL.md
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: speckit.quizme
|
||||
description: Challenge the specification with Socratic questioning to identify logical gaps, unhandled edge cases, and robustness issues.
|
||||
handoffs:
|
||||
- label: Clarify Spec Requirements
|
||||
agent: speckit.clarify
|
||||
prompt: Clarify specification requirements
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Red Teamer**. Your role is to play the "Socratic Teacher" and challenge specifications for logical fallacies, naive assumptions, and happy-path bias. You find the edge cases that others miss and force robustness into the design.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Goal: Act as a "Red Team" or "Socratic Teacher" to challenge the current feature specification. Unlike `speckit.clarify` (which looks for missing definitions), `speckit.quizme` looks for logical fallacies, race conditions, naive assumptions, and "happy path" bias.
|
||||
|
||||
Execution steps:
|
||||
|
||||
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR.
|
||||
|
||||
2. **Load Spec**: Read `spec.md` and `plan.md` (if exists).
|
||||
|
||||
3. **Analyze for Weaknesses** (Internal Thought Process):
|
||||
- Identify "Happy Path" assumptions (e.g., "User clicks button and saves").
|
||||
- Look for temporal/state gaps (e.g., "What if the user clicks twice?", "What if the network fails mid-save?").
|
||||
- Challenge business logic (e.g., "You allow deleting users, but what happens to their data?").
|
||||
- Challenge security (e.g., "You rely on client-side validation here, but what if I curl the API?").
|
||||
|
||||
4. **The Quiz Loop**:
|
||||
- Present 3-5 challenging scenarios *one by one*.
|
||||
- Format:
|
||||
> **Scenario**: [Describe a plausible edge case or failure]
|
||||
> **Current Spec**: [Quote where the spec implies behavior or is silent]
|
||||
> **The Quiz**: What should the system do here?
|
||||
|
||||
- Wait for user answer.
|
||||
- Critique the answer:
|
||||
- If user says "It errors", ask "What error? To whom? Logged where?"
|
||||
- If user says "It shouldn't happen", ask "How do you prevent it?"
|
||||
|
||||
5. **Capture & Refine**:
|
||||
- For each resolved scenario, generate a new requirement or edge case bullet.
|
||||
- Ask user for permission to add it to `spec.md`.
|
||||
- On approval, append to `Edge Cases` or `Requirements` section.
|
||||
|
||||
6. **Completion**:
|
||||
- Report number of scenarios covered.
|
||||
- List new requirements added.
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Be a Skeptic**: Don't assume the happy path works.
|
||||
- **Focus on "When" and "If"**: When high load, If network drops, When concurrent edits.
|
||||
- **Don't be annoying**: Focus on *critical* flaws, not nitpicks.
|
||||
136
.agents/skills/speckit.reviewer/SKILL.md
Normal file
136
.agents/skills/speckit.reviewer/SKILL.md
Normal file
@@ -0,0 +1,136 @@
|
||||
---
|
||||
name: speckit.reviewer
|
||||
description: Perform code review with actionable feedback and suggestions.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Code Reviewer**. Your role is to perform thorough code reviews, identify issues, and provide constructive, actionable feedback.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Review code changes and provide structured feedback with severity levels.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Determine Review Scope**:
|
||||
- If user provides file paths: Review those files
|
||||
- If user says "staged" or no args: Review git staged changes
|
||||
- If user says "branch": Compare current branch to main/master
|
||||
|
||||
```bash
|
||||
# Get staged changes
|
||||
git diff --cached --name-only
|
||||
|
||||
# Get branch changes
|
||||
git diff main...HEAD --name-only
|
||||
```
|
||||
|
||||
2. **Load Files for Review**:
|
||||
- Read each file in scope
|
||||
- For diffs, focus on changed lines with context
|
||||
|
||||
3. **Review Categories**:
|
||||
|
||||
| Category | What to Check |
|
||||
|----------|--------------|
|
||||
| **Correctness** | Logic errors, off-by-one, null handling |
|
||||
| **Security** | SQL injection, XSS, secrets in code |
|
||||
| **Performance** | N+1 queries, unnecessary loops, memory leaks |
|
||||
| **Maintainability** | Complexity, duplication, naming |
|
||||
| **Best Practices** | Error handling, logging, typing |
|
||||
| **Style** | Consistency, formatting (if no linter) |
|
||||
|
||||
4. **Analyze Each File**:
|
||||
For each file, check:
|
||||
- Does the code do what it claims?
|
||||
- Are edge cases handled?
|
||||
- Is error handling appropriate?
|
||||
- Are there security concerns?
|
||||
- Is the code testable?
|
||||
- Is the naming clear and consistent?
|
||||
|
||||
5. **Severity Levels**:
|
||||
|
||||
| Level | Meaning | Block Merge? |
|
||||
|-------|---------|--------------|
|
||||
| 🔴 CRITICAL | Security issue, data loss risk | Yes |
|
||||
| 🟠 HIGH | Bug, logic error | Yes |
|
||||
| 🟡 MEDIUM | Code smell, maintainability | Maybe |
|
||||
| 🟢 LOW | Style, minor improvement | No |
|
||||
| 💡 SUGGESTION | Nice-to-have, optional | No |
|
||||
|
||||
6. **Generate Review Report**:
|
||||
```markdown
|
||||
# Code Review Report
|
||||
|
||||
**Date**: [timestamp]
|
||||
**Scope**: [files reviewed]
|
||||
**Overall**: APPROVE | REQUEST CHANGES | NEEDS DISCUSSION
|
||||
|
||||
## Summary
|
||||
|
||||
| Severity | Count |
|
||||
|----------|-------|
|
||||
| 🔴 Critical | X |
|
||||
| 🟠 High | X |
|
||||
| 🟡 Medium | X |
|
||||
| 🟢 Low | X |
|
||||
| 💡 Suggestions | X |
|
||||
|
||||
## Findings
|
||||
|
||||
### 🔴 CRITICAL: SQL Injection Risk
|
||||
**File**: `src/db/queries.ts:45`
|
||||
**Code**:
|
||||
```typescript
|
||||
const query = `SELECT * FROM users WHERE id = ${userId}`;
|
||||
```
|
||||
**Issue**: User input directly concatenated into SQL query
|
||||
**Fix**: Use parameterized queries:
|
||||
```typescript
|
||||
const query = 'SELECT * FROM users WHERE id = $1';
|
||||
await db.query(query, [userId]);
|
||||
```
|
||||
|
||||
### 🟡 MEDIUM: Complex Function
|
||||
**File**: `src/auth/handler.ts:120`
|
||||
**Issue**: Function has cyclomatic complexity of 15
|
||||
**Suggestion**: Extract into smaller functions
|
||||
|
||||
## What's Good
|
||||
|
||||
- Clear naming conventions
|
||||
- Good test coverage
|
||||
- Proper TypeScript types
|
||||
|
||||
## Recommended Actions
|
||||
|
||||
1. **Must fix before merge**: [critical/high items]
|
||||
2. **Should address**: [medium items]
|
||||
3. **Consider for later**: [low/suggestions]
|
||||
```
|
||||
|
||||
7. **Output**:
|
||||
- Display report
|
||||
- If CRITICAL or HIGH issues: Recommend blocking merge
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Be Constructive**: Every criticism should have a fix suggestion
|
||||
- **Be Specific**: Quote exact code, provide exact line numbers
|
||||
- **Be Balanced**: Mention what's good, not just what's wrong
|
||||
- **Prioritize**: Focus on real issues, not style nitpicks
|
||||
- **Be Educational**: Explain WHY something is an issue
|
||||
@@ -1,7 +1,5 @@
|
||||
description = "Create or update the feature specification from a natural language feature description."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.specify
|
||||
description: Create or update the feature specification from a natural language feature description.
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
@@ -21,7 +19,13 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Domain Scribe**. Your role is to translate natural language feature descriptions into highly structured, high-quality feature specifications (`spec.md`). You ensure clarity, testability, and alignment with the project's success criteria.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
The text the user typed after `/speckit.specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `{{args}}` appears literally below. Do not ask the user to repeat it unless they provided an empty command.
|
||||
|
||||
@@ -56,10 +60,10 @@ Given that feature description, do this:
|
||||
- Find the highest number N
|
||||
- Use N+1 for the new branch number
|
||||
|
||||
d. Run the script `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}"` with the calculated number and short-name:
|
||||
d. Run the script `../scripts/bash/create-new-feature.sh --json "{{args}}"` with the calculated number and short-name:
|
||||
- Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description
|
||||
- Bash example: `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}" --json --number 5 --short-name "user-auth" "Add user authentication"`
|
||||
- PowerShell example: `.specify/scripts/powershell/create-new-feature.ps1 -Json "{{args}}" -Json -Number 5 -ShortName "user-auth" "Add user authentication"`
|
||||
- Bash example: `.specify/scripts/bash/create-new-feature.sh --json "{{args}}" --json --number 5 --short-name "user-auth" "Add user authentication"`
|
||||
- PowerShell example: `.specify/scripts/bash/create-new-feature.sh --json "{{args}}" -Json -Number 5 -ShortName "user-auth" "Add user authentication"`
|
||||
|
||||
**IMPORTANT**:
|
||||
- Check all three sources (remote branches, local branches, specs directories) to find the highest number
|
||||
@@ -70,7 +74,7 @@ Given that feature description, do this:
|
||||
- The JSON output will contain BRANCH_NAME and SPEC_FILE paths
|
||||
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot")
|
||||
|
||||
3. Load `.specify/templates/spec-template.md` to understand required sections.
|
||||
3. Load `templates/spec-template.md` to understand required sections.
|
||||
|
||||
4. Follow this execution flow:
|
||||
|
||||
@@ -258,4 +262,3 @@ Success criteria must be:
|
||||
- "Database can handle 1000 TPS" (implementation detail, use user-facing metric)
|
||||
- "React components render efficiently" (framework-specific)
|
||||
- "Redis cache hit rate above 80%" (technology-specific)
|
||||
"""
|
||||
115
.agents/skills/speckit.specify/templates/spec-template.md
Normal file
115
.agents/skills/speckit.specify/templates/spec-template.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Feature Specification: [FEATURE NAME]
|
||||
|
||||
**Feature Branch**: `[###-feature-name]`
|
||||
**Created**: [DATE]
|
||||
**Status**: Draft
|
||||
**Input**: User description: "$ARGUMENTS"
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
<!--
|
||||
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
|
||||
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
|
||||
you should still have a viable MVP (Minimum Viable Product) that delivers value.
|
||||
|
||||
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
|
||||
Think of each story as a standalone slice of functionality that can be:
|
||||
- Developed independently
|
||||
- Tested independently
|
||||
- Deployed independently
|
||||
- Demonstrated to users independently
|
||||
-->
|
||||
|
||||
### User Story 1 - [Brief Title] (Priority: P1)
|
||||
|
||||
[Describe this user journey in plain language]
|
||||
|
||||
**Why this priority**: [Explain the value and why it has this priority level]
|
||||
|
||||
**Independent Test**: [Describe how this can be tested independently - e.g., "Can be fully tested by [specific action] and delivers [specific value]"]
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
||||
2. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - [Brief Title] (Priority: P2)
|
||||
|
||||
[Describe this user journey in plain language]
|
||||
|
||||
**Why this priority**: [Explain the value and why it has this priority level]
|
||||
|
||||
**Independent Test**: [Describe how this can be tested independently]
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - [Brief Title] (Priority: P3)
|
||||
|
||||
[Describe this user journey in plain language]
|
||||
|
||||
**Why this priority**: [Explain the value and why it has this priority level]
|
||||
|
||||
**Independent Test**: [Describe how this can be tested independently]
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
||||
|
||||
---
|
||||
|
||||
[Add more user stories as needed, each with an assigned priority]
|
||||
|
||||
### Edge Cases
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: The content in this section represents placeholders.
|
||||
Fill them out with the right edge cases.
|
||||
-->
|
||||
|
||||
- What happens when [boundary condition]?
|
||||
- How does system handle [error scenario]?
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: The content in this section represents placeholders.
|
||||
Fill them out with the right functional requirements.
|
||||
-->
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"]
|
||||
- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
|
||||
- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
|
||||
- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
|
||||
- **FR-005**: System MUST [behavior, e.g., "log all security events"]
|
||||
|
||||
*Example of marking unclear requirements:*
|
||||
|
||||
- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
|
||||
- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **[Entity 1]**: [What it represents, key attributes without implementation]
|
||||
- **[Entity 2]**: [What it represents, relationships to other entities]
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Define measurable success criteria.
|
||||
These must be technology-agnostic and measurable.
|
||||
-->
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: [Measurable metric, e.g., "Users can complete account creation in under 2 minutes"]
|
||||
- **SC-002**: [Measurable metric, e.g., "System handles 1000 concurrent users without degradation"]
|
||||
- **SC-003**: [User satisfaction metric, e.g., "90% of users successfully complete primary task on first attempt"]
|
||||
- **SC-004**: [Business metric, e.g., "Reduce support tickets related to [X] by 50%"]
|
||||
107
.agents/skills/speckit.status/SKILL.md
Normal file
107
.agents/skills/speckit.status/SKILL.md
Normal file
@@ -0,0 +1,107 @@
|
||||
---
|
||||
name: speckit.status
|
||||
description: Display a dashboard showing feature status, completion percentage, and blockers.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Status Reporter**. Your role is to provide clear, actionable status updates on project progress.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Generate a dashboard view of all features and their completion status.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Discover Features**:
|
||||
```bash
|
||||
# Find all feature directories
|
||||
find .specify/features -maxdepth 1 -type d 2>/dev/null || echo "No features found"
|
||||
```
|
||||
|
||||
2. **For Each Feature, Gather Metrics**:
|
||||
|
||||
| Artifact | Check | Metric |
|
||||
|----------|-------|--------|
|
||||
| spec.md | Exists? | Has [NEEDS CLARIFICATION]? |
|
||||
| plan.md | Exists? | All sections complete? |
|
||||
| tasks.md | Exists? | Count [x] vs [ ] vs [/] |
|
||||
| checklists/*.md | All items checked? | Checklist completion % |
|
||||
|
||||
3. **Calculate Completion**:
|
||||
```
|
||||
Phase 1 (Specify): spec.md exists & no clarifications needed
|
||||
Phase 2 (Plan): plan.md exists & complete
|
||||
Phase 3 (Tasks): tasks.md exists
|
||||
Phase 4 (Implement): tasks.md completion %
|
||||
Phase 5 (Validate): validation-report.md exists with PASS
|
||||
```
|
||||
|
||||
4. **Identify Blockers**:
|
||||
- [NEEDS CLARIFICATION] markers
|
||||
- [ ] tasks with no progress
|
||||
- Failed checklist items
|
||||
- Missing dependencies
|
||||
|
||||
5. **Generate Dashboard**:
|
||||
```markdown
|
||||
# Speckit Status Dashboard
|
||||
|
||||
**Generated**: [timestamp]
|
||||
**Total Features**: X
|
||||
|
||||
## Overview
|
||||
|
||||
| Feature | Phase | Progress | Blockers | Next Action |
|
||||
|---------|-------|----------|----------|-------------|
|
||||
| auth-system | Implement | 75% | 0 | Complete remaining tasks |
|
||||
| payment-flow | Plan | 40% | 2 | Resolve clarifications |
|
||||
|
||||
## Feature Details
|
||||
|
||||
### [Feature Name]
|
||||
|
||||
```
|
||||
Spec: ████████░░ 80%
|
||||
Plan: ██████████ 100%
|
||||
Tasks: ██████░░░░ 60%
|
||||
```
|
||||
|
||||
**Blockers**:
|
||||
- [ ] Clarification needed: "What payment providers?"
|
||||
|
||||
**Recent Activity**:
|
||||
- Last modified: [date]
|
||||
- Files changed: [list]
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
- Features Ready for Implementation: X
|
||||
- Features Blocked: Y
|
||||
- Overall Project Completion: Z%
|
||||
```
|
||||
|
||||
6. **Output**:
|
||||
- Display in terminal
|
||||
- Optionally write to `.specify/STATUS.md`
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Be Current**: Always read latest file state
|
||||
- **Be Visual**: Use progress bars and tables
|
||||
- **Be Actionable**: Every status should have a "next action"
|
||||
- **Be Fast**: Cache nothing, always recalculate
|
||||
@@ -1,8 +1,9 @@
|
||||
description = "Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.tasks
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.plan
|
||||
handoffs:
|
||||
- label: Analyze For Consistency
|
||||
agent: speckit.analyze
|
||||
@@ -22,9 +23,15 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
1. **Setup**: Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
You are the **Antigravity Execution Strategist**. Your role is to deconstruct complex technical plans into atomic, dependency-ordered tasks. You organize work into user-story-driven phases to ensure incremental delivery and high observability.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
1. **Setup**: Run `../scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. **Load design documents**: Read from FEATURE_DIR:
|
||||
- **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities)
|
||||
@@ -42,7 +49,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- Create parallel execution examples per user story
|
||||
- Validate task completeness (each user story has all needed tasks, independently testable)
|
||||
|
||||
4. **Generate tasks.md**: Use `.specify.specify/templates/tasks-template.md` as structure, fill with:
|
||||
4. **Generate tasks.md**: Use `templates/tasks-template.md` as structure, fill with:
|
||||
- Correct feature name from plan.md
|
||||
- Phase 1: Setup tasks (project initialization)
|
||||
- Phase 2: Foundational tasks (blocking prerequisites for all user stories)
|
||||
@@ -138,4 +145,3 @@ Every task MUST strictly follow this format:
|
||||
- Within each story: Tests (if requested) → Models → Services → Endpoints → Integration
|
||||
- Each phase should be a complete, independently testable increment
|
||||
- **Final Phase**: Polish & Cross-Cutting Concerns
|
||||
"""
|
||||
251
.agents/skills/speckit.tasks/templates/tasks-template.md
Normal file
251
.agents/skills/speckit.tasks/templates/tasks-template.md
Normal file
@@ -0,0 +1,251 @@
|
||||
---
|
||||
|
||||
description: "Task list template for feature implementation"
|
||||
---
|
||||
|
||||
# Tasks: [FEATURE NAME]
|
||||
|
||||
**Input**: Design documents from `/specs/[###-feature-name]/`
|
||||
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
|
||||
|
||||
**Tests**: The examples below include test tasks. Tests are OPTIONAL - only include them if explicitly requested in the feature specification.
|
||||
|
||||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
||||
- Include exact file paths in descriptions
|
||||
|
||||
## Path Conventions
|
||||
|
||||
- **Single project**: `src/`, `tests/` at repository root
|
||||
- **Web app**: `backend/src/`, `frontend/src/`
|
||||
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
|
||||
- Paths shown below assume single project - adjust based on plan.md structure
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
|
||||
|
||||
The /speckit.tasks command MUST replace these with actual tasks based on:
|
||||
- User stories from spec.md (with their priorities P1, P2, P3...)
|
||||
- Feature requirements from plan.md
|
||||
- Entities from data-model.md
|
||||
- Endpoints from contracts/
|
||||
|
||||
Tasks MUST be organized by user story so each story can be:
|
||||
- Implemented independently
|
||||
- Tested independently
|
||||
- Delivered as an MVP increment
|
||||
|
||||
DO NOT keep these sample tasks in the generated tasks.md file.
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Project initialization and basic structure
|
||||
|
||||
- [ ] T001 Create project structure per implementation plan
|
||||
- [ ] T002 Initialize [language] project with [framework] dependencies
|
||||
- [ ] T003 [P] Configure linting and formatting tools
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
|
||||
|
||||
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
|
||||
|
||||
Examples of foundational tasks (adjust based on your project):
|
||||
|
||||
- [ ] T004 Setup database schema and migrations framework
|
||||
- [ ] T005 [P] Implement authentication/authorization framework
|
||||
- [ ] T006 [P] Setup API routing and middleware structure
|
||||
- [ ] T007 Create base models/entities that all stories depend on
|
||||
- [ ] T008 Configure error handling and logging infrastructure
|
||||
- [ ] T009 Setup environment configuration management
|
||||
|
||||
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - [Title] (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: [Brief description of what this story delivers]
|
||||
|
||||
**Independent Test**: [How to verify this story works on its own]
|
||||
|
||||
### Tests for User Story 1 (OPTIONAL - only if tests requested) ⚠️
|
||||
|
||||
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
||||
|
||||
- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||
- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [ ] T012 [P] [US1] Create [Entity1] model in src/models/[entity1].py
|
||||
- [ ] T013 [P] [US1] Create [Entity2] model in src/models/[entity2].py
|
||||
- [ ] T014 [US1] Implement [Service] in src/services/[service].py (depends on T012, T013)
|
||||
- [ ] T015 [US1] Implement [endpoint/feature] in src/[location]/[file].py
|
||||
- [ ] T016 [US1] Add validation and error handling
|
||||
- [ ] T017 [US1] Add logging for user story 1 operations
|
||||
|
||||
**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - [Title] (Priority: P2)
|
||||
|
||||
**Goal**: [Brief description of what this story delivers]
|
||||
|
||||
**Independent Test**: [How to verify this story works on its own]
|
||||
|
||||
### Tests for User Story 2 (OPTIONAL - only if tests requested) ⚠️
|
||||
|
||||
- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||
- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [ ] T020 [P] [US2] Create [Entity] model in src/models/[entity].py
|
||||
- [ ] T021 [US2] Implement [Service] in src/services/[service].py
|
||||
- [ ] T022 [US2] Implement [endpoint/feature] in src/[location]/[file].py
|
||||
- [ ] T023 [US2] Integrate with User Story 1 components (if needed)
|
||||
|
||||
**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - [Title] (Priority: P3)
|
||||
|
||||
**Goal**: [Brief description of what this story delivers]
|
||||
|
||||
**Independent Test**: [How to verify this story works on its own]
|
||||
|
||||
### Tests for User Story 3 (OPTIONAL - only if tests requested) ⚠️
|
||||
|
||||
- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||
- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [ ] T026 [P] [US3] Create [Entity] model in src/models/[entity].py
|
||||
- [ ] T027 [US3] Implement [Service] in src/services/[service].py
|
||||
- [ ] T028 [US3] Implement [endpoint/feature] in src/[location]/[file].py
|
||||
|
||||
**Checkpoint**: All user stories should now be independently functional
|
||||
|
||||
---
|
||||
|
||||
[Add more user story phases as needed, following the same pattern]
|
||||
|
||||
---
|
||||
|
||||
## Phase N: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Improvements that affect multiple user stories
|
||||
|
||||
- [ ] TXXX [P] Documentation updates in docs/
|
||||
- [ ] TXXX Code cleanup and refactoring
|
||||
- [ ] TXXX Performance optimization across all stories
|
||||
- [ ] TXXX [P] Additional unit tests (if requested) in tests/unit/
|
||||
- [ ] TXXX Security hardening
|
||||
- [ ] TXXX Run quickstart.md validation
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies - can start immediately
|
||||
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
|
||||
- **User Stories (Phase 3+)**: All depend on Foundational phase completion
|
||||
- User stories can then proceed in parallel (if staffed)
|
||||
- Or sequentially in priority order (P1 → P2 → P3)
|
||||
- **Polish (Final Phase)**: Depends on all desired user stories being complete
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) - No dependencies on other stories
|
||||
- **User Story 2 (P2)**: Can start after Foundational (Phase 2) - May integrate with US1 but should be independently testable
|
||||
- **User Story 3 (P3)**: Can start after Foundational (Phase 2) - May integrate with US1/US2 but should be independently testable
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Tests (if included) MUST be written and FAIL before implementation
|
||||
- Models before services
|
||||
- Services before endpoints
|
||||
- Core implementation before integration
|
||||
- Story complete before moving to next priority
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- All Setup tasks marked [P] can run in parallel
|
||||
- All Foundational tasks marked [P] can run in parallel (within Phase 2)
|
||||
- Once Foundational phase completes, all user stories can start in parallel (if team capacity allows)
|
||||
- All tests for a user story marked [P] can run in parallel
|
||||
- Models within a story marked [P] can run in parallel
|
||||
- Different user stories can be worked on in parallel by different team members
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: User Story 1
|
||||
|
||||
```bash
|
||||
# Launch all tests for User Story 1 together (if tests requested):
|
||||
Task: "Contract test for [endpoint] in tests/contract/test_[name].py"
|
||||
Task: "Integration test for [user journey] in tests/integration/test_[name].py"
|
||||
|
||||
# Launch all models for User Story 1 together:
|
||||
Task: "Create [Entity1] model in src/models/[entity1].py"
|
||||
Task: "Create [Entity2] model in src/models/[entity2].py"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1 Only)
|
||||
|
||||
1. Complete Phase 1: Setup
|
||||
2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
|
||||
3. Complete Phase 3: User Story 1
|
||||
4. **STOP and VALIDATE**: Test User Story 1 independently
|
||||
5. Deploy/demo if ready
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Complete Setup + Foundational → Foundation ready
|
||||
2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
|
||||
3. Add User Story 2 → Test independently → Deploy/Demo
|
||||
4. Add User Story 3 → Test independently → Deploy/Demo
|
||||
5. Each story adds value without breaking previous stories
|
||||
|
||||
### Parallel Team Strategy
|
||||
|
||||
With multiple developers:
|
||||
|
||||
1. Team completes Setup + Foundational together
|
||||
2. Once Foundational is done:
|
||||
- Developer A: User Story 1
|
||||
- Developer B: User Story 2
|
||||
- Developer C: User Story 3
|
||||
3. Stories complete and integrate independently
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- [P] tasks = different files, no dependencies
|
||||
- [Story] label maps task to specific user story for traceability
|
||||
- Each user story should be independently completable and testable
|
||||
- Verify tests fail before implementing
|
||||
- Commit after each task or logical group
|
||||
- Stop at any checkpoint to validate story independently
|
||||
- Avoid: vague tasks, same file conflicts, cross-story dependencies that break independence
|
||||
@@ -1,7 +1,5 @@
|
||||
description = "Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts."
|
||||
|
||||
prompt = """
|
||||
---
|
||||
name: speckit.taskstoissues
|
||||
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
|
||||
tools: ['github/github-mcp-server/issue_write']
|
||||
---
|
||||
@@ -14,9 +12,15 @@ $ARGUMENTS
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
## Role
|
||||
|
||||
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
You are the **Antigravity Tracker Integrator**. Your role is to synchronize technical tasks with external project management systems like GitHub Issues. You ensure that every piece of work has a clear, tracked identity for collaborative execution.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
1. Run `../scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
1. From the executed script, extract the path to **tasks**.
|
||||
1. Get the Git remote by running:
|
||||
|
||||
@@ -29,4 +33,3 @@ git config --get remote.origin.url
|
||||
1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote.
|
||||
|
||||
**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL**
|
||||
"""
|
||||
119
.agents/skills/speckit.tester/SKILL.md
Normal file
119
.agents/skills/speckit.tester/SKILL.md
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: speckit.tester
|
||||
description: Execute tests, measure coverage, and report results.
|
||||
version: 1.0.0
|
||||
depends-on: []
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Test Runner**. Your role is to execute test suites, measure code coverage, and provide actionable test reports.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Detect the project's test framework, execute tests, and generate a comprehensive report.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Detect Test Framework**:
|
||||
```bash
|
||||
# Check package.json for test frameworks
|
||||
cat package.json 2>/dev/null | grep -E "(jest|vitest|mocha|ava|tap)"
|
||||
|
||||
# Check for Python test frameworks
|
||||
ls pytest.ini setup.cfg pyproject.toml 2>/dev/null
|
||||
|
||||
# Check for Go tests
|
||||
find . -name "*_test.go" -maxdepth 3 2>/dev/null | head -1
|
||||
```
|
||||
|
||||
| Indicator | Framework |
|
||||
|-----------|-----------|
|
||||
| `jest` in package.json | Jest |
|
||||
| `vitest` in package.json | Vitest |
|
||||
| `pytest.ini` or `[tool.pytest]` | Pytest |
|
||||
| `*_test.go` files | Go test |
|
||||
| `Cargo.toml` + `#[test]` | Cargo test |
|
||||
|
||||
2. **Run Tests with Coverage**:
|
||||
|
||||
| Framework | Command |
|
||||
|-----------|---------|
|
||||
| Jest | `npx jest --coverage --json --outputFile=coverage/test-results.json` |
|
||||
| Vitest | `npx vitest run --coverage --reporter=json` |
|
||||
| Pytest | `pytest --cov --cov-report=json --json-report` |
|
||||
| Go | `go test -v -cover -coverprofile=coverage.out ./...` |
|
||||
| Cargo | `cargo test -- --test-threads=1` |
|
||||
|
||||
3. **Parse Test Results**:
|
||||
Extract from test output:
|
||||
- Total tests
|
||||
- Passed / Failed / Skipped
|
||||
- Execution time
|
||||
- Coverage percentage (if available)
|
||||
|
||||
4. **Identify Failures**:
|
||||
For each failing test:
|
||||
- Test name and file location
|
||||
- Error message
|
||||
- Stack trace (truncated to relevant lines)
|
||||
- Suggested fix (if pattern is recognizable)
|
||||
|
||||
5. **Generate Report**:
|
||||
```markdown
|
||||
# Test Report
|
||||
|
||||
**Date**: [timestamp]
|
||||
**Framework**: [detected]
|
||||
**Status**: PASS | FAIL
|
||||
|
||||
## Summary
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Tests | X |
|
||||
| Passed | X |
|
||||
| Failed | X |
|
||||
| Skipped | X |
|
||||
| Duration | X.Xs |
|
||||
| Coverage | X% |
|
||||
|
||||
## Failed Tests
|
||||
|
||||
### [test name]
|
||||
**File**: `path/to/test.ts:42`
|
||||
**Error**: Expected X but received Y
|
||||
**Suggestion**: Check mock setup for...
|
||||
|
||||
## Coverage by File
|
||||
|
||||
| File | Lines | Branches | Functions |
|
||||
|------|-------|----------|-----------|
|
||||
| src/auth.ts | 85% | 70% | 90% |
|
||||
|
||||
## Next Actions
|
||||
|
||||
1. Fix failing test: [name]
|
||||
2. Increase coverage in: [low coverage files]
|
||||
```
|
||||
|
||||
6. **Output**:
|
||||
- Display report in terminal
|
||||
- Optionally save to `FEATURE_DIR/test-report.md`
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Run All Tests**: Don't skip tests unless explicitly requested
|
||||
- **Preserve Output**: Keep full test output for debugging
|
||||
- **Be Helpful**: Suggest fixes for common failure patterns
|
||||
- **Respect Timeouts**: Set reasonable timeout (5 min default)
|
||||
93
.agents/skills/speckit.validate/SKILL.md
Normal file
93
.agents/skills/speckit.validate/SKILL.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: speckit.validate
|
||||
description: Validate that implementation matches specification requirements.
|
||||
version: 1.0.0
|
||||
depends-on:
|
||||
- speckit.implement
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Role
|
||||
|
||||
You are the **Antigravity Validator**. Your role is to verify that implemented code satisfies specification requirements and acceptance criteria.
|
||||
|
||||
## Task
|
||||
|
||||
### Outline
|
||||
|
||||
Post-implementation validation that compares code against spec requirements.
|
||||
|
||||
### Execution Steps
|
||||
|
||||
1. **Setup**:
|
||||
- Run `../scripts/bash/check-prerequisites.sh --json --require-tasks`
|
||||
- Parse FEATURE_DIR from output
|
||||
- Load: `spec.md`, `plan.md`, `tasks.md`
|
||||
|
||||
2. **Build Requirements Matrix**:
|
||||
Extract from spec.md:
|
||||
- All functional requirements
|
||||
- All acceptance criteria
|
||||
- All success criteria
|
||||
- Edge cases listed
|
||||
|
||||
3. **Scan Implementation**:
|
||||
From tasks.md, identify all files created/modified:
|
||||
- Read each file
|
||||
- Extract functions, classes, endpoints
|
||||
- Map to requirements (by name matching, comments, or explicit references)
|
||||
|
||||
4. **Validation Checks**:
|
||||
|
||||
| Check | Method |
|
||||
|-------|--------|
|
||||
| Requirement Coverage | Each requirement has ≥1 implementation reference |
|
||||
| Acceptance Criteria | Each criterion is testable in code |
|
||||
| Edge Case Handling | Each edge case has explicit handling code |
|
||||
| Test Coverage | Each requirement has ≥1 test |
|
||||
|
||||
5. **Generate Validation Report**:
|
||||
```markdown
|
||||
# Validation Report: [Feature Name]
|
||||
|
||||
**Date**: [timestamp]
|
||||
**Status**: PASS | PARTIAL | FAIL
|
||||
|
||||
## Coverage Summary
|
||||
|
||||
| Metric | Count | Percentage |
|
||||
|--------|-------|------------|
|
||||
| Requirements Covered | X/Y | Z% |
|
||||
| Acceptance Criteria Met | X/Y | Z% |
|
||||
| Edge Cases Handled | X/Y | Z% |
|
||||
| Tests Present | X/Y | Z% |
|
||||
|
||||
## Uncovered Requirements
|
||||
|
||||
| Requirement | Status | Notes |
|
||||
|-------------|--------|-------|
|
||||
| [REQ-001] | Missing | No implementation found |
|
||||
|
||||
## Recommendations
|
||||
|
||||
1. [Action item for gaps]
|
||||
```
|
||||
|
||||
6. **Output**:
|
||||
- Display report
|
||||
- Write to `FEATURE_DIR/validation-report.md`
|
||||
- Set exit status based on coverage threshold (default: 80%)
|
||||
|
||||
## Operating Principles
|
||||
|
||||
- **Be Thorough**: Check every requirement, not just obvious ones
|
||||
- **Be Fair**: Semantic matching, not just keyword matching
|
||||
- **Be Actionable**: Every gap should have a clear fix recommendation
|
||||
- **Don't Block on Style**: Focus on functional coverage, not code style
|
||||
47
.agents/workflows/00-speckit.all.md
Normal file
47
.agents/workflows/00-speckit.all.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
description: Run the full speckit pipeline from specification to analysis in one command.
|
||||
---
|
||||
|
||||
# Workflow: speckit.all
|
||||
|
||||
This meta-workflow orchestrates the complete specification pipeline.
|
||||
|
||||
## Pipeline Steps
|
||||
|
||||
1. **Specify** (`/speckit.specify`):
|
||||
- Use the `view_file` tool to read: `.agent/skills/speckit.specify/SKILL.md`
|
||||
- Execute with user's feature description
|
||||
- Creates: `spec.md`
|
||||
|
||||
2. **Clarify** (`/speckit.clarify`):
|
||||
- Use the `view_file` tool to read: `.agent/skills/speckit.clarify/SKILL.md`
|
||||
- Execute to resolve ambiguities
|
||||
- Updates: `spec.md`
|
||||
|
||||
3. **Plan** (`/speckit.plan`):
|
||||
- Use the `view_file` tool to read: `.agent/skills/speckit.plan/SKILL.md`
|
||||
- Execute to create technical design
|
||||
- Creates: `plan.md`
|
||||
|
||||
4. **Tasks** (`/speckit.tasks`):
|
||||
- Use the `view_file` tool to read: `.agent/skills/speckit.tasks/SKILL.md`
|
||||
- Execute to generate task breakdown
|
||||
- Creates: `tasks.md`
|
||||
|
||||
5. **Analyze** (`/speckit.analyze`):
|
||||
- Use the `view_file` tool to read: `.agent/skills/speckit.analyze/SKILL.md`
|
||||
- Execute to validate consistency
|
||||
- Output: Analysis report
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/speckit.all "Build a user authentication system with OAuth2 support"
|
||||
```
|
||||
|
||||
## On Error
|
||||
|
||||
If any step fails, stop the pipeline and report:
|
||||
- Which step failed
|
||||
- The error message
|
||||
- Suggested remediation (e.g., "Run `/speckit.clarify` to resolve ambiguities before continuing")
|
||||
18
.agents/workflows/01-speckit.constitution.md
Normal file
18
.agents/workflows/01-speckit.constitution.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
|
||||
---
|
||||
|
||||
# Workflow: speckit.constitution
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.constitution/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `.specify/` directory doesn't exist: Initialize the speckit structure first
|
||||
19
.agents/workflows/02-speckit.specify.md
Normal file
19
.agents/workflows/02-speckit.specify.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Create or update the feature specification from a natural language feature description.
|
||||
---
|
||||
|
||||
# Workflow: speckit.specify
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
- This is typically the starting point of a new feature.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.specify/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the feature description for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no feature description provided: Ask the user to describe the feature they want to specify
|
||||
18
.agents/workflows/03-speckit.clarify.md
Normal file
18
.agents/workflows/03-speckit.clarify.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
|
||||
---
|
||||
|
||||
# Workflow: speckit.clarify
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.clarify/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
18
.agents/workflows/04-speckit.plan.md
Normal file
18
.agents/workflows/04-speckit.plan.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.plan
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.plan/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
19
.agents/workflows/05-speckit.tasks.md
Normal file
19
.agents/workflows/05-speckit.tasks.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.tasks
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.tasks/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
22
.agents/workflows/06-speckit.analyze.md
Normal file
22
.agents/workflows/06-speckit.analyze.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.analyze
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.analyze/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
20
.agents/workflows/07-speckit.implement.md
Normal file
20
.agents/workflows/07-speckit.implement.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
|
||||
---
|
||||
|
||||
# Workflow: speckit.implement
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.implement/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If `plan.md` is missing: Run `/speckit.plan` first
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first
|
||||
21
.agents/workflows/08-speckit.checker.md
Normal file
21
.agents/workflows/08-speckit.checker.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: Run static analysis tools and aggregate results.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.checker
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify paths to check or run on entire project.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.checker/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no linting tools available: Report which tools to install based on project type
|
||||
- If tools fail: Show raw error and suggest config fixes
|
||||
21
.agents/workflows/09-speckit.tester.md
Normal file
21
.agents/workflows/09-speckit.tester.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: Execute tests, measure coverage, and report results.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.tester
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify test paths, options, or just run all tests.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.tester/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no test framework detected: Report "No test framework found. Install Jest, Vitest, Pytest, or similar."
|
||||
- If tests fail: Show failure details and suggest fixes
|
||||
19
.agents/workflows/10-speckit.reviewer.md
Normal file
19
.agents/workflows/10-speckit.reviewer.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Perform code review with actionable feedback and suggestions.
|
||||
---
|
||||
|
||||
# Workflow: speckit.reviewer
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may specify files to review, "staged" for git staged changes, or "branch" for branch diff.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.reviewer/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no files to review: Ask user to stage changes or specify file paths
|
||||
- If not a git repo: Review current directory files instead
|
||||
19
.agents/workflows/11-speckit.validate.md
Normal file
19
.agents/workflows/11-speckit.validate.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Validate that implementation matches specification requirements.
|
||||
---
|
||||
|
||||
# Workflow: speckit.validate
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.validate/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
- If implementation not started: Run `/speckit.implement` first
|
||||
49
.agents/workflows/create-backend-module.md
Normal file
49
.agents/workflows/create-backend-module.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
description: Create a new NestJS backend feature module following project standards
|
||||
---
|
||||
|
||||
# Create NestJS Backend Module
|
||||
|
||||
Use this workflow when creating a new feature module in `backend/src/modules/`.
|
||||
Follows `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md` and ADR-005.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Verify requirements exist** — confirm the feature is in `specs/01-Requirements/` before starting
|
||||
|
||||
2. **Check schema** — read `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql` for relevant tables
|
||||
|
||||
3. **Scaffold module folder**
|
||||
|
||||
```
|
||||
backend/src/modules/<module-name>/
|
||||
├── <module-name>.module.ts
|
||||
├── <module-name>.controller.ts
|
||||
├── <module-name>.service.ts
|
||||
├── dto/
|
||||
│ ├── create-<module-name>.dto.ts
|
||||
│ └── update-<module-name>.dto.ts
|
||||
├── entities/
|
||||
│ └── <module-name>.entity.ts
|
||||
└── <module-name>.controller.spec.ts
|
||||
```
|
||||
|
||||
4. **Create Entity** — map ONLY columns defined in the schema SQL. Use TypeORM decorators. Add `@VersionColumn()` if the entity needs optimistic locking.
|
||||
|
||||
5. **Create DTOs** — use `class-validator` decorators. Never use `any`. Validate all inputs.
|
||||
|
||||
6. **Create Service** — inject repository via constructor DI. Use transactions for multi-step writes. Add `Idempotency-Key` guard for POST/PUT/PATCH operations.
|
||||
|
||||
7. **Create Controller** — apply `@UseGuards(JwtAuthGuard, CaslAbilityGuard)`. Use proper HTTP status codes. Document with `@ApiTags` and `@ApiOperation`.
|
||||
|
||||
8. **Register in Module** — add to `imports`, `providers`, `controllers`, `exports` as needed.
|
||||
|
||||
9. **Register in AppModule** — import the new module in `app.module.ts`.
|
||||
|
||||
10. **Write unit test** — cover service methods with Jest mocks. Run:
|
||||
|
||||
```bash
|
||||
pnpm test:watch
|
||||
```
|
||||
|
||||
11. **Citation** — confirm implementation references `specs/01-Requirements/` and `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md`
|
||||
64
.agents/workflows/create-frontend-page.md
Normal file
64
.agents/workflows/create-frontend-page.md
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
description: Create a new Next.js App Router page following project standards
|
||||
---
|
||||
|
||||
# Create Next.js Frontend Page
|
||||
|
||||
Use this workflow when creating a new page in `frontend/app/`.
|
||||
Follows `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md`, ADR-011, ADR-012, ADR-013, ADR-014.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Determine route** — decide the route path, e.g. `app/(dashboard)/documents/page.tsx`
|
||||
|
||||
2. **Classify components** — decide what is Server Component (default) vs Client Component (`'use client'`)
|
||||
- Server Component: initial data load, static content, SEO
|
||||
- Client Component: interactivity, forms, TanStack Query hooks, Zustand
|
||||
|
||||
3. **Create page file** — Server Component by default:
|
||||
|
||||
```typescript
|
||||
// app/(dashboard)/<route>/page.tsx
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: '<Page Title> | LCBP3-DMS',
|
||||
};
|
||||
|
||||
export default async function <PageName>Page() {
|
||||
return (
|
||||
<div>
|
||||
{/* Page content */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
4. **Create API hook** (if client-side data needed) — add to `hooks/use-<feature>.ts`:
|
||||
|
||||
```typescript
|
||||
'use client';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
|
||||
export function use<Feature>() {
|
||||
return useQuery({
|
||||
queryKey: ['<feature>'],
|
||||
queryFn: () => apiClient.get('<endpoint>'),
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
5. **Build UI components** — use Shadcn/UI primitives. Place reusable components in `components/<feature>/`.
|
||||
|
||||
6. **Handle forms** — use React Hook Form + Zod schema validation. Never access form values without validation.
|
||||
|
||||
7. **Handle errors** — add `error.tsx` alongside `page.tsx` for route-level error boundaries.
|
||||
|
||||
8. **Add loading state** — add `loading.tsx` for Suspense fallback if page does async work.
|
||||
|
||||
9. **Add to navigation** — update sidebar/nav config if the page should appear in the menu.
|
||||
|
||||
10. **Access control** — ensure page checks CASL permissions. Redirect unauthorized users via middleware or `notFound()`.
|
||||
|
||||
11. **Citation** — confirm implementation references `specs/01-Requirements/` and `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md`
|
||||
71
.agents/workflows/deploy.md
Normal file
71
.agents/workflows/deploy.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
description: Deploy the application via Gitea Actions to QNAP Container Station
|
||||
---
|
||||
|
||||
# Deploy to Production
|
||||
|
||||
Use this workflow to deploy updated backend and/or frontend to QNAP via Gitea Actions CI/CD.
|
||||
Follows `specs/04-Infrastructure-OPS/` and ADR-015.
|
||||
|
||||
## Pre-deployment Checklist
|
||||
|
||||
- [ ] All tests pass locally (`pnpm test:watch`)
|
||||
- [ ] No TypeScript errors (`tsc --noEmit`)
|
||||
- [ ] No `any` types introduced
|
||||
- [ ] Schema changes applied to `specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`
|
||||
- [ ] Environment variables documented (NOT in `.env` files)
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Commit and push to Gitea**
|
||||
|
||||
```bash
|
||||
git status
|
||||
git add .
|
||||
git commit -m "feat(<scope>): <description>"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
2. **Monitor Gitea Actions** — open Gitea web UI → Actions tab → verify pipeline starts
|
||||
|
||||
3. **Pipeline stages (automatic)**
|
||||
- `build-backend` → Docker image build + push to registry
|
||||
- `build-frontend` → Docker image build + push to registry
|
||||
- `deploy` → SSH to QNAP → `docker compose pull` + `docker compose up -d`
|
||||
|
||||
4. **Verify backend health**
|
||||
|
||||
```bash
|
||||
curl http://<QNAP_IP>:3000/health
|
||||
# Expected: { "status": "ok" }
|
||||
```
|
||||
|
||||
5. **Verify frontend**
|
||||
|
||||
```bash
|
||||
curl -I http://<QNAP_IP>:3001
|
||||
# Expected: HTTP 200
|
||||
```
|
||||
|
||||
6. **Check logs in Grafana** — navigate to Grafana → Loki → filter by container name
|
||||
- Backend: `container_name="lcbp3-backend"`
|
||||
- Frontend: `container_name="lcbp3-frontend"`
|
||||
|
||||
7. **Verify database** — confirm schema changes are reflected (if any)
|
||||
|
||||
8. **Rollback (if needed)**
|
||||
|
||||
```bash
|
||||
# SSH into QNAP
|
||||
docker compose pull <service>=<previous-image-tag>
|
||||
docker compose up -d <service>
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
| ----------------- | --------------------- | ----------------------------------- |
|
||||
| Backend unhealthy | DB connection failed | Check MariaDB container + env vars |
|
||||
| Frontend blank | Build error | Check Next.js build logs in Grafana |
|
||||
| 502 Bad Gateway | Container not started | `docker compose ps` to check status |
|
||||
| Pipeline stuck | Gitea runner offline | Restart runner on QNAP |
|
||||
27
.agents/workflows/speckit.prepare.md
Normal file
27
.agents/workflows/speckit.prepare.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
description: Execute the full preparation pipeline (Specify -> Clarify -> Plan -> Tasks -> Analyze) in sequence.
|
||||
---
|
||||
|
||||
# Workflow: speckit.prepare
|
||||
|
||||
This workflow orchestrates the sequential execution of the Speckit preparation phase skills (02-06).
|
||||
|
||||
1. **Step 1: Specify (Skill 02)**
|
||||
- Goal: Create or update the `spec.md` based on user input.
|
||||
- Action: Read and execute `.agent/skills/speckit.specify/SKILL.md`.
|
||||
|
||||
2. **Step 2: Clarify (Skill 03)**
|
||||
- Goal: Refine the `spec.md` by identifying and resolving ambiguities.
|
||||
- Action: Read and execute `.agent/skills/speckit.clarify/SKILL.md`.
|
||||
|
||||
3. **Step 3: Plan (Skill 04)**
|
||||
- Goal: Generate `plan.md` from the finalized spec.
|
||||
- Action: Read and execute `.agent/skills/speckit.plan/SKILL.md`.
|
||||
|
||||
4. **Step 4: Tasks (Skill 05)**
|
||||
- Goal: Generate actional `tasks.md` from the plan.
|
||||
- Action: Read and execute `.agent/skills/speckit.tasks/SKILL.md`.
|
||||
|
||||
5. **Step 5: Analyze (Skill 06)**
|
||||
- Goal: Validate consistency across all design artifacts (spec, plan, tasks).
|
||||
- Action: Read and execute `.agent/skills/speckit.analyze/SKILL.md`.
|
||||
18
.agents/workflows/util-speckit.checklist.md
Normal file
18
.agents/workflows/util-speckit.checklist.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Generate a custom checklist for the current feature based on user requirements.
|
||||
---
|
||||
|
||||
# Workflow: speckit.checklist
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.checklist/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `spec.md` is missing: Run `/speckit.specify` first to create the feature specification
|
||||
19
.agents/workflows/util-speckit.diff.md
Normal file
19
.agents/workflows/util-speckit.diff.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Compare two versions of a spec or plan to highlight changes.
|
||||
---
|
||||
|
||||
# Workflow: speckit.diff
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt (optional file paths or version references).
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.diff/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no files to compare: Use current feature's `spec.md` vs git HEAD
|
||||
- If `spec.md` doesn't exist: Run `/speckit.specify` first
|
||||
19
.agents/workflows/util-speckit.migrate.md
Normal file
19
.agents/workflows/util-speckit.migrate.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: Migrate existing projects into the speckit structure by generating spec.md, plan.md, and tasks.md from existing code.
|
||||
---
|
||||
|
||||
# Workflow: speckit.migrate
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt (path to analyze, feature name).
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.migrate/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If path doesn't exist: Ask user to provide valid directory path
|
||||
- If no code found: Report that no analyzable code was detected
|
||||
20
.agents/workflows/util-speckit.quizme.md
Normal file
20
.agents/workflows/util-speckit.quizme.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Challenge the specification with Socratic questioning to identify logical gaps, unhandled edge cases, and robustness issues.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.quizme
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.quizme/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If required files don't exist, inform the user which prerequisite workflow to run first (e.g., `/speckit.specify` to create `spec.md`).
|
||||
20
.agents/workflows/util-speckit.status.md
Normal file
20
.agents/workflows/util-speckit.status.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Display a dashboard showing feature status, completion percentage, and blockers.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
# Workflow: speckit.status
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user may optionally specify a feature to focus on.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.status/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If no features exist: Report "No features found. Run `/speckit.specify` to create your first feature."
|
||||
18
.agents/workflows/util-speckit.taskstoissues.md
Normal file
18
.agents/workflows/util-speckit.taskstoissues.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
|
||||
---
|
||||
|
||||
# Workflow: speckit.taskstoissues
|
||||
|
||||
1. **Context Analysis**:
|
||||
- The user has provided an input prompt. Treat this as the primary input for the skill.
|
||||
|
||||
2. **Load Skill**:
|
||||
- Use the `view_file` tool to read the skill file at: `.agent/skills/speckit.taskstoissues/SKILL.md`
|
||||
|
||||
3. **Execute**:
|
||||
- Follow the instructions in the `SKILL.md` exactly.
|
||||
- Apply the user's prompt as the input arguments/context for the skill's logic.
|
||||
|
||||
4. **On Error**:
|
||||
- If `tasks.md` is missing: Run `/speckit.tasks` first
|
||||
@@ -7,35 +7,67 @@ trigger: always_on
|
||||
## 🧠 Role & Persona
|
||||
|
||||
Act as a **Senior Full Stack Developer** expert in **NestJS**, **Next.js**, and **TypeScript**.
|
||||
You are a **Document Intelligence Engine** — not a general chatbot.
|
||||
You value **Data Integrity**, **Security**, and **Clean Architecture**.
|
||||
|
||||
## 🏗️ Project Overview
|
||||
|
||||
This is **LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)**.
|
||||
**LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)** — Version 1.8.0
|
||||
|
||||
- **Goal:** Manage construction documents (Correspondence, RFA, Drawings) with complex approval workflows.
|
||||
- **Infrastructure:** Deployed on QNAP Server via Docker Container Station.
|
||||
- **Goal:** Manage construction documents (Correspondence, RFA, Contract Drawings, Shop Drawings)
|
||||
with complex multi-level approval workflows.
|
||||
- **Infrastructure:** QNAP Container Station (Docker Compose), Nginx Proxy Manager (Reverse Proxy),
|
||||
Gitea (Git + CI/CD), n8n (Workflow Automation), Prometheus + Loki + Grafana (Monitoring/Logging)
|
||||
|
||||
## 💻 Tech Stack & Constraints
|
||||
|
||||
- **Backend:** NestJS (Modular Architecture), TypeORM, MariaDB 11.8, Redis 7.2 (BullMQ), Elasticsearch 8.11, JWT (JSON Web Tokens), CASL (4-Level RBAC).
|
||||
- **Frontend:** Next.js 14+ (App Router), Tailwind CSS, Shadcn/UI, TanStack Query (Server State), Zustand (Client State), React Hook Form + Zod, Axios.
|
||||
- **Backend:** NestJS (Modular Architecture), TypeORM, MariaDB 11.8, Redis 7.2 (BullMQ),
|
||||
Elasticsearch 8.11, JWT + Passport, CASL (4-Level RBAC), ClamAV (Virus Scanning), Helmet.js
|
||||
- **Frontend:** Next.js 14+ (App Router), Tailwind CSS, Shadcn/UI,
|
||||
TanStack Query (**Server State**), Zustand (**Client State**), React Hook Form + Zod (**Form State**), Axios
|
||||
- **Notifications:** BullMQ Queue → Email / LINE Notify / In-App
|
||||
- **Language:** TypeScript (Strict Mode). **NO `any` types allowed.**
|
||||
|
||||
## 🛡️ Security & Integrity Rules
|
||||
|
||||
1. **Idempotency:** All critical POST/PUT requests MUST check for `Idempotency-Key` header.
|
||||
2. **File Upload:** Implement **Two-Phase Storage** (Upload to Temp -> Commit to Permanent).
|
||||
3. **Race Conditions:** Use **Redis Lock** + **Optimistic Locking** for Document Numbering generation.
|
||||
4. **Validation:** Use Zod or Class-validator for all inputs.
|
||||
1. **Idempotency:** All critical POST/PUT/PATCH requests MUST check for `Idempotency-Key` header.
|
||||
2. **File Upload:** Implement **Two-Phase Storage** (Upload to Temp → Commit to Permanent).
|
||||
3. **Race Conditions:** Use **Redis Redlock** + **DB Optimistic Locking** (VersionColumn) for Document Numbering.
|
||||
4. **Validation:** Use Zod (frontend) or Class-validator (backend DTO) for all inputs.
|
||||
5. **Password:** bcrypt with 12 salt rounds. Enforce password policy.
|
||||
6. **Rate Limiting:** Apply ThrottlerGuard on auth endpoints.
|
||||
|
||||
## workflow Guidelines
|
||||
## 📋 Workflow & Spec Guidelines
|
||||
|
||||
- When implementing strictly follow the documents in `specs/`.
|
||||
- Always verify database schema against `specs/07-database/` before writing queries.
|
||||
- Always follow specs in `specs/` (v1.8.0). Priority: `06-Decision-Records` > `05-Engineering-Guidelines` > others.
|
||||
- Always verify database schema against **`specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql`** before writing queries.
|
||||
- Adhere to ADRs: ADR-001 (Workflow Engine), ADR-002 (Doc Numbering), ADR-009 (DB Strategy),
|
||||
ADR-011 (App Router), ADR-013 (Form Handling), ADR-016 (Security).
|
||||
|
||||
## 🎯 Active Skills
|
||||
|
||||
- **`nestjs-best-practices`** — Apply when writing/reviewing any NestJS code (modules, services, controllers, guards, interceptors, DTOs)
|
||||
- **`next-best-practices`** — Apply when writing/reviewing any Next.js code (App Router, RSC boundaries, async patterns, data fetching, error handling)
|
||||
|
||||
## 🔄 Speckit Workflow Pipeline
|
||||
|
||||
Use `/slash-command` to trigger these workflows. Always prefer spec-driven development for new features.
|
||||
|
||||
| Phase | Command | เมื่อใช้ |
|
||||
| -------------------- | ---------------------------------------------------------- | --------------------------------------------------- |
|
||||
| **Feature Design** | `/speckit.prepare` | Feature ใหม่ — รัน Specify→Clarify→Plan→Tasks→Analyze |
|
||||
| **Implement** | `/07-speckit.implement` | เขียนโค้ดตาม tasks.md พร้อม anti-regression |
|
||||
| **QA** | `/08-speckit.checker` | ตรวจ TypeScript + ESLint + Security |
|
||||
| **Test** | `/09-speckit.tester` | รัน Jest/Vitest + coverage report |
|
||||
| **Review** | `/10-speckit.reviewer` | Code review — Logic, Performance, Style |
|
||||
| **Validate** | `/11-speckit.validate` | ยืนยันว่า implementation ตรงกับ spec.md |
|
||||
| **Project-Specific** | `/create-backend-module` `/create-frontend-page` `/deploy` | งานประจำของ LCBP3-DMS |
|
||||
|
||||
## 🚫 Forbidden Actions
|
||||
|
||||
- DO NOT use SQL Triggers (Business logic must be in NestJS services).
|
||||
- DO NOT use `.env` files for production configuration (Use Docker environment variables).
|
||||
- DO NOT run database migrations — modify the schema SQL file directly.
|
||||
- DO NOT invent table names or columns — use ONLY what is defined in the schema SQL file.
|
||||
- DO NOT generate code that violates OWASP Top 10 security practices.
|
||||
- DO NOT use `any` TypeScript type anywhere.
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
description = "Execute the implementation plan by processing and executing all tasks defined in tasks.md"
|
||||
|
||||
prompt = """
|
||||
---
|
||||
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
|
||||
1. Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
|
||||
- Scan all checklist files in the checklists/ directory
|
||||
- For each checklist, count:
|
||||
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
|
||||
- Completed items: Lines matching `- [X]` or `- [x]`
|
||||
- Incomplete items: Lines matching `- [ ]`
|
||||
- Create a status table:
|
||||
|
||||
```text
|
||||
| Checklist | Total | Completed | Incomplete | Status |
|
||||
|-----------|-------|-----------|------------|--------|
|
||||
| ux.md | 12 | 12 | 0 | ✓ PASS |
|
||||
| test.md | 8 | 5 | 3 | ✗ FAIL |
|
||||
| security.md | 6 | 6 | 0 | ✓ PASS |
|
||||
```
|
||||
|
||||
- Calculate overall status:
|
||||
- **PASS**: All checklists have 0 incomplete items
|
||||
- **FAIL**: One or more checklists have incomplete items
|
||||
|
||||
- **If any checklist is incomplete**:
|
||||
- Display the table with incomplete item counts
|
||||
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
|
||||
- Wait for user response before continuing
|
||||
- If user says "no" or "wait" or "stop", halt execution
|
||||
- If user says "yes" or "proceed" or "continue", proceed to step 3
|
||||
|
||||
- **If all checklists are complete**:
|
||||
- Display the table showing all checklists passed
|
||||
- Automatically proceed to step 3
|
||||
|
||||
3. Load and analyze the implementation context:
|
||||
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
|
||||
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
|
||||
- **IF EXISTS**: Read data-model.md for entities and relationships
|
||||
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
|
||||
- **IF EXISTS**: Read research.md for technical decisions and constraints
|
||||
- **IF EXISTS**: Read quickstart.md for integration scenarios
|
||||
|
||||
4. **Project Setup Verification**:
|
||||
- **REQUIRED**: Create/verify ignore files based on actual project setup:
|
||||
|
||||
**Detection & Creation Logic**:
|
||||
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
|
||||
|
||||
```sh
|
||||
git rev-parse --git-dir 2>/dev/null
|
||||
```
|
||||
|
||||
- Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore
|
||||
- Check if .eslintrc* exists → create/verify .eslintignore
|
||||
- Check if eslint.config.* exists → ensure the config's `ignores` entries cover required patterns
|
||||
- Check if .prettierrc* exists → create/verify .prettierignore
|
||||
- Check if .npmrc or package.json exists → create/verify .npmignore (if publishing)
|
||||
- Check if terraform files (*.tf) exist → create/verify .terraformignore
|
||||
- Check if .helmignore needed (helm charts present) → create/verify .helmignore
|
||||
|
||||
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
|
||||
**If ignore file missing**: Create with full pattern set for detected technology
|
||||
|
||||
**Common Patterns by Technology** (from plan.md tech stack):
|
||||
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
|
||||
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
|
||||
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
|
||||
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
|
||||
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
|
||||
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
|
||||
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
|
||||
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
|
||||
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
|
||||
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
|
||||
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
|
||||
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
|
||||
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
|
||||
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
|
||||
|
||||
**Tool-Specific Patterns**:
|
||||
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
|
||||
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
|
||||
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
|
||||
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
|
||||
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
|
||||
|
||||
5. Parse tasks.md structure and extract:
|
||||
- **Task phases**: Setup, Tests, Core, Integration, Polish
|
||||
- **Task dependencies**: Sequential vs parallel execution rules
|
||||
- **Task details**: ID, description, file paths, parallel markers [P]
|
||||
- **Execution flow**: Order and dependency requirements
|
||||
|
||||
6. Execute implementation following the task plan:
|
||||
- **Phase-by-phase execution**: Complete each phase before moving to the next
|
||||
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
|
||||
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
|
||||
- **File-based coordination**: Tasks affecting the same files must run sequentially
|
||||
- **Validation checkpoints**: Verify each phase completion before proceeding
|
||||
|
||||
7. Implementation execution rules:
|
||||
- **Setup first**: Initialize project structure, dependencies, configuration
|
||||
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
|
||||
- **Core development**: Implement models, services, CLI commands, endpoints
|
||||
- **Integration work**: Database connections, middleware, logging, external services
|
||||
- **Polish and validation**: Unit tests, performance optimization, documentation
|
||||
|
||||
8. Progress tracking and error handling:
|
||||
- Report progress after each completed task
|
||||
- Halt execution if any non-parallel task fails
|
||||
- For parallel tasks [P], continue with successful tasks, report failed ones
|
||||
- Provide clear error messages with context for debugging
|
||||
- Suggest next steps if implementation cannot proceed
|
||||
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
|
||||
|
||||
9. Completion validation:
|
||||
- Verify all required tasks are completed
|
||||
- Check that implemented features match the original specification
|
||||
- Validate that tests pass and coverage meets requirements
|
||||
- Confirm the implementation follows the technical plan
|
||||
- Report final status with summary of completed work
|
||||
|
||||
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.
|
||||
"""
|
||||
48
CHANGELOG.md
48
CHANGELOG.md
@@ -3,18 +3,40 @@
|
||||
## [Unreleased]
|
||||
|
||||
### In Progress
|
||||
- Backend Document Numbering Refactor (TASK-BE-017)
|
||||
- E2E Testing & UAT preparation
|
||||
- Production deployment preparation
|
||||
|
||||
- Continuous Integration & End-to-End Test (E2E) Improvements
|
||||
- Advanced Analytics Dashboard Planning
|
||||
|
||||
## 1.8.0 (2026-02-24)
|
||||
|
||||
### Summary
|
||||
|
||||
**Documentation Realignment & Type Safety** - Comprehensive overhaul of the specifications structure and frontend codebase to enforce strict typing and consistency.
|
||||
|
||||
### Codebase Changes 💻
|
||||
|
||||
- **Frontend Type Safety**: Removed all `any` types from Frontend DTOs and Hooks. Implemented explicit types (`AuditLog[]`, `Record<string, unknown>`) avoiding implicit fallbacks.
|
||||
- **Frontend Refactoring**: Refactored data fetching and mutations utilizing `TanStack Query` hooks aligned with real API endpoints.
|
||||
- **Admin Pages Fixes**: Addressed crashes on Reference Data/Categories pages by introducing robust error handling and proper generic typing on DataTables.
|
||||
|
||||
### Documentation 📚
|
||||
|
||||
- **Specification Restructuring**: Restructured the entire `specs/` directory into 7 canonical layers (`00-Overview`, `01-Requirements`, `02-Architecture`, `03-Data-and-Storage`, `04-Infrastructure-OPS`, `05-Engineering-Guidelines`, `06-Decision-Records`).
|
||||
- **Guidelines Synchronization**: Updated Engineering Guidelines (`05-1` to `05-4`) to reflect the latest state management (Zustand, React Hook Form) and testing strategies.
|
||||
- **ADR Alignment**: Audited Architecture Decision Records (ADR 1 to 16) against actual implementation (e.g., LocalStorage JWT vs HTTP-Only cookies, bcrypt salt rounds).
|
||||
- **Root Docs Update**: Fully updated `README.md` and `CONTRIBUTING.md` to reflect the current v1.8.0 folder structure and rules.
|
||||
- **Cleanups**: Consolidated standalone infrastructure specs (formerly `08-infrastructure`) into `04-Infrastructure-OPS` and cleaned up legacy scripts and blank diagrams from the repository root.
|
||||
|
||||
## 1.7.0 (2025-12-18)
|
||||
|
||||
### Summary
|
||||
|
||||
**Schema Stabilization & Document Numbering Overhaul** - Significant schema updates to support advanced document numbering (reservations, varying reset scopes) and a unified workflow engine.
|
||||
|
||||
### Database Schema Changes 💾
|
||||
|
||||
#### Document Numbering System (V2) 🔢
|
||||
|
||||
- **`document_number_counters`**:
|
||||
- **Breaking Change**: Primary Key changed to 8-column Composite Key (`project_id`, `originator_id`, `recipient_id`, `type_id`, `sub_type_id`, `rfa_type_id`, `discipline_id`, `reset_scope`).
|
||||
- **New Feature**: Added `reset_scope` column to support flexible resetting (YEAR, MONTH, PROJECT, NONE).
|
||||
@@ -28,6 +50,7 @@
|
||||
- Enhanced with reservation tokens and performance metrics.
|
||||
|
||||
#### Unified Workflow Engine 🔄
|
||||
|
||||
- **`workflow_definitions`**:
|
||||
- Updated structure to support compiled DSL and versioning.
|
||||
- Added `dsl` (JSON) and `compiled` (JSON) columns.
|
||||
@@ -38,6 +61,7 @@
|
||||
- Updated to link with UUID instances.
|
||||
|
||||
#### System & Audit 🛡️
|
||||
|
||||
- **`audit_logs`**:
|
||||
- Updated schema for better partitioning support (`created_at` in PK).
|
||||
- Standardized JSON details column.
|
||||
@@ -45,25 +69,30 @@
|
||||
- Updated schema to support polymorphic entity linking.
|
||||
|
||||
#### Master Data
|
||||
|
||||
- **`disciplines`**:
|
||||
- Added relation to `correspondences` and `rfas`.
|
||||
|
||||
### Documentation 📚
|
||||
|
||||
- **Data Dictionary**: Updated to v1.7.0 with full index summaries and business rules.
|
||||
- **Schema**: Released `lcbp3-v1.7.0-schema.sql` and `lcbp3-v1.7.0-seed.sql`.
|
||||
|
||||
## 1.6.0 (2025-12-13)
|
||||
|
||||
### Summary
|
||||
|
||||
**Schema Refactoring Release** - Major restructuring of correspondence and RFA tables for improved data consistency.
|
||||
|
||||
### Database Schema Changes 💾
|
||||
|
||||
#### Breaking Changes ⚠️
|
||||
|
||||
- **`correspondence_recipients`**: FK changed from `correspondence_revisions(correspondence_id)` → `correspondences(id)`
|
||||
- **`rfa_items`**: Column renamed `rfarev_correspondence_id` → `rfa_revision_id`
|
||||
|
||||
#### Schema Refactoring
|
||||
|
||||
- **`correspondences`**: Reordered columns, `discipline_id` now inline (no ALTER TABLE)
|
||||
- **`correspondence_revisions`**:
|
||||
- Renamed: `title` → `subject`
|
||||
@@ -79,12 +108,14 @@
|
||||
- Added Virtual Column: `v_ref_drawing_count`
|
||||
|
||||
### Documentation 📚
|
||||
|
||||
- Updated Data Dictionary to v1.6.0
|
||||
- Updated schema SQL files (`lcbp3-v1.6.0-schema.sql`, seed files)
|
||||
|
||||
## 1.5.1 (2025-12-10)
|
||||
|
||||
### Summary
|
||||
|
||||
**Major Milestone: System Feature Complete (~95%)** - Ready for UAT and production deployment.
|
||||
|
||||
All core modules implemented and operational. Backend and frontend fully integrated with comprehensive admin tools.
|
||||
@@ -92,6 +123,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
### Backend Completed ✅
|
||||
|
||||
#### Core Infrastructure
|
||||
|
||||
- ✅ All 18 core modules implemented and tested
|
||||
- ✅ JWT Authentication with Refresh Token mechanism
|
||||
- ✅ RBAC 4-Level (Global, Organization, Project, Contract) using CASL
|
||||
@@ -102,6 +134,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ Health Monitoring & Metrics endpoints
|
||||
|
||||
#### Business Modules
|
||||
|
||||
- ✅ **Correspondence Module** - Master-Revision pattern, Workflow integration, References
|
||||
- ✅ **RFA Module** - Full CRUD, Item management, Revision handling, Approval workflow
|
||||
- ✅ **Drawing Module** - Separated into Shop Drawing & Contract Drawing
|
||||
@@ -110,6 +143,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ **Elasticsearch Integration** - Direct indexing, Full-text search (95% complete)
|
||||
|
||||
#### Supporting Services
|
||||
|
||||
- ✅ **Notification System** - Email and LINE notification integration
|
||||
- ✅ **Master Data Management** - Consolidated service for Organizations, Projects, Disciplines, Types
|
||||
- ✅ **User Management** - CRUD, Assignments, Preferences, Soft Delete
|
||||
@@ -119,6 +153,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
### Frontend Completed ✅
|
||||
|
||||
#### Application Structure
|
||||
|
||||
- ✅ All 15 frontend tasks (FE-001 to FE-015) completed
|
||||
- ✅ Next.js 14 App Router with TypeScript
|
||||
- ✅ Complete UI implementation (17 component groups, 22 Shadcn/UI components)
|
||||
@@ -128,6 +163,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ Responsive layout (Desktop & Mobile)
|
||||
|
||||
#### End-User Modules
|
||||
|
||||
- ✅ **Authentication UI** - Login, Token Management, Session Sync
|
||||
- ✅ **RBAC UI** - `<Can />` component for permission-based rendering
|
||||
- ✅ **Correspondence UI** - List, Create, Detail views with file uploads
|
||||
@@ -139,6 +175,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ **Transmittal UI** - Transmittal tracking and management
|
||||
|
||||
#### Admin Panel (10 Routes)
|
||||
|
||||
- ✅ **Workflow Configuration** - DSL Editor, Visual Builder, Workflow Definition management
|
||||
- ✅ **Document Numbering Config** - Template Editor, Token Tester, Sequence Viewer
|
||||
- ✅ **User Management** - CRUD, Role assignments, Preferences
|
||||
@@ -151,12 +188,14 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ **Settings** - System configuration
|
||||
|
||||
### Database 💾
|
||||
|
||||
- ✅ Schema v1.5.1 with standardized audit columns (`created_at`, `updated_at`, `deleted_at`)
|
||||
- ✅ Complete seed data for all master tables
|
||||
- ✅ Migration scripts and patches (`patch-audit-columns.sql`)
|
||||
- ✅ Data Dictionary v1.5.1 documentation
|
||||
|
||||
### Documentation 📚
|
||||
|
||||
- ✅ Complete specs/ reorganization to v1.5.1
|
||||
- ✅ 21 requirements documents in `specs/01-requirements/`
|
||||
- ✅ 17 ADRs (Architecture Decision Records) in `specs/05-decisions/`
|
||||
@@ -166,6 +205,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- ✅ Task archiving to `specs/09-history/` (27 completed tasks)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
|
||||
- 🐛 Fixed role selection bug in User Edit form (2025-12-09)
|
||||
- 🐛 Fixed workflow permissions - 403 error on workflow action endpoints
|
||||
- 🐛 Fixed TypeORM relation errors in RFA and Drawing services
|
||||
@@ -175,6 +215,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
- 🐛 Fixed invalid refresh token error loop
|
||||
|
||||
### Changed 📝
|
||||
|
||||
- 📝 Updated progress reports to reflect ~95% backend, 100% frontend completion
|
||||
- 📝 Aligned all TypeORM entities with schema v1.5.1
|
||||
- 📝 Enhanced data dictionary with business rules
|
||||
@@ -183,6 +224,7 @@ All core modules implemented and operational. Backend and frontend fully integra
|
||||
## 1.5.0 (2025-11-30)
|
||||
|
||||
### Summary
|
||||
|
||||
Initial spec-kit structure establishment and documentation organization.
|
||||
|
||||
### Changed
|
||||
|
||||
123
CONTRIBUTING.md
123
CONTRIBUTING.md
@@ -24,86 +24,67 @@
|
||||
|
||||
```
|
||||
specs/
|
||||
├── 00-overview/ # ภาพรวมโครงการ (3 docs)
|
||||
├── 00-Overview/ # ภาพรวมโครงการ
|
||||
│ ├── README.md # Project overview
|
||||
│ ├── glossary.md # คำศัพท์เทคนิค
|
||||
│ └── quick-start.md # Quick start guide
|
||||
│ ├── 00-02-glossary.md # คำศัพท์เทคนิค
|
||||
│ └── 00-01-quick-start.md # Quick start guide
|
||||
│
|
||||
├── 01-requirements/ # ข้อกำหนดระบบ (21 docs)
|
||||
├── 01-Requirements/ # ข้อกำหนดระบบ (21 docs)
|
||||
│ ├── README.md # Requirements overview
|
||||
│ ├── 01-objectives.md # วัตถุประสงค์
|
||||
│ ├── 02-architecture.md # สถาปัตยกรรม
|
||||
│ ├── 03-functional-requirements.md
|
||||
│ ├── 03.1-project-management.md
|
||||
│ ├── 03.2-correspondence.md
|
||||
│ ├── 03.3-rfa.md
|
||||
│ ├── 03.4-contract-drawing.md
|
||||
│ ├── 03.5-shop-drawing.md
|
||||
│ ├── 03.6-unified-workflow.md
|
||||
│ ├── 03.7-transmittals.md
|
||||
│ ├── 03.8-circulation-sheet.md
|
||||
│ ├── 03.9-logs.md
|
||||
│ ├── 03.10-file-handling.md
|
||||
│ ├── 03.11-document-numbering.md
|
||||
│ ├── 03.12-json-details.md
|
||||
│ ├── 04-access-control.md
|
||||
│ ├── 05-ui-ux.md
|
||||
│ ├── 06-non-functional.md
|
||||
│ └── 07-testing.md
|
||||
│ ├── 01-01-objectives.md # วัตถุประสงค์
|
||||
│ ├── 01-02-business-rules/ # กฏธุรกิจที่ห้ามละเมิด
|
||||
│ └── 01-03-modules/ # สเปกของแต่ละฟีเจอร์หลัก
|
||||
│
|
||||
├── 02-architecture/ # สถาปัตยกรรมระบบ (4 docs)
|
||||
├── 02-Architecture/ # สถาปัตยกรรมระบบ (4 docs)
|
||||
│ ├── README.md
|
||||
│ ├── system-architecture.md
|
||||
│ ├── api-design.md
|
||||
│ └── data-model.md
|
||||
│ ├── 02-01-system-context.md
|
||||
│ ├── 02-02-software-architecture.md
|
||||
│ ├── 02-03-network-design.md
|
||||
│ └── 02-04-api-design.md
|
||||
│
|
||||
├── 03-implementation/ # แผนการพัฒนา (5 docs)
|
||||
├── 03-Data-and-Storage/ # Database Schema (4 files)
|
||||
│ ├── README.md
|
||||
│ ├── backend-guidelines.md
|
||||
│ ├── frontend-guidelines.md
|
||||
│ ├── testing-strategy.md
|
||||
│ └── code-standards.md
|
||||
│ ├── lcbp3-v1.7.0-schema.sql
|
||||
│ ├── lcbp3-v1.7.0-seed-basic.sql
|
||||
│ └── 03-01-data-dictionary.md
|
||||
│
|
||||
├── 04-operations/ # การดำเนินงาน (9 docs)
|
||||
├── 04-Infrastructure-OPS/ # Deployment & Operations (9 docs)
|
||||
│ ├── README.md
|
||||
│ ├── deployment.md
|
||||
│ ├── monitoring.md
|
||||
│ ├── 04-01-docker-compose.md
|
||||
│ ├── 04-03-monitoring.md
|
||||
│ └── ...
|
||||
│
|
||||
├── 05-decisions/ # Architecture Decision Records (17 ADRs)
|
||||
├── 05-Engineering-Guidelines/# แผนการพัฒนา (5 docs)
|
||||
│ ├── README.md
|
||||
│ ├── ADR-001-workflow-engine.md
|
||||
│ ├── 05-01-fullstack-js-guidelines.md
|
||||
│ ├── 05-02-backend-guidelines.md
|
||||
│ ├── 05-03-frontend-guidelines.md
|
||||
│ └── 05-04-testing-strategy.md
|
||||
│
|
||||
├── 06-Decision-Records/ # Architecture Decision Records (17 ADRs)
|
||||
│ ├── README.md
|
||||
│ ├── ADR-001-unified-workflow.md
|
||||
│ ├── ADR-002-document-numbering.md
|
||||
│ └── ...
|
||||
│
|
||||
├── 06-tasks/ # Active Tasks & Progress (34 files)
|
||||
│ ├── frontend-progress-report.md
|
||||
│ ├── backend-progress-report.md
|
||||
│ └── ...
|
||||
│
|
||||
├── 07-database/ # Database Schema (8 files)
|
||||
│ ├── lcbp3-v1.7.0-schema.sql
|
||||
│ ├── lcbp3-v1.7.0-seed.sql
|
||||
│ ├── data-dictionary-v1.7.0.md
|
||||
│ └── ...
|
||||
│
|
||||
└── 09-history/ # Archived Implementations (9 files)
|
||||
└── ...
|
||||
└── 99-archives/ # ประวัติการทำงานและ Tasks เก่า
|
||||
├── history/
|
||||
├── tasks/
|
||||
└── obsolete-specs/
|
||||
```
|
||||
|
||||
### 📋 หมวดหมู่เอกสาร
|
||||
|
||||
| หมวด | วัตถุประสงค์ | ผู้ดูแล |
|
||||
| --------------------- | ----------------------------- | ----------------------------- |
|
||||
| **00-overview** | ภาพรวมโครงการและคำศัพท์ | Project Manager |
|
||||
| **01-requirements** | ข้อกำหนดฟังก์ชันและระบบ | Business Analyst + Tech Lead |
|
||||
| **02-architecture** | สถาปัตยกรรมและการออกแบบ | Tech Lead + Architects |
|
||||
| **03-implementation** | แผนการพัฒนาและ Implementation | Development Team Leads |
|
||||
| **04-operations** | Deployment และ Operations | DevOps Team |
|
||||
| **05-decisions** | Architecture Decision Records | Tech Lead + Senior Developers |
|
||||
| **06-tasks** | Active Tasks & Progress | All Team Members |
|
||||
| **07-database** | Database Schema & Seed Data | Backend Lead + DBA |
|
||||
| **09-history** | Archived Implementations | Tech Lead |
|
||||
| ----------------------------- | ----------------------------- | ----------------------------- |
|
||||
| **00-Overview** | ภาพรวมโครงการและคำศัพท์ | Project Manager |
|
||||
| **01-Requirements** | ข้อกำหนดฟังก์ชันและระบบ | Business Analyst + Tech Lead |
|
||||
| **02-Architecture** | สถาปัตยกรรมและการออกแบบ | Tech Lead + Architects |
|
||||
| **03-Data-and-Storage** | Database Schema & Seed Data | Backend Lead + DBA |
|
||||
| **04-Infrastructure-OPS** | Deployment และ Operations | DevOps Team |
|
||||
| **05-Engineering-Guidelines** | แผนการพัฒนาและ Implementation | Development Team Leads |
|
||||
| **06-Decision-Records** | Architecture Decision Records | Tech Lead + Senior Developers |
|
||||
| **99-archives** | Archived / Tasks | All Team Members |
|
||||
|
||||
---
|
||||
|
||||
@@ -184,8 +165,8 @@ POST /api/correspondences
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-30
|
||||
**Version**: 1.4.5
|
||||
**Last Updated**: 2026-02-24
|
||||
**Version**: 1.8.0
|
||||
**Status**: Draft | Review | Approved
|
||||
```
|
||||
|
||||
@@ -222,7 +203,7 @@ git checkout -b spec/adr/file-storage-strategy
|
||||
|
||||
```bash
|
||||
# แก้ไขไฟล์ที่เกี่ยวข้อง
|
||||
vim specs/01-requirements/03.2-correspondence.md
|
||||
vim specs/01-Requirements/01-03-modules/03-correspondence.md
|
||||
|
||||
# ตรวจสอบ markdown syntax
|
||||
pnpm run lint:markdown
|
||||
@@ -526,10 +507,10 @@ graph LR
|
||||
```markdown
|
||||
## Related Documents
|
||||
|
||||
- Requirements: [03.2-correspondence.md](./03.2-correspondence.md)
|
||||
- Architecture: [system-architecture.md](../02-architecture/system-architecture.md)
|
||||
- ADR: [ADR-001: Workflow Engine](../05-decisions/001-workflow-engine.md)
|
||||
- Implementation: [Backend Plan](../../docs/2_Backend_Plan_V1_4_5.md)
|
||||
- Requirements: [03.2-correspondence.md](../01-Requirements/01-03-modules/03-correspondence.md)
|
||||
- Architecture: [02-02-software-architecture.md](../02-Architecture/02-02-software-architecture.md)
|
||||
- ADR: [ADR-001-unified-workflow.md](../06-Decision-Records/ADR-001-unified-workflow.md)
|
||||
- Implementation: [05-02-backend-guidelines.md](../05-Engineering-Guidelines/05-02-backend-guidelines.md)
|
||||
````
|
||||
|
||||
### 4. Version Control
|
||||
@@ -545,14 +526,14 @@ graph LR
|
||||
| 1.1.0 | 2025-02-20 | Jane Smith | Add CC support |
|
||||
| 1.2.0 | 2025-03-10 | John Doe | Update workflow |
|
||||
|
||||
**Current Version**: 1.2.0
|
||||
**Current Version**: 1.8.0
|
||||
**Status**: Approved
|
||||
**Last Updated**: 2025-03-10
|
||||
**Last Updated**: 2026-02-24
|
||||
```
|
||||
|
||||
### 5. ใช้ Consistent Terminology
|
||||
|
||||
อ้างอิงจาก [glossary.md](./specs/00-overview/glossary.md) เสมอ
|
||||
อ้างอิงจาก [glossary.md](./specs/00-Overview/00-02-glossary.md) เสมอ
|
||||
|
||||
```markdown
|
||||
- ✅ ใช้: "Correspondence" (เอกสารโต้ตอบ)
|
||||
@@ -625,7 +606,7 @@ Create `.markdownlint.json`:
|
||||
### คำถามเกี่ยวกับ Specs
|
||||
|
||||
1. **ตรวจสอบเอกสารที่มีอยู่**: [specs/](./specs/)
|
||||
2. **ดู Glossary**: [specs/00-overview/glossary.md](./specs/00-overview/glossary.md)
|
||||
2. **ดู Glossary**: [00-02-glossary.md](./specs/00-Overview/00-02-glossary.md)
|
||||
3. **ค้นหา Issues**: [Gitea Issues](https://git.np-dms.work/lcbp3/lcbp3-dms/issues)
|
||||
4. **ถาม Team**: [ช่องทางการติดต่อ]
|
||||
|
||||
|
||||
Binary file not shown.
76
README.md
76
README.md
@@ -4,20 +4,20 @@
|
||||
>
|
||||
> ระบบบริหารจัดการเอกสารโครงการแบบครบวงจร สำหรับโครงการก่อสร้างท่าเรือแหลมฉบังระยะที่ 3
|
||||
|
||||
[](./CHANGELOG.md)
|
||||
[](./CHANGELOG.md)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
---
|
||||
|
||||
## 📈 Current Status (As of 2025-12-18)
|
||||
## 📈 Current Status (As of 2026-02-24)
|
||||
|
||||
**Overall Progress: ~97% Feature Complete - Production Ready Preparation**
|
||||
**Overall Progress: ~98% Feature Complete - Production Ready Preparation**
|
||||
|
||||
- ✅ **Backend**: Core modules implemented, refactoring for v1.7.0 Schema
|
||||
- ✅ **Frontend**: UI tasks completed (100%), integrating new v1.7.0 features
|
||||
- ✅ **Database**: Schema v1.7.0 active (Stabilized for Production)
|
||||
- ✅ **Documentation**: Comprehensive specs/ at v1.7.0
|
||||
- ✅ **Backend**: Core modules implemented, refactoring for v1.8.0 Schema
|
||||
- ✅ **Frontend**: UI tasks completed (100%), integrating new v1.8.0 features
|
||||
- ✅ **Database**: Schema v1.8.0 active (Stabilized for Production)
|
||||
- ✅ **Documentation**: Comprehensive specs/ at v1.8.0
|
||||
- ✅ **Admin Tools**: Unified Workflow & Advanced Numbering Config
|
||||
- 🔄 **Testing**: E2E tests and UAT preparation
|
||||
- 📋 **Next**: Final Security Audit & Deployment
|
||||
@@ -269,23 +269,21 @@ lcbp3-dms/
|
||||
│ ├── types/ # TypeScript definitions
|
||||
│ └── package.json
|
||||
│
|
||||
├── specs/ # 📘 Project Specifications (v1.5.1)
|
||||
│ ├── 00-overview/ # Project overview & glossary
|
||||
│ ├── 01-requirements/ # Functional requirements (21 docs)
|
||||
│ ├── 02-architecture/ # System architecture
|
||||
│ ├── 03-implementation/ # Implementation guidelines
|
||||
│ ├── 04-operations/ # Deployment & operations
|
||||
│ ├── 05-decisions/ # ADRs (17 decisions)
|
||||
│ ├── 06-tasks/ # Active tasks & progress
|
||||
│ ├── 07-database/ # Schema v1.5.1 & seed data
|
||||
│ └── 09-history/ # Archived implementations
|
||||
├── specs/ # 📘 Project Specifications (v1.8.0)
|
||||
│ ├── 00-Overview/ # ภาพรวมระบบและแบบย่อ
|
||||
│ ├── 01-Requirements/ # Business Requirements & กฎระเบียบ (21 docs)
|
||||
│ ├── 02-Architecture/ # สถาปัตยกรรมระบบ
|
||||
│ ├── 03-Data-and-Storage/ # โครงสร้างฐานข้อมูล v1.8.0 & Data Dictionary
|
||||
│ ├── 04-Infrastructure-OPS/ # การเตรียม Operations & Infrastructure
|
||||
│ ├── 05-Engineering-Guidelines/ # มาตรฐานการพัฒนาสำหรับโปรแกรมเมอร์
|
||||
│ ├── 06-Decision-Records/ # สรุปเหตุผลด้านสถาปัตยกรรม (ADRs)
|
||||
│ └── 99-archives/ # ประวัติการทำงานและ Tasks เก่า
|
||||
│
|
||||
├── docs/ # 📚 Legacy documentation
|
||||
├── diagrams/ # 📊 Architecture diagrams
|
||||
├── infrastructure/ # 🐳 Docker & Deployment configs
|
||||
│
|
||||
├── .gemini/ # 🤖 AI agent configuration
|
||||
├── .agent/ # Agent workflows
|
||||
├── .agents/ # Agent workflows and tools
|
||||
├── GEMINI.md # AI coding guidelines
|
||||
├── CONTRIBUTING.md # Contribution guidelines
|
||||
├── CHANGELOG.md # Version history
|
||||
@@ -299,21 +297,23 @@ lcbp3-dms/
|
||||
### เอกสารหลัก (specs/ folder)
|
||||
|
||||
| เอกสาร | คำอธิบาย | โฟลเดอร์ |
|
||||
| ------------------ | ------------------------------ | -------------------------- |
|
||||
| **Overview** | ภาพรวมโครงการ, Glossary | `specs/00-overview/` |
|
||||
| **Requirements** | ข้อกำหนดระบบและฟังก์ชันการทำงาน | `specs/01-requirements/` |
|
||||
| **Architecture** | สถาปัตยกรรมระบบ, ADRs | `specs/02-architecture/` |
|
||||
| **Implementation** | แนวทางการพัฒนา Backend/Frontend | `specs/03-implementation/` |
|
||||
| **Database** | Schema v1.7.0 + Seed Data | `specs/07-database/` |
|
||||
| ------------------- | ------------------------------ | ---------------------------------- |
|
||||
| **Overview** | ภาพรวมโครงการ, Glossary | `specs/00-Overview/` |
|
||||
| **Requirements** | ข้อกำหนดระบบและฟังก์ชันการทำงาน | `specs/01-Requirements/` |
|
||||
| **Architecture** | สถาปัตยกรรมระบบ | `specs/02-Architecture/` |
|
||||
| **Database** | Schema v1.8.0 + Seed Data | `specs/03-Data-and-Storage/` |
|
||||
| **Ops & Deploy** | วิธีการนำระบบขึ้นเซิร์ฟเวอร์ | `specs/04-Infrastructure-OPS/` |
|
||||
| **Guidelines** | แนวทางการพัฒนา Backend/Frontend | `specs/05-Engineering-Guidelines/` |
|
||||
| **Decisions (ADR)** | เหตุผลการตัดสินใจทางสถาปัตยกรรม | `specs/06-Decision-Records/` |
|
||||
|
||||
### Schema & Seed Data
|
||||
|
||||
```bash
|
||||
# Import schema
|
||||
mysql -u root -p lcbp3_dev < specs/07-database/lcbp3-v1.7.0-schema.sql
|
||||
mysql -u root -p lcbp3_dev < specs/03-Data-and-Storage/lcbp3-v1.7.0-schema.sql
|
||||
|
||||
# Import seed data
|
||||
mysql -u root -p lcbp3_dev < specs/07-database/lcbp3-v1.7.0-seed.sql
|
||||
mysql -u root -p lcbp3_dev < specs/03-Data-and-Storage/lcbp3-v1.7.0-seed-basic.sql
|
||||
```
|
||||
|
||||
### Legacy Documentation
|
||||
@@ -401,12 +401,10 @@ pnpm test:e2e # Playwright E2E
|
||||
### Security Best Practices
|
||||
|
||||
1. **ห้ามเก็บ Secrets ใน Git**
|
||||
|
||||
- ใช้ `.env` สำหรับ Development
|
||||
- ใช้ `docker-compose.override.yml` (gitignored)
|
||||
|
||||
2. **Password Policy**
|
||||
|
||||
- ความยาวขั้นต่ำ: 8 ตัวอักษร
|
||||
- ต้องมี uppercase, lowercase, number, special character
|
||||
- เปลี่ยน password ทุก 90 วัน
|
||||
@@ -533,6 +531,7 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
|
||||
### Version 1.5.1 (Current - Dec 2025) ✅ **FEATURE COMPLETE**
|
||||
|
||||
**Backend (18 Modules - ~95%)**
|
||||
|
||||
- ✅ Core Infrastructure (Auth, RBAC, File Storage)
|
||||
- ✅ Authentication & Authorization (JWT + CASL RBAC 4-Level)
|
||||
- ✅ Correspondence Module (Master-Revision Pattern)
|
||||
@@ -549,6 +548,7 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
|
||||
- ✅ Swagger API Documentation
|
||||
|
||||
**Frontend (15 Tasks - 100%)**
|
||||
|
||||
- ✅ Complete UI Implementation (17 component groups)
|
||||
- ✅ All Business Modules (Correspondence, RFA, Drawings)
|
||||
- ✅ Admin Panel (10 routes including Workflow & Numbering Config)
|
||||
@@ -558,22 +558,24 @@ This project is **Internal Use Only** - ลิขสิทธิ์เป็น
|
||||
- ✅ Responsive Layout (Desktop & Mobile)
|
||||
|
||||
**Documentation**
|
||||
|
||||
- ✅ Complete specs/ v1.6.0 (21 requirements, 17 ADRs)
|
||||
- ✅ Database Schema v1.6.0 with seed data
|
||||
- ✅ Implementation & Operations Guides
|
||||
|
||||
### Version 1.7.0 (Current - Dec 2025)
|
||||
### Version 1.8.0 (Current - Feb 2026)
|
||||
|
||||
**Schema & Core Stabilization**
|
||||
- ✅ **Document Numbering V2**: Composite Keys, Reservations, Reset Scopes
|
||||
- ✅ **Unified Workflow Engine**: Compiled DSL, Polymorphic Instances
|
||||
- ✅ **Data Dictionary**: Complete Update to v1.7.0
|
||||
- 🔄 **Backend Refactor**: Aligning services with new schema
|
||||
- 📋 **E2E Test Coverage**: Playwright/Cypress rollout
|
||||
**Schema & Documentation Realignment**
|
||||
|
||||
### Version 1.8.0+ (Planned - Q1 2026)
|
||||
- ✅ **Specs Refactoring**: Merged infrastructure docs, reorganized `specs` tree to standard structure.
|
||||
- ✅ **Database & Models**: Fully aligned Next.js features and TanStack Query with real v1.8.0 implementation.
|
||||
- ✅ **Clean Code**: Comprehensive purge of `any` types from Frontend and robust Error Handling.
|
||||
- 📋 **Deployment Readiness**: Preparing robust healthcheck and Nginx configurations for QNAP/ASUSTOR.
|
||||
|
||||
### Version 1.9.0+ (Planned)
|
||||
|
||||
**Production Enhancements**
|
||||
|
||||
- 📊 Advanced Reporting & Analytics Dashboard
|
||||
- 🔔 Enhanced Notifications (Real-time WebSocket)
|
||||
- 📈 Prometheus Metrics & Grafana Dashboards
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
at Readable.push (node:internal/streams/readable:392:5) {
|
||||
|
||||
query: 'DELETE FROM `notifications` WHERE (`is_read` = ? AND `createdAt` < ?)',
|
||||
|
||||
parameters: [
|
||||
|
||||
true,
|
||||
|
||||
2026-01-17T17:00:00.024Z
|
||||
|
||||
],
|
||||
|
||||
driverError: Error: Unknown column 'createdAt' in 'WHERE'
|
||||
|
||||
at Packet.asError (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packets/packet.js:740:17)
|
||||
|
||||
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:29:26)
|
||||
|
||||
at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)
|
||||
|
||||
at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)
|
||||
|
||||
at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)
|
||||
|
||||
at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)
|
||||
|
||||
at Socket.emit (node:events:519:28)
|
||||
|
||||
at addChunk (node:internal/streams/readable:561:12)
|
||||
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||
|
||||
at Readable.push (node:internal/streams/readable:392:5) {
|
||||
|
||||
code: 'ER_BAD_FIELD_ERROR',
|
||||
|
||||
errno: 1054,
|
||||
|
||||
sqlState: '42S22',
|
||||
|
||||
sqlMessage: "Unknown column 'createdAt' in 'WHERE'",
|
||||
|
||||
sql: "DELETE FROM `notifications` WHERE (`is_read` = true AND `createdAt` < '2026-01-18 00:00:00.024')"
|
||||
|
||||
},
|
||||
|
||||
code: 'ER_BAD_FIELD_ERROR',
|
||||
|
||||
errno: 1054,
|
||||
|
||||
sqlState: '42S22',
|
||||
|
||||
sqlMessage: "Unknown column 'createdAt' in 'WHERE'",
|
||||
|
||||
sql: "DELETE FROM `notifications` WHERE (`is_read` = true AND `createdAt` < '2026-01-18 00:00:00.024')"
|
||||
|
||||
}
|
||||
|
||||
[Nest] 1 - 02/17/2026, 12:00:00 AM LOG [FileCleanupService] No expired files found.
|
||||
|
||||
[Nest] 1 - 02/17/2026, 12:00:00 AM ERROR [NotificationCleanupService] Failed to cleanup notifications
|
||||
|
||||
[Nest] 1 - 02/17/2026, 12:00:00 AM ERROR [NotificationCleanupService] QueryFailedError: Unknown column 'createdAt' in 'WHERE'
|
||||
|
||||
at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_cb81dfd56f1203fe00eb0fec5dfcce08/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)
|
||||
|
||||
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)
|
||||
|
||||
at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)
|
||||
|
||||
at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)
|
||||
|
||||
at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)
|
||||
|
||||
at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)
|
||||
|
||||
at Socket.emit (node:events:519:28)
|
||||
|
||||
at addChunk (node:internal/streams/readable:561:12)
|
||||
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||
|
||||
at Readable.push (node:internal/streams/readable:392:5) {
|
||||
|
||||
query: 'DELETE FROM `notifications` WHERE (`is_read` = ? AND `createdAt` < ?)',
|
||||
|
||||
parameters: [
|
||||
|
||||
true,
|
||||
|
||||
2026-01-17T17:00:00.038Z
|
||||
|
||||
],
|
||||
|
||||
driverError: Error: Unknown column 'createdAt' in 'WHERE'
|
||||
|
||||
at Packet.asError (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packets/packet.js:740:17)
|
||||
|
||||
at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:29:26)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@casl/ability": "^6.7.3",
|
||||
"@casl/ability": "^6.7.5",
|
||||
"@elastic/elasticsearch": "^8.11.1",
|
||||
"@nestjs-modules/ioredis": "^2.0.2",
|
||||
"@nestjs/axios": "^4.0.1",
|
||||
@@ -130,5 +130,10 @@
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"fast-xml-parser": "^5.3.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Mermaid diagrams
|
||||
@@ -42,24 +42,24 @@ interface FieldConfig {
|
||||
label: string;
|
||||
type: "text" | "textarea" | "checkbox" | "select";
|
||||
required?: boolean;
|
||||
options?: { label: string; value: any }[];
|
||||
options?: { label: string; value: string | number | boolean }[];
|
||||
}
|
||||
|
||||
interface GenericCrudTableProps {
|
||||
interface GenericCrudTableProps<TEntity extends { id: number }> {
|
||||
entityName: string;
|
||||
queryKey: string[];
|
||||
fetchFn: () => Promise<any>;
|
||||
createFn: (data: any) => Promise<any>;
|
||||
updateFn: (id: number, data: any) => Promise<any>;
|
||||
deleteFn: (id: number) => Promise<any>;
|
||||
columns: ColumnDef<any>[];
|
||||
fetchFn: () => Promise<TEntity[]>;
|
||||
createFn: (data: Record<string, unknown>) => Promise<TEntity>;
|
||||
updateFn: (id: number, data: Record<string, unknown>) => Promise<TEntity>;
|
||||
deleteFn: (id: number) => Promise<unknown>;
|
||||
columns: ColumnDef<TEntity>[];
|
||||
fields: FieldConfig[];
|
||||
title?: string;
|
||||
description?: string;
|
||||
filters?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function GenericCrudTable({
|
||||
export function GenericCrudTable<TEntity extends { id: number }>({
|
||||
entityName,
|
||||
queryKey,
|
||||
fetchFn,
|
||||
@@ -71,11 +71,11 @@ export function GenericCrudTable({
|
||||
title,
|
||||
description,
|
||||
filters,
|
||||
}: GenericCrudTableProps) {
|
||||
}: GenericCrudTableProps<TEntity>) {
|
||||
const queryClient = useQueryClient();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [editingItem, setEditingItem] = useState<any>(null);
|
||||
const [formData, setFormData] = useState<any>({});
|
||||
const [editingItem, setEditingItem] = useState<TEntity | null>(null);
|
||||
const [formData, setFormData] = useState<Record<string, unknown>>({});
|
||||
|
||||
// Delete Dialog State
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
@@ -97,7 +97,7 @@ export function GenericCrudTable({
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: number; data: any }) => updateFn(id, data),
|
||||
mutationFn: ({ id, data }: { id: number; data: Record<string, unknown> }) => updateFn(id, data),
|
||||
onSuccess: () => {
|
||||
toast.success(`${entityName} updated successfully`);
|
||||
queryClient.invalidateQueries({ queryKey });
|
||||
@@ -123,7 +123,7 @@ export function GenericCrudTable({
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleEdit = (item: any) => {
|
||||
const handleEdit = (item: TEntity) => {
|
||||
setEditingItem(item);
|
||||
setFormData({ ...item });
|
||||
setIsOpen(true);
|
||||
@@ -155,8 +155,8 @@ export function GenericCrudTable({
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (field: string, value: any) => {
|
||||
setFormData((prev: any) => ({ ...prev, [field]: value }));
|
||||
const handleChange = (field: string, value: unknown) => {
|
||||
setFormData((prev: Record<string, unknown>) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
// Add default Actions column if not present
|
||||
@@ -165,7 +165,7 @@ export function GenericCrudTable({
|
||||
{
|
||||
id: "actions",
|
||||
header: "Actions",
|
||||
cell: ({ row }: { row: any }) => (
|
||||
cell: ({ row }: { row: { original: TEntity } }) => (
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -239,7 +239,7 @@ export function GenericCrudTable({
|
||||
{field.type === "textarea" ? (
|
||||
<Textarea
|
||||
id={field.name}
|
||||
value={formData[field.name] || ""}
|
||||
value={(formData[field.name] as string) || ""}
|
||||
onChange={(e) => handleChange(field.name, e.target.value)}
|
||||
required={field.required}
|
||||
/>
|
||||
@@ -266,7 +266,7 @@ export function GenericCrudTable({
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{field.options?.map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value.toString()}>
|
||||
<SelectItem key={(opt.value as string | number)} value={opt.value.toString()}>
|
||||
{opt.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
@@ -276,7 +276,7 @@ export function GenericCrudTable({
|
||||
<Input
|
||||
id={field.name}
|
||||
type="text"
|
||||
value={formData[field.name] || ""}
|
||||
value={(formData[field.name] as string) || ""}
|
||||
onChange={(e) => handleChange(field.name, e.target.value)}
|
||||
required={field.required}
|
||||
/>
|
||||
|
||||
@@ -14,6 +14,14 @@ import {
|
||||
} from "@/components/ui/popover";
|
||||
import { useSearchSuggestions } from "@/hooks/use-search";
|
||||
|
||||
/** Search suggestion item returned from the API */
|
||||
interface SearchSuggestion {
|
||||
id: string | number;
|
||||
type: string;
|
||||
title: string;
|
||||
documentNumber?: string;
|
||||
}
|
||||
|
||||
function useDebounceValue<T>(value: T, delay: number): T {
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
||||
useEffect(() => {
|
||||
@@ -87,7 +95,7 @@ export function GlobalSearch() {
|
||||
<CommandList>
|
||||
{suggestions && suggestions.length > 0 && (
|
||||
<CommandGroup heading="Suggestions">
|
||||
{suggestions.map((item: any) => (
|
||||
{(suggestions as SearchSuggestion[]).map((item) => (
|
||||
<CommandItem
|
||||
key={`${item.type}-${item.id}`}
|
||||
onSelect={() => {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { useNotifications, useMarkNotificationRead } from "@/hooks/use-notification";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { Notification } from "@/types/notification";
|
||||
|
||||
export function NotificationsDropdown() {
|
||||
const router = useRouter();
|
||||
@@ -23,7 +24,7 @@ export function NotificationsDropdown() {
|
||||
const notifications = data?.items || [];
|
||||
const unreadCount = data?.unreadCount || 0;
|
||||
|
||||
const handleNotificationClick = (notification: any) => {
|
||||
const handleNotificationClick = (notification: Notification) => {
|
||||
if (!notification.isRead) {
|
||||
markAsRead.mutate(notification.notificationId);
|
||||
}
|
||||
@@ -62,7 +63,7 @@ export function NotificationsDropdown() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="max-h-96 overflow-y-auto">
|
||||
{notifications.slice(0, 5).map((notification: any) => (
|
||||
{notifications.slice(0, 5).map((notification: Notification) => (
|
||||
<DropdownMenuItem
|
||||
key={notification.notificationId}
|
||||
className={`flex flex-col items-start p-3 cursor-pointer ${
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { AuditLog, AuditLogQueryParams } from '@/lib/services/audit-log.service';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { auditLogService, AuditLog } from '@/lib/services/audit-log.service';
|
||||
import { auditLogService } from '@/lib/services/audit-log.service';
|
||||
|
||||
export const auditLogKeys = {
|
||||
all: ['audit-logs'] as const,
|
||||
list: (params: any) => [...auditLogKeys.all, 'list', params] as const,
|
||||
list: (params?: AuditLogQueryParams) => [...auditLogKeys.all, 'list', params] as const,
|
||||
};
|
||||
|
||||
export function useAuditLogs(params?: any) {
|
||||
export function useAuditLogs(params?: AuditLogQueryParams) {
|
||||
return useQuery<AuditLog[]>({
|
||||
queryKey: auditLogKeys.list(params),
|
||||
queryFn: () => auditLogService.getLogs(params),
|
||||
|
||||
@@ -37,7 +37,7 @@ export const useNumberingMetrics = () => {
|
||||
export const useNumberingAuditLogs = (params?: AuditQueryParams) => {
|
||||
return useQuery({
|
||||
queryKey: numberingKeys.auditLogs(params),
|
||||
queryFn: () => documentNumberingService.getAuditLogs(params),
|
||||
queryFn: () => documentNumberingService.getAuditLogs(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ export const useCancelNumbering = () => {
|
||||
export const useBulkImportNumbering = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: FormData | any[]) => documentNumberingService.bulkImport(data),
|
||||
mutationFn: (data: FormData | { documentNumber: string; projectId: number; sequenceNumber: number }[]) => documentNumberingService.bulkImport(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: numberingKeys.all });
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { projectService } from '@/lib/services/project.service';
|
||||
import { CreateProjectDto, UpdateProjectDto, SearchProjectDto } from '@/types/dto/project/project.dto';
|
||||
import { toast } from 'sonner';
|
||||
import { getApiErrorMessage } from '@/types/api-error';
|
||||
|
||||
export const projectKeys = {
|
||||
all: ['projects'] as const,
|
||||
@@ -24,9 +25,9 @@ export function useCreateProject() {
|
||||
toast.success("Project created successfully");
|
||||
queryClient.invalidateQueries({ queryKey: projectKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to create project", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -40,9 +41,9 @@ export function useUpdateProject() {
|
||||
toast.success("Project updated successfully");
|
||||
queryClient.invalidateQueries({ queryKey: projectKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to update project", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -56,9 +57,9 @@ export function useDeleteProject() {
|
||||
toast.success("Project deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: projectKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to delete project", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { masterDataService } from '@/lib/services/master-data.service';
|
||||
import type { CreateDisciplineDto } from '@/types/dto/master/discipline.dto';
|
||||
import type { CreateRfaTypeDto, UpdateRfaTypeDto } from '@/types/dto/master/rfa-type.dto';
|
||||
import type { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from '@/types/dto/master/correspondence-type.dto';
|
||||
|
||||
export const referenceDataKeys = {
|
||||
all: ['reference-data'] as const,
|
||||
@@ -19,7 +22,7 @@ export const useRfaTypes = (contractId?: number) => {
|
||||
export const useCreateRfaType = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: any) => masterDataService.createRfaType(data),
|
||||
mutationFn: (data: CreateRfaTypeDto) => masterDataService.createRfaType(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['reference-data', 'rfaTypes'] });
|
||||
},
|
||||
@@ -29,7 +32,7 @@ export const useCreateRfaType = () => {
|
||||
export const useUpdateRfaType = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: number; data: any }) => masterDataService.updateRfaType(id, data),
|
||||
mutationFn: ({ id, data }: { id: number; data: UpdateRfaTypeDto }) => masterDataService.updateRfaType(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['reference-data', 'rfaTypes'] });
|
||||
},
|
||||
@@ -57,7 +60,7 @@ export const useDisciplines = (contractId?: number) => {
|
||||
export const useCreateDiscipline = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: any) => masterDataService.createDiscipline(data),
|
||||
mutationFn: (data: CreateDisciplineDto) => masterDataService.createDiscipline(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['reference-data', 'disciplines'] });
|
||||
},
|
||||
@@ -85,7 +88,7 @@ export const useCorrespondenceTypes = () => {
|
||||
export const useCreateCorrespondenceType = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: any) => masterDataService.createCorrespondenceType(data),
|
||||
mutationFn: (data: CreateCorrespondenceTypeDto) => masterDataService.createCorrespondenceType(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['reference-data', 'correspondenceTypes'] });
|
||||
},
|
||||
@@ -95,7 +98,7 @@ export const useCreateCorrespondenceType = () => {
|
||||
export const useUpdateCorrespondenceType = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: number; data: any }) => masterDataService.updateCorrespondenceType(id, data),
|
||||
mutationFn: ({ id, data }: { id: number; data: UpdateCorrespondenceTypeDto }) => masterDataService.updateCorrespondenceType(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['reference-data', 'correspondenceTypes'] });
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import { rfaService } from '@/lib/services/rfa.service';
|
||||
import { SearchRfaDto, CreateRfaDto, UpdateRfaDto } from '@/types/dto/rfa/rfa.dto';
|
||||
import { WorkflowActionDto } from '@/lib/services/rfa.service';
|
||||
import { toast } from 'sonner';
|
||||
import { getApiErrorMessage } from '@/types/api-error';
|
||||
|
||||
// Keys
|
||||
export const rfaKeys = {
|
||||
@@ -42,9 +43,9 @@ export function useCreateRFA() {
|
||||
toast.success('RFA created successfully');
|
||||
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error('Failed to create RFA', {
|
||||
description: error.response?.data?.message || 'Something went wrong',
|
||||
description: getApiErrorMessage(error, 'Something went wrong'),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -61,9 +62,9 @@ export function useUpdateRFA() {
|
||||
queryClient.invalidateQueries({ queryKey: rfaKeys.detail(id) });
|
||||
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error('Failed to update RFA', {
|
||||
description: error.response?.data?.message || 'Something went wrong',
|
||||
description: getApiErrorMessage(error, 'Something went wrong'),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -80,9 +81,9 @@ export function useProcessRFA() {
|
||||
queryClient.invalidateQueries({ queryKey: rfaKeys.detail(id) });
|
||||
queryClient.invalidateQueries({ queryKey: rfaKeys.lists() });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error('Failed to process workflow', {
|
||||
description: error.response?.data?.message || 'Something went wrong',
|
||||
description: getApiErrorMessage(error, 'Something went wrong'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { userService } from '@/lib/services/user.service';
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto } from '@/types/user'; // Ensure types exist
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto } from '@/types/user';
|
||||
import { toast } from 'sonner';
|
||||
import { getApiErrorMessage } from '@/types/api-error';
|
||||
|
||||
export const userKeys = {
|
||||
all: ['users'] as const,
|
||||
list: (params: any) => [...userKeys.all, 'list', params] as const,
|
||||
list: (params?: SearchUserDto) => [...userKeys.all, 'list', params] as const,
|
||||
detail: (id: number) => [...userKeys.all, 'detail', id] as const,
|
||||
};
|
||||
|
||||
@@ -31,9 +32,9 @@ export function useCreateUser() {
|
||||
toast.success("User created successfully");
|
||||
queryClient.invalidateQueries({ queryKey: userKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to create user", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -47,9 +48,9 @@ export function useUpdateUser() {
|
||||
toast.success("User updated successfully");
|
||||
queryClient.invalidateQueries({ queryKey: userKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to update user", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -63,9 +64,9 @@ export function useDeleteUser() {
|
||||
toast.success("User deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: userKeys.all });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
onError: (error: unknown) => {
|
||||
toast.error("Failed to delete user", {
|
||||
description: error.response?.data?.message || "Unknown error"
|
||||
description: getApiErrorMessage(error, "Unknown error")
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import NextAuth from "next-auth";
|
||||
import Credentials from "next-auth/providers/credentials";
|
||||
import { z } from "zod";
|
||||
import type { User } from "next-auth";
|
||||
import type { JWT } from "next-auth/jwt";
|
||||
|
||||
// Schema for input validation
|
||||
const loginSchema = z.object({
|
||||
@@ -17,12 +18,12 @@ function getJwtExpiry(token: string): number {
|
||||
try {
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
return payload.exp * 1000; // Convert to ms
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return Date.now(); // If invalid, treat as expired
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshAccessToken(token: any) {
|
||||
async function refreshAccessToken(token: JWT) {
|
||||
try {
|
||||
const response = await fetch(`${baseUrl}/auth/refresh`, {
|
||||
method: "POST",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { AuditQueryParams } from '@/types/dto/numbering.dto';
|
||||
|
||||
export interface AuditLog {
|
||||
auditId: string;
|
||||
@@ -12,16 +13,18 @@ export interface AuditLog {
|
||||
severity: string;
|
||||
entityType?: string;
|
||||
entityId?: string;
|
||||
detailsJson?: any;
|
||||
detailsJson?: Record<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export type AuditLogQueryParams = AuditQueryParams;
|
||||
|
||||
export const auditLogService = {
|
||||
getLogs: async (params?: any) => {
|
||||
const response = await apiClient.get<any>("/audit-logs", { params });
|
||||
getLogs: async (params?: AuditLogQueryParams) => {
|
||||
const response = await apiClient.get<{ data: AuditLog[] } | AuditLog[]>("/audit-logs", { params });
|
||||
// Support both wrapped and unwrapped scenarios
|
||||
return response.data.data || response.data;
|
||||
return (response.data as { data: AuditLog[] }).data ?? response.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export const correspondenceService = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
update: async (id: string | number, data: any) => {
|
||||
update: async (id: string | number, data: Partial<CreateCorrespondenceDto>) => {
|
||||
const response = await apiClient.put(`/correspondences/${id}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -4,9 +4,16 @@ import {
|
||||
ManualOverrideDto,
|
||||
VoidReplaceDto,
|
||||
CancelNumberDto,
|
||||
AuditQueryParams
|
||||
} from "@/types/dto/numbering.dto";
|
||||
|
||||
/** A bulk-import record row */
|
||||
export interface BulkImportRecord {
|
||||
documentNumber: string;
|
||||
projectId: number;
|
||||
sequenceNumber: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export const documentNumberingService = {
|
||||
// --- Admin Dashboard Metrics ---
|
||||
getMetrics: async (): Promise<NumberingMetrics> => {
|
||||
@@ -19,7 +26,7 @@ export const documentNumberingService = {
|
||||
await apiClient.post("/admin/document-numbering/manual-override", dto);
|
||||
},
|
||||
|
||||
voidAndReplace: async (dto: VoidReplaceDto): Promise<any> => {
|
||||
voidAndReplace: async (dto: VoidReplaceDto): Promise<{ documentNumber: string }> => {
|
||||
const response = await apiClient.post("/admin/document-numbering/void-and-replace", dto);
|
||||
return response.data;
|
||||
},
|
||||
@@ -28,7 +35,7 @@ export const documentNumberingService = {
|
||||
await apiClient.post("/admin/document-numbering/cancel", dto);
|
||||
},
|
||||
|
||||
bulkImport: async (data: FormData | any[]): Promise<any> => {
|
||||
bulkImport: async (data: FormData | BulkImportRecord[]): Promise<{ imported: number; errors: string[] }> => {
|
||||
const isFormData = data instanceof FormData;
|
||||
const config = isFormData ? { headers: { "Content-Type": "multipart/form-data" } } : {};
|
||||
const response = await apiClient.post("/admin/document-numbering/bulk-import", data, config);
|
||||
@@ -36,7 +43,7 @@ export const documentNumberingService = {
|
||||
},
|
||||
|
||||
// --- Audit Logs ---
|
||||
getAuditLogs: async (params?: AuditQueryParams) => {
|
||||
getAuditLogs: async () => {
|
||||
// NOTE: endpoint might be merged with metrics or separate
|
||||
// Currently controller has getMetrics returning audit logs too.
|
||||
// But if we want separate pagination later:
|
||||
|
||||
@@ -64,7 +64,7 @@ export const jsonSchemaService = {
|
||||
/**
|
||||
* (Optional) ตรวจสอบความถูกต้องของข้อมูลกับ Schema ฝั่ง Server
|
||||
*/
|
||||
validate: async (code: string, data: any) => {
|
||||
validate: async (code: string, data: Record<string, unknown>) => {
|
||||
// POST /json-schemas/validate
|
||||
const response = await apiClient.post(`/json-schemas/validate`, {
|
||||
schemaCode: code,
|
||||
|
||||
@@ -6,6 +6,8 @@ import { CreateTagDto, UpdateTagDto, SearchTagDto } from "@/types/dto/master/tag
|
||||
import { CreateDisciplineDto } from "@/types/dto/master/discipline.dto";
|
||||
import { CreateSubTypeDto } from "@/types/dto/master/sub-type.dto";
|
||||
import { SaveNumberFormatDto } from "@/types/dto/master/number-format.dto";
|
||||
import { CreateRfaTypeDto, UpdateRfaTypeDto } from "@/types/dto/master/rfa-type.dto";
|
||||
import { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from "@/types/dto/master/correspondence-type.dto";
|
||||
import { Organization } from "@/types/organization";
|
||||
import {
|
||||
CreateOrganizationDto,
|
||||
@@ -137,21 +139,11 @@ export const masterDataService = {
|
||||
},
|
||||
|
||||
/** สร้างประเภท RFA ใหม่ */
|
||||
createRfaType: async (data: any) => {
|
||||
// Note: Assuming endpoint is /master/rfa-types (POST)
|
||||
// Currently RfaController handles /rfas, but master data usually goes to MasterController or dedicated
|
||||
// The previous implementation used direct apiClient calls in the page.
|
||||
// Let's assume we use the endpoint we just updated in MasterController which is GET only?
|
||||
// Wait, MasterController doesn't have createRfaType.
|
||||
// Let's check where RFA Types are created. RfaController creates RFAs (documents).
|
||||
// RFA Types are likely master data.
|
||||
// I need to add create/update/delete endpoints for RFA Types to MasterController if they don't exist.
|
||||
// Checking MasterController again... it DOES NOT have createRfaType.
|
||||
// I will add them to MasterController first.
|
||||
createRfaType: async (data: CreateRfaTypeDto) => {
|
||||
return apiClient.post("/master/rfa-types", data).then(res => res.data);
|
||||
},
|
||||
|
||||
updateRfaType: async (id: number, data: any) => {
|
||||
updateRfaType: async (id: number, data: UpdateRfaTypeDto) => {
|
||||
return apiClient.patch(`/master/rfa-types/${id}`, data).then(res => res.data);
|
||||
},
|
||||
|
||||
@@ -167,11 +159,11 @@ export const masterDataService = {
|
||||
return response.data.data || response.data;
|
||||
},
|
||||
|
||||
createCorrespondenceType: async (data: any) => {
|
||||
createCorrespondenceType: async (data: CreateCorrespondenceTypeDto) => {
|
||||
return apiClient.post("/master/correspondence-types", data).then(res => res.data);
|
||||
},
|
||||
|
||||
updateCorrespondenceType: async (id: number, data: any) => {
|
||||
updateCorrespondenceType: async (id: number, data: UpdateCorrespondenceTypeDto) => {
|
||||
return apiClient.patch(`/master/correspondence-types/${id}`, data).then(res => res.data);
|
||||
},
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ export interface Session {
|
||||
|
||||
export const sessionService = {
|
||||
getActiveSessions: async () => {
|
||||
const response = await apiClient.get<any>('/auth/sessions');
|
||||
return response.data.data || response.data;
|
||||
const response = await apiClient.get<Session[] | { data: Session[] }>('/auth/sessions');
|
||||
return (response.data as { data: Session[] }).data ?? response.data;
|
||||
},
|
||||
|
||||
revokeSession: async (sessionId: number) => {
|
||||
|
||||
@@ -1,54 +1,62 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto, User } from "@/types/user";
|
||||
|
||||
const transformUser = (user: any): User => {
|
||||
/** Raw API user shape (before transform) */
|
||||
interface RawUser {
|
||||
user_id?: number;
|
||||
userId?: number;
|
||||
assignments?: Array<{ role: unknown }>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const transformUser = (user: RawUser): User => {
|
||||
return {
|
||||
...user,
|
||||
userId: user.user_id,
|
||||
roles: user.assignments?.map((a: any) => a.role) || [],
|
||||
...(user as unknown as User),
|
||||
userId: (user.user_id ?? user.userId) as number,
|
||||
roles: (user.assignments?.map((a) => a.role) ?? []) as User['roles'],
|
||||
};
|
||||
};
|
||||
|
||||
/** Paginated or unwrapped response shape */
|
||||
type UserListResponse = User[] | { data: User[] | { data: User[] } };
|
||||
|
||||
export const userService = {
|
||||
getAll: async (params?: SearchUserDto) => {
|
||||
const response = await apiClient.get<any>("/users", { params });
|
||||
const response = await apiClient.get<UserListResponse>("/users", { params });
|
||||
|
||||
// Handle both paginated and non-paginated responses
|
||||
let rawData = response.data?.data || response.data;
|
||||
|
||||
// If paginated (has .data property which is array)
|
||||
if (rawData && Array.isArray(rawData.data)) {
|
||||
rawData = rawData.data;
|
||||
let rawData: RawUser[] | unknown = response.data;
|
||||
if (rawData && !Array.isArray(rawData) && 'data' in (rawData as object)) {
|
||||
rawData = (rawData as { data: unknown }).data;
|
||||
}
|
||||
|
||||
// If still not array (e.g. error or empty), default to []
|
||||
if (!Array.isArray(rawData)) {
|
||||
return [];
|
||||
if (rawData && !Array.isArray(rawData) && typeof rawData === 'object' && 'data' in (rawData as object)) {
|
||||
rawData = (rawData as { data: unknown }).data;
|
||||
}
|
||||
if (!Array.isArray(rawData)) return [];
|
||||
|
||||
return rawData.map(transformUser);
|
||||
return (rawData as RawUser[]).map(transformUser);
|
||||
},
|
||||
|
||||
getRoles: async () => {
|
||||
const response = await apiClient.get<any>("/users/roles");
|
||||
if (response.data?.data) {
|
||||
return response.data.data;
|
||||
const response = await apiClient.get<{ data: unknown } | unknown>("/users/roles");
|
||||
if (response.data && typeof response.data === 'object' && 'data' in (response.data as object)) {
|
||||
return (response.data as { data: unknown }).data;
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getById: async (id: number) => {
|
||||
const response = await apiClient.get<User>(`/users/${id}`);
|
||||
const response = await apiClient.get<RawUser>(`/users/${id}`);
|
||||
return transformUser(response.data);
|
||||
},
|
||||
|
||||
create: async (data: CreateUserDto) => {
|
||||
const response = await apiClient.post<User>("/users", data);
|
||||
const response = await apiClient.post<RawUser>("/users", data);
|
||||
return transformUser(response.data);
|
||||
},
|
||||
|
||||
update: async (id: number, data: UpdateUserDto) => {
|
||||
const response = await apiClient.put<User>(`/users/${id}`, data);
|
||||
const response = await apiClient.put<RawUser>(`/users/${id}`, data);
|
||||
return transformUser(response.data);
|
||||
},
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist, createJSONStorage } from 'zustand/middleware';
|
||||
|
||||
/** A draft can hold any serializable form data — typed as unknown for strictness */
|
||||
type DraftValue = Record<string, unknown>;
|
||||
|
||||
interface DraftState {
|
||||
drafts: Record<string, any>;
|
||||
saveDraft: (key: string, data: any) => void;
|
||||
getDraft: (key: string) => any;
|
||||
drafts: Record<string, DraftValue>;
|
||||
saveDraft: (key: string, data: DraftValue) => void;
|
||||
getDraft: (key: string) => DraftValue | undefined;
|
||||
clearDraft: (key: string) => void;
|
||||
}
|
||||
|
||||
|
||||
20
frontend/types/api-error.ts
Normal file
20
frontend/types/api-error.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// Shared API error type for Axios-based error handling in TanStack Query
|
||||
export interface ApiErrorResponse {
|
||||
message?: string;
|
||||
error?: string;
|
||||
statusCode?: number;
|
||||
}
|
||||
|
||||
/** Axios-compatible error with typed response data */
|
||||
export interface ApiError extends Error {
|
||||
response?: {
|
||||
data?: ApiErrorResponse;
|
||||
status?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/** Extract human-readable message from API error */
|
||||
export function getApiErrorMessage(error: unknown, fallback = 'An unexpected error occurred'): string {
|
||||
const apiError = error as ApiError;
|
||||
return apiError?.response?.data?.message ?? apiError?.message ?? fallback;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export interface CorrespondenceRevision {
|
||||
statusCode: string;
|
||||
statusName: string;
|
||||
};
|
||||
details?: any;
|
||||
details?: Record<string, unknown> | null;
|
||||
attachments?: Attachment[];
|
||||
createdAt: string;
|
||||
|
||||
@@ -80,7 +80,7 @@ export interface CreateCorrespondenceDto {
|
||||
remarks?: string;
|
||||
dueDate?: string;
|
||||
description?: string;
|
||||
details?: Record<string, any>;
|
||||
details?: Record<string, unknown>;
|
||||
isInternal?: boolean;
|
||||
originatorId?: number;
|
||||
recipients?: { organizationId: number; type: 'TO' | 'CC' }[];
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface CreateContractDto {
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
export interface UpdateContractDto extends Partial<CreateContractDto> {}
|
||||
export type UpdateContractDto = Partial<CreateContractDto>;
|
||||
|
||||
export interface SearchContractDto {
|
||||
search?: string;
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface CreateCorrespondenceDto {
|
||||
dueDate?: string;
|
||||
|
||||
/** ข้อมูล JSON เฉพาะประเภท (เช่น RFI question, RFA details) */
|
||||
details?: Record<string, any>;
|
||||
details?: Record<string, unknown>;
|
||||
|
||||
/** เอกสารภายในหรือไม่ (True = ภายใน) */
|
||||
isInternal?: boolean;
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface CreateContractDrawingDto {
|
||||
}
|
||||
|
||||
// --- Update (Partial) ---
|
||||
export interface UpdateContractDrawingDto extends Partial<CreateContractDrawingDto> {}
|
||||
export type UpdateContractDrawingDto = Partial<CreateContractDrawingDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchContractDrawingDto {
|
||||
|
||||
@@ -9,14 +9,14 @@ export interface CreateJsonSchemaDto {
|
||||
version?: number;
|
||||
|
||||
/** โครงสร้าง JSON Schema (Standard Format) */
|
||||
schemaDefinition: Record<string, any>;
|
||||
schemaDefinition: Record<string, unknown>;
|
||||
|
||||
/** สถานะการใช้งาน */
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
// --- Update (Partial) ---
|
||||
export interface UpdateJsonSchemaDto extends Partial<CreateJsonSchemaDto> {}
|
||||
export type UpdateJsonSchemaDto = Partial<CreateJsonSchemaDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchJsonSchemaDto {
|
||||
|
||||
24
frontend/types/dto/master/correspondence-type.dto.ts
Normal file
24
frontend/types/dto/master/correspondence-type.dto.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// File: src/types/dto/master/correspondence-type.dto.ts
|
||||
|
||||
export interface CreateCorrespondenceTypeDto {
|
||||
/** ชื่อประเภทเอกสาร (เช่น 'Letter', 'RFA') */
|
||||
typeName: string;
|
||||
|
||||
/** รหัสประเภทเอกสาร (เช่น 'LTR', 'RFA') */
|
||||
typeCode: string;
|
||||
|
||||
/** มีการออกเลขเอกสารอัตโนมัติหรือไม่ */
|
||||
hasNumbering?: boolean;
|
||||
|
||||
/** สถานะการใช้งาน (Default: true) */
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
export type UpdateCorrespondenceTypeDto = Partial<CreateCorrespondenceTypeDto>;
|
||||
|
||||
export interface SearchCorrespondenceTypeDto {
|
||||
search?: string;
|
||||
isActive?: boolean;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
21
frontend/types/dto/master/rfa-type.dto.ts
Normal file
21
frontend/types/dto/master/rfa-type.dto.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// File: src/types/dto/master/rfa-type.dto.ts
|
||||
|
||||
export interface CreateRfaTypeDto {
|
||||
/** ชื่อประเภท RFA (เช่น 'Drawing Approval') */
|
||||
typeName: string;
|
||||
|
||||
/** รหัสประเภท RFA (เช่น 'DWG', 'MAT') */
|
||||
typeCode: string;
|
||||
|
||||
/** สถานะการใช้งาน (Default: true) */
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
export type UpdateRfaTypeDto = Partial<CreateRfaTypeDto>;
|
||||
|
||||
export interface SearchRfaTypeDto {
|
||||
search?: string;
|
||||
isActive?: boolean;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export interface CreateTagDto {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface UpdateTagDto extends Partial<CreateTagDto> {}
|
||||
export type UpdateTagDto = Partial<CreateTagDto>;
|
||||
|
||||
export interface SearchTagDto {
|
||||
/** คำค้นหา (ชื่อ Tag หรือ คำอธิบาย) */
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import type { AuditLog } from '@/lib/services/audit-log.service';
|
||||
|
||||
export interface AuditErrorRecord {
|
||||
code: string;
|
||||
message: string;
|
||||
timestamp: string;
|
||||
context?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface NumberingMetrics {
|
||||
audit: any[]; // Replace with specific AuditLog type if available
|
||||
errors: any[]; // Replace with specific ErrorLog type
|
||||
audit: AuditLog[];
|
||||
errors: AuditErrorRecord[];
|
||||
}
|
||||
|
||||
export interface ManualOverrideDto {
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface CreateProjectDto {
|
||||
}
|
||||
|
||||
// --- Update (Partial) ---
|
||||
export interface UpdateProjectDto extends Partial<CreateProjectDto> {}
|
||||
export type UpdateProjectDto = Partial<CreateProjectDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchProjectDto {
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface CreateRfaDto {
|
||||
}
|
||||
|
||||
// --- Update (Partial) ---
|
||||
export interface UpdateRfaDto extends Partial<CreateRfaDto> {}
|
||||
export type UpdateRfaDto = Partial<CreateRfaDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchRfaDto {
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface CreateTransmittalItemDto {
|
||||
}
|
||||
|
||||
// --- Update (Partial) ---
|
||||
export interface UpdateTransmittalDto extends Partial<CreateTransmittalDto> {}
|
||||
export type UpdateTransmittalDto = Partial<CreateTransmittalDto>;
|
||||
|
||||
// --- Search ---
|
||||
export interface SearchTransmittalDto {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user