mirror of
https://github.com/jparkerweb/plan2code.git
synced 2026-07-21 10:23:23 -07:00
v1.6.1
This commit is contained in:
@@ -5,3 +5,6 @@ dist/
|
||||
plan2code-loop/dist
|
||||
plan2code-loop/node_modules
|
||||
plan2code-loop/package-lock.json
|
||||
nul
|
||||
node_modules/
|
||||
package-lock.json
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
node scripts/validate-char-count.js
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# Exclude user-generated spec files
|
||||
specs/
|
||||
specs--completed/
|
||||
|
||||
# Exclude development files
|
||||
.husky/
|
||||
.git/
|
||||
.gitignore
|
||||
CLAUDE.md
|
||||
|
||||
# Exclude generated files (installer generates dist/ dynamically)
|
||||
dist/
|
||||
|
||||
# Exclude dependencies (installer will run npm install if needed)
|
||||
node_modules/
|
||||
package-lock.json
|
||||
plan2code-loop/node_modules/
|
||||
plan2code-loop/package-lock.json
|
||||
plan2code-loop/dist/
|
||||
@@ -18,12 +18,17 @@ plan2code/
|
||||
├── plan2code-loop/ # Autonomous loop CLI tool (Node.js/TypeScript)
|
||||
│ ├── src/ # TypeScript source
|
||||
│ └── dist/ # Built output (tsup)
|
||||
├── scripts/ # Development scripts
|
||||
│ └── validate-char-count.js # Pre-commit character count validator
|
||||
├── dist/ # Generated distribution files (auto-generated)
|
||||
│ ├── global-commands/ # For global installation (~/.claude/, etc.)
|
||||
│ └── local-commands/ # For per-project installation (.claude/, etc.)
|
||||
├── .husky/ # Git hooks (husky)
|
||||
│ └── pre-commit # Runs character count validation
|
||||
├── docs/ # Documentation and assets
|
||||
├── specs/ # Feature specs (if any in-progress)
|
||||
├── install.js # Interactive installer (Node.js)
|
||||
├── package.json # Root package (husky only, private: true)
|
||||
├── version.json # Version metadata
|
||||
└── README.md # User documentation
|
||||
```
|
||||
@@ -34,6 +39,7 @@ plan2code/
|
||||
|------|---------|
|
||||
| `install.js` | Main installer - generates and installs workflow files to AI tool directories |
|
||||
| `src/plan2code-*.md` | Source workflow prompts (the "source of truth") |
|
||||
| `scripts/validate-char-count.js` | Pre-commit validator ensuring all source prompts ≤ 11,000 chars |
|
||||
| `version.json` | Version metadata (name, version, description) |
|
||||
| `QUICK-REFERENCE.md` | User quick-reference card |
|
||||
|
||||
@@ -91,6 +97,9 @@ The LLM must output one of these formats:
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
# Install dev dependencies (sets up husky pre-commit hooks)
|
||||
npm install
|
||||
|
||||
# Run the interactive installer
|
||||
node install.js
|
||||
|
||||
@@ -177,6 +186,7 @@ When modifying workflow prompts in `src/`:
|
||||
|
||||
- **Version sync:** When adding a new version to `CHANGELOG.md`, also update `version.json` to match. The installer displays the version from `version.json` in its header.
|
||||
- **Loop `.gitignore` setup:** `ensureGitignore()` runs at startup in `Controller.run()` as a pre-flight step, not just inside `createTaskCommit()`. This is critical for phase mode where the Node controller doesn't handle commits — without it, `git add -A` would stage spec files.
|
||||
- **Workflow file character limit:** All `src/plan2code-*.md` files must be ≤ 11,000 characters. A husky pre-commit hook enforces this. The 11,000 limit leaves buffer for platform-specific YAML headers (106-142 chars) to stay under Windsurf's 12,000 char limit.
|
||||
|
||||
## Git Commit Messages
|
||||
|
||||
@@ -185,11 +195,11 @@ When modifying workflow prompts in `src/`:
|
||||
- Loop task mode: `createTaskCommit()` in `plan2code-loop/src/utils/git.ts` appends the footer automatically
|
||||
- Loop phase mode: Prompt template instructs the LLM to add `-m "AI Assisted"` as the final flag
|
||||
- Implement mode: User-facing commit suggestions in `src/plan2code-3--implement.md` include the footer
|
||||
- **Init workflow:** `src/smarsh2code---init.md` generates AGENTS.md files with a Git Commit Messages section that includes this convention by default
|
||||
- **Init workflow:** `src/plan2code---init.md` generates AGENTS.md files with a Git Commit Messages section that includes this convention by default
|
||||
|
||||
## Mascot
|
||||
|
||||
The project has a mascot called "Smarshy" - an ASCII art robot that appears in installer output and workflow prompts. Mascot variants are defined in `MASCOT` constant in `install.js` and appear in workflow markdown files.
|
||||
The project has a mascot - an ASCII art robot that appears in installer output and workflow prompts. Mascot variants are defined in `MASCOT` constant in `install.js` and appear in workflow markdown files.
|
||||
|
||||
```
|
||||
╭───╮
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
|
||||
All notable changes to Plan2Code will be documented in this file.
|
||||
|
||||
## v1.6.1
|
||||
|
||||
### ✨ Added
|
||||
|
||||
- **NPX installation support** - Team members can now install directly from GitHub without cloning
|
||||
- Added `name`, `version`, and `bin` fields to `package.json` for npm compatibility
|
||||
- Installation via `npx git+ssh://git@github.com/jparkerweb/plan2code.git` (SSH)
|
||||
- Installation via `npx git+https://github.com/jparkerweb/plan2code.git` (HTTPS)
|
||||
- Installer runs from temporary location and cleans up automatically
|
||||
- Updated README.md with Quick Start section showing both authentication methods
|
||||
- Added `.npmignore` file to suppress npm warnings during npx execution
|
||||
|
||||
## v1.6.0
|
||||
|
||||
### 🏎️ Improved
|
||||
|
||||
- **Reduced workflow file sizes** - All 4 over-target source prompts compressed to ≤ 11,000 characters for Windsurf IDE compatibility (12,000 char limit minus header buffer)
|
||||
- `plan2code-3--implement.md` - 14,806 → 8,533 chars (42% reduction)
|
||||
- `plan2code-1--plan.md` - 13,587 → 10,348 chars (24% reduction)
|
||||
- `plan2code-4--finalize.md` - 12,012 → 8,586 chars (29% reduction)
|
||||
- `plan2code-2--document.md` - 11,842 → 9,031 chars (24% reduction)
|
||||
- All functional workflow behavior preserved
|
||||
- Compression techniques: template-to-section-list specs, removed bad examples, consolidated redundant sections, simplified decorative boxes, imperative directives
|
||||
|
||||
### 🧪 Testing
|
||||
|
||||
- **Pre-commit character count validation** - Husky pre-commit hook prevents workflow files from exceeding 11,000 characters
|
||||
- `scripts/validate-char-count.js` - Cross-platform Node.js validation script using only built-in modules
|
||||
- `.husky/pre-commit` - Git hook trigger calling the validation script
|
||||
- Root `package.json` with husky as sole devDependency (`private: true`)
|
||||
- `.gitignore` updated with `node_modules/` and `package-lock.json`
|
||||
|
||||
## v1.5.4
|
||||
|
||||
### ✨ Added
|
||||
|
||||
@@ -64,6 +64,24 @@ The install script requires **Node.js** (v14 or later). If you don't have Node.j
|
||||
|
||||
### Quick Start
|
||||
|
||||
#### No Clone Required
|
||||
|
||||
Run the interactive installer directly using `npx` with your preferred GitHub authentication method:
|
||||
|
||||
**If you use SSH keys:**
|
||||
```bash
|
||||
npx git+ssh://git@github.com/jparkerweb/plan2code.git
|
||||
```
|
||||
|
||||
**If you use HTTPS authentication:**
|
||||
```bash
|
||||
npx git+https://github.com/jparkerweb/plan2code.git
|
||||
```
|
||||
|
||||
This downloads the installer to a temporary location, runs it, installs the workflow files to your machine, and cleans up automatically. The installed workflows remain on your system and work independently. To update or reinstall, simply run the command again.
|
||||
|
||||
#### Standard Installation (Clone Method)
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/plan/plan2code.git
|
||||
@@ -71,6 +89,9 @@ cd plan2code
|
||||
|
||||
# Run the interactive installer
|
||||
node install.js
|
||||
|
||||
# OPTIONAL: Install dev dependencies (ONLY if you plan to modify/contribute to Plan2Code)
|
||||
npm install
|
||||
```
|
||||
|
||||
The installer will display an interactive menu:
|
||||
@@ -219,10 +240,10 @@ The `overview.md` includes a "Parallel Execution Groups" section that identifies
|
||||
After running `node install.js`, use the slash commands directly in your AI tool:
|
||||
|
||||
```
|
||||
/smarsh2code-1--plan # Start planning a new feature
|
||||
/smarsh2code-2--document # Create implementation docs from plan
|
||||
/smarsh2code-3--implement # Begin/continue implementation
|
||||
/smarsh2code-4--finalize # Wrap up after all phases complete
|
||||
/plan2code-1--plan # Start planning a new feature
|
||||
/plan2code-2--document # Create implementation docs from plan
|
||||
/plan2code-3--implement # Begin/continue implementation
|
||||
/plan2code-4--finalize # Wrap up after all phases complete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -110,6 +110,7 @@ const MASCOT = {
|
||||
' ╰───╯ ',
|
||||
],
|
||||
};
|
||||
|
||||
// Source directory containing pre-formatted global installation files
|
||||
const SOURCE_BASE = 'dist/global-commands';
|
||||
|
||||
@@ -1247,6 +1248,7 @@ function runInteractive() {
|
||||
rl.close();
|
||||
process.exit(displayLocalInstructions());
|
||||
}
|
||||
|
||||
if (input === 'O') {
|
||||
// Install plan2code-loop
|
||||
rl.close();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "plan2code",
|
||||
"version": "1.6.1",
|
||||
"private": true,
|
||||
"bin": {
|
||||
"plan2code": "./install.js"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "husky"
|
||||
},
|
||||
"devDependencies": {
|
||||
"husky": "^9.0.0"
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ The CLI will:
|
||||
1. Auto-detect specs in `./specs/` directory
|
||||
2. Let you select a spec if multiple are found
|
||||
3. Prompt to continue if an existing session is found
|
||||
4. Ask for JIRA ticket ID, agent selection, and max iterations
|
||||
4. Ask for JIRA ticket ID, agent selection, loop mode, and max iterations
|
||||
|
||||
## How It Works
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "plan2code-loop",
|
||||
"version": "1.0.0",
|
||||
"version": "1.6.1",
|
||||
"description": "Plan2Code Loop - Autonomous spec-driven implementation CLI",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
@@ -43,3 +43,4 @@
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,11 @@ async function selectSpec(cwd: string = process.cwd()): Promise<string | null> {
|
||||
logger.info('');
|
||||
logger.info('To get started:');
|
||||
logger.info('');
|
||||
logger.info('1. Create a spec using `smarsh2code-1--plan`');
|
||||
logger.info('1. Create a spec using `plan2code-1--plan`');
|
||||
logger.info(' command in our AI Agent');
|
||||
logger.info('');
|
||||
logger.info('2. Come back here and run `smarsh2code-loop`');
|
||||
logger.info(' as an alternative to `smarsh2code-3--implement`');
|
||||
logger.info('2. Come back here and run `plan2code-loop`');
|
||||
logger.info(' as an alternative to `plan2code-3--implement`');
|
||||
logger.info('');
|
||||
return null;
|
||||
}
|
||||
@@ -67,8 +67,6 @@ async function selectSpec(cwd: string = process.cwd()): Promise<string | null> {
|
||||
async function selectAgent(): Promise<string> {
|
||||
const allAgents = agentRegistry.getAll();
|
||||
|
||||
|
||||
|
||||
const agentName = await select({
|
||||
message: 'Select AI agent:',
|
||||
choices: allAgents.map((agent) => ({
|
||||
@@ -108,6 +106,7 @@ async function selectMaxIterations(): Promise<number> {
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select loop mode: one task per loop or one phase per loop
|
||||
*/
|
||||
@@ -126,6 +125,7 @@ async function selectLoopMode(): Promise<LoopMode> {
|
||||
],
|
||||
default: 'task',
|
||||
});
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,12 +142,14 @@ export class Controller {
|
||||
logger.info(`Please ensure the "${this.agent.config.command}" command is installed and available in your PATH.`);
|
||||
throw new Error(`Agent "${this.agent.config.displayName}" is not available. Please install it and try again.`);
|
||||
}
|
||||
|
||||
// Ensure git repo and .gitignore are set up before any iterations
|
||||
const gitReady = await ensureGitRepo(process.cwd());
|
||||
if (!gitReady) {
|
||||
throw new Error('Failed to initialize a git repository in the current working directory. Cannot start Plan2Code Loop.');
|
||||
}
|
||||
ensureGitignore(process.cwd());
|
||||
|
||||
const loopModeLabel = (this.config.loopMode || 'task') === 'phase' ? 'One phase per loop' : 'One task per loop';
|
||||
logger.header('Starting Plan2Code Loop');
|
||||
logger.info(`Agent: ${this.agent.config.displayName}`);
|
||||
@@ -215,9 +217,11 @@ export class Controller {
|
||||
|
||||
// Branch completion handling based on loop mode
|
||||
const isPhaseMode = (this.config.loopMode || 'task') === 'phase';
|
||||
|
||||
if (isPhaseMode) {
|
||||
// Phase mode: parse ALL completion markers from output
|
||||
const allCompletions = checkForAllCompletions(result.stdout + result.stderr);
|
||||
|
||||
// Determine status
|
||||
let status: IterationLogEntry['status'] = 'running';
|
||||
if (allCompletions.tasks.length > 0 || allCompletions.loopComplete || allCompletions.phaseComplete) {
|
||||
@@ -229,10 +233,12 @@ export class Controller {
|
||||
} else if (result.exitCode !== 0) {
|
||||
status = 'error';
|
||||
}
|
||||
|
||||
// Log iteration with count of tasks
|
||||
const markerSummary = allCompletions.tasks.map(t => `${t.marker}: ${t.taskId}`).join(', ');
|
||||
const logEntry = this.createLogEntry(result, status, markerSummary || undefined);
|
||||
await this.stateManager.appendIterationLog(logEntry);
|
||||
|
||||
// Display each completed task
|
||||
const duration = Math.round(result.duration / 1000);
|
||||
for (const task of allCompletions.tasks) {
|
||||
@@ -259,6 +265,7 @@ export class Controller {
|
||||
logger.warning(blockInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Show phase-level summary
|
||||
if (allCompletions.tasks.length > 0) {
|
||||
const completedCount = allCompletions.tasks.filter(t => t.marker === 'TASK_COMPLETE').length;
|
||||
@@ -273,6 +280,7 @@ export class Controller {
|
||||
} else {
|
||||
logger.iteration(iterNum, this.config.maxIterations, `completed in ${duration}s`);
|
||||
}
|
||||
|
||||
// Verbose output
|
||||
if (this.config.verbose) {
|
||||
console.log();
|
||||
@@ -287,6 +295,7 @@ export class Controller {
|
||||
} else if (result.exitCode !== 0 && result.stderr.trim()) {
|
||||
logger.error(` ${result.stderr.trim().split('\n')[0]}`);
|
||||
}
|
||||
|
||||
// Handle LOOP_COMPLETE
|
||||
if (allCompletions.loopComplete) {
|
||||
this.onLoopComplete?.();
|
||||
@@ -302,42 +311,41 @@ export class Controller {
|
||||
}
|
||||
} else {
|
||||
// Task mode (default): existing single-marker logic
|
||||
const completion = checkForCompletion(result.stdout + result.stderr);
|
||||
const completion = checkForCompletion(result.stdout + result.stderr);
|
||||
|
||||
// Determine status
|
||||
let status: IterationLogEntry['status'] = 'running';
|
||||
if (completion.completed) {
|
||||
if (completion.marker === 'TASK_BLOCKED') {
|
||||
status = 'blocked';
|
||||
} else {
|
||||
status = 'completed';
|
||||
// Determine status
|
||||
let status: IterationLogEntry['status'] = 'running';
|
||||
if (completion.completed) {
|
||||
if (completion.marker === 'TASK_BLOCKED') {
|
||||
status = 'blocked';
|
||||
} else {
|
||||
status = 'completed';
|
||||
}
|
||||
} else if (result.timedOut) {
|
||||
status = 'timeout';
|
||||
} else if (result.exitCode !== 0) {
|
||||
status = 'error';
|
||||
}
|
||||
} else if (result.timedOut) {
|
||||
status = 'timeout';
|
||||
} else if (result.exitCode !== 0) {
|
||||
status = 'error';
|
||||
}
|
||||
|
||||
// Log iteration
|
||||
const logEntry = this.createLogEntry(result, status, completion.marker);
|
||||
await this.stateManager.appendIterationLog(logEntry);
|
||||
// Log iteration
|
||||
const logEntry = this.createLogEntry(result, status, completion.marker);
|
||||
await this.stateManager.appendIterationLog(logEntry);
|
||||
|
||||
// Display iteration result with task info from completion marker
|
||||
this.displayIterationResult(result, iterNum, completion);
|
||||
// Display iteration result with task info from completion marker
|
||||
this.displayIterationResult(result, iterNum, completion);
|
||||
|
||||
// Handle completion markers
|
||||
if (completion.completed) {
|
||||
const taskDisplay = this.formatTaskDisplay(completion);
|
||||
|
||||
// Handle completion markers
|
||||
if (completion.completed) {
|
||||
const taskDisplay = this.formatTaskDisplay(completion);
|
||||
|
||||
if (completion.marker === 'TASK_COMPLETE') {
|
||||
this.tasksCompleted++;
|
||||
await this.onTaskComplete?.({
|
||||
marker: completion.marker,
|
||||
taskId: completion.taskId,
|
||||
taskName: completion.taskName,
|
||||
});
|
||||
logger.success(taskDisplay ? `Completed: ${taskDisplay}` : 'Task completed!');
|
||||
if (completion.marker === 'TASK_COMPLETE') {
|
||||
this.tasksCompleted++;
|
||||
await this.onTaskComplete?.({
|
||||
marker: completion.marker,
|
||||
taskId: completion.taskId,
|
||||
taskName: completion.taskName,
|
||||
});
|
||||
logger.success(taskDisplay ? `Completed: ${taskDisplay}` : 'Task completed!');
|
||||
} else if (completion.marker === 'PREREQ_COMPLETE' || completion.marker === 'PREREQ_ASSUMED') {
|
||||
this.prereqsCompleted++;
|
||||
await this.onTaskComplete?.({
|
||||
@@ -350,29 +358,29 @@ export class Controller {
|
||||
: completion.taskId ? `Prereq ${completion.taskId}` : 'Prerequisite';
|
||||
const verb = completion.marker === 'PREREQ_COMPLETE' ? 'Verified' : 'Assumed';
|
||||
logger.success(`${verb}: ${prereqDisplay}`);
|
||||
} else if (completion.marker === 'TASK_BLOCKED') {
|
||||
const blockInfo = completion.taskId
|
||||
? `Task ${completion.taskId} blocked: ${completion.reason || 'Unknown reason'}`
|
||||
: `Task blocked: ${completion.reason || 'Unknown reason'}`;
|
||||
logger.warning(blockInfo);
|
||||
} else if (completion.marker === 'LOOP_COMPLETE') {
|
||||
// Commit any final changes before completing
|
||||
this.tasksCompleted++;
|
||||
await this.onTaskComplete?.({
|
||||
marker: completion.marker,
|
||||
taskId: completion.taskId,
|
||||
taskName: completion.taskName || 'Final implementation complete',
|
||||
});
|
||||
this.onLoopComplete?.();
|
||||
logger.success('All tasks complete!');
|
||||
return {
|
||||
completed: true,
|
||||
iterations: iterNum,
|
||||
finalMarker: 'LOOP_COMPLETE',
|
||||
exitReason: 'all_complete',
|
||||
tasksCompleted: this.tasksCompleted,
|
||||
} else if (completion.marker === 'TASK_BLOCKED') {
|
||||
const blockInfo = completion.taskId
|
||||
? `Task ${completion.taskId} blocked: ${completion.reason || 'Unknown reason'}`
|
||||
: `Task blocked: ${completion.reason || 'Unknown reason'}`;
|
||||
logger.warning(blockInfo);
|
||||
} else if (completion.marker === 'LOOP_COMPLETE') {
|
||||
// Commit any final changes before completing
|
||||
this.tasksCompleted++;
|
||||
await this.onTaskComplete?.({
|
||||
marker: completion.marker,
|
||||
taskId: completion.taskId,
|
||||
taskName: completion.taskName || 'Final implementation complete',
|
||||
});
|
||||
this.onLoopComplete?.();
|
||||
logger.success('All tasks complete!');
|
||||
return {
|
||||
completed: true,
|
||||
iterations: iterNum,
|
||||
finalMarker: 'LOOP_COMPLETE',
|
||||
exitReason: 'all_complete',
|
||||
tasksCompleted: this.tasksCompleted,
|
||||
prereqsCompleted: this.prereqsCompleted,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,7 +402,7 @@ export class Controller {
|
||||
? checkForAllCompletions(result.stdout + result.stderr).tasks.length > 0
|
||||
: checkForCompletion(result.stdout + result.stderr).completed;
|
||||
if (!hasCompletions) {
|
||||
logger.warning(`Iteration ${iterNum} exited with code ${result.exitCode}, continuing...`);
|
||||
logger.warning(`Iteration ${iterNum} exited with code ${result.exitCode}, continuing...`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const LOOP_PROMPT_TEMPLATE = `# PLAN-LOOP: Autonomous Task Implementation
|
||||
export const LOOP_PROMPT_TEMPLATE = `# PLAN2CODE-LOOP: Autonomous Task Implementation
|
||||
|
||||
## CRITICAL CONSTRAINT
|
||||
**IMPLEMENT EXACTLY ONE TASK PER ITERATION.**
|
||||
@@ -83,7 +83,9 @@ If key patterns or learnings were discovered, update \`./AGENTS.md\` if it exist
|
||||
|
||||
Remember: ONE TASK ONLY. Find it, implement it, mark it done, output TASK_COMPLETE with the task ID and description, then stop.
|
||||
`;
|
||||
|
||||
export const LOOP_PROMPT_TEMPLATE_PHASE = `# PLAN2CODE-LOOP: Autonomous Phase Implementation
|
||||
|
||||
## CRITICAL CONSTRAINT
|
||||
**IMPLEMENT ALL REMAINING TASKS IN THE CURRENT PHASE.**
|
||||
Find the first incomplete phase, then implement every remaining task in that phase before stopping.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export type LoopMode = 'task' | 'phase';
|
||||
|
||||
export interface SessionConfig {
|
||||
agent: string; // "claude-code" | "copilot-cli"
|
||||
model: string; // Selected model
|
||||
|
||||
@@ -54,6 +54,7 @@ export function checkForCompletion(output: string): CompletionCheckResult {
|
||||
taskName: prereqMatch[2].trim(),
|
||||
};
|
||||
}
|
||||
|
||||
// Check for PREREQ_ASSUMED with prereq info
|
||||
// Format: PREREQ_ASSUMED: P2.1 - Design approval (cannot verify)
|
||||
const assumedMatch = output.match(/PREREQ_ASSUMED[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/i);
|
||||
@@ -65,6 +66,7 @@ export function checkForCompletion(output: string): CompletionCheckResult {
|
||||
taskName: assumedMatch[2].trim(),
|
||||
};
|
||||
}
|
||||
|
||||
// Check for TASK_BLOCKED with task info and reason
|
||||
// Format: TASK_BLOCKED: 1.1 - Reason why blocked
|
||||
const blockedWithTaskMatch = output.match(/TASK_BLOCKED[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/i);
|
||||
@@ -94,6 +96,7 @@ export function checkForCompletion(output: string): CompletionCheckResult {
|
||||
|
||||
return { completed: false };
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract ALL completion markers from output (for phase mode).
|
||||
* Returns an array of all TASK_COMPLETE/TASK_BLOCKED markers found,
|
||||
@@ -107,12 +110,15 @@ export function checkForAllCompletions(output: string): {
|
||||
const tasks: CompletionCheckResult[] = [];
|
||||
let loopComplete = false;
|
||||
let phaseComplete = false;
|
||||
|
||||
if (output.includes('LOOP_COMPLETE')) {
|
||||
loopComplete = true;
|
||||
}
|
||||
|
||||
if (output.includes('PHASE_COMPLETE')) {
|
||||
phaseComplete = true;
|
||||
}
|
||||
|
||||
// Find all TASK_COMPLETE markers with task info
|
||||
// Format: TASK_COMPLETE: 1.1 - Task description
|
||||
const completeRegex = /TASK_COMPLETE[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
|
||||
@@ -125,6 +131,7 @@ export function checkForAllCompletions(output: string): {
|
||||
taskName: match[2].trim(),
|
||||
});
|
||||
}
|
||||
|
||||
// Find all TASK_BLOCKED markers with task info
|
||||
const blockedRegex = /TASK_BLOCKED[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
|
||||
while ((match = blockedRegex.exec(output)) !== null) {
|
||||
@@ -135,6 +142,7 @@ export function checkForAllCompletions(output: string): {
|
||||
reason: match[2].trim(),
|
||||
});
|
||||
}
|
||||
|
||||
// Find PREREQ_COMPLETE markers
|
||||
const prereqRegex = /PREREQ_COMPLETE[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
|
||||
while ((match = prereqRegex.exec(output)) !== null) {
|
||||
@@ -145,6 +153,7 @@ export function checkForAllCompletions(output: string): {
|
||||
taskName: match[2].trim(),
|
||||
});
|
||||
}
|
||||
|
||||
// Find PREREQ_ASSUMED markers
|
||||
const assumedRegex = /PREREQ_ASSUMED[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
|
||||
while ((match = assumedRegex.exec(output)) !== null) {
|
||||
@@ -155,5 +164,6 @@ export function checkForAllCompletions(output: string): {
|
||||
taskName: match[2].trim(),
|
||||
});
|
||||
}
|
||||
|
||||
return { tasks, loopComplete, phaseComplete };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { logger, MASCOT, type Logger } from './logger.js';
|
||||
export {
|
||||
checkForCompletion,
|
||||
checkForAllCompletions,
|
||||
type CompletionMarker,
|
||||
type CompletionCheckResult
|
||||
} from './completion.js';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const CHAR_LIMIT = 11000;
|
||||
const srcDir = path.join(__dirname, '..', 'src');
|
||||
|
||||
const files = fs.readdirSync(srcDir)
|
||||
.filter(f => f.startsWith('plan2code-') && f.endsWith('.md'))
|
||||
.sort();
|
||||
|
||||
const failures = [];
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(srcDir, file);
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const charCount = content.length;
|
||||
if (charCount > CHAR_LIMIT) {
|
||||
failures.push({ file: path.join('src', file), charCount });
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error('Character limit exceeded:');
|
||||
console.error('');
|
||||
for (const { file, charCount } of failures) {
|
||||
console.error(` ${file}: ${charCount} / ${CHAR_LIMIT} (+${charCount - CHAR_LIMIT} over)`);
|
||||
}
|
||||
console.error('');
|
||||
console.error(`${failures.length} file(s) over the ${CHAR_LIMIT} character limit.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`All ${files.length} files under ${CHAR_LIMIT} characters \u2713`);
|
||||
process.exit(0);
|
||||
@@ -18,7 +18,7 @@ Interactive Q&A flow to update an existing `AGENTS.md` with new learnings and pr
|
||||
|
||||
Check if `AGENTS.md` exists in project root.
|
||||
|
||||
**If missing:** "No AGENTS.md found. Create one from scratch? I can analyze the codebase and generate an initial file." Stop and wait. If yes, use `smarsh2code---init.md` workflow.
|
||||
**If missing:** "No AGENTS.md found. Create one from scratch? I can analyze the codebase and generate an initial file." Stop and wait. If yes, use `plan2code---init.md` workflow.
|
||||
|
||||
**If exists:** Read and summarize:
|
||||
- Main sections (bullets)
|
||||
|
||||
+20
-171
@@ -61,7 +61,7 @@ Before Phase 1, check for `specs/*/PLAN-DRAFT-*.md`:
|
||||
When assumptions made, end with:
|
||||
**Assumptions this phase:** [Assumption] - [impact if wrong]
|
||||
|
||||
User should confirm before next phase.
|
||||
User MUST confirm before next phase.
|
||||
|
||||
### Confidence Calculation
|
||||
|
||||
@@ -76,20 +76,6 @@ Four dimensions (0-25% each):
|
||||
|
||||
Report each sub-score with overall percentage.
|
||||
|
||||
## Examples
|
||||
|
||||
### Requirement Gathering
|
||||
**Bad:** "You want auth. I'll design JWT with bcrypt." (Made tech decisions without asking)
|
||||
|
||||
**Good:** "You mentioned authentication. Before proposing:
|
||||
1. What methods? (email/password, social, SSO?)
|
||||
2. Compliance? (SOC2, HIPAA?)
|
||||
3. Token storage? (cookies, localStorage?)"
|
||||
|
||||
### Scope Assessment
|
||||
**Bad:** "Medium project. Moving to Phase 4." (No justification)
|
||||
|
||||
**Good:** "Analysis: 8 requirements (Medium: 10-15), 4 components (Medium: 4-6), 2 integrations (Medium: 2-3). Appears **Medium**. Agree?"
|
||||
|
||||
## Process
|
||||
|
||||
@@ -231,160 +217,29 @@ State assessment and ask user to confirm.
|
||||
- Ask targeted questions
|
||||
- State: "Need clarity on [areas] to improve [dimension] confidence."
|
||||
|
||||
---
|
||||
|
||||
#### STEP 7A: Save Conversation Log
|
||||
|
||||
Create `specs/<feature-name>/PLAN-CONVERSATION-<YYYYMMDD>.md`:
|
||||
|
||||
```markdown
|
||||
# Planning Conversation Log
|
||||
|
||||
**Feature:** [Name]
|
||||
**Date:** [YYYYMMDD]
|
||||
**Related:** specs/<feature-name>/PLAN-DRAFT-<date>.md
|
||||
|
||||
---
|
||||
|
||||
## Transcript
|
||||
|
||||
### Phase 1: Requirements Analysis
|
||||
**[AGENT]** [Response]
|
||||
**[USER]** [Response]
|
||||
[...continue for all phases...]
|
||||
|
||||
---
|
||||
|
||||
## Decision Summary
|
||||
|
||||
### Key Decisions
|
||||
| Phase | Decision | User Confirmation |
|
||||
|-------|----------|-------------------|
|
||||
|
||||
### Requirements Confirmed
|
||||
| ID | Requirement | Phase |
|
||||
|----|-------------|-------|
|
||||
|
||||
### Technology Approved
|
||||
| Tech | Category | Phase | Confirmation |
|
||||
|------|----------|-------|--------------|
|
||||
|
||||
### Assumptions
|
||||
| Assumption | Phase | Impact if Wrong | Acknowledged |
|
||||
|------------|-------|-----------------|--------------|
|
||||
```
|
||||
|
||||
Save before STEP 7B.
|
||||
|
||||
---
|
||||
|
||||
#### STEP 7B: Create PLAN-DRAFT
|
||||
|
||||
Using same date, create `specs/<feature-name>/PLAN-DRAFT-<date>.md` (template below).
|
||||
|
||||
---
|
||||
|
||||
#### STEP 7C: Verification Pass
|
||||
|
||||
After PLAN-DRAFT:
|
||||
|
||||
1. Re-read conversation log as source of truth
|
||||
2. Verify against PLAN-DRAFT:
|
||||
|
||||
| From Conversation | Verify In PLAN-DRAFT |
|
||||
|-------------------|----------------------|
|
||||
| Functional requirements | 2.1 |
|
||||
| Non-functional requirements | 2.2 |
|
||||
| Technology decisions | 3. Tech Stack |
|
||||
| Architecture decisions | 4. Architecture |
|
||||
| Risks | 6. Risks |
|
||||
| Assumptions | 9. Assumptions |
|
||||
| Success criteria | 7. Success Criteria |
|
||||
|
||||
3. For gaps: Add with `<!-- VERIFICATION: Added from Phase X -->`
|
||||
4. Output summary:
|
||||
```
|
||||
## Verification Complete
|
||||
| Section | In Conversation | In PLAN-DRAFT | Added |
|
||||
|---------|-----------------|---------------|-------|
|
||||
**Status:** [All captured / X items added]
|
||||
```
|
||||
5. Save updated PLAN-DRAFT if needed
|
||||
|
||||
---
|
||||
**Phase 7 Outputs:**
|
||||
1. Save PLAN-CONVERSATION (see template below) — transcript + decision summary tables
|
||||
2. Create PLAN-DRAFT (see template below) using same date
|
||||
3. Verify: re-read conversation as source of truth, cross-reference against PLAN-DRAFT sections (Reqs→2.1/2.2, Tech→3, Architecture→4, Risks→6, Assumptions→9, Criteria→7). Add gaps with `<!-- VERIFICATION -->` comments. Output verification summary table.
|
||||
|
||||
## Templates
|
||||
|
||||
### PLAN-DRAFT Format
|
||||
|
||||
```markdown
|
||||
# [Feature Name] - Implementation Plan
|
||||
File: `specs/<feature-name>/PLAN-DRAFT-<YYYYMMDD>.md`
|
||||
|
||||
**Created:** [Date]
|
||||
**Status:** Draft | Phase 3 Complete - Resume at Phase 4 | Complete
|
||||
**Confidence:** [X]% (Reqs: X/25, Feasibility: X/25, Integration: X/25, Risk: X/25)
|
||||
**Conversation Log:** specs/<feature-name>/PLAN-CONVERSATION-<date>.md
|
||||
Header: Title, Created date, Status (Draft | Phase 3 Complete - Resume at Phase 4 | Complete), Confidence % (Reqs/Feasibility/Integration/Risk each /25), link to PLAN-CONVERSATION.
|
||||
|
||||
## 1. Executive Summary
|
||||
[2-3 sentences]
|
||||
|
||||
## 2. Requirements
|
||||
### 2.1 Functional
|
||||
- [ ] FR-1: [Description]
|
||||
|
||||
### 2.2 Non-Functional
|
||||
- [ ] NFR-1: [Description]
|
||||
|
||||
### 2.3 Out of Scope
|
||||
- [Exclusions]
|
||||
|
||||
### 2.4 Testing Strategy
|
||||
| Preference | Selection |
|
||||
|------------|-----------|
|
||||
| Types | [Unit/Integration/E2E/None] |
|
||||
| Phase Testing | [After each/Dedicated/None] |
|
||||
| Coverage | [Critical/Moderate/Comprehensive/N/A] |
|
||||
|
||||
## 3. Tech Stack
|
||||
| Category | Technology | Version | Justification |
|
||||
|----------|------------|---------|---------------|
|
||||
|
||||
## 4. Architecture
|
||||
### 4.1 Pattern
|
||||
[Name and rationale]
|
||||
|
||||
### 4.2 System Context Diagram
|
||||
[ASCII or description]
|
||||
|
||||
### 4.3 Components
|
||||
| Component | Responsibility | Dependencies |
|
||||
|-----------|----------------|--------------|
|
||||
|
||||
### 4.4 Data Model
|
||||
[Schema, relationships]
|
||||
|
||||
### 4.5 API Design
|
||||
[Endpoints if applicable]
|
||||
|
||||
## 5. Implementation Phases
|
||||
### Phase 1: [Name]
|
||||
**Goal:** [Accomplishment]
|
||||
**Dependencies:** None / [List]
|
||||
- [ ] Task 1.1: [Description]
|
||||
|
||||
## 6. Risks and Mitigations
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
|
||||
## 7. Success Criteria
|
||||
- [ ] [Criterion]
|
||||
|
||||
## 8. Open Questions
|
||||
[Remove if none]
|
||||
|
||||
## 9. Assumptions
|
||||
[List]
|
||||
```
|
||||
Sections:
|
||||
1. **Executive Summary** — 2-3 sentences
|
||||
2. **Requirements** — 2.1 Functional (FR-N checklist), 2.2 Non-Functional (NFR-N checklist), 2.3 Out of Scope, 2.4 Testing Strategy table (Types, Phase Testing, Coverage)
|
||||
3. **Tech Stack** — table: Category / Technology / Version / Justification
|
||||
4. **Architecture** — 4.1 Pattern (name + rationale), 4.2 System Context Diagram, 4.3 Components table, 4.4 Data Model, 4.5 API Design
|
||||
5. **Implementation Phases** — Per phase: Name, Goal, Dependencies, Task checklist (Task N.N)
|
||||
6. **Risks and Mitigations** — table: Risk / Likelihood / Impact / Mitigation
|
||||
7. **Success Criteria** — checklist
|
||||
8. **Open Questions** — remove if none
|
||||
9. **Assumptions** — list
|
||||
|
||||
### Response Format
|
||||
|
||||
@@ -414,15 +269,9 @@ When complete (PLAN-DRAFT created), tell user:
|
||||
> │ ★ │
|
||||
> │ ◡ │ Planning done! Ready for documentation!
|
||||
> ╰───╯
|
||||
>
|
||||
> ╔═══════════════════════════════════════════════════════════════════╗
|
||||
> ║ NEXT STEPS ║
|
||||
> ╠═══════════════════════════════════════════════════════════════════╣
|
||||
> ║ ║
|
||||
> ║ 1. Start a NEW conversation ║
|
||||
> ║ 2. Use command: /plan2code-2--document ║
|
||||
> ║ ║
|
||||
> ╚═══════════════════════════════════════════════════════════════════╝
|
||||
> =============================================
|
||||
> NEXT STEP: Start a NEW conversation then run:
|
||||
> `/plan2code-2--document`
|
||||
> ```"
|
||||
|
||||
## Abort Handling
|
||||
|
||||
+10
-145
@@ -37,7 +37,7 @@ If no PLAN-DRAFT found and user hasn't provided one, ask for:
|
||||
|
||||
If no plan exists and user wants to skip:
|
||||
> "Documentation transforms planning into specs. Without a plan, either:
|
||||
> 1. Run planning first (`/smarsh2code-1--plan`)
|
||||
> 1. Run planning first (`/plan2code-1--plan`)
|
||||
> 2. Describe requirements so I can help create a minimal plan"
|
||||
|
||||
## Phase Sizing
|
||||
@@ -50,14 +50,6 @@ If no plan exists and user wants to skip:
|
||||
| Independence | Testable/verifiable independently |
|
||||
| Dependencies | Logical dependency order |
|
||||
|
||||
**Typical progression:**
|
||||
1. Project setup/configuration
|
||||
2. Data models/database layer
|
||||
3. Core business logic/services
|
||||
4. API/Interface layer
|
||||
5. Integration, error handling, polish
|
||||
6. Additional features as needed
|
||||
|
||||
## Task Writing
|
||||
|
||||
| Criterion | Description |
|
||||
@@ -130,29 +122,9 @@ Or if none:
|
||||
| None | - | All phases must run sequentially |
|
||||
```
|
||||
|
||||
### Documentation Verification
|
||||
### Documentation Verification (Step 9)
|
||||
|
||||
**STEP 9A:** Re-read PLAN-DRAFT as source of truth
|
||||
|
||||
**STEP 9B:** Cross-reference:
|
||||
|
||||
| PLAN-DRAFT Section | Verify Against |
|
||||
|--------------------|----------------|
|
||||
| 2.1 Functional Requirements | phase-X.md tasks (each FR-X has tasks) |
|
||||
| 2.2 Non-Functional Requirements | overview.md or tasks |
|
||||
| 3 Tech Stack | overview.md (exact match) |
|
||||
| 4.1 Architecture Pattern | overview.md |
|
||||
| 4.3 Component Overview | overview.md |
|
||||
| 5 Implementation Phases | Phase Checklist (all have phase-X.md) |
|
||||
| 6 Risks and Mitigations | overview.md |
|
||||
| 7 Success Criteria | overview.md |
|
||||
| 9 Assumptions | Tasks or overview |
|
||||
|
||||
**STEP 9C:** For gaps:
|
||||
- Missing requirement: Add task with `<!-- VERIFICATION: Added - FR-X from PLAN-DRAFT -->`
|
||||
- Missing section: Add to overview.md with `<!-- VERIFICATION: Added from PLAN-DRAFT section X -->`
|
||||
|
||||
**STEP 9D:** Output verification summary
|
||||
Re-read PLAN-DRAFT as source of truth. Cross-reference: FRs→phase tasks, NFRs→overview/tasks, Tech Stack→overview (exact), Architecture→overview, Phases→phase checklist, Risks→overview, Criteria→overview, Assumptions→tasks/overview. Fix gaps with `<!-- VERIFICATION: Added -->` comments. Output verification summary.
|
||||
|
||||
### Output Structure
|
||||
|
||||
@@ -182,112 +154,15 @@ Use kebab-case for feature name (e.g., `user-authentication`).
|
||||
|
||||
### overview.md
|
||||
|
||||
```markdown
|
||||
# [Feature Name] - Implementation Overview
|
||||
Header: Title, Created date, Source (PLAN-DRAFT path), Status (Not Started | In Progress | Complete).
|
||||
|
||||
**Created:** [Date]
|
||||
**Source:** PLAN-DRAFT-<date>.md
|
||||
**Status:** Not Started | In Progress | Complete
|
||||
|
||||
## Summary
|
||||
[From Executive Summary]
|
||||
|
||||
## Tech Stack
|
||||
[Copy table from planning doc]
|
||||
|
||||
## Architecture
|
||||
### Pattern
|
||||
[From section 4.1]
|
||||
|
||||
### Component Overview
|
||||
| Component | Responsibility | Dependencies |
|
||||
|-----------|----------------|--------------|
|
||||
[From section 4.3]
|
||||
|
||||
## Risks and Mitigations
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
[From section 6]
|
||||
|
||||
## Success Criteria
|
||||
[From section 7]
|
||||
- [ ] [Criterion]
|
||||
|
||||
## Phase Checklist
|
||||
- [ ] Phase 1: [Name] - [Description]
|
||||
|
||||
## Parallel Execution Groups
|
||||
<!-- This section enables running multiple phases simultaneously in separate agent instances -->
|
||||
<!-- Phases in the same group have no file conflicts or dependencies between them -->
|
||||
|
||||
| Group | Phases | Reason |
|
||||
|-------|--------|--------|
|
||||
| [A/None] | [numbers] | [Why parallel-eligible] |
|
||||
|
||||
## Quick Reference
|
||||
### Key Files
|
||||
[Files to be created]
|
||||
|
||||
### Environment Variables
|
||||
[Required env vars or "None"]
|
||||
|
||||
### External Dependencies
|
||||
[External services/APIs]
|
||||
|
||||
---
|
||||
## Completion Summary
|
||||
[Filled during finalization]
|
||||
```
|
||||
Sections: Summary (from Executive Summary), Tech Stack table (exact copy from PLAN-DRAFT), Architecture (Pattern + Component Overview table), Risks and Mitigations table, Success Criteria checklist, Phase Checklist, Parallel Execution Groups table (from analysis), Quick Reference (Key Files, Environment Variables, External Dependencies), Completion Summary (filled during finalization).
|
||||
|
||||
### phase-X.md
|
||||
|
||||
```markdown
|
||||
# Phase X: [Name]
|
||||
Header: Phase name, Status, Estimated Tasks count.
|
||||
|
||||
**Status:** Not Started | In Progress | Complete
|
||||
**Estimated Tasks:** [N]
|
||||
|
||||
## Overview
|
||||
[2-3 sentences: what this phase accomplishes]
|
||||
|
||||
## Prerequisites
|
||||
- [ ] Phase X-1 complete (if applicable)
|
||||
- [ ] [Other prerequisites]
|
||||
|
||||
## Tasks
|
||||
|
||||
### [Category 1]
|
||||
- [ ] **Task X.1:** [Description]
|
||||
- File: `path/to/file`
|
||||
- [Details]
|
||||
|
||||
### Phase Testing (if enabled)
|
||||
- [ ] **Task X.N:** Run test suite
|
||||
- Command: `[test command]`
|
||||
- Pass criteria: [criteria]
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ] [Verifiable criterion]
|
||||
|
||||
## Notes
|
||||
[Additional context]
|
||||
|
||||
---
|
||||
## Phase Completion Summary
|
||||
_[Filled after implementation]_
|
||||
|
||||
**Completed:** [Date]
|
||||
**Implemented by:** [AI/human]
|
||||
|
||||
### What was done:
|
||||
[Summary]
|
||||
|
||||
### Files created/modified:
|
||||
- `path/to/file` - [description]
|
||||
|
||||
### Issues encountered:
|
||||
[Issues or "None"]
|
||||
```
|
||||
Sections: Overview (2-3 sentences), Prerequisites checklist, Tasks (grouped by category, `- [ ] **Task X.N:** [Description]` with File path and details), Phase Testing (if enabled), Acceptance Criteria checklist, Notes, Phase Completion Summary (filled after implementation: date, implementer, what was done, files changed, issues).
|
||||
|
||||
## Session End
|
||||
|
||||
@@ -333,19 +208,9 @@ Parallel Execution: [Groups or "None - sequential only"]
|
||||
> │ ★ │
|
||||
> │ ◡ │ Specs are ready! Time to build!
|
||||
> ╰───╯
|
||||
>
|
||||
> ╔═══════════════════════════════════════════════════════════════════╗
|
||||
> ║ NEXT STEPS ║
|
||||
> ╠═══════════════════════════════════════════════════════════════════╣
|
||||
> ║ ║
|
||||
> ║ 1. Start a NEW conversation ║
|
||||
> ║ 2. Use command: /plan2code-3--implement ║
|
||||
> ║ 3. Provide path: specs/<feature-name>/overview.md ║
|
||||
> ║ ║
|
||||
> ║ The command will auto-detect Phase 1 as the next phase. ║
|
||||
> ║ Complete ONE phase per conversation. ║
|
||||
> ║ ║
|
||||
> ╚═══════════════════════════════════════════════════════════════════╝
|
||||
> ============================================
|
||||
> NEXT STEP: Start a NEW conversation and run:
|
||||
> `/plan2code-3--implement`
|
||||
> ```"
|
||||
|
||||
## Abort Handling
|
||||
|
||||
+49
-267
@@ -60,75 +60,16 @@ Never reset `[/]` to `[ ]`. Started work stays marked for conscious resume decis
|
||||
|
||||
## Parallel Phase Selection
|
||||
|
||||
After identifying workable phases, check for parallel execution:
|
||||
Check overview.md for "Parallel Execution Groups" section. Find workable phases (`[ ]` or `[/]`).
|
||||
|
||||
1. Look for "Parallel Execution Groups" section in overview.md
|
||||
2. Find if next phase belongs to a group with other uncompleted phases
|
||||
3. Only show consecutive uncompleted phases in same group
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| 2+ workable phases in same parallel group | Show selection prompt listing each with status. TIP: run another agent on a different phase simultaneously. If all are `[/]`, warn about duplication. |
|
||||
| Single `[/]` phase | Prompt: "Phase X is in progress. Resume? (yes/no)" |
|
||||
| Single `[ ]` phase | Auto-start: mark `[/]` and begin |
|
||||
| No parallel groups section | Sequential mode (single-phase rules above) |
|
||||
|
||||
**Decision Logic:**
|
||||
|
||||
```
|
||||
Find workable phases = all phases marked [ ] or [/] (not [x])
|
||||
Check Parallel Execution Groups table:
|
||||
|
||||
CASE 1: Multiple parallel phases available
|
||||
- If 2+ workable phases exist in the same parallel group
|
||||
→ Show parallel selection UI with status for each
|
||||
|
||||
CASE 2: Single workable phase that is IN PROGRESS [/]
|
||||
- Phase was started but not completed (possibly by another session)
|
||||
→ Show resume prompt: "Phase X is in progress. Resume? (yes/no)"
|
||||
|
||||
CASE 3: Single workable phase that is PENDING [ ]
|
||||
- Fresh phase, no parallel options
|
||||
→ Auto-start: mark [/] and begin implementation
|
||||
|
||||
CASE 4: No Parallel Execution Groups section exists
|
||||
→ Fall back to sequential mode using Cases 2-3 logic
|
||||
```
|
||||
|
||||
**Parallel Selection UI:**
|
||||
|
||||
When parallel options are available (CASE 1), present this prompt:
|
||||
|
||||
```
|
||||
⚡ PARALLEL PHASES AVAILABLE
|
||||
|
||||
These phases can run in parallel:
|
||||
[1] Phase N: [Name] [IN PROGRESS]
|
||||
[2] Phase N+1: [Name] [AVAILABLE]
|
||||
[3] Phase N+2: [Name] [AVAILABLE]
|
||||
|
||||
Which phase? (1/2/3)
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ TIP: Run another agent instance with /smarsh2code-3--implement to work │
|
||||
│ on a different phase simultaneously. │
|
||||
│ │
|
||||
│ IN PROGRESS phases may be running in another session - selecting one │
|
||||
│ will resume work on it. │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Single Phase Resume UI:**
|
||||
```
|
||||
⚡ PHASE RESUME CHECK
|
||||
|
||||
Phase N: [Name] is IN PROGRESS.
|
||||
- Another session may be working on it
|
||||
- Previous session may have been aborted
|
||||
|
||||
Resume? (yes / no - I'll wait)
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- Only show consecutive, same-group, incomplete phases (`[ ]` or `[/]`)
|
||||
- Stop at first phase NOT in same group
|
||||
- After selection, mark `[/]` if not already, read `phase-X.md`, begin
|
||||
- If ALL parallel phases are `[/]`, warn about potential duplication
|
||||
|
||||
**Fallback:** If Parallel Execution Groups missing or shows "None", use sequential (Cases 2-3).
|
||||
Only show consecutive same-group incomplete phases. After selection, mark `[/]`, read `phase-X.md`, begin.
|
||||
|
||||
## Code Consistency Rules
|
||||
|
||||
@@ -143,18 +84,9 @@ Resume? (yes / no - I'll wait)
|
||||
|
||||
## Examples
|
||||
|
||||
**Following Specs:**
|
||||
- Bad: Task says "create UserService.ts" but creates "services/user.service.ts"
|
||||
- Good: Creates exactly `src/services/UserService.ts` as specified
|
||||
**Following Specs:** Create exactly `src/services/UserService.ts` as specified — never rename or relocate.
|
||||
|
||||
**Handling Blockers:**
|
||||
```
|
||||
- [!] **Task 2.3:** Connect to Stripe API
|
||||
> BLOCKED: STRIPE_SECRET_KEY not in environment.
|
||||
> User action: Add to .env
|
||||
|
||||
Proceeding to Task 2.4 (no Stripe dependency).
|
||||
```
|
||||
**Blocker format:** `- [!] **Task 2.3:** ... > BLOCKED: [reason]. > User action: [action].` Then proceed to next non-dependent task.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -214,51 +146,17 @@ After all tasks:
|
||||
|
||||
### 6. After User Approval
|
||||
|
||||
When user replies "approved":
|
||||
1. Update `overview.md`: `[/]` -> `[x]`
|
||||
2. Update `phase-X.md`: Status -> "Complete"
|
||||
3. Confirm and provide next steps
|
||||
See "After Approval / Session End" section below.
|
||||
|
||||
## Handling Blockers
|
||||
## Issue Handling
|
||||
|
||||
**1. Mark as Blocked:**
|
||||
```markdown
|
||||
- [!] **Task 3.2:** Create OAuth integration
|
||||
> BLOCKED: Missing GOOGLE_CLIENT_ID environment variable.
|
||||
> Required: User must configure OAuth credentials.
|
||||
```
|
||||
| Type | Action | Format |
|
||||
|------|--------|--------|
|
||||
| Blocker | Mark `[!]`, continue non-dependent tasks, report at phase end | `> BLOCKED: [reason]. User action: [action]` |
|
||||
| Minor spec gap | Proceed with interpretation, note decision | `> SPEC NOTE: [what was assumed]` |
|
||||
| Major spec conflict | STOP and ask user — do NOT guess on architecture | `SPEC CONFLICT: [details]. Please clarify.` |
|
||||
|
||||
**2. Continue** with non-dependent tasks.
|
||||
|
||||
**3. Report** all blocked tasks at phase end.
|
||||
|
||||
## Handling Spec Issues
|
||||
|
||||
**Minor (proceed with interpretation):**
|
||||
```markdown
|
||||
- [x] **Task 2.4:** Create user validation
|
||||
> SPEC NOTE: Format not specified. Implemented RFC 5322 email regex.
|
||||
```
|
||||
|
||||
**Major (stop and ask):**
|
||||
```markdown
|
||||
[PHASE 2: Database Layer] - PAUSED
|
||||
|
||||
SPEC CONFLICT:
|
||||
- Task 2.3: "email as primary key"
|
||||
- Architecture section: "id (UUID) as primary key"
|
||||
|
||||
Please clarify before continuing.
|
||||
```
|
||||
|
||||
Do NOT guess on architectural decisions.
|
||||
|
||||
## Phase Size Flexibility
|
||||
|
||||
- **Small phase (<5 tasks):** After completing, ask if should continue with next phase
|
||||
- **Large phase (>40 tasks):** Warn at start, suggest breaking into sub-phases for future
|
||||
|
||||
Default: ONE phase per conversation.
|
||||
Default: ONE phase per conversation. Small phase (<5 tasks): ask if should continue with next. Large (>40): warn at start.
|
||||
|
||||
## Templates
|
||||
|
||||
@@ -278,34 +176,9 @@ Before sign-off, verify:
|
||||
|
||||
### Completion Report Format
|
||||
|
||||
```markdown
|
||||
⚡ [PHASE X: Phase Name] - READY FOR SIGN-OFF
|
||||
Header: `⚡ [PHASE X: Phase Name] - READY FOR SIGN-OFF`
|
||||
|
||||
## Summary
|
||||
[2-3 sentences on accomplishments]
|
||||
|
||||
## Tasks Completed: Y/Z
|
||||
[List blocked tasks if any]
|
||||
|
||||
## Test Results (if run)
|
||||
| Run | Passed | Failed | Skipped |
|
||||
|-----|--------|--------|---------|
|
||||
| X | X | X | X |
|
||||
|
||||
## Files Created
|
||||
- `path/to/file.ts` - [description]
|
||||
|
||||
## Files Modified
|
||||
- `path/to/file.ts` - [changes]
|
||||
|
||||
## Issues
|
||||
[Blockers, clarifications, deviations - or "None"]
|
||||
|
||||
## Verify
|
||||
- Files listed above exist
|
||||
- No syntax errors in editor
|
||||
- App runs (if applicable)
|
||||
- [1-2 specific checks for what was built]
|
||||
Sections: Summary (2-3 sentences), Tasks Completed (Y/Z + blocked list), Test Results table (if run), Files Created, Files Modified, Issues (or "None"), Verify (files exist, no syntax errors, app runs, 1-2 specific checks).
|
||||
|
||||
```
|
||||
⋅
|
||||
@@ -315,108 +188,35 @@ Before sign-off, verify:
|
||||
╰───╯
|
||||
```
|
||||
|
||||
╔═══════════════════════════════════════════════════════════════════════════════╗
|
||||
║ Reply "approved" to mark this phase complete, or describe any issues. ║
|
||||
╚═══════════════════════════════════════════════════════════════════════════════╝
|
||||
> Reply "approved" to mark this phase complete, or describe any issues.
|
||||
|
||||
### After Approval / Session End
|
||||
|
||||
On user "approved":
|
||||
1. Mark `[/]` → `[x]` in overview.md, update phase-X.md status to "Complete"
|
||||
2. Show Mascot art with completion message
|
||||
3. Provide: `git add -A && git commit -m "Complete Phase X: [Phase Name]" -m "AI Assisted"`
|
||||
4. **If more phases:** "NEXT STEP: Start NEW conversation and run: `/plan2code-3--implement`"
|
||||
5. **If final phase:** "NEXT STEP: Start NEW conversation and run: `/plan2code-4--finalize`"
|
||||
6. Mention `/plan2code-1b--revise` option
|
||||
|
||||
continuing:
|
||||
```
|
||||
⋅
|
||||
╭───╮
|
||||
│ ★ │
|
||||
│ ◡ │ Phase done! Great progress!
|
||||
╰───╯
|
||||
```
|
||||
|
||||
### After Approval Format
|
||||
|
||||
```markdown
|
||||
⚡ [PHASE X: Phase Name] - COMPLETE
|
||||
|
||||
Phase marked complete in overview.md.
|
||||
|
||||
## Save Your Progress
|
||||
|
||||
\`\`\`bash
|
||||
git add -A
|
||||
git commit -m "Complete Phase X: [Phase Name]" -m "AI Assisted"
|
||||
\`\`\`
|
||||
|
||||
This creates a checkpoint you can return to if needed.
|
||||
|
||||
## Next Steps
|
||||
|
||||
The next uncompleted phase is Phase Y: [Name].
|
||||
To continue, start a NEW conversation with:
|
||||
|
||||
> /smarsh2code-3--implement specs/<feature-name>/overview.md
|
||||
|
||||
The command will auto-detect Phase Y as the next phase to implement.
|
||||
final phase:
|
||||
```
|
||||
⋅
|
||||
╭───╮
|
||||
│ ★ │
|
||||
│ ◡ │ All phases complete! Amazing work!
|
||||
╰───╯
|
||||
```
|
||||
|
||||
## Session End
|
||||
|
||||
When the user approves the phase (replies "approved"), provide:
|
||||
|
||||
1. Confirmation that the phase is marked complete
|
||||
2. Git commit command (for user to execute)
|
||||
3. Files to attach in next session for the next phase
|
||||
4. Reminder to start a NEW conversation
|
||||
5. If all phases complete: recommend proceeding to finalization
|
||||
|
||||
Example for continuing:
|
||||
|
||||
> "⚡ [PHASE 2: Phase Name] - COMPLETE ✓
|
||||
>
|
||||
> Phase marked complete in overview.md.
|
||||
>
|
||||
> ```
|
||||
> ⋅
|
||||
> ╭───╮
|
||||
> │ ★ │
|
||||
> │ ◡ │ Phase done! Great progress!
|
||||
> ╰───╯
|
||||
>
|
||||
> ╔═══════════════════════════════════════════════════════════════════╗
|
||||
> ║ NEXT STEPS ║
|
||||
> ╠═══════════════════════════════════════════════════════════════════╣
|
||||
> ║ ║
|
||||
> ║ Save your progress: ║
|
||||
> ║ git add -A && git commit -m "Complete Phase 2: [Phase Name]" -m "AI Assisted" ║
|
||||
> ║ ║
|
||||
> ║ Then: ║
|
||||
> ║ 1. Start a NEW conversation ║
|
||||
> ║ 2. Use command: /smarsh2code-3--implement ║
|
||||
> ║ 3. Provide path: specs/<feature-name>/overview.md ║
|
||||
> ║ ║
|
||||
> ║ The command will auto-detect Phase 3 as next. ║
|
||||
> ║ ║
|
||||
> ╚═══════════════════════════════════════════════════════════════════╝
|
||||
> ```
|
||||
>
|
||||
> Need to change the plan? Use `/smarsh2code-1b--revise` before continuing."
|
||||
|
||||
Example for final phase:
|
||||
|
||||
> "⚡ [PHASE 4: Phase Name] - COMPLETE ✓
|
||||
>
|
||||
> This was the final implementation phase!
|
||||
>
|
||||
> ```
|
||||
> ⋅
|
||||
> ╭───╮
|
||||
> │ ★ │
|
||||
> │ ◡ │ All phases complete! Amazing work!
|
||||
> ╰───╯
|
||||
>
|
||||
> ╔═══════════════════════════════════════════════════════════════════╗
|
||||
> ║ NEXT STEPS - FINAL PHASE COMPLETE ║
|
||||
> ╠═══════════════════════════════════════════════════════════════════╣
|
||||
> ║ ║
|
||||
> ║ Save your progress: ║
|
||||
> ║ git add -A && git commit -m "Complete Phase 4: [Phase Name]" -m "AI Assisted" ║
|
||||
> ║ ║
|
||||
> ║ Then: ║
|
||||
> ║ 1. Start a NEW conversation ║
|
||||
> ║ 2. Use command: /smarsh2code-4--finalize ║
|
||||
> ║ 3. Provide path: specs/<feature-name>/overview.md ║
|
||||
> ║ ║
|
||||
> ╚═══════════════════════════════════════════════════════════════════╝
|
||||
> ```
|
||||
>
|
||||
> Need to revise before finalizing? Use `/smarsh2code-1b--revise` first."
|
||||
|
||||
## Abort Handling
|
||||
|
||||
@@ -426,7 +226,7 @@ If user says "abort", "cancel", or similar:
|
||||
- List completed vs remaining tasks
|
||||
- Note created/modified files
|
||||
- Do NOT change phase checkbox (stays `[/]`)
|
||||
- Explain: "Run `/smarsh2code-3--implement` again to resume."
|
||||
- Explain: "Run `/plan2code-3--implement` again to resume."
|
||||
3. Stop implementation
|
||||
|
||||
## Recovery
|
||||
@@ -437,24 +237,6 @@ If user says "abort", "cancel", or similar:
|
||||
| Spec unclear/conflicting | Mark task blocked, ask user |
|
||||
| Need to change plan | Pause, use `/plan2code-1b--revise` |
|
||||
|
||||
## Learning Capture Protocol
|
||||
## Learning Capture
|
||||
|
||||
At END of each session, check for auto-capture triggers:
|
||||
- [ ] Discovered undocumented build/test command
|
||||
- [ ] Found non-obvious dependency relationship
|
||||
- [ ] Encountered "gotcha" costing >5 minutes
|
||||
- [ ] Made workaround for framework quirk
|
||||
- [ ] Found patterns not in `AGENTS.md`
|
||||
|
||||
**Capture Format:**
|
||||
```
|
||||
📚 LEARNING DETECTED
|
||||
|
||||
Category: [Commands / Architecture / Gotchas / Testing / Config]
|
||||
Learning: [concise description]
|
||||
Context: [why this matters]
|
||||
|
||||
Update AGENTS.md with this? (yes/no)
|
||||
```
|
||||
|
||||
If yes, apply the edit directly.
|
||||
At session end, if you discovered undocumented commands, dependency quirks, gotchas (>5min cost), framework workarounds, or missing `AGENTS.md` patterns → prompt user to update AGENTS.md. If yes, apply the edit directly.
|
||||
|
||||
+22
-124
@@ -31,24 +31,9 @@ If multiple active spec folders exist or nothing provided, ask user for:
|
||||
|
||||
## Examples
|
||||
|
||||
### Task Audit
|
||||
**Bad:** "All tasks complete. Moving to Step 2." (No verification shown)
|
||||
**Task Audit:** Always show verification table with phase totals, blocked items, and completion %. Never just assert "all complete" without evidence.
|
||||
|
||||
**Good:**
|
||||
| Phase | Total | Completed | Blocked |
|
||||
|-------|-------|-----------|---------|
|
||||
| Phase 1 | 12 | 12 | 0 |
|
||||
| Phase 2 | 18 | 17 | 1 |
|
||||
Blocked: Task 2.14 - OAuth awaiting credentials. Completion: 96.7%
|
||||
|
||||
### Documentation Review
|
||||
**Bad:** "No docs need updating." (No evidence of review)
|
||||
|
||||
**Good:**
|
||||
| Document | Needs Update? | Changes |
|
||||
|----------|---------------|---------|
|
||||
| README.md | Yes | Add auth setup |
|
||||
| .env.example | Yes | Add JWT_SECRET |
|
||||
**Documentation Review:** Always show review table with each document checked and proposed changes. Never assert "no updates needed" without evidence.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -190,40 +175,21 @@ Add this summary to `overview.md` under `## Completion Summary`.
|
||||
| `API.md` / docs | API documentation | Update with new endpoints |
|
||||
| `CLAUDE.md` | AI assistant context | Update if patterns changed |
|
||||
|
||||
#### Report:
|
||||
Report: table of documents needing updates with proposed changes. List each document with specific additions.
|
||||
|
||||
```markdown
|
||||
## Documentation Review
|
||||
| Document | Needs Update? | Proposed Changes |
|
||||
|----------|---------------|------------------|
|
||||
| README.md | Yes | Add "Authentication" section |
|
||||
| CHANGELOG.md | Yes | Add entry: "Added user auth with JWT" |
|
||||
If updates needed, show Mascot and ask for approval:
|
||||
|
||||
### Proposed Updates
|
||||
#### README.md
|
||||
[Show specific additions]
|
||||
|
||||
#### CHANGELOG.md
|
||||
[Show specific entry]
|
||||
```
|
||||
⋅
|
||||
╭───╮
|
||||
│ ● │
|
||||
│ ~ │ Found some docs that need updating!
|
||||
╰───╯
|
||||
```
|
||||
|
||||
**If ANY documentation needs updates:**
|
||||
> Reply "approve" to proceed with doc updates, or specify which to skip.
|
||||
|
||||
> ```
|
||||
> ⋅
|
||||
> ╭───╮
|
||||
> │ ● │
|
||||
> │ ~ │ Found some docs that need updating!
|
||||
> ╰───╯
|
||||
> ```
|
||||
>
|
||||
> "The following documentation updates are recommended. Review and approve:
|
||||
>
|
||||
> [List proposed changes]
|
||||
>
|
||||
> Reply 'approve' to proceed, or specify which to skip."
|
||||
|
||||
**Do NOT make documentation changes without user approval.**
|
||||
Do NOT make documentation changes without user approval.
|
||||
|
||||
---
|
||||
|
||||
@@ -297,68 +263,17 @@ specs--completed/
|
||||
╰───╯
|
||||
```
|
||||
|
||||
╔═══════════════════════════════════════════════════════════════════╗
|
||||
║ IMPLEMENTATION COMPLETE ║
|
||||
╠═══════════════════════════════════════════════════════════════════╣
|
||||
║ ║
|
||||
║ All tasks finished. Specs archived to: ║
|
||||
║ specs--completed/<feature-name>/ ║
|
||||
║ ║
|
||||
║ Thank you for using the Smarsh2Code workflow! ║
|
||||
║ ║
|
||||
╚═══════════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
> IMPLEMENTATION COMPLETED!
|
||||
> All tasks finished.
|
||||
> Specs archived to `specs--completed/<feature-name>/`.
|
||||
> Thank you for using the Plan2Code workflow!
|
||||
|
||||
### Handling Incomplete Implementations
|
||||
|
||||
**Partial Completion (>75%):** Allow finalization with documentation:
|
||||
|
||||
```markdown
|
||||
## Partial Completion Notice
|
||||
Feature finalized at [X]% completion.
|
||||
|
||||
### Incomplete Items
|
||||
- Phase X, Task Y: [Description] - [Reason]
|
||||
|
||||
╔═══════════════════════════════════════════════════════════════════╗
|
||||
║ NEXT STEPS - REMAINING WORK ║
|
||||
╠═══════════════════════════════════════════════════════════════════╣
|
||||
║ ║
|
||||
║ [X] incomplete tasks remain. ║
|
||||
║ Review the overview.md for remaining items. ║
|
||||
║ Address these in a follow-up implementation cycle. ║
|
||||
║ ║
|
||||
╚═══════════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
|
||||
**Low Completion (<75%):** Recommend returning to implementation:
|
||||
|
||||
```markdown
|
||||
Implementation only [X]% complete. Recommend returning to Implementation Mode.
|
||||
|
||||
**Incomplete phases:**
|
||||
- Phase X: [Y]/[Z] tasks
|
||||
- Phase Y: [Y]/[Z] tasks
|
||||
|
||||
Options:
|
||||
1. Return to implementation
|
||||
2. Proceed with partial finalization
|
||||
|
||||
╔═══════════════════════════════════════════════════════════════════╗
|
||||
║ NEXT STEPS - IMPLEMENTATION INCOMPLETE ║
|
||||
╠═══════════════════════════════════════════════════════════════════╣
|
||||
║ ║
|
||||
║ Completion rate is below 75%. ║
|
||||
║ Return to implementation before finalizing. ║
|
||||
║ ║
|
||||
║ 1. Start a NEW conversation ║
|
||||
║ 2. Use command: /smarsh2code-3--implement ║
|
||||
║ 3. Provide path: specs/<feature-name>/overview.md ║
|
||||
║ ║
|
||||
║ The command will auto-detect the next Phase to implement. ║
|
||||
║ ║
|
||||
╚═══════════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
| Completion | Action |
|
||||
|-----------|--------|
|
||||
| **>75%** | Finalize with notice. List incomplete items. Note remaining tasks for follow-up cycle. |
|
||||
| **<75%** | Recommend returning to implementation. List incomplete phases with task counts. Options: 1) Return via `/plan2code-3--implement` 2) Proceed with partial finalization. |
|
||||
|
||||
## Abort Handling
|
||||
|
||||
@@ -375,23 +290,6 @@ If user says "abort", "cancel", or similar:
|
||||
| Missing spec files | Ask for all phase-X.md files |
|
||||
| Doc updates rejected | Skip updates, note in summary |
|
||||
|
||||
## Learning Capture Protocol
|
||||
## Learning Capture
|
||||
|
||||
At END of session, check for auto-capture triggers:
|
||||
- [ ] Discovered undocumented build/test command
|
||||
- [ ] Found non-obvious dependency relationship
|
||||
- [ ] Encountered "gotcha" costing >5 minutes
|
||||
- [ ] Made workaround for framework quirk
|
||||
- [ ] Found patterns not in `AGENTS.md`
|
||||
|
||||
If any triggered:
|
||||
```
|
||||
📚 LEARNING DETECTED
|
||||
- Category: [Commands / Architecture / Gotchas / Testing / Config]
|
||||
- Learning: [description]
|
||||
- Context: [why this matters]
|
||||
|
||||
Update AGENTS.md with this? (yes/no)
|
||||
```
|
||||
|
||||
If yes, generate and apply the edit directly.
|
||||
At session end, if you discovered undocumented commands, dependency quirks, gotchas (>5min cost), framework workarounds, or missing `AGENTS.md` patterns → prompt user to update AGENTS.md. If yes, apply the edit directly.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Plan2Code",
|
||||
"version": "1.5.4",
|
||||
"version": "1.6.1",
|
||||
"description": "A structured 4-step workflow methodology for AI-assisted software development",
|
||||
"keywords": [
|
||||
"ai",
|
||||
|
||||
Reference in New Issue
Block a user