@popoverai/dotrequirements 0.24.3 → 0.26.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.
- package/README.md +7 -8
- package/dist/cli.js +8 -1
- package/dist/codebase-to-spec/dispatch.d.ts +60 -14
- package/dist/codebase-to-spec/dispatch.js +381 -15
- package/dist/codebase-to-spec/pack.d.ts +7 -0
- package/dist/codebase-to-spec/pack.js +29 -8
- package/dist/codebase-to-spec/present.d.ts +9 -0
- package/dist/codebase-to-spec/present.js +23 -2
- package/dist/codebase-to-spec/prompts/editor.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/editor.js +1 -1
- package/dist/codebase-to-spec/prompts/specifier.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/specifier.js +3 -2
- package/dist/codebase-to-spec/schemas.d.ts +153 -0
- package/dist/codebase-to-spec/schemas.js +111 -0
- package/dist/codebase-to-spec/skill-install.d.ts +42 -29
- package/dist/codebase-to-spec/skill-install.js +122 -112
- package/dist/codebase-to-spec/version-check.d.ts +31 -0
- package/dist/codebase-to-spec/version-check.js +56 -0
- package/dist/commands/ai-setup.d.ts +12 -1
- package/dist/commands/ai-setup.js +65 -33
- package/dist/commands/codebase-to-spec/dispatch-context.d.ts +2 -5
- package/dist/commands/codebase-to-spec/dispatch-context.js +2 -5
- package/dist/commands/codebase-to-spec/dispatch-editor.d.ts +0 -1
- package/dist/commands/codebase-to-spec/dispatch-editor.js +0 -1
- package/dist/commands/codebase-to-spec/dispatch-planner.d.ts +0 -1
- package/dist/commands/codebase-to-spec/dispatch-planner.js +0 -1
- package/dist/commands/codebase-to-spec/dispatch-spec.d.ts +3 -6
- package/dist/commands/codebase-to-spec/dispatch-spec.js +3 -6
- package/dist/commands/codebase-to-spec/index.js +3 -2
- package/dist/commands/codebase-to-spec/pack.d.ts +9 -0
- package/dist/commands/codebase-to-spec/pack.js +23 -3
- package/dist/commands/codebase-to-spec/skill-install.js +2 -9
- package/dist/commands/init.js +6 -1
- package/dist/commands/link-resolution.d.ts +79 -0
- package/dist/commands/link-resolution.js +141 -0
- package/dist/commands/link.d.ts +14 -4
- package/dist/commands/link.js +369 -16
- package/dist/commands/pull.js +19 -2
- package/dist/commands/push.js +36 -2
- package/dist/convex.d.ts +5 -3
- package/dist/convex.js +5 -3
- package/dist/harness/cache.d.ts +0 -14
- package/dist/harness/cache.js +1 -41
- package/dist/harness/finalize.js +2 -2
- package/dist/harness/prepare.js +1 -3
- package/dist/harness/requirementsLoader.d.ts +3 -3
- package/dist/harness/requirementsLoader.js +13 -8
- package/dist/mcp/handlers/authoring.d.ts +5 -5
- package/dist/mcp/handlers/authoring.js +9 -9
- package/dist/mcp/handlers/push.d.ts +2 -2
- package/dist/mcp/handlers/push.js +36 -3
- package/dist/mcp/handlers/review.d.ts +4 -4
- package/dist/mcp/handlers/review.js +4 -4
- package/dist/mcp/handlers/search.d.ts +1 -1
- package/dist/mcp/handlers/search.js +1 -1
- package/dist/mcp/index.js +29 -0
- package/dist/push/core.d.ts +18 -0
- package/dist/push/core.js +70 -3
- package/dist/push/index.d.ts +1 -1
- package/dist/push/index.js +1 -1
- package/dist/schema/parser-core.js +5 -1
- package/dist/schema/parser.js +5 -1
- package/dist/schema/run-marker.d.ts +38 -0
- package/dist/schema/run-marker.js +138 -0
- package/dist/schema/schemas.d.ts +12 -0
- package/dist/schema/schemas.js +1 -0
- package/dist/templates/agents/cts-worker.md +3 -3
- package/dist/templates/skills/codebase-to-spec/SKILL.md +56 -158
- package/dist/templates/workflows/specify-codebase.js +374 -0
- package/dist/utils/own-package.d.ts +10 -0
- package/dist/utils/own-package.js +13 -0
- package/dist/utils/project-selector.d.ts +5 -0
- package/dist/utils/project-selector.js +4 -0
- package/package.json +3 -3
- package/dist/templates/hooks/cts-worker-persona.sh +0 -76
|
@@ -13,9 +13,11 @@ function loadContextFileSection() {
|
|
|
13
13
|
return loadTemplate("context-file-section.md");
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Install workflow guidance to the appropriate context file for a platform
|
|
16
|
+
* Install workflow guidance to the appropriate context file for a platform.
|
|
17
|
+
* With `yes` (the non-interactive --assistant path, AISETUP-1.0), both
|
|
18
|
+
* confirmations are auto-accepted — matching their interactive defaults.
|
|
17
19
|
*/
|
|
18
|
-
async function installContextFileSection(platform) {
|
|
20
|
+
async function installContextFileSection(platform, yes = false) {
|
|
19
21
|
const fileName = getContextFileName(platform);
|
|
20
22
|
if (!fileName) {
|
|
21
23
|
console.error(`\n❌ Unknown platform: ${platform}`);
|
|
@@ -37,24 +39,26 @@ async function installContextFileSection(platform) {
|
|
|
37
39
|
existingSection = section.content;
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
|
-
// Prompt user
|
|
42
|
+
// Prompt user (auto-accepted in non-interactive mode)
|
|
41
43
|
const action = existingSection
|
|
42
44
|
? "Update"
|
|
43
45
|
: existsSync(contextFilePath)
|
|
44
46
|
? "Add to"
|
|
45
47
|
: "Create";
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
if (!yes) {
|
|
49
|
+
const response = await prompts({
|
|
50
|
+
type: "confirm",
|
|
51
|
+
name: "install",
|
|
52
|
+
message: `${action} ${fileName} with dotrequirements workflow guidance?`,
|
|
53
|
+
initial: true,
|
|
54
|
+
});
|
|
55
|
+
if (!response.install) {
|
|
56
|
+
console.log("");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
|
-
// If updating, show what will change
|
|
57
|
-
if (existingSection) {
|
|
60
|
+
// If updating, show what will change (auto-accepted in non-interactive mode)
|
|
61
|
+
if (existingSection && !yes) {
|
|
58
62
|
const confirmUpdate = await prompts({
|
|
59
63
|
type: "confirm",
|
|
60
64
|
name: "confirm",
|
|
@@ -80,12 +84,37 @@ async function installContextFileSection(platform) {
|
|
|
80
84
|
console.log(` Error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Assistant identifiers accepted by the non-interactive --assistant flag
|
|
89
|
+
* (AISETUP-1). "other" is interactive-only: it prompts for a custom path.
|
|
90
|
+
*/
|
|
91
|
+
export const SUPPORTED_ASSISTANTS = [
|
|
92
|
+
"claude-code",
|
|
93
|
+
"claude-desktop",
|
|
94
|
+
"cursor",
|
|
95
|
+
"antigravity",
|
|
96
|
+
"codex",
|
|
97
|
+
"github-copilot",
|
|
98
|
+
];
|
|
83
99
|
/**
|
|
84
100
|
* AI setup command - configures the MCP server for AI assistants
|
|
101
|
+
*
|
|
102
|
+
* AISETUP-1: with --assistant <id>, setup runs without any interactive prompt
|
|
103
|
+
* (an AI assistant configuring itself knows which assistant it is).
|
|
85
104
|
*/
|
|
86
|
-
export async function aiSetupCommand() {
|
|
105
|
+
export async function aiSetupCommand(options = {}) {
|
|
87
106
|
console.log(`🔧 Setting up ${brand} MCP server\n`);
|
|
88
|
-
|
|
107
|
+
if (options.assistant) {
|
|
108
|
+
const id = options.assistant.toLowerCase();
|
|
109
|
+
if (!SUPPORTED_ASSISTANTS.includes(id)) {
|
|
110
|
+
// AISETUP-1.1: unsupported value → error listing supported identifiers
|
|
111
|
+
throw new Error(`Unsupported assistant "${options.assistant}". Supported: ${SUPPORTED_ASSISTANTS.join(", ")}`);
|
|
112
|
+
}
|
|
113
|
+
// AISETUP-1.0: no prompt; same setup path as the interactive selector
|
|
114
|
+
await dispatchSetup(id, true);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// AISETUP-1.2: no flag → interactive selector, unchanged
|
|
89
118
|
const response = await prompts({
|
|
90
119
|
type: "select",
|
|
91
120
|
name: "client",
|
|
@@ -105,34 +134,37 @@ export async function aiSetupCommand() {
|
|
|
105
134
|
console.log("\nSetup cancelled.");
|
|
106
135
|
return;
|
|
107
136
|
}
|
|
108
|
-
|
|
137
|
+
await dispatchSetup(response.client);
|
|
138
|
+
}
|
|
139
|
+
async function dispatchSetup(client, yes = false) {
|
|
140
|
+
switch (client) {
|
|
109
141
|
case "claude-code":
|
|
110
|
-
await setupClaudeCode();
|
|
142
|
+
await setupClaudeCode(yes);
|
|
111
143
|
break;
|
|
112
144
|
case "claude-desktop":
|
|
113
145
|
await setupClaudeDesktop();
|
|
114
146
|
break;
|
|
115
147
|
case "cursor":
|
|
116
|
-
await setupCursor();
|
|
148
|
+
await setupCursor(yes);
|
|
117
149
|
break;
|
|
118
150
|
case "antigravity":
|
|
119
|
-
await setupAntigravity();
|
|
151
|
+
await setupAntigravity(yes);
|
|
120
152
|
break;
|
|
121
153
|
case "codex":
|
|
122
|
-
await setupCodex();
|
|
154
|
+
await setupCodex(yes);
|
|
123
155
|
break;
|
|
124
156
|
case "github-copilot":
|
|
125
|
-
await setupGitHubCopilot();
|
|
157
|
+
await setupGitHubCopilot(yes);
|
|
126
158
|
break;
|
|
127
159
|
case "other":
|
|
128
160
|
await setupOther();
|
|
129
161
|
break;
|
|
130
162
|
default:
|
|
131
|
-
console.log(`\n❌ ${
|
|
163
|
+
console.log(`\n❌ ${client} is not yet supported.`);
|
|
132
164
|
console.log("Please refer to the documentation for manual setup.");
|
|
133
165
|
}
|
|
134
166
|
}
|
|
135
|
-
async function setupClaudeCode() {
|
|
167
|
+
async function setupClaudeCode(yes = false) {
|
|
136
168
|
console.log("\n📦 Configuring MCP for Claude Code...\n");
|
|
137
169
|
const command = `claude mcp add-json dotrequirements '{"type":"stdio","command":"npx","args":["-y","@popoverai/dotrequirements","mcp"]}'`;
|
|
138
170
|
let mcpConfigured = false;
|
|
@@ -162,7 +194,7 @@ async function setupClaudeCode() {
|
|
|
162
194
|
if (mcpConfigured) {
|
|
163
195
|
console.log("\n⚠️ Important: Restart Claude Code for changes to take effect.");
|
|
164
196
|
console.log("\nYou can now ask your AI assistant to help write requirements!\n");
|
|
165
|
-
await installContextFileSection("claude-code");
|
|
197
|
+
await installContextFileSection("claude-code", yes);
|
|
166
198
|
}
|
|
167
199
|
}
|
|
168
200
|
async function setupClaudeDesktop() {
|
|
@@ -237,7 +269,7 @@ async function setupClaudeDesktop() {
|
|
|
237
269
|
console.log(JSON.stringify(manualConfig, null, 2));
|
|
238
270
|
}
|
|
239
271
|
}
|
|
240
|
-
async function setupCursor() {
|
|
272
|
+
async function setupCursor(yes = false) {
|
|
241
273
|
console.log("\n📦 Configuring MCP for Cursor (project-specific)...\n");
|
|
242
274
|
const configPath = join(process.cwd(), ".cursor", "mcp.json");
|
|
243
275
|
const configDir = join(process.cwd(), ".cursor");
|
|
@@ -272,7 +304,7 @@ async function setupCursor() {
|
|
|
272
304
|
console.log(` Config file: ${configPath}\n`);
|
|
273
305
|
console.log("⚠️ Important: Reload or restart Cursor for changes to take effect.");
|
|
274
306
|
console.log("\nYou can now ask your AI assistant to help write requirements!\n");
|
|
275
|
-
await installContextFileSection("cursor");
|
|
307
|
+
await installContextFileSection("cursor", yes);
|
|
276
308
|
}
|
|
277
309
|
catch (error) {
|
|
278
310
|
console.error("❌ Failed to configure MCP automatically.");
|
|
@@ -288,7 +320,7 @@ async function setupCursor() {
|
|
|
288
320
|
console.log(JSON.stringify(manualConfig, null, 2));
|
|
289
321
|
}
|
|
290
322
|
}
|
|
291
|
-
async function setupAntigravity() {
|
|
323
|
+
async function setupAntigravity(yes = false) {
|
|
292
324
|
console.log("\n📦 Configuring MCP for Google Antigravity...\n");
|
|
293
325
|
const configPath = join(homedir(), ".gemini", "antigravity", "mcp_config.json");
|
|
294
326
|
const configDir = join(homedir(), ".gemini", "antigravity");
|
|
@@ -367,7 +399,7 @@ async function setupAntigravity() {
|
|
|
367
399
|
else {
|
|
368
400
|
console.log("");
|
|
369
401
|
}
|
|
370
|
-
await installContextFileSection("antigravity");
|
|
402
|
+
await installContextFileSection("antigravity", yes);
|
|
371
403
|
}
|
|
372
404
|
catch (error) {
|
|
373
405
|
console.error("❌ Failed to configure MCP automatically.");
|
|
@@ -376,7 +408,7 @@ async function setupAntigravity() {
|
|
|
376
408
|
console.log(` ${configPath}`);
|
|
377
409
|
}
|
|
378
410
|
}
|
|
379
|
-
async function setupCodex() {
|
|
411
|
+
async function setupCodex(yes = false) {
|
|
380
412
|
console.log("\n📦 Configuring MCP for OpenAI Codex...\n");
|
|
381
413
|
const command = `codex mcp add dotrequirements -- npx -y @popoverai/dotrequirements mcp`;
|
|
382
414
|
try {
|
|
@@ -384,7 +416,7 @@ async function setupCodex() {
|
|
|
384
416
|
console.log("\n✅ MCP configured successfully for Codex!");
|
|
385
417
|
console.log("\n⚠️ Important: Restart Codex for changes to take effect.");
|
|
386
418
|
console.log("\nYou can now ask your AI assistant to help write requirements!\n");
|
|
387
|
-
await installContextFileSection("codex");
|
|
419
|
+
await installContextFileSection("codex", yes);
|
|
388
420
|
}
|
|
389
421
|
catch {
|
|
390
422
|
console.error("\n❌ Failed to configure MCP automatically.");
|
|
@@ -396,12 +428,12 @@ async function setupCodex() {
|
|
|
396
428
|
console.log('args = ["-y", "@popoverai/dotrequirements", "mcp"]');
|
|
397
429
|
}
|
|
398
430
|
}
|
|
399
|
-
async function setupGitHubCopilot() {
|
|
431
|
+
async function setupGitHubCopilot(yes = false) {
|
|
400
432
|
console.log("\n📦 Configuring skills for GitHub Copilot...\n");
|
|
401
433
|
console.log("ℹ️ GitHub Copilot discovers MCP servers from your IDE configuration.");
|
|
402
434
|
console.log(" Please configure the MCP server in VS Code settings or GitHub settings.\n");
|
|
403
435
|
console.log(" MCP server command: npx -y @popoverai/dotrequirements mcp\n");
|
|
404
|
-
await installContextFileSection("github-copilot");
|
|
436
|
+
await installContextFileSection("github-copilot", yes);
|
|
405
437
|
}
|
|
406
438
|
async function setupOther() {
|
|
407
439
|
console.log("\n📦 Custom Context File Setup\n");
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
* `dotrequirements codebase-to-spec dispatch-context <dispatch-id>` subcommand.
|
|
3
3
|
*
|
|
4
4
|
* Returns the composed prompt for a worker dispatch as a JSON object on stdout.
|
|
5
|
-
*
|
|
6
|
-
* prompt
|
|
7
|
-
*
|
|
8
|
-
* Requirements covered:
|
|
9
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
5
|
+
* Run by cts-worker subagents at the start of their turn to fetch the composed
|
|
6
|
+
* first-turn prompt for their dispatch-id (see the specify-codebase workflow).
|
|
10
7
|
*/
|
|
11
8
|
export declare function dispatchContextCommand(dispatchId: string): Promise<void>;
|
|
12
9
|
//# sourceMappingURL=dispatch-context.d.ts.map
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
* `dotrequirements codebase-to-spec dispatch-context <dispatch-id>` subcommand.
|
|
3
3
|
*
|
|
4
4
|
* Returns the composed prompt for a worker dispatch as a JSON object on stdout.
|
|
5
|
-
*
|
|
6
|
-
* prompt
|
|
7
|
-
*
|
|
8
|
-
* Requirements covered:
|
|
9
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
5
|
+
* Run by cts-worker subagents at the start of their turn to fetch the composed
|
|
6
|
+
* first-turn prompt for their dispatch-id (see the specify-codebase workflow).
|
|
10
7
|
*/
|
|
11
8
|
import { composeDispatchContext } from "../../codebase-to-spec/dispatch.js";
|
|
12
9
|
import { ExitCode } from "../../codebase-to-spec/exit-codes.js";
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* in outline.yaml stays where it is (the orchestrator manages it).
|
|
10
10
|
*
|
|
11
11
|
* Requirements covered:
|
|
12
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
13
12
|
* - CTSO-CONV-3: orchestrator dispatches an editor when revisions are needed
|
|
14
13
|
*/
|
|
15
14
|
export declare function dispatchEditorCommand(areaPrefix: string): Promise<void>;
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* in outline.yaml stays where it is (the orchestrator manages it).
|
|
10
10
|
*
|
|
11
11
|
* Requirements covered:
|
|
12
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
13
12
|
* - CTSO-CONV-3: orchestrator dispatches an editor when revisions are needed
|
|
14
13
|
*/
|
|
15
14
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* preserving the review section.
|
|
10
10
|
*
|
|
11
11
|
* Requirements covered:
|
|
12
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
13
12
|
* - CTSO-CONV-2: orchestrator iterates on planner's outline until approved
|
|
14
13
|
*/
|
|
15
14
|
export interface DispatchPlannerOptions {
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* preserving the review section.
|
|
10
10
|
*
|
|
11
11
|
* Requirements covered:
|
|
12
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
13
12
|
* - CTSO-CONV-2: orchestrator iterates on planner's outline until approved
|
|
14
13
|
*/
|
|
15
14
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
* `dotrequirements codebase-to-spec dispatch-spec` subcommand.
|
|
3
3
|
*
|
|
4
4
|
* Returns an array of specifier dispatch payloads — one per area in the
|
|
5
|
-
* approved outline. The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* approved outline. The specify-codebase workflow reads this, fires N
|
|
6
|
+
* cts-worker dispatches in parallel (one per area), and collects the
|
|
7
|
+
* resulting partials.
|
|
8
8
|
*
|
|
9
9
|
* Errors clearly if `outline.yaml`'s `review.result` isn't `"approved"` —
|
|
10
10
|
* the orchestrator should approve the outline before fan-out.
|
|
11
|
-
*
|
|
12
|
-
* Requirements covered:
|
|
13
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
14
11
|
*/
|
|
15
12
|
export declare function dispatchSpecCommand(): Promise<void>;
|
|
16
13
|
//# sourceMappingURL=dispatch-spec.d.ts.map
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
* `dotrequirements codebase-to-spec dispatch-spec` subcommand.
|
|
3
3
|
*
|
|
4
4
|
* Returns an array of specifier dispatch payloads — one per area in the
|
|
5
|
-
* approved outline. The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* approved outline. The specify-codebase workflow reads this, fires N
|
|
6
|
+
* cts-worker dispatches in parallel (one per area), and collects the
|
|
7
|
+
* resulting partials.
|
|
8
8
|
*
|
|
9
9
|
* Errors clearly if `outline.yaml`'s `review.result` isn't `"approved"` —
|
|
10
10
|
* the orchestrator should approve the outline before fan-out.
|
|
11
|
-
*
|
|
12
|
-
* Requirements covered:
|
|
13
|
-
* - CTSO-CLI-1: CLI exposes commands that return dispatch instructions
|
|
14
11
|
*/
|
|
15
12
|
import { existsSync, readFileSync } from "node:fs";
|
|
16
13
|
import { cachePaths } from "../../codebase-to-spec/cache.js";
|
|
@@ -46,7 +46,8 @@ export function registerCodebaseToSpec(program) {
|
|
|
46
46
|
cts
|
|
47
47
|
.command("pack")
|
|
48
48
|
.description("Pack the codebase (compressed and uncompressed views) into the cache")
|
|
49
|
-
.option("-s, --scope <path>", "Limit to files under this path (subdir of project root)")
|
|
49
|
+
.option("-s, --scope <path>", "Limit to files under this path (subdir of project root, or of the remote repo when --remote is set)")
|
|
50
|
+
.option("--remote <url>", "Pack a remote repository (GitHub URL or owner/repo) instead of the local project; repomix clones, packs, and cleans up. Combine with --scope to pack just a subdirectory.")
|
|
50
51
|
.option("--fresh", "Clear the cache before running")
|
|
51
52
|
.option("--budget <tokens>", "Override the working-context budget (in tokens)", (v) => parseInt(v, 10))
|
|
52
53
|
.option("--ignore-requirements", "Exclude `.requirements/**` from the pack (use when testing cts against a codebase whose existing requirements should not influence the output)")
|
|
@@ -150,7 +151,7 @@ export function registerCodebaseToSpec(program) {
|
|
|
150
151
|
});
|
|
151
152
|
cts
|
|
152
153
|
.command("dispatch-context <dispatch-id>", HIDDEN)
|
|
153
|
-
.description("Return the composed prompt for a worker dispatch as JSON on stdout (
|
|
154
|
+
.description("Return the composed prompt for a worker dispatch as JSON on stdout (run by cts-worker subagents to fetch their dispatch prompt)")
|
|
154
155
|
.action((dispatchId) => dispatchContextCommand(dispatchId));
|
|
155
156
|
cts
|
|
156
157
|
.command("dispatch-planner", HIDDEN)
|
|
@@ -7,10 +7,17 @@
|
|
|
7
7
|
* - CTS-CLI-3: Pipeline refuses to spec a codebase that exceeds the working context budget
|
|
8
8
|
* - CTS-PACK-1: Pack stage produces compressed and uncompressed views of the codebase
|
|
9
9
|
* - CTS-PACK-2: Engineer can extend the ignore list per project
|
|
10
|
+
* - CTS-PACK-4: Pack surfaces when a newer CLI version is available
|
|
10
11
|
* - CTS-OBSERVE-1: CLI emits structured progress as the pipeline runs
|
|
11
12
|
*/
|
|
13
|
+
import { checkForNewerVersion } from "../../codebase-to-spec/version-check.js";
|
|
12
14
|
export interface PackOptions {
|
|
13
15
|
scope?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Pack a remote repository (GitHub URL or `owner/repo`) instead of the local
|
|
18
|
+
* project. Combine with `scope` to pack just a subdirectory of the remote.
|
|
19
|
+
*/
|
|
20
|
+
remote?: string;
|
|
14
21
|
fresh?: boolean;
|
|
15
22
|
budgetTokens?: number;
|
|
16
23
|
/**
|
|
@@ -23,6 +30,8 @@ export interface PackOptions {
|
|
|
23
30
|
progress?: import("../../codebase-to-spec/progress.js").ProgressEmitter;
|
|
24
31
|
/** Override the project root, mainly for tests. */
|
|
25
32
|
projectRoot?: string;
|
|
33
|
+
/** Override the registry version check, mainly for tests. */
|
|
34
|
+
checkVersion?: typeof checkForNewerVersion;
|
|
26
35
|
}
|
|
27
36
|
export declare function packCommand(rawOptions?: PackOptions): Promise<void>;
|
|
28
37
|
//# sourceMappingURL=pack.d.ts.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - CTS-CLI-3: Pipeline refuses to spec a codebase that exceeds the working context budget
|
|
8
8
|
* - CTS-PACK-1: Pack stage produces compressed and uncompressed views of the codebase
|
|
9
9
|
* - CTS-PACK-2: Engineer can extend the ignore list per project
|
|
10
|
+
* - CTS-PACK-4: Pack surfaces when a newer CLI version is available
|
|
10
11
|
* - CTS-OBSERVE-1: CLI emits structured progress as the pipeline runs
|
|
11
12
|
*/
|
|
12
13
|
import { resolve } from "node:path";
|
|
@@ -15,11 +16,16 @@ import { clearCache, ensureCacheDir } from "../../codebase-to-spec/cache.js";
|
|
|
15
16
|
import { ExitCode } from "../../codebase-to-spec/exit-codes.js";
|
|
16
17
|
import { runPack } from "../../codebase-to-spec/pack.js";
|
|
17
18
|
import { StdoutProgress } from "../../codebase-to-spec/progress.js";
|
|
19
|
+
import { checkForNewerVersion } from "../../codebase-to-spec/version-check.js";
|
|
18
20
|
import { findProjectRoot } from "../../utils/project-settings.js";
|
|
19
21
|
export async function packCommand(rawOptions = {}) {
|
|
20
22
|
const progress = rawOptions.progress ?? new StdoutProgress();
|
|
21
23
|
const projectRoot = rawOptions.projectRoot ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
22
24
|
const budgetTokens = rawOptions.budgetTokens ?? DEFAULT_BUDGET_TOKENS;
|
|
25
|
+
// Fail-soft staleness check (CTS-PACK-4), started now so the registry
|
|
26
|
+
// round-trip overlaps the pack work and adds no wall-clock on the happy
|
|
27
|
+
// path. Resolves to undefined on any failure or timeout.
|
|
28
|
+
const versionCheck = (rawOptions.checkVersion ?? checkForNewerVersion)();
|
|
23
29
|
if (rawOptions.fresh) {
|
|
24
30
|
progress.emit({
|
|
25
31
|
stage: "pack",
|
|
@@ -35,14 +41,17 @@ export async function packCommand(rawOptions = {}) {
|
|
|
35
41
|
progress.emit({
|
|
36
42
|
stage: "pack",
|
|
37
43
|
step: "start",
|
|
38
|
-
message:
|
|
39
|
-
? `Packing
|
|
40
|
-
:
|
|
44
|
+
message: rawOptions.remote
|
|
45
|
+
? `Packing remote ${rawOptions.remote}${rawOptions.scope ? ` (scope: ${rawOptions.scope})` : ""}`
|
|
46
|
+
: scope
|
|
47
|
+
? `Packing codebase at ${scope}`
|
|
48
|
+
: `Packing codebase at ${projectRoot}`,
|
|
41
49
|
});
|
|
42
50
|
const packResult = await runPack({
|
|
43
51
|
projectRoot,
|
|
44
52
|
paths,
|
|
45
53
|
scope: rawOptions.scope,
|
|
54
|
+
remote: rawOptions.remote,
|
|
46
55
|
ignoreRequirements: rawOptions.ignoreRequirements,
|
|
47
56
|
});
|
|
48
57
|
progress.emit({
|
|
@@ -51,6 +60,17 @@ export async function packCommand(rawOptions = {}) {
|
|
|
51
60
|
message: `Packed ${packResult.fileCount} files → ${paths.overview} (compressed), ${paths.source} (uncompressed)`,
|
|
52
61
|
data: { fileCount: packResult.fileCount },
|
|
53
62
|
});
|
|
63
|
+
// Surface a stale install (CTS-PACK-4). Informational only: outputs and
|
|
64
|
+
// exit code are unaffected, and a failed check emits nothing.
|
|
65
|
+
const versionInfo = await versionCheck.catch(() => undefined);
|
|
66
|
+
if (versionInfo?.stale) {
|
|
67
|
+
progress.emit({
|
|
68
|
+
stage: "pack",
|
|
69
|
+
step: "stale-version",
|
|
70
|
+
message: `A newer dotrequirements CLI is available: ${versionInfo.latest} (running ${versionInfo.current}). Re-run skill-install to refresh.`,
|
|
71
|
+
data: { current: versionInfo.current, latest: versionInfo.latest },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
54
74
|
// Budget check (CTS-CLI-3)
|
|
55
75
|
const measured = countTokensInFileExact(paths.overview);
|
|
56
76
|
const budget = checkBudget(measured, budgetTokens);
|
|
@@ -43,16 +43,9 @@ export async function skillInstallCommand(options = {}) {
|
|
|
43
43
|
}
|
|
44
44
|
if (result.companions) {
|
|
45
45
|
process.stdout.write(`Installed cts-worker agent at ${result.companions.agentPath}\n`);
|
|
46
|
-
process.stdout.write(`Installed
|
|
47
|
-
if (result.companions.hookRegistered) {
|
|
48
|
-
process.stdout.write(`Registered PreToolUse hook in ${result.companions.settingsPath}\n`);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
process.stdout.write(`PreToolUse hook already registered in ${result.companions.settingsPath}\n`);
|
|
52
|
-
}
|
|
53
|
-
process.stdout.write("\n⚠️ The hook script uses `dotrequirements` from PATH. If you're working in a local dev clone, set DOTREQUIREMENTS_CLI to override (see the hook script for details).\n");
|
|
46
|
+
process.stdout.write(`Installed specify-codebase workflow at ${result.companions.workflowPath}\n`);
|
|
54
47
|
}
|
|
55
|
-
process.stdout.write("\nSkill ready. In Claude Code, invoke it with `/codebase-to-spec` (or via natural language).\n");
|
|
48
|
+
process.stdout.write("\nSkill ready. In Claude Code, invoke it with `/codebase-to-spec` (or via natural language). Requires a Claude Code version with dynamic-workflow support.\n");
|
|
56
49
|
}
|
|
57
50
|
catch (err) {
|
|
58
51
|
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
package/dist/commands/init.js
CHANGED
|
@@ -353,8 +353,13 @@ async function inviteFlow(cwd, token) {
|
|
|
353
353
|
console.log(`✓ Joined team "${inviteInfo.teamName}"`);
|
|
354
354
|
}
|
|
355
355
|
catch (err) {
|
|
356
|
+
// Production redacts ConvexError messages to "Server Error" but keeps
|
|
357
|
+
// error.data — check both, or this graceful path only works in dev
|
|
358
|
+
const data = err.data;
|
|
359
|
+
const dataMessage = typeof data?.message === "string" ? data.message : "";
|
|
356
360
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
357
|
-
if (
|
|
361
|
+
if (dataMessage.includes("already a member") ||
|
|
362
|
+
errorMessage.includes("already a member")) {
|
|
358
363
|
console.log(`Already a member of "${inviteInfo.teamName}"`);
|
|
359
364
|
}
|
|
360
365
|
else {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic for `dotrequirements link`'s non-interactive mode
|
|
3
|
+
* (LINK-10/11/12). No I/O: the link command gathers state (teams, projects)
|
|
4
|
+
* and these functions decide what to do — use a project, create one, rename,
|
|
5
|
+
* or stop with a decision-needed result that carries everything an AI
|
|
6
|
+
* assistant needs to ask the user and retry with a deviation flag.
|
|
7
|
+
*/
|
|
8
|
+
export interface TeamOption {
|
|
9
|
+
teamId: string;
|
|
10
|
+
name: string;
|
|
11
|
+
tier: string;
|
|
12
|
+
tierName: string;
|
|
13
|
+
projectCount: number;
|
|
14
|
+
projectLimit: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ProjectOption {
|
|
17
|
+
projectId: string;
|
|
18
|
+
projectName: string;
|
|
19
|
+
projectSlug: string | null;
|
|
20
|
+
isDefault: boolean;
|
|
21
|
+
hasUserContent: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LinkFlags {
|
|
24
|
+
yes?: boolean;
|
|
25
|
+
team?: string;
|
|
26
|
+
connect?: string;
|
|
27
|
+
create?: boolean;
|
|
28
|
+
name?: string;
|
|
29
|
+
json?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* LINK-12.3: any deviation flag implies non-interactive mode.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isNonInteractive(flags: LinkFlags): boolean;
|
|
35
|
+
export declare function hasCapacity(team: TeamOption): boolean;
|
|
36
|
+
/** A choice the user must make, with everything needed to ask and retry. */
|
|
37
|
+
export interface DecisionNeeded {
|
|
38
|
+
kind: "decision";
|
|
39
|
+
decision: "team" | "project" | "capacity";
|
|
40
|
+
message: string;
|
|
41
|
+
options: Array<{
|
|
42
|
+
label: string;
|
|
43
|
+
/** Exact flag to pass on retry (LINK-11.4), when retryable via link */
|
|
44
|
+
retryFlag?: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export interface NoMatch {
|
|
48
|
+
kind: "no-match";
|
|
49
|
+
flag: "team" | "connect";
|
|
50
|
+
provided: string;
|
|
51
|
+
alternatives: string[];
|
|
52
|
+
}
|
|
53
|
+
export type TeamResolution = {
|
|
54
|
+
kind: "use";
|
|
55
|
+
team: TeamOption;
|
|
56
|
+
} | DecisionNeeded | NoMatch;
|
|
57
|
+
/**
|
|
58
|
+
* LINK-10.1, LINK-11.0, LINK-12.0, LINK-12.4
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveTeam(teams: TeamOption[], flags: LinkFlags): TeamResolution;
|
|
61
|
+
export type ProjectResolution = {
|
|
62
|
+
kind: "connect";
|
|
63
|
+
project: ProjectOption;
|
|
64
|
+
rename: boolean;
|
|
65
|
+
} | {
|
|
66
|
+
kind: "create";
|
|
67
|
+
} | DecisionNeeded | NoMatch;
|
|
68
|
+
/**
|
|
69
|
+
* LINK-10.2/10.3 (default-project rule), LINK-11.1/11.2 (decision menus),
|
|
70
|
+
* LINK-12.1/12.2/12.4 (deviation flags).
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveProject(projects: ProjectOption[], team: TeamOption, flags: LinkFlags): ProjectResolution;
|
|
73
|
+
/**
|
|
74
|
+
* Prompt-free project naming for non-interactive mode (LINK-9.0): explicit
|
|
75
|
+
* flag, then package metadata, then directory name, then a fixed fallback —
|
|
76
|
+
* never a prompt.
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveProjectName(flags: LinkFlags, packageName: string | undefined, directoryName: string | undefined): string;
|
|
79
|
+
//# sourceMappingURL=link-resolution.d.ts.map
|