intentdocs 0.10.1 → 0.11.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 +1 -1
- package/dist/chunk-64I7RLP3.js +171 -0
- package/dist/{chunk-6X4BORMW.js → chunk-65EDM7QH.js} +1 -1
- package/dist/{chunk-F52HPVNQ.js → chunk-BNEU6TLJ.js} +54 -20
- package/dist/chunk-GFKZ5CRL.js +12 -0
- package/dist/{chunk-NHNBCNND.js → chunk-ID4B5RZ2.js} +37 -16
- package/dist/{chunk-PUGYRSMK.js → chunk-IORMKLAQ.js} +122 -65
- package/dist/{chunk-JX2RLGOM.js → chunk-K5SNF6CG.js} +11 -0
- package/dist/{chunk-34JCN66H.js → chunk-KTGQO3AE.js} +24 -1
- package/dist/{ci-XCOXFTLB.js → ci-NOCV3XUV.js} +2 -2
- package/dist/{complexity-X3IJKNNV.js → complexity-OJVM37NF.js} +2 -2
- package/dist/{import-prd-IJTM6FZE.js → import-prd-5FCVXCYO.js} +12 -5
- package/dist/index.js +344 -326
- package/dist/{keys-UVXCCWCS.js → keys-2W5V56FS.js} +30 -9
- package/dist/{log-XIH4BGFL.js → log-DFCCAAJN.js} +21 -5
- package/dist/{map-extract-V6D27I3H.js → map-extract-YUCFLGJS.js} +1 -1
- package/dist/{map-import-LORTI4K4.js → map-import-7RN2NEUZ.js} +5 -4
- package/dist/push-33V7ANJW.js +462 -0
- package/dist/{research-CO3W7PLC.js → research-SHO5SXVQ.js} +2 -2
- package/dist/scope-RRGJHS2G.js +13 -0
- package/dist/{setup-WSYIG2CR.js → setup-UILQVYIB.js} +5 -5
- package/package.json +6 -5
- package/dist/scope-ZZLKQEF5.js +0 -11
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeStoryContext
|
|
3
|
+
} from "./chunk-BNEU6TLJ.js";
|
|
1
4
|
import {
|
|
2
5
|
captureCli,
|
|
3
6
|
shutdownCliAnalytics
|
|
4
7
|
} from "./chunk-KPQ42YE6.js";
|
|
5
|
-
import {
|
|
6
|
-
writeStoryContext
|
|
7
|
-
} from "./chunk-F52HPVNQ.js";
|
|
8
8
|
import {
|
|
9
9
|
apiFetch,
|
|
10
10
|
getContext,
|
|
11
11
|
listStories
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KTGQO3AE.js";
|
|
13
13
|
import {
|
|
14
14
|
hasConfig,
|
|
15
15
|
requireConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-K5SNF6CG.js";
|
|
17
17
|
import {
|
|
18
18
|
choose,
|
|
19
19
|
closePrompt
|
|
@@ -23,9 +23,8 @@ import {
|
|
|
23
23
|
} from "./chunk-XZE2XP6O.js";
|
|
24
24
|
|
|
25
25
|
// src/commands/setup.ts
|
|
26
|
-
import { existsSync as
|
|
27
|
-
import { join as
|
|
28
|
-
import { homedir } from "os";
|
|
26
|
+
import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync3, readFileSync as readFileSync2, unlinkSync } from "fs";
|
|
27
|
+
import { join as join3 } from "path";
|
|
29
28
|
|
|
30
29
|
// src/commands/sync.ts
|
|
31
30
|
import { writeFileSync, readdirSync, existsSync, statSync } from "fs";
|
|
@@ -120,6 +119,61 @@ async function sync(opts) {
|
|
|
120
119
|
await shutdownCliAnalytics();
|
|
121
120
|
}
|
|
122
121
|
|
|
122
|
+
// src/lib/claude-mcp-config.ts
|
|
123
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
124
|
+
import { join as join2 } from "path";
|
|
125
|
+
import { homedir } from "os";
|
|
126
|
+
var LOCAL_SERVER_NAME = "intent";
|
|
127
|
+
var LOCAL_SERVER_ENTRY = { type: "stdio", command: "npx", args: ["intentdocs", "mcp"], env: {} };
|
|
128
|
+
var CLAUDE_MCP_ADD_COMMAND = `claude mcp add --scope project ${LOCAL_SERVER_NAME} -- npx intentdocs mcp`;
|
|
129
|
+
function sameEntry(a, b) {
|
|
130
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
131
|
+
}
|
|
132
|
+
function registerLocalServerInMcpJson(cwd = process.cwd()) {
|
|
133
|
+
const path = join2(cwd, ".mcp.json");
|
|
134
|
+
let config = {};
|
|
135
|
+
if (existsSync2(path)) {
|
|
136
|
+
try {
|
|
137
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
138
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { status: "unreadable", path };
|
|
139
|
+
config = parsed;
|
|
140
|
+
} catch {
|
|
141
|
+
return { status: "unreadable", path };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const rawServers = config.mcpServers;
|
|
145
|
+
if (rawServers !== void 0 && (typeof rawServers !== "object" || rawServers === null || Array.isArray(rawServers))) {
|
|
146
|
+
return { status: "unreadable", path };
|
|
147
|
+
}
|
|
148
|
+
const servers = { ...rawServers ?? {} };
|
|
149
|
+
const before = servers[LOCAL_SERVER_NAME];
|
|
150
|
+
if (sameEntry(before, LOCAL_SERVER_ENTRY)) return { status: "unchanged", path };
|
|
151
|
+
servers[LOCAL_SERVER_NAME] = { ...LOCAL_SERVER_ENTRY, args: [...LOCAL_SERVER_ENTRY.args], env: {} };
|
|
152
|
+
writeFileSync2(path, JSON.stringify({ ...config, mcpServers: servers }, null, 2) + "\n");
|
|
153
|
+
return { status: before === void 0 ? "added" : "updated", path };
|
|
154
|
+
}
|
|
155
|
+
var LEGACY_SETTINGS_ENTRY = { command: "npx", args: ["intentdocs", "mcp"] };
|
|
156
|
+
function removeLegacySettingsEntry(home = homedir()) {
|
|
157
|
+
const path = join2(home, ".claude", "settings.json");
|
|
158
|
+
if (!existsSync2(path)) return false;
|
|
159
|
+
let settings;
|
|
160
|
+
try {
|
|
161
|
+
settings = JSON.parse(readFileSync(path, "utf-8"));
|
|
162
|
+
} catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings)) return false;
|
|
166
|
+
const servers = settings.mcpServers;
|
|
167
|
+
if (!servers || typeof servers !== "object" || !sameEntry(servers[LOCAL_SERVER_NAME], LEGACY_SETTINGS_ENTRY)) return false;
|
|
168
|
+
const rest = { ...servers };
|
|
169
|
+
delete rest[LOCAL_SERVER_NAME];
|
|
170
|
+
const next = { ...settings };
|
|
171
|
+
if (Object.keys(rest).length > 0) next.mcpServers = rest;
|
|
172
|
+
else delete next.mcpServers;
|
|
173
|
+
writeFileSync2(path, JSON.stringify(next, null, 2) + "\n");
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
123
177
|
// src/commands/setup.ts
|
|
124
178
|
async function setup() {
|
|
125
179
|
await requireValidAuth();
|
|
@@ -174,7 +228,7 @@ async function setup() {
|
|
|
174
228
|
}
|
|
175
229
|
function setupClaudeCode() {
|
|
176
230
|
const cwd = process.cwd();
|
|
177
|
-
const claudeMdPath =
|
|
231
|
+
const claudeMdPath = join3(cwd, "CLAUDE.md");
|
|
178
232
|
const claudeBlock = `
|
|
179
233
|
# intentdocs Integration
|
|
180
234
|
|
|
@@ -194,29 +248,29 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
194
248
|
| \`npx intentdocs sync --context\` | Regenerate this file from intentdocs |
|
|
195
249
|
| \`npx intentdocs status\` | Show recent activity |
|
|
196
250
|
`;
|
|
197
|
-
if (
|
|
198
|
-
const existing =
|
|
251
|
+
if (existsSync3(claudeMdPath)) {
|
|
252
|
+
const existing = readFileSync2(claudeMdPath, "utf-8");
|
|
199
253
|
if (!existing.includes("intentdocs Integration")) {
|
|
200
|
-
|
|
254
|
+
writeFileSync3(claudeMdPath, existing + "\n" + claudeBlock);
|
|
201
255
|
console.log(" \u2713 Updated CLAUDE.md with intentdocs agent workflow");
|
|
202
256
|
} else {
|
|
203
257
|
console.log(" \u2713 CLAUDE.md already configured");
|
|
204
258
|
}
|
|
205
259
|
} else {
|
|
206
|
-
|
|
260
|
+
writeFileSync3(claudeMdPath, claudeBlock.trim() + "\n");
|
|
207
261
|
console.log(" \u2713 Created CLAUDE.md with intentdocs agent workflow");
|
|
208
262
|
}
|
|
209
|
-
const commandsDir =
|
|
210
|
-
if (!
|
|
263
|
+
const commandsDir = join3(cwd, ".claude", "commands");
|
|
264
|
+
if (!existsSync3(commandsDir)) mkdirSync(commandsDir, { recursive: true });
|
|
211
265
|
const oldPbCommands = ["pb-next", "pb-implement", "pb-review", "pb-document", "pb-test", "pb-status", "pb-done", "pb-sync", "pb-propose", "pb-context"];
|
|
212
266
|
for (const name of oldPbCommands) {
|
|
213
|
-
const oldPath =
|
|
214
|
-
if (
|
|
267
|
+
const oldPath = join3(commandsDir, name + ".md");
|
|
268
|
+
if (existsSync3(oldPath)) {
|
|
215
269
|
unlinkSync(oldPath);
|
|
216
270
|
}
|
|
217
271
|
}
|
|
218
|
-
|
|
219
|
-
|
|
272
|
+
writeFileSync3(
|
|
273
|
+
join3(commandsDir, "intent-next.md"),
|
|
220
274
|
`# Pick up the next story
|
|
221
275
|
|
|
222
276
|
1. Run \`npx intentdocs next\` to get the highest-priority story
|
|
@@ -227,8 +281,8 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
227
281
|
6. Ask for confirmation before proceeding
|
|
228
282
|
`
|
|
229
283
|
);
|
|
230
|
-
|
|
231
|
-
|
|
284
|
+
writeFileSync3(
|
|
285
|
+
join3(commandsDir, "intent-implement.md"),
|
|
232
286
|
`# Implement a story
|
|
233
287
|
|
|
234
288
|
## Context to load first
|
|
@@ -275,8 +329,8 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
275
329
|
- Never mark a story done with a failing or unreported \`must\` criterion.
|
|
276
330
|
`
|
|
277
331
|
);
|
|
278
|
-
|
|
279
|
-
|
|
332
|
+
writeFileSync3(
|
|
333
|
+
join3(commandsDir, "intent-review.md"),
|
|
280
334
|
`# Review against acceptance criteria
|
|
281
335
|
|
|
282
336
|
1. Identify the story being worked on
|
|
@@ -287,8 +341,8 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
287
341
|
4. Summarise: what's done, what needs work, any concerns
|
|
288
342
|
`
|
|
289
343
|
);
|
|
290
|
-
|
|
291
|
-
|
|
344
|
+
writeFileSync3(
|
|
345
|
+
join3(commandsDir, "intent-document.md"),
|
|
292
346
|
`# Document a feature
|
|
293
347
|
|
|
294
348
|
1. Check which story was just completed
|
|
@@ -306,8 +360,8 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
306
360
|
7. Update CONVENTIONS.md if new patterns were introduced
|
|
307
361
|
`
|
|
308
362
|
);
|
|
309
|
-
|
|
310
|
-
|
|
363
|
+
writeFileSync3(
|
|
364
|
+
join3(commandsDir, "intent-test.md"),
|
|
311
365
|
`# Write tests for a story
|
|
312
366
|
|
|
313
367
|
1. Get the story details: \`npx intentdocs next\` or provided story ID
|
|
@@ -317,12 +371,12 @@ story map, decisions, examples, tools, and guardrails.
|
|
|
317
371
|
5. Run the tests to verify they pass
|
|
318
372
|
`
|
|
319
373
|
);
|
|
320
|
-
|
|
321
|
-
|
|
374
|
+
writeFileSync3(
|
|
375
|
+
join3(commandsDir, "intent-status.md"),
|
|
322
376
|
`Run \`npx intentdocs status\` and \`npx intentdocs stories --filter todo\` to show current progress and remaining backlog. Summarise what's done and what's left.`
|
|
323
377
|
);
|
|
324
|
-
|
|
325
|
-
|
|
378
|
+
writeFileSync3(
|
|
379
|
+
join3(commandsDir, "intent-done.md"),
|
|
326
380
|
`Ask which story was just completed, then run \`npx intentdocs done <id>\`.
|
|
327
381
|
\`npx intentdocs done\` prints the acceptance-criteria table first. If any \`must\` criterion is still failing or was
|
|
328
382
|
never reported via \`report_criteria\`, it will list them and ask "Mark done anyway?" \u2014 only confirm that
|
|
@@ -331,8 +385,8 @@ The CLI will prompt for an optional decision or lesson learned \u2014 encourage
|
|
|
331
385
|
Also ask if there are implementation notes to add: \`npx intentdocs note <id> "..."\`
|
|
332
386
|
Both decisions and notes flow back to the project page on intentdocs.com.`
|
|
333
387
|
);
|
|
334
|
-
|
|
335
|
-
|
|
388
|
+
writeFileSync3(
|
|
389
|
+
join3(commandsDir, "intent-sync.md"),
|
|
336
390
|
`# Refresh context from intentdocs
|
|
337
391
|
|
|
338
392
|
## Refresh story map summary
|
|
@@ -349,8 +403,8 @@ Run \`npx intentdocs sync --context\` \u2014 rebuilds CLAUDE.md from your projec
|
|
|
349
403
|
|
|
350
404
|
Run \`npx intentdocs sync --context\` after updating any section on intentdocs.com.`
|
|
351
405
|
);
|
|
352
|
-
|
|
353
|
-
|
|
406
|
+
writeFileSync3(
|
|
407
|
+
join3(commandsDir, "intent-propose.md"),
|
|
354
408
|
`# Propose a new change
|
|
355
409
|
|
|
356
410
|
Use this when you want to plan a new feature, improvement, or fix before writing code.
|
|
@@ -374,8 +428,8 @@ stories there AND saves a local spec for the AI to reference during implementati
|
|
|
374
428
|
- If the change is already defined in the UI, just run \`npx intentdocs sync\` instead
|
|
375
429
|
`
|
|
376
430
|
);
|
|
377
|
-
|
|
378
|
-
|
|
431
|
+
writeFileSync3(
|
|
432
|
+
join3(commandsDir, "intent-context.md"),
|
|
379
433
|
`# Load current story context
|
|
380
434
|
|
|
381
435
|
Use this to focus on a single story without loading the full story map.
|
|
@@ -398,8 +452,8 @@ Use this to focus on a single story without loading the full story map.
|
|
|
398
452
|
The file is at \`.intent/stories/<full-story-id>.md\` \u2014 read it directly.
|
|
399
453
|
`
|
|
400
454
|
);
|
|
401
|
-
|
|
402
|
-
|
|
455
|
+
writeFileSync3(
|
|
456
|
+
join3(commandsDir, "intent-decide.md"),
|
|
403
457
|
`# Log an architectural or product decision
|
|
404
458
|
|
|
405
459
|
Use this when you've made a decision that future agents (or teammates) should know about.
|
|
@@ -417,8 +471,8 @@ Good decisions to log:
|
|
|
417
471
|
- "Decided not to do Z because..."
|
|
418
472
|
- "This pattern is used throughout because..."`
|
|
419
473
|
);
|
|
420
|
-
|
|
421
|
-
|
|
474
|
+
writeFileSync3(
|
|
475
|
+
join3(commandsDir, "intent-example.md"),
|
|
422
476
|
`# Log a reference pattern for this codebase
|
|
423
477
|
|
|
424
478
|
Use this when you've written code that represents the right way to do something in this project.
|
|
@@ -437,24 +491,22 @@ and are included in CLAUDE.md as Reference Patterns the next time you run \`npx
|
|
|
437
491
|
registerMcpWithClaudeCode();
|
|
438
492
|
}
|
|
439
493
|
function registerMcpWithClaudeCode() {
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
494
|
+
const result = registerLocalServerInMcpJson(process.cwd());
|
|
495
|
+
if (result.status === "unreadable") {
|
|
496
|
+
console.log(` \u26A0 Couldn't read ${result.path}, so it was left as it is. Add the IntentDocs server yourself:`);
|
|
497
|
+
console.log(` ${CLAUDE_MCP_ADD_COMMAND}`);
|
|
498
|
+
} else if (result.status === "unchanged") {
|
|
499
|
+
console.log(` \u2713 MCP server "${LOCAL_SERVER_NAME}" already registered in .mcp.json`);
|
|
500
|
+
} else {
|
|
501
|
+
console.log(` \u2713 Registered MCP server "${LOCAL_SERVER_NAME}" in .mcp.json \u2014 restart Claude Code and approve it when asked`);
|
|
502
|
+
}
|
|
503
|
+
if (removeLegacySettingsEntry()) {
|
|
504
|
+
console.log(" \u2713 Removed the old entry from ~/.claude/settings.json, where Claude Code doesn't read MCP servers");
|
|
447
505
|
}
|
|
448
|
-
const servers = settings.mcpServers ?? {};
|
|
449
|
-
servers.intent = { command: "npx", args: ["intentdocs", "mcp"] };
|
|
450
|
-
settings.mcpServers = servers;
|
|
451
|
-
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
452
|
-
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
453
|
-
console.log(" \u2713 Registered MCP server in ~/.claude/settings.json \u2014 restart Claude Code to activate");
|
|
454
506
|
}
|
|
455
507
|
function setupCursor() {
|
|
456
508
|
const cwd = process.cwd();
|
|
457
|
-
const cursorRulesPath =
|
|
509
|
+
const cursorRulesPath = join3(cwd, ".cursorrules");
|
|
458
510
|
const cursorBlock = `
|
|
459
511
|
# intentdocs Integration
|
|
460
512
|
|
|
@@ -463,6 +515,11 @@ function setupCursor() {
|
|
|
463
515
|
2. **ARCHITECTURE.md** \u2014 technical decisions and system structure
|
|
464
516
|
3. **CONVENTIONS.md** \u2014 coding patterns, naming, file structure
|
|
465
517
|
|
|
518
|
+
## First run
|
|
519
|
+
- No story started yet? The founder's next step is their first story:
|
|
520
|
+
claim it with \`npx intentdocs next\` (or \`start_story\` over MCP), build it,
|
|
521
|
+
report each criterion, then mark it done.
|
|
522
|
+
|
|
466
523
|
## Workflow
|
|
467
524
|
- Next story: \`npx intentdocs next\`
|
|
468
525
|
- Mark done: \`npx intentdocs done <id>\`
|
|
@@ -489,14 +546,14 @@ function setupCursor() {
|
|
|
489
546
|
- Log decisions and trade-offs back to intentdocs
|
|
490
547
|
- Follow patterns in CONVENTIONS.md
|
|
491
548
|
`;
|
|
492
|
-
if (
|
|
493
|
-
const existing =
|
|
549
|
+
if (existsSync3(cursorRulesPath)) {
|
|
550
|
+
const existing = readFileSync2(cursorRulesPath, "utf-8");
|
|
494
551
|
if (!existing.includes("intentdocs Integration")) {
|
|
495
|
-
|
|
552
|
+
writeFileSync3(cursorRulesPath, existing + "\n" + cursorBlock);
|
|
496
553
|
console.log(" \u2713 Updated .cursorrules");
|
|
497
554
|
}
|
|
498
555
|
} else {
|
|
499
|
-
|
|
556
|
+
writeFileSync3(cursorRulesPath, cursorBlock.trim() + "\n");
|
|
500
557
|
console.log(" \u2713 Created .cursorrules");
|
|
501
558
|
}
|
|
502
559
|
console.log(`
|
|
@@ -515,9 +572,9 @@ function setupCursor() {
|
|
|
515
572
|
}
|
|
516
573
|
function generateAgentDocs() {
|
|
517
574
|
const cwd = process.cwd();
|
|
518
|
-
const archPath =
|
|
519
|
-
if (!
|
|
520
|
-
|
|
575
|
+
const archPath = join3(cwd, "ARCHITECTURE.md");
|
|
576
|
+
if (!existsSync3(archPath)) {
|
|
577
|
+
writeFileSync3(
|
|
521
578
|
archPath,
|
|
522
579
|
`# Architecture
|
|
523
580
|
|
|
@@ -544,9 +601,9 @@ _Record trade-offs and why._
|
|
|
544
601
|
);
|
|
545
602
|
console.log(" \u2713 Created ARCHITECTURE.md scaffold");
|
|
546
603
|
}
|
|
547
|
-
const convPath =
|
|
548
|
-
if (!
|
|
549
|
-
|
|
604
|
+
const convPath = join3(cwd, "CONVENTIONS.md");
|
|
605
|
+
if (!existsSync3(convPath)) {
|
|
606
|
+
writeFileSync3(
|
|
550
607
|
convPath,
|
|
551
608
|
`# Conventions
|
|
552
609
|
|
|
@@ -5,6 +5,16 @@ import {
|
|
|
5
5
|
// src/lib/config.ts
|
|
6
6
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
7
7
|
import { join, dirname } from "path";
|
|
8
|
+
function checkoutConfig(input) {
|
|
9
|
+
return {
|
|
10
|
+
apiBase: input.apiBase,
|
|
11
|
+
mapTitle: input.map.title,
|
|
12
|
+
projectId: input.project.id,
|
|
13
|
+
mapId: input.map.id,
|
|
14
|
+
workspace: input.project.workspace ? { orgId: input.project.workspace.orgId, name: input.project.workspace.name } : { orgId: null, name: null },
|
|
15
|
+
...input.appUrl && { appUrl: input.appUrl }
|
|
16
|
+
};
|
|
17
|
+
}
|
|
8
18
|
var CONFIG_DIR = ".intent";
|
|
9
19
|
var CONFIG_FILE = "config.json";
|
|
10
20
|
function configPath() {
|
|
@@ -52,6 +62,7 @@ function requireConfig() {
|
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
export {
|
|
65
|
+
checkoutConfig,
|
|
55
66
|
hasConfig,
|
|
56
67
|
readConfig,
|
|
57
68
|
writeConfig,
|
|
@@ -9,6 +9,14 @@ var AuthError = class extends Error {
|
|
|
9
9
|
this.name = "AuthError";
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
+
var ApiError = class extends Error {
|
|
13
|
+
constructor(message, status, code = null) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.status = status;
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = "ApiError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
12
20
|
function checkoutMismatch(config, binding) {
|
|
13
21
|
const checkout = config.workspace;
|
|
14
22
|
if (!checkout || !checkout.orgId) return null;
|
|
@@ -42,6 +50,17 @@ async function refusalMessage(res) {
|
|
|
42
50
|
}
|
|
43
51
|
return null;
|
|
44
52
|
}
|
|
53
|
+
async function errorCode(res) {
|
|
54
|
+
try {
|
|
55
|
+
const body = await res.clone().json();
|
|
56
|
+
if (typeof body.error === "string") return body.error;
|
|
57
|
+
if (body.error && typeof body.error === "object" && typeof body.error.code === "string") {
|
|
58
|
+
return body.error.code;
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
45
64
|
async function apiFetch(config, path, init) {
|
|
46
65
|
const auth = getAuth();
|
|
47
66
|
const mismatch = checkoutMismatch(config, auth?.binding);
|
|
@@ -65,7 +84,10 @@ async function apiFetch(config, path, init) {
|
|
|
65
84
|
said ?? "Access denied \u2014 you may not have permission for this project. Run `npx intentdocs login` to re-authenticate."
|
|
66
85
|
);
|
|
67
86
|
}
|
|
68
|
-
if (!res.ok)
|
|
87
|
+
if (!res.ok) {
|
|
88
|
+
const said = await refusalMessage(res);
|
|
89
|
+
throw new ApiError(said ?? `API error: ${res.status}`, res.status, await errorCode(res));
|
|
90
|
+
}
|
|
69
91
|
return res;
|
|
70
92
|
}
|
|
71
93
|
function apiUrl(config, path) {
|
|
@@ -154,6 +176,7 @@ async function retractDecision(config, decisionId, reason) {
|
|
|
154
176
|
}
|
|
155
177
|
|
|
156
178
|
export {
|
|
179
|
+
checkoutMismatch,
|
|
157
180
|
syncHeaders,
|
|
158
181
|
apiFetch,
|
|
159
182
|
apiUrl,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ci
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-65EDM7QH.js";
|
|
4
4
|
import "./chunk-KPQ42YE6.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-K5SNF6CG.js";
|
|
6
6
|
import "./chunk-WRRUCCVZ.js";
|
|
7
7
|
import "./chunk-XZE2XP6O.js";
|
|
8
8
|
import "./chunk-UYTVTYNB.js";
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
apiUrl,
|
|
10
10
|
listStories,
|
|
11
11
|
syncHeaders
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KTGQO3AE.js";
|
|
13
13
|
import {
|
|
14
14
|
requireConfig
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-K5SNF6CG.js";
|
|
16
16
|
import "./chunk-XZE2XP6O.js";
|
|
17
17
|
import "./chunk-UYTVTYNB.js";
|
|
18
18
|
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
apiUrl,
|
|
7
7
|
syncHeaders
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KTGQO3AE.js";
|
|
9
9
|
import {
|
|
10
10
|
requireConfig
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-K5SNF6CG.js";
|
|
12
12
|
import {
|
|
13
13
|
closePrompt,
|
|
14
14
|
confirm
|
|
@@ -19,8 +19,15 @@ import "./chunk-UYTVTYNB.js";
|
|
|
19
19
|
// src/commands/import-prd.ts
|
|
20
20
|
import { readFileSync, existsSync } from "fs";
|
|
21
21
|
import ora from "ora";
|
|
22
|
-
async function importPrd(filePath) {
|
|
22
|
+
async function importPrd(filePath, opts = {}) {
|
|
23
23
|
const config = requireConfig();
|
|
24
|
+
if (!filePath && !opts.yes) {
|
|
25
|
+
console.error(" Reading the document from standard input leaves nothing to answer the confirmation with.");
|
|
26
|
+
console.error(" Pass a file to review before importing: npx intentdocs import prd.md");
|
|
27
|
+
console.error(" Or import without asking: npx intentdocs import --yes < prd.md");
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
24
31
|
let prdText;
|
|
25
32
|
let format = "PRD";
|
|
26
33
|
if (filePath) {
|
|
@@ -32,7 +39,7 @@ async function importPrd(filePath) {
|
|
|
32
39
|
if (filePath.endsWith(".md")) format = "Markdown";
|
|
33
40
|
else if (filePath.endsWith(".txt")) format = "text";
|
|
34
41
|
} else {
|
|
35
|
-
console.log(" Paste your PRD below (press Ctrl+D when done):\n");
|
|
42
|
+
if (process.stdin.isTTY) console.log(" Paste your PRD below (press Ctrl+D when done):\n");
|
|
36
43
|
const chunks = [];
|
|
37
44
|
for await (const chunk of process.stdin) {
|
|
38
45
|
chunks.push(chunk);
|
|
@@ -86,7 +93,7 @@ async function importPrd(filePath) {
|
|
|
86
93
|
}
|
|
87
94
|
console.log();
|
|
88
95
|
}
|
|
89
|
-
const doImport = await confirm(
|
|
96
|
+
const doImport = opts.yes ? true : await confirm(
|
|
90
97
|
` Import this story map structure?`
|
|
91
98
|
);
|
|
92
99
|
if (doImport) {
|