@pixelcraft-tw/spec 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/bin/pxs.d.ts +2 -0
  4. package/dist/bin/pxs.js +5 -0
  5. package/dist/bin/pxs.js.map +1 -0
  6. package/dist/src/backends/claude.d.ts +9 -0
  7. package/dist/src/backends/claude.js +80 -0
  8. package/dist/src/backends/claude.js.map +1 -0
  9. package/dist/src/backends/codex.d.ts +9 -0
  10. package/dist/src/backends/codex.js +72 -0
  11. package/dist/src/backends/codex.js.map +1 -0
  12. package/dist/src/backends/factory.d.ts +2 -0
  13. package/dist/src/backends/factory.js +14 -0
  14. package/dist/src/backends/factory.js.map +1 -0
  15. package/dist/src/backends/interface.d.ts +15 -0
  16. package/dist/src/backends/interface.js +2 -0
  17. package/dist/src/backends/interface.js.map +1 -0
  18. package/dist/src/cli.d.ts +2 -0
  19. package/dist/src/cli.js +94 -0
  20. package/dist/src/cli.js.map +1 -0
  21. package/dist/src/commands/clarify.d.ts +5 -0
  22. package/dist/src/commands/clarify.js +46 -0
  23. package/dist/src/commands/clarify.js.map +1 -0
  24. package/dist/src/commands/diff.d.ts +1 -0
  25. package/dist/src/commands/diff.js +81 -0
  26. package/dist/src/commands/diff.js.map +1 -0
  27. package/dist/src/commands/implement.d.ts +9 -0
  28. package/dist/src/commands/implement.js +247 -0
  29. package/dist/src/commands/implement.js.map +1 -0
  30. package/dist/src/commands/init.d.ts +6 -0
  31. package/dist/src/commands/init.js +183 -0
  32. package/dist/src/commands/init.js.map +1 -0
  33. package/dist/src/commands/new.d.ts +5 -0
  34. package/dist/src/commands/new.js +186 -0
  35. package/dist/src/commands/new.js.map +1 -0
  36. package/dist/src/commands/refine.d.ts +8 -0
  37. package/dist/src/commands/refine.js +158 -0
  38. package/dist/src/commands/refine.js.map +1 -0
  39. package/dist/src/commands/reset.d.ts +3 -0
  40. package/dist/src/commands/reset.js +44 -0
  41. package/dist/src/commands/reset.js.map +1 -0
  42. package/dist/src/commands/review.d.ts +4 -0
  43. package/dist/src/commands/review.js +70 -0
  44. package/dist/src/commands/review.js.map +1 -0
  45. package/dist/src/commands/status.d.ts +1 -0
  46. package/dist/src/commands/status.js +53 -0
  47. package/dist/src/commands/status.js.map +1 -0
  48. package/dist/src/discovery/project.d.ts +7 -0
  49. package/dist/src/discovery/project.js +135 -0
  50. package/dist/src/discovery/project.js.map +1 -0
  51. package/dist/src/git/operations.d.ts +10 -0
  52. package/dist/src/git/operations.js +56 -0
  53. package/dist/src/git/operations.js.map +1 -0
  54. package/dist/src/parsers/arguments.d.ts +18 -0
  55. package/dist/src/parsers/arguments.js +43 -0
  56. package/dist/src/parsers/arguments.js.map +1 -0
  57. package/dist/src/parsers/plan.d.ts +23 -0
  58. package/dist/src/parsers/plan.js +117 -0
  59. package/dist/src/parsers/plan.js.map +1 -0
  60. package/dist/src/parsers/spec.d.ts +10 -0
  61. package/dist/src/parsers/spec.js +46 -0
  62. package/dist/src/parsers/spec.js.map +1 -0
  63. package/dist/src/state/manager.d.ts +24 -0
  64. package/dist/src/state/manager.js +103 -0
  65. package/dist/src/state/manager.js.map +1 -0
  66. package/dist/src/state/types.d.ts +48 -0
  67. package/dist/src/state/types.js +20 -0
  68. package/dist/src/state/types.js.map +1 -0
  69. package/dist/src/utils/display.d.ts +7 -0
  70. package/dist/src/utils/display.js +42 -0
  71. package/dist/src/utils/display.js.map +1 -0
  72. package/dist/src/utils/prompt.d.ts +15 -0
  73. package/dist/src/utils/prompt.js +139 -0
  74. package/dist/src/utils/prompt.js.map +1 -0
  75. package/package.json +52 -0
  76. package/templates/agents-md-snippet.md +20 -0
  77. package/templates/architectures/clean/csharp-aspnet.md +56 -0
  78. package/templates/architectures/clean/dart-flutter.md +73 -0
  79. package/templates/architectures/clean/go-gin.md +50 -0
  80. package/templates/architectures/clean/go-std.md +49 -0
  81. package/templates/architectures/clean/kotlin-android.md +70 -0
  82. package/templates/architectures/clean/python-fastapi.md +49 -0
  83. package/templates/architectures/clean/swift-ios.md +69 -0
  84. package/templates/architectures/clean/typescript-express.md +60 -0
  85. package/templates/architectures/clean/typescript-nestjs.md +61 -0
  86. package/templates/architectures/ddd/csharp-aspnet.md +55 -0
  87. package/templates/architectures/ddd/go-gin.md +53 -0
  88. package/templates/architectures/ddd/python-fastapi.md +52 -0
  89. package/templates/architectures/ddd/typescript-nestjs.md +62 -0
  90. package/templates/architectures/hexagonal/csharp-aspnet.md +45 -0
  91. package/templates/architectures/hexagonal/go-gin.md +47 -0
  92. package/templates/architectures/hexagonal/python-fastapi.md +43 -0
  93. package/templates/architectures/hexagonal/typescript-nestjs.md +44 -0
  94. package/templates/architectures/layered/csharp-aspnet.md +45 -0
  95. package/templates/architectures/layered/go-gin.md +41 -0
  96. package/templates/architectures/layered/python-fastapi.md +42 -0
  97. package/templates/architectures/layered/typescript-nestjs.md +48 -0
  98. package/templates/architectures/modular/csharp-aspnet.md +45 -0
  99. package/templates/architectures/modular/dart-flutter.md +64 -0
  100. package/templates/architectures/modular/go-gin.md +47 -0
  101. package/templates/architectures/modular/kotlin-android.md +68 -0
  102. package/templates/architectures/modular/python-fastapi.md +45 -0
  103. package/templates/architectures/modular/swift-ios.md +55 -0
  104. package/templates/architectures/modular/typescript-nestjs.md +48 -0
  105. package/templates/architectures/mvvm/dart-flutter.md +69 -0
  106. package/templates/architectures/mvvm/kotlin-android.md +79 -0
  107. package/templates/architectures/mvvm/swift-ios.md +66 -0
  108. package/templates/claude-commands/sf.clarify.md +18 -0
  109. package/templates/claude-commands/sf.implement.md +80 -0
  110. package/templates/claude-commands/sf.new.md +22 -0
  111. package/templates/claude-commands/sf.refine.md +47 -0
  112. package/templates/claude-commands/sf.review.md +17 -0
  113. package/templates/claude-commands/sf.status.md +12 -0
  114. package/templates/workflow/config.yaml +17 -0
  115. package/templates/workflow/prompts/clarify.md +39 -0
  116. package/templates/workflow/prompts/final-review.md +30 -0
  117. package/templates/workflow/prompts/implement-tdd.md +35 -0
  118. package/templates/workflow/prompts/implement.md +43 -0
  119. package/templates/workflow/prompts/refine.md +52 -0
  120. package/templates/workflow/prompts/review.md +33 -0
  121. package/templates/workflow/prompts/test.md +14 -0
  122. package/templates/workflow/templates/spec-template.md +13 -0
@@ -0,0 +1,186 @@
1
+ import fs from 'node:fs';
2
+ import inquirer from 'inquirer';
3
+ import { StateManager } from '../state/manager.js';
4
+ import { createBackend } from '../backends/factory.js';
5
+ import * as display from '../utils/display.js';
6
+ export async function newCommand(name, options) {
7
+ const state = new StateManager();
8
+ state.ensureWorkflow();
9
+ const specPath = state.specPath(name);
10
+ // Check if spec already exists
11
+ if (fs.existsSync(specPath)) {
12
+ const { overwrite } = await inquirer.prompt([
13
+ {
14
+ type: 'confirm',
15
+ name: 'overwrite',
16
+ message: `Spec "${name}" already exists. Overwrite?`,
17
+ default: false,
18
+ },
19
+ ]);
20
+ if (!overwrite) {
21
+ display.info('Aborted.');
22
+ return;
23
+ }
24
+ }
25
+ // Ensure specs dir exists
26
+ fs.mkdirSync(state.specsDir(), { recursive: true });
27
+ if (options.jira && options.jira.length > 0) {
28
+ await createFromJira(name, options.jira, state);
29
+ }
30
+ else if (options.desc) {
31
+ await createFromDesc(name, options.desc, state);
32
+ }
33
+ else if (options.interactive) {
34
+ await createInteractive(name, state);
35
+ }
36
+ else {
37
+ createBlank(name, state);
38
+ }
39
+ // Update state
40
+ state.upsertFeature({
41
+ feature: name,
42
+ type: 'feat',
43
+ branch: '',
44
+ phase: 'spec_created',
45
+ total_tasks: 0,
46
+ current_task: 0,
47
+ tasks: [],
48
+ });
49
+ display.success(`Spec created: ${state.specPath(name)}`);
50
+ display.info(`Edit the spec, then run \`pxs refine ${name}\``);
51
+ }
52
+ function createBlank(name, state) {
53
+ const templatePath = state.templatesDir() + '/spec-template.md';
54
+ let template;
55
+ if (fs.existsSync(templatePath)) {
56
+ template = fs.readFileSync(templatePath, 'utf-8');
57
+ template = template.replace('<name>', name);
58
+ }
59
+ else {
60
+ template = `# Feature: ${name}
61
+
62
+ ## Context
63
+ <!-- 2-3 sentences of project background -->
64
+
65
+ ## Requirements
66
+ <!-- Numbered list with acceptance criteria -->
67
+
68
+ ## Constraints
69
+ <!-- Technical limitations, compatibility requirements -->
70
+
71
+ ## Notes
72
+ <!-- Additional notes -->
73
+ `;
74
+ }
75
+ fs.writeFileSync(state.specPath(name), template, 'utf-8');
76
+ }
77
+ async function createFromDesc(name, desc, state) {
78
+ display.info('Generating spec from description...');
79
+ try {
80
+ const config = state.readConfig();
81
+ const backend = createBackend(config.backend.default);
82
+ if (!(await backend.isAvailable())) {
83
+ display.error(`Backend "${config.backend.default}" is not available. Install claude or codex.`);
84
+ createBlank(name, state);
85
+ display.warn('Created blank spec instead.');
86
+ return;
87
+ }
88
+ const prompt = `Create a detailed feature spec in markdown format for the following feature:
89
+
90
+ Name: ${name}
91
+ Description: ${desc}
92
+
93
+ Output format:
94
+ # Feature: ${name}
95
+
96
+ ## Context
97
+ (2-3 sentences of background)
98
+
99
+ ## Requirements
100
+ (Numbered list with acceptance criteria)
101
+
102
+ ## Constraints
103
+ (Technical limitations)
104
+
105
+ ## Notes
106
+ (Additional notes)`;
107
+ const result = await backend.execute(prompt);
108
+ fs.writeFileSync(state.specPath(name), result.output, 'utf-8');
109
+ }
110
+ catch (err) {
111
+ display.warn(`AI generation failed: ${err}. Creating blank spec.`);
112
+ createBlank(name, state);
113
+ }
114
+ }
115
+ async function createFromJira(name, tickets, state) {
116
+ display.info(`Fetching Jira tickets: ${tickets.join(', ')}...`);
117
+ try {
118
+ const config = state.readConfig();
119
+ const backend = createBackend(config.backend.default);
120
+ if (!(await backend.isAvailable())) {
121
+ display.error(`Backend "${config.backend.default}" is not available.`);
122
+ createBlank(name, state);
123
+ display.warn('Created blank spec instead.');
124
+ return;
125
+ }
126
+ const ticketList = tickets.map((t) => `- ${t}`).join('\n');
127
+ const prompt = `You have access to a Jira MCP server. Use it to read the following tickets and generate a feature spec.
128
+
129
+ Tickets:
130
+ ${ticketList}
131
+
132
+ For each ticket, retrieve: summary, description, acceptance criteria, labels, and priority.
133
+
134
+ Then combine the information into a single feature spec in this format:
135
+
136
+ # Feature: ${name}
137
+
138
+ ## Context
139
+ (2-3 sentences of background, derived from ticket descriptions)
140
+
141
+ ## Requirements
142
+ (Numbered list with acceptance criteria, merged from all tickets)
143
+
144
+ ## Constraints
145
+ (Technical limitations mentioned in tickets)
146
+
147
+ ## Source Tickets
148
+ ${ticketList}
149
+
150
+ ## Notes
151
+ (Additional notes from ticket comments or labels)
152
+
153
+ If you cannot access Jira MCP, output the spec template with the ticket IDs listed so the user can fill in details manually.`;
154
+ const result = await backend.execute(prompt);
155
+ fs.writeFileSync(state.specPath(name), result.output, 'utf-8');
156
+ display.success(`Generated spec from ${tickets.length} Jira ticket(s).`);
157
+ }
158
+ catch (err) {
159
+ display.warn(`Jira integration failed: ${err}. Creating blank spec.`);
160
+ createBlank(name, state);
161
+ }
162
+ }
163
+ async function createInteractive(name, state) {
164
+ const answers = await inquirer.prompt([
165
+ { type: 'input', name: 'context', message: 'Project context (2-3 sentences):' },
166
+ { type: 'editor', name: 'requirements', message: 'Requirements (one per line):' },
167
+ { type: 'input', name: 'constraints', message: 'Constraints:' },
168
+ { type: 'input', name: 'notes', message: 'Additional notes:' },
169
+ ]);
170
+ const spec = `# Feature: ${name}
171
+
172
+ ## Context
173
+ ${answers.context}
174
+
175
+ ## Requirements
176
+ ${answers.requirements}
177
+
178
+ ## Constraints
179
+ ${answers.constraints}
180
+
181
+ ## Notes
182
+ ${answers.notes}
183
+ `;
184
+ fs.writeFileSync(state.specPath(name), spec, 'utf-8');
185
+ }
186
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../../src/commands/new.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function refineCommand(name: string, args: {
2
+ agents: string[];
3
+ skills: string[];
4
+ text: string;
5
+ }, options: {
6
+ skipClarify?: boolean;
7
+ clarify?: number;
8
+ }): Promise<void>;
@@ -0,0 +1,158 @@
1
+ import fs from 'node:fs';
2
+ import inquirer from 'inquirer';
3
+ import { StateManager } from '../state/manager.js';
4
+ import { createBackend } from '../backends/factory.js';
5
+ import { assemblePrompt } from '../utils/prompt.js';
6
+ import { parsePlan } from '../parsers/plan.js';
7
+ import * as display from '../utils/display.js';
8
+ export async function refineCommand(name, args, options) {
9
+ const state = new StateManager();
10
+ state.ensureWorkflow();
11
+ state.checkPhaseGuard('refine', name);
12
+ const specPath = state.specPath(name);
13
+ if (!fs.existsSync(specPath)) {
14
+ display.error(`Spec "${name}" not found. Run \`pxs new ${name}\` first.`);
15
+ return;
16
+ }
17
+ const config = state.readConfig();
18
+ const backend = createBackend(config.backend.default);
19
+ if (!(await backend.isAvailable())) {
20
+ display.error(`Backend "${config.backend.default}" not available.`);
21
+ return;
22
+ }
23
+ let specContent = fs.readFileSync(specPath, 'utf-8');
24
+ const feature = state.getFeature(name);
25
+ let sessionId = feature.session?.id ?? '';
26
+ // Sub-flow 1: Clarify (unless skipped)
27
+ if (!options.skipClarify) {
28
+ display.heading('Phase 1: Requirement Clarification');
29
+ const clarifyPrompt = assemblePrompt({
30
+ templateName: 'clarify',
31
+ vars: { spec_content: specContent },
32
+ agents: args.agents,
33
+ skills: args.skills,
34
+ extraText: args.text,
35
+ });
36
+ const clarifyResult = sessionId
37
+ ? await backend.resume(sessionId, clarifyPrompt)
38
+ : await backend.execute(clarifyPrompt);
39
+ sessionId = clarifyResult.sessionId;
40
+ console.log('\n' + clarifyResult.output);
41
+ feature.phase = 'clarifying';
42
+ feature.session = { backend: config.backend.default, id: sessionId };
43
+ state.upsertFeature(feature);
44
+ // Wait for user to answer questions (in CLI mode, AI handles the conversation)
45
+ const { proceed } = await inquirer.prompt([
46
+ {
47
+ type: 'confirm',
48
+ name: 'proceed',
49
+ message: 'Proceed to spec refinement?',
50
+ default: true,
51
+ },
52
+ ]);
53
+ if (!proceed) {
54
+ display.info('Paused. Run `pxs refine` again when ready.');
55
+ return;
56
+ }
57
+ }
58
+ // Sub-flow 2: Refine spec
59
+ display.heading('Phase 2: Refine Spec');
60
+ specContent = fs.readFileSync(specPath, 'utf-8');
61
+ const refinePrompt = assemblePrompt({
62
+ templateName: 'refine',
63
+ vars: { spec_content: specContent },
64
+ agents: args.agents,
65
+ skills: args.skills,
66
+ extraText: args.text,
67
+ });
68
+ const refineResult = sessionId
69
+ ? await backend.resume(sessionId, refinePrompt)
70
+ : await backend.execute(refinePrompt);
71
+ sessionId = refineResult.sessionId;
72
+ // Save refined spec
73
+ fs.writeFileSync(specPath, refineResult.output, 'utf-8');
74
+ display.success(`Refined spec saved to ${specPath}`);
75
+ console.log('\n' + refineResult.output.slice(0, 500) + '...\n');
76
+ feature.phase = 'spec_approved';
77
+ feature.session = { backend: config.backend.default, id: sessionId };
78
+ state.upsertFeature(feature);
79
+ const { approveSpec } = await inquirer.prompt([
80
+ {
81
+ type: 'list',
82
+ name: 'approveSpec',
83
+ message: 'Spec refinement:',
84
+ choices: ['approve', 'edit'],
85
+ },
86
+ ]);
87
+ if (approveSpec === 'edit') {
88
+ display.info(`Edit ${specPath} and run \`pxs refine ${name} --skip-clarify\``);
89
+ return;
90
+ }
91
+ // Sub-flow 3: Decompose plan
92
+ display.heading('Phase 3: Decompose Plan');
93
+ specContent = fs.readFileSync(specPath, 'utf-8');
94
+ const planPrompt = `Decompose the following refined spec into an implementation plan with discrete tasks.
95
+
96
+ ${specContent}
97
+
98
+ Output the plan in this exact format:
99
+ # Implementation Plan: ${name}
100
+
101
+ > type: feat
102
+ > branch: feat/${name}
103
+ > total_tasks: N
104
+
105
+ ## Task 1: <title>
106
+ - **Files**:
107
+ - \`path/to/file\` (new|modify)
108
+ - **Description**: What to implement
109
+ - **Depends on**: None | Task N
110
+ - **Complexity**: Low | Medium | High
111
+ - **Acceptance**: Definition of done
112
+
113
+ (repeat for each task)`;
114
+ const planResult = sessionId
115
+ ? await backend.resume(sessionId, planPrompt)
116
+ : await backend.execute(planPrompt);
117
+ sessionId = planResult.sessionId;
118
+ // Save plan
119
+ fs.mkdirSync(state.plansDir(), { recursive: true });
120
+ const planPath = state.planPath(name);
121
+ fs.writeFileSync(planPath, planResult.output, 'utf-8');
122
+ display.success(`Plan saved to ${planPath}`);
123
+ console.log('\n' + planResult.output + '\n');
124
+ // Parse plan for state
125
+ const plan = parsePlan(planResult.output);
126
+ feature.phase = 'plan_pending_approval';
127
+ feature.session = { backend: config.backend.default, id: sessionId };
128
+ state.upsertFeature(feature);
129
+ const { approvePlan } = await inquirer.prompt([
130
+ {
131
+ type: 'list',
132
+ name: 'approvePlan',
133
+ message: 'Implementation plan:',
134
+ choices: ['approve', 'edit', 're-split'],
135
+ },
136
+ ]);
137
+ if (approvePlan === 'edit') {
138
+ display.info(`Edit ${planPath} and run \`pxs refine ${name} --skip-clarify\``);
139
+ return;
140
+ }
141
+ if (approvePlan === 're-split') {
142
+ display.info('Re-splitting not yet implemented. Edit the plan manually.');
143
+ return;
144
+ }
145
+ // Approve: update state
146
+ feature.type = plan.type;
147
+ feature.branch = plan.branch || `${plan.type}/${name}`;
148
+ feature.phase = 'ready_to_implement';
149
+ feature.total_tasks = plan.tasks.length;
150
+ feature.current_task = 0;
151
+ feature.tasks = plan.tasks.map((t) => ({
152
+ name: t.title,
153
+ status: 'pending',
154
+ }));
155
+ state.upsertFeature(feature);
156
+ display.success('Plan approved! Run `pxs implement ' + name + '` to start.');
157
+ }
158
+ //# sourceMappingURL=refine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refine.js","sourceRoot":"","sources":["../../../src/commands/refine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function resetCommand(name: string, options: {
2
+ to?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,44 @@
1
+ import { StateManager } from '../state/manager.js';
2
+ import * as display from '../utils/display.js';
3
+ const VALID_RESET_TARGETS = [
4
+ 'spec_created',
5
+ 'clarifying',
6
+ 'spec_approved',
7
+ 'plan_pending_approval',
8
+ 'ready_to_implement',
9
+ ];
10
+ export async function resetCommand(name, options) {
11
+ const state = new StateManager();
12
+ state.ensureWorkflow();
13
+ const feature = state.getFeature(name);
14
+ if (!feature) {
15
+ display.error(`Feature "${name}" not found.`);
16
+ return;
17
+ }
18
+ const targetPhase = (options.to ?? 'spec_created');
19
+ if (!VALID_RESET_TARGETS.includes(targetPhase)) {
20
+ display.error(`Cannot reset to "${targetPhase}". Valid targets: ${VALID_RESET_TARGETS.join(', ')}`);
21
+ return;
22
+ }
23
+ const previousPhase = feature.phase;
24
+ feature.phase = targetPhase;
25
+ // Clear downstream state depending on target
26
+ if (targetPhase === 'spec_created' || targetPhase === 'clarifying'
27
+ || targetPhase === 'spec_approved' || targetPhase === 'plan_pending_approval') {
28
+ feature.tasks = [];
29
+ feature.total_tasks = 0;
30
+ feature.current_task = 0;
31
+ feature.session = undefined;
32
+ }
33
+ if (targetPhase === 'ready_to_implement') {
34
+ // Reset task statuses to pending
35
+ for (const task of feature.tasks) {
36
+ task.status = 'pending';
37
+ }
38
+ feature.current_task = 0;
39
+ feature.session = undefined;
40
+ }
41
+ state.upsertFeature(feature);
42
+ display.success(`Reset "${name}": ${previousPhase} → ${targetPhase}`);
43
+ }
44
+ //# sourceMappingURL=reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset.js","sourceRoot":"","sources":["../../../src/commands/reset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,MAAM,mBAAmB,GAAY;IACnC,cAAc;IACd,YAAY;IACZ,eAAe;IACf,uBAAuB;IACvB,oBAAoB;CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY,EACZ,OAAwB;IAExB,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE,CAAC;IACjC,KAAK,CAAC,cAAc,EAAE,CAAC;IAEvB,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,cAAc,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,cAAc,CAAU,CAAC;IAE5D,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CACX,oBAAoB,WAAW,qBAAqB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC;IACpC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC;IAE5B,6CAA6C;IAC7C,IAAI,WAAW,KAAK,cAAc,IAAI,WAAW,KAAK,YAAY;WAC7D,WAAW,KAAK,eAAe,IAAI,WAAW,KAAK,uBAAuB,EAAE,CAAC;QAChF,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;QACnB,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;QACxB,OAAO,CAAC,YAAY,GAAG,CAAC,CAAC;QACzB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED,IAAI,WAAW,KAAK,oBAAoB,EAAE,CAAC;QACzC,iCAAiC;QACjC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QAC1B,CAAC;QACD,OAAO,CAAC,YAAY,GAAG,CAAC,CAAC;QACzB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,aAAa,MAAM,WAAW,EAAE,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function reviewCommand(name: string, options: {
2
+ step?: number;
3
+ summary?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,70 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { StateManager } from '../state/manager.js';
4
+ import * as display from '../utils/display.js';
5
+ export async function reviewCommand(name, options) {
6
+ const state = new StateManager();
7
+ state.ensureWorkflow();
8
+ state.checkPhaseGuard('review', name);
9
+ const feature = state.getFeature(name);
10
+ if (!feature) {
11
+ display.error(`Feature "${name}" not found.`);
12
+ return;
13
+ }
14
+ if (options.summary) {
15
+ display.heading(`Review Summary: ${name}`);
16
+ for (let i = 0; i < feature.tasks.length; i++) {
17
+ const t = feature.tasks[i];
18
+ const reviewPath = state.reviewPath(name, i + 1);
19
+ const hasReview = fs.existsSync(reviewPath);
20
+ console.log(` ${i + 1}. ${display.taskIcon(t.status)} ${t.name} ${hasReview ? '(reviewed)' : ''}`);
21
+ }
22
+ // Show final review status
23
+ const finalReviewPath = path.join(state.reviewsDir(), `${name}-final.md`);
24
+ if (fs.existsSync(finalReviewPath)) {
25
+ console.log(`\n Final branch review: exists`);
26
+ }
27
+ return;
28
+ }
29
+ if (options.step !== undefined) {
30
+ const reviewPath = state.reviewPath(name, options.step);
31
+ if (!fs.existsSync(reviewPath)) {
32
+ display.error(`Review for task ${options.step} not found.`);
33
+ return;
34
+ }
35
+ const content = fs.readFileSync(reviewPath, 'utf-8');
36
+ display.heading(`Review: ${name} - Task ${options.step}`);
37
+ console.log(content);
38
+ return;
39
+ }
40
+ // Default: if completed, show final review first
41
+ if (feature.phase === 'completed' || feature.phase === 'merged') {
42
+ const finalReviewPath = path.join(state.reviewsDir(), `${name}-final.md`);
43
+ if (fs.existsSync(finalReviewPath)) {
44
+ display.heading(`Final Branch Review: ${name}`);
45
+ console.log(fs.readFileSync(finalReviewPath, 'utf-8'));
46
+ return;
47
+ }
48
+ }
49
+ // Show most recent or pending review
50
+ const pendingIdx = feature.tasks.findIndex((t) => t.status === 'review_pending');
51
+ if (pendingIdx >= 0) {
52
+ const reviewPath = state.reviewPath(name, pendingIdx + 1);
53
+ if (fs.existsSync(reviewPath)) {
54
+ display.heading(`Pending Review: Task ${pendingIdx + 1}`);
55
+ console.log(fs.readFileSync(reviewPath, 'utf-8'));
56
+ return;
57
+ }
58
+ }
59
+ // Show last completed task's review
60
+ for (let i = feature.tasks.length - 1; i >= 0; i--) {
61
+ const reviewPath = state.reviewPath(name, i + 1);
62
+ if (fs.existsSync(reviewPath)) {
63
+ display.heading(`Latest Review: Task ${i + 1}`);
64
+ console.log(fs.readFileSync(reviewPath, 'utf-8'));
65
+ return;
66
+ }
67
+ }
68
+ display.info('No reviews found.');
69
+ }
70
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function statusCommand(name?: string): Promise<void>;
@@ -0,0 +1,53 @@
1
+ import { StateManager } from '../state/manager.js';
2
+ import * as display from '../utils/display.js';
3
+ export async function statusCommand(name) {
4
+ const state = new StateManager();
5
+ if (!state.workflowExists()) {
6
+ display.error('Workflow not initialized. Run `pxs init` first.');
7
+ return;
8
+ }
9
+ const workflowState = state.readState();
10
+ if (!name) {
11
+ // List all features
12
+ if (workflowState.features.length === 0) {
13
+ display.info('No features tracked. Run `pxs new <name>` to start.');
14
+ return;
15
+ }
16
+ display.heading('Workflow Status');
17
+ display.table(['Feature', 'Type', 'Phase', 'Tasks', 'Branch'], workflowState.features.map((f) => {
18
+ const completedTasks = f.tasks.filter((t) => t.status === 'complete').length;
19
+ return [
20
+ f.feature,
21
+ f.type,
22
+ f.phase,
23
+ `${completedTasks}/${f.total_tasks}`,
24
+ f.branch || '-',
25
+ ];
26
+ }));
27
+ }
28
+ else {
29
+ // Show specific feature
30
+ const feature = state.getFeature(name);
31
+ if (!feature) {
32
+ display.error(`Feature "${name}" not found.`);
33
+ return;
34
+ }
35
+ display.heading(`Feature: ${feature.feature}`);
36
+ console.log(` Type: ${feature.type}`);
37
+ console.log(` Branch: ${feature.branch || '-'}`);
38
+ console.log(` Phase: ${feature.phase}`);
39
+ if (feature.session) {
40
+ console.log(` Backend: ${feature.session.backend}`);
41
+ console.log(` Session: ${feature.session.id}`);
42
+ }
43
+ if (feature.tasks.length > 0) {
44
+ console.log('\n Tasks:');
45
+ for (let i = 0; i < feature.tasks.length; i++) {
46
+ const t = feature.tasks[i];
47
+ const icon = display.taskIcon(t.status);
48
+ console.log(` ${i + 1}. ${icon} ${t.name} (${t.status})`);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface ProjectInfo {
2
+ name: string;
3
+ language: string;
4
+ framework: string;
5
+ lang_framework: string;
6
+ }
7
+ export declare function detectProject(cwd?: string): ProjectInfo;