intentdocs 0.8.0 → 0.10.1

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 (34) hide show
  1. package/README.md +7 -1
  2. package/bin/intentdocs.js +2 -0
  3. package/dist/chunk-34JCN66H.js +170 -0
  4. package/dist/chunk-6X4BORMW.js +317 -0
  5. package/dist/{chunk-6FGYJ3W2.js → chunk-F52HPVNQ.js} +43 -4
  6. package/dist/{chunk-ICOMMHKG.js → chunk-JX2RLGOM.js} +13 -2
  7. package/dist/chunk-KPQ42YE6.js +43 -0
  8. package/dist/chunk-LQTPZL2Y.js +15 -0
  9. package/dist/{chunk-4OWPN2RE.js → chunk-NHNBCNND.js} +28 -47
  10. package/dist/{chunk-IKF3ZLHK.js → chunk-PUGYRSMK.js} +72 -108
  11. package/dist/{chunk-ITQUQYWB.js → chunk-UQDMUKLP.js} +2 -2
  12. package/dist/chunk-UYTVTYNB.js +11 -0
  13. package/dist/{chunk-WPVDURTJ.js → chunk-WRRUCCVZ.js} +27 -3
  14. package/dist/chunk-XZE2XP6O.js +105 -0
  15. package/dist/ci-XCOXFTLB.js +11 -0
  16. package/dist/{complexity-NSSYVT54.js → complexity-X3IJKNNV.js} +12 -7
  17. package/dist/{import-prd-CKV3R67G.js → import-prd-IJTM6FZE.js} +13 -11
  18. package/dist/index.js +435 -194
  19. package/dist/{keys-EDWET3WG.js → keys-UVXCCWCS.js} +8 -7
  20. package/dist/log-XIH4BGFL.js +206 -0
  21. package/dist/{map-extract-I3AACTGL.js → map-extract-V6D27I3H.js} +3 -2
  22. package/dist/{map-import-IYUMRASO.js → map-import-LORTI4K4.js} +12 -10
  23. package/dist/{map-schema-JVL3O2TJ.js → map-schema-5BEIJM2J.js} +1 -1
  24. package/dist/projects-AYAYVFKL.js +37 -0
  25. package/dist/{prompt-WAWCRGHN.js → prompt-GOAFIKBZ.js} +3 -1
  26. package/dist/{research-6SXJ37TI.js → research-CO3W7PLC.js} +12 -10
  27. package/dist/scope-ZZLKQEF5.js +11 -0
  28. package/dist/setup-WSYIG2CR.js +14 -0
  29. package/package.json +4 -2
  30. package/dist/chunk-6XKB6RTU.js +0 -123
  31. package/dist/chunk-PCNDP5SX.js +0 -34
  32. package/dist/log-TT2UCJP7.js +0 -94
  33. package/dist/scope-OGKQ472D.js +0 -10
  34. package/dist/setup-SOI2HQAL.js +0 -11
@@ -0,0 +1,15 @@
1
+ // src/lib/story-ref.ts
2
+ function storyRef(story) {
3
+ return story.key ?? story.id.slice(0, 8);
4
+ }
5
+ function matchesStoryRef(story, typed) {
6
+ const ref = typed.trim();
7
+ if (!ref) return false;
8
+ if (story.key && story.key.toLowerCase() === ref.toLowerCase()) return true;
9
+ return story.id === ref || story.id.startsWith(ref);
10
+ }
11
+
12
+ export {
13
+ storyRef,
14
+ matchesStoryRef
15
+ };
@@ -1,37 +1,29 @@
1
+ import {
2
+ getContext
3
+ } from "./chunk-34JCN66H.js";
4
+ import {
5
+ writeConfig
6
+ } from "./chunk-JX2RLGOM.js";
1
7
  import {
2
8
  ask,
3
9
  closePrompt,
4
10
  confirm
5
- } from "./chunk-WPVDURTJ.js";
6
- import {
7
- getContext
8
- } from "./chunk-6XKB6RTU.js";
11
+ } from "./chunk-WRRUCCVZ.js";
9
12
  import {
10
- writeConfig
11
- } from "./chunk-ICOMMHKG.js";
13
+ authenticatedFetch,
14
+ requireValidAuth
15
+ } from "./chunk-XZE2XP6O.js";
12
16
  import {
13
- API_BASE,
14
- requireAuth
15
- } from "./chunk-PCNDP5SX.js";
17
+ API_BASE
18
+ } from "./chunk-UYTVTYNB.js";
16
19
 
17
20
  // src/commands/scope.ts
18
21
  import { writeFileSync, existsSync } from "fs";
19
22
  import { join } from "path";
20
- async function apiFetch(path, token, opts = {}) {
21
- return fetch(`${API_BASE}${path}`, {
22
- ...opts,
23
- headers: {
24
- "Content-Type": "application/json",
25
- Authorization: `Bearer ${token}`,
26
- ...opts.headers ?? {}
27
- }
28
- });
29
- }
30
23
  async function scope(projectId) {
31
- const auth = requireAuth();
32
- const { token } = auth;
24
+ await requireValidAuth();
33
25
  if (!projectId) {
34
- projectId = await ask(" Project ID (from `intent start`): ");
26
+ projectId = await ask(" Project ID (from `intentdocs start`): ");
35
27
  }
36
28
  if (!projectId?.trim()) {
37
29
  console.log(" Project ID required.");
@@ -60,7 +52,7 @@ async function scope(projectId) {
60
52
  mvp ? `MVP scope: ${mvp}` : "",
61
53
  constraints ? `Technical constraints: ${constraints}` : ""
62
54
  ].filter(Boolean).join("\n");
63
- const res = await apiFetch("/api/blueprint/generate", token, {
55
+ const res = await authenticatedFetch("/api/blueprint/generate", {
64
56
  method: "POST",
65
57
  body: JSON.stringify({
66
58
  projectId,
@@ -120,30 +112,19 @@ async function scope(projectId) {
120
112
  console.log(" \u2713 Blueprint generated (couldn't parse summary)\n");
121
113
  }
122
114
  console.log("\n Connecting project to your codebase...");
123
- const mapsRes = await apiFetch(
124
- `/api/storymapper/project/${projectId}`,
125
- token
115
+ const mapsRes = await authenticatedFetch(
116
+ `/api/storymapper/project/${projectId}`
126
117
  );
127
- let syncToken = null;
118
+ let mapId = null;
128
119
  if (mapsRes.ok) {
129
120
  const mapData = await mapsRes.json();
130
- if (mapData.mapId) {
131
- const tokenRes = await apiFetch(
132
- `/api/storymapper/${mapData.mapId}/sync-token`,
133
- token,
134
- { method: "POST" }
135
- );
136
- if (tokenRes.ok) {
137
- const tokenData = await tokenRes.json();
138
- syncToken = tokenData.sync_token;
139
- }
140
- }
121
+ if (mapData.mapId) mapId = mapData.mapId;
141
122
  }
142
- if (syncToken) {
143
- writeConfig({ syncToken, apiBase: API_BASE });
123
+ if (mapId) {
124
+ const config = { apiBase: API_BASE, projectId, mapId };
125
+ writeConfig(config);
144
126
  console.log(" \u2713 Connected\n");
145
127
  try {
146
- const config = { syncToken, apiBase: API_BASE };
147
128
  const md = await getContext(config);
148
129
  writeFileSync(join(process.cwd(), "INTENT.md"), md);
149
130
  console.log(" \u2713 Downloaded INTENT.md\n");
@@ -190,12 +171,12 @@ async function scope(projectId) {
190
171
  }
191
172
  }
192
173
  }
193
- const { confirm: confirmSetup } = await import("./prompt-WAWCRGHN.js");
174
+ const { confirm: confirmSetup } = await import("./prompt-GOAFIKBZ.js");
194
175
  const wantSetup = await confirmSetup(
195
176
  " Configure your AI tool (Claude Code / Cursor) with intentdocs agent workflows?"
196
177
  );
197
178
  if (wantSetup) {
198
- const { setup } = await import("./setup-SOI2HQAL.js");
179
+ const { setup } = await import("./setup-WSYIG2CR.js");
199
180
  await setup();
200
181
  return;
201
182
  }
@@ -203,10 +184,10 @@ async function scope(projectId) {
203
184
  \u2705 Your project is scoped and ready to build!
204
185
 
205
186
  Next steps:
206
- \u2022 intent setup \u2014 configure your AI tool
207
- \u2022 intent status \u2014 see your story map progress
208
- \u2022 intent next \u2014 see what to build first
209
- \u2022 intent done <id> \u2014 mark stories as you complete them
187
+ \u2022 npx intentdocs setup \u2014 configure your AI tool
188
+ \u2022 npx intentdocs status \u2014 see your story map progress
189
+ \u2022 npx intentdocs next \u2014 see what to build first
190
+ \u2022 npx intentdocs done <id> \u2014 mark stories as you complete them
210
191
 
211
192
  Your story map is also live at ${API_BASE}
212
193
  Seek advice from the community and our resources.
@@ -1,23 +1,26 @@
1
1
  import {
2
- writeStoryContext
3
- } from "./chunk-6FGYJ3W2.js";
2
+ captureCli,
3
+ shutdownCliAnalytics
4
+ } from "./chunk-KPQ42YE6.js";
4
5
  import {
5
- choose,
6
- closePrompt
7
- } from "./chunk-WPVDURTJ.js";
6
+ writeStoryContext
7
+ } from "./chunk-F52HPVNQ.js";
8
8
  import {
9
9
  apiFetch,
10
10
  getContext,
11
11
  listStories
12
- } from "./chunk-6XKB6RTU.js";
12
+ } from "./chunk-34JCN66H.js";
13
13
  import {
14
14
  hasConfig,
15
15
  requireConfig
16
- } from "./chunk-ICOMMHKG.js";
16
+ } from "./chunk-JX2RLGOM.js";
17
17
  import {
18
- getAuth,
19
- requireAuth
20
- } from "./chunk-PCNDP5SX.js";
18
+ choose,
19
+ closePrompt
20
+ } from "./chunk-WRRUCCVZ.js";
21
+ import {
22
+ requireValidAuth
23
+ } from "./chunk-XZE2XP6O.js";
21
24
 
22
25
  // src/commands/setup.ts
23
26
  import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2, readFileSync, unlinkSync } from "fs";
@@ -27,43 +30,6 @@ import { homedir } from "os";
27
30
  // src/commands/sync.ts
28
31
  import { writeFileSync, readdirSync, existsSync, statSync } from "fs";
29
32
  import { join } from "path";
30
-
31
- // src/lib/analytics.ts
32
- import { PostHog } from "posthog-node";
33
- var client = null;
34
- function getClient() {
35
- if (client) return client;
36
- const auth = getAuth();
37
- if (!auth?.posthogKey) return null;
38
- client = new PostHog(auth.posthogKey, {
39
- host: auth.posthogHost ?? "https://eu.i.posthog.com",
40
- flushAt: 1,
41
- flushInterval: 0
42
- });
43
- return client;
44
- }
45
- function getDistinctId() {
46
- return getAuth()?.userId ?? null;
47
- }
48
- function captureCli(event, properties, groups) {
49
- const posthog = getClient();
50
- const distinctId = getDistinctId();
51
- if (!posthog || !distinctId) return;
52
- posthog.capture({
53
- distinctId,
54
- event,
55
- properties: {
56
- ...properties,
57
- ...groups?.project ? { project_id: groups.project } : {}
58
- },
59
- ...groups ? { groups } : {}
60
- });
61
- }
62
- async function shutdownCliAnalytics() {
63
- if (client) await client.shutdown();
64
- }
65
-
66
- // src/commands/sync.ts
67
33
  async function syncContextFile(config) {
68
34
  const res = await apiFetch(config, "/context-file?format=claude");
69
35
  const { content } = await res.json();
@@ -156,9 +122,9 @@ async function sync(opts) {
156
122
 
157
123
  // src/commands/setup.ts
158
124
  async function setup() {
159
- requireAuth();
125
+ await requireValidAuth();
160
126
  if (!hasConfig()) {
161
- console.log(" Not connected to a project. Run `intent init` first.");
127
+ console.log(" Not connected to a project. Run `npx intentdocs init` first.");
162
128
  closePrompt();
163
129
  return;
164
130
  }
@@ -170,13 +136,13 @@ async function setup() {
170
136
  ]);
171
137
  const tools = idx === 0 ? ["claude"] : idx === 1 ? ["cursor"] : ["claude", "cursor"];
172
138
  for (const tool of tools) {
173
- if (tool === "claude") setupClaudeCode(config.syncToken);
174
- if (tool === "cursor") setupCursor(config.syncToken);
139
+ if (tool === "claude") setupClaudeCode();
140
+ if (tool === "cursor") setupCursor();
175
141
  }
176
142
  try {
177
143
  await syncContextFile(config);
178
144
  } catch {
179
- console.log(" \u26A0 Could not fetch project context (run `intent sync --context` to retry)");
145
+ console.log(" \u26A0 Could not fetch project context (run `npx intentdocs sync --context` to retry)");
180
146
  }
181
147
  generateAgentDocs();
182
148
  console.log(`
@@ -196,37 +162,37 @@ async function setup() {
196
162
  /intent-sync Refresh context from intentdocs
197
163
 
198
164
  Terminal commands:
199
- intent next Next priority story
200
- intent done <id> Mark done + log decision/lesson
201
- intent decide Log an architectural decision
202
- intent example Log a reference pattern
203
- intent sync Refresh INTENT.md
204
- intent sync --context Regenerate CLAUDE.md from intentdocs
205
- intent status Recent activity
165
+ npx intentdocs next Next priority story
166
+ npx intentdocs done <id> Mark done + log decision/lesson
167
+ npx intentdocs decide Log an architectural decision
168
+ npx intentdocs example Log a reference pattern
169
+ npx intentdocs sync Refresh INTENT.md
170
+ npx intentdocs sync --context Regenerate CLAUDE.md from intentdocs
171
+ npx intentdocs status Recent activity
206
172
  `);
207
173
  closePrompt();
208
174
  }
209
- function setupClaudeCode(syncToken) {
175
+ function setupClaudeCode() {
210
176
  const cwd = process.cwd();
211
177
  const claudeMdPath = join2(cwd, "CLAUDE.md");
212
178
  const claudeBlock = `
213
179
  # intentdocs Integration
214
180
 
215
181
  This project is connected to a intentdocs story map.
216
- Run \`intent sync --context\` to generate the full CLAUDE.md with your project's instructions,
182
+ Run \`npx intentdocs sync --context\` to generate the full CLAUDE.md with your project's instructions,
217
183
  story map, decisions, examples, tools, and guardrails.
218
184
 
219
185
  ## Quick reference
220
186
 
221
187
  | Command | What it does |
222
188
  |---|---|
223
- | \`intent next\` | Pick up the next priority story |
224
- | \`intent done <id>\` | Mark a story done + log a decision |
225
- | \`intent decide\` | Log an architectural or product decision |
226
- | \`intent example\` | Log a reference pattern for this codebase |
227
- | \`intent sync\` | Refresh story map + INTENT.md |
228
- | \`intent sync --context\` | Regenerate this file from intentdocs |
229
- | \`intent status\` | Show recent activity |
189
+ | \`npx intentdocs next\` | Pick up the next priority story |
190
+ | \`npx intentdocs done <id>\` | Mark a story done + log a decision |
191
+ | \`npx intentdocs decide\` | Log an architectural or product decision |
192
+ | \`npx intentdocs example\` | Log a reference pattern for this codebase |
193
+ | \`npx intentdocs sync\` | Refresh story map + INTENT.md |
194
+ | \`npx intentdocs sync --context\` | Regenerate this file from intentdocs |
195
+ | \`npx intentdocs status\` | Show recent activity |
230
196
  `;
231
197
  if (existsSync2(claudeMdPath)) {
232
198
  const existing = readFileSync(claudeMdPath, "utf-8");
@@ -253,7 +219,7 @@ story map, decisions, examples, tools, and guardrails.
253
219
  join2(commandsDir, "intent-next.md"),
254
220
  `# Pick up the next story
255
221
 
256
- 1. Run \`intent next\` to get the highest-priority story
222
+ 1. Run \`npx intentdocs next\` to get the highest-priority story
257
223
  2. Read the acceptance criteria carefully \u2014 these define "done"
258
224
  3. Check ARCHITECTURE.md for relevant technical decisions
259
225
  4. Read CONVENTIONS.md for coding patterns to follow
@@ -267,7 +233,7 @@ story map, decisions, examples, tools, and guardrails.
267
233
 
268
234
  ## Context to load first
269
235
  1. Read CLAUDE.md \u2014 your full project harness (instructions, decisions, examples, tools, guardrails)
270
- 2. Run \`intent next\` if you don't have a story yet
236
+ 2. Run \`npx intentdocs next\` if you don't have a story yet
271
237
  3. Review the "Done when" acceptance criteria \u2014 each one carries a priority
272
238
  (\`must\`/\`should\`) and a verification method: \`[executable]\` gives you a
273
239
  \`check:\` command to run, \`[self-check]\`/\`[visual]\`/\`[founder]\` give you
@@ -288,18 +254,18 @@ story map, decisions, examples, tools, and guardrails.
288
254
  \`must\` criterion fails 3 times, call \`raise_blocker\` with what you
289
255
  attempted, what's failing, and the single decision the founder needs to
290
256
  make \u2014 then stop working on this story.
291
- 10. Never call \`mark_done\` (or \`intent done\`) while a \`must\` criterion is
257
+ 10. Never call \`mark_done\` (or \`npx intentdocs done\`) while a \`must\` criterion is
292
258
  still failing or has never been reported \u2014 both will warn you and
293
259
  require an explicit override if you try.
294
260
 
295
261
  ## Write back to intentdocs
296
262
  11. Add implementation notes:
297
- \`intent note <story-id> "How this was implemented"\`
298
- 12. Log decisions: \`intent decide "Title" -d "What and why" -c architecture\`
299
- 13. Log useful patterns: \`intent example\`
263
+ \`npx intentdocs note <story-id> "How this was implemented"\`
264
+ 12. Log decisions: \`npx intentdocs decide "Title" -d "What and why" -c architecture\`
265
+ 13. Log useful patterns: \`npx intentdocs example\`
300
266
  14. If you discovered new requirements:
301
- \`intent add "title" --activity "Activity" --priority should\`
302
- 15. Mark done: \`intent done <story-id>\`
267
+ \`npx intentdocs add "title" --activity "Activity" --priority should\`
268
+ 15. Mark done: \`npx intentdocs done <story-id>\`
303
269
  16. Commit: \`git commit -m "feat: description [SC-<id>]"\`
304
270
 
305
271
  ## Rules
@@ -333,9 +299,9 @@ story map, decisions, examples, tools, and guardrails.
333
299
  - Decisions made and trade-offs
334
300
  - How to test it manually
335
301
  4. Log decisions to intentdocs:
336
- \`intent decide "Title" -d "Description" -c architecture\`
302
+ \`npx intentdocs decide "Title" -d "Description" -c architecture\`
337
303
  5. Add implementation notes:
338
- \`intent note <story-id> "Summary of how it works"\`
304
+ \`npx intentdocs note <story-id> "Summary of how it works"\`
339
305
  6. Update ARCHITECTURE.md if needed
340
306
  7. Update CONVENTIONS.md if new patterns were introduced
341
307
  `
@@ -344,7 +310,7 @@ story map, decisions, examples, tools, and guardrails.
344
310
  join2(commandsDir, "intent-test.md"),
345
311
  `# Write tests for a story
346
312
 
347
- 1. Get the story details: \`intent next\` or provided story ID
313
+ 1. Get the story details: \`npx intentdocs next\` or provided story ID
348
314
  2. Each acceptance criterion becomes at least one test
349
315
  3. Also consider: error cases, boundary conditions, integration points
350
316
  4. Follow testing patterns in CONVENTIONS.md
@@ -353,16 +319,16 @@ story map, decisions, examples, tools, and guardrails.
353
319
  );
354
320
  writeFileSync2(
355
321
  join2(commandsDir, "intent-status.md"),
356
- `Run \`intent status\` and \`intent stories --filter todo\` to show current progress and remaining backlog. Summarise what's done and what's left.`
322
+ `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.`
357
323
  );
358
324
  writeFileSync2(
359
325
  join2(commandsDir, "intent-done.md"),
360
- `Ask which story was just completed, then run \`intent done <id>\`.
361
- \`intent done\` prints the acceptance-criteria table first. If any \`must\` criterion is still failing or was
326
+ `Ask which story was just completed, then run \`npx intentdocs done <id>\`.
327
+ \`npx intentdocs done\` prints the acceptance-criteria table first. If any \`must\` criterion is still failing or was
362
328
  never reported via \`report_criteria\`, it will list them and ask "Mark done anyway?" \u2014 only confirm that
363
- if the founder explicitly wants to override; otherwise go fix the failing criterion and re-run \`intent done\`.
329
+ if the founder explicitly wants to override; otherwise go fix the failing criterion and re-run \`npx intentdocs done\`.
364
330
  The CLI will prompt for an optional decision or lesson learned \u2014 encourage the user to capture it.
365
- Also ask if there are implementation notes to add: \`intent note <id> "..."\`
331
+ Also ask if there are implementation notes to add: \`npx intentdocs note <id> "..."\`
366
332
  Both decisions and notes flow back to the project page on intentdocs.com.`
367
333
  );
368
334
  writeFileSync2(
@@ -370,10 +336,10 @@ Both decisions and notes flow back to the project page on intentdocs.com.`
370
336
  `# Refresh context from intentdocs
371
337
 
372
338
  ## Refresh story map summary
373
- Run \`intent sync\` \u2014 updates INTENT.md with the latest stories and their status.
339
+ Run \`npx intentdocs sync\` \u2014 updates INTENT.md with the latest stories and their status.
374
340
 
375
341
  ## Regenerate the full CLAUDE.md harness
376
- Run \`intent sync --context\` \u2014 rebuilds CLAUDE.md from your project page, pulling in:
342
+ Run \`npx intentdocs sync --context\` \u2014 rebuilds CLAUDE.md from your project page, pulling in:
377
343
  - Role & Goals (Instructions section)
378
344
  - Scope (all story maps + story counts)
379
345
  - Decisions & Memory (last 10 decisions)
@@ -381,7 +347,7 @@ Run \`intent sync --context\` \u2014 rebuilds CLAUDE.md from your project page,
381
347
  - Tools & Stack (structured tool registry + MCP config)
382
348
  - Guardrails (hard constraints)
383
349
 
384
- Run \`intent sync --context\` after updating any section on intentdocs.com.`
350
+ Run \`npx intentdocs sync --context\` after updating any section on intentdocs.com.`
385
351
  );
386
352
  writeFileSync2(
387
353
  join2(commandsDir, "intent-propose.md"),
@@ -394,18 +360,18 @@ stories there AND saves a local spec for the AI to reference during implementati
394
360
  ## Process
395
361
  1. Ask the user: "What do you want to build or change? Describe the problem and the solution."
396
362
  2. Help them break it into 2-5 stories with clear acceptance criteria (each AC is testable)
397
- 3. Run: \`intent propose <change-name>\`
363
+ 3. Run: \`npx intentdocs propose <change-name>\`
398
364
  - The CLI will guide through: problem, solution, activity, priority, stories + ACs
399
365
  - Stories are created in the live story map at intentdocs.com
400
366
  - A local spec is saved to \`intent-changes/<name>/proposal.md\`
401
- 4. Once done: \`intent sync\` to pull the new stories into INTENT.md
402
- 5. Run \`intent next\` to start implementing
367
+ 4. Once done: \`npx intentdocs sync\` to pull the new stories into INTENT.md
368
+ 5. Run \`npx intentdocs next\` to start implementing
403
369
 
404
370
  ## Tips
405
371
  - Change names should be kebab-case: add-dark-mode, fix-auth-flow, onboarding-revamp
406
372
  - Keep stories small \u2014 one story = one deployable increment
407
373
  - Write ACs as testable outcomes: "Given X, when Y, then Z" or "User can..."
408
- - If the change is already defined in the UI, just run \`intent sync\` instead
374
+ - If the change is already defined in the UI, just run \`npx intentdocs sync\` instead
409
375
  `
410
376
  );
411
377
  writeFileSync2(
@@ -420,13 +386,13 @@ Use this to focus on a single story without loading the full story map.
420
386
  - When you need a clean, focused view of ACs and notes
421
387
 
422
388
  ## Process
423
- 1. Run \`intent next\` to get the active story \u2014 this automatically writes the context file to \`.intent/stories/<id>.md\`
389
+ 1. Run \`npx intentdocs next\` to get the active story \u2014 this automatically writes the context file to \`.intent/stories/<id>.md\`
424
390
  2. Read that file \u2014 it contains: title, user story, acceptance criteria (as checkboxes), notes, and space for relevant files
425
391
  3. Use it as your working document throughout implementation:
426
392
  - Check off ACs as you satisfy them
427
393
  - Add file paths under "Relevant files" as you discover them
428
- - Run \`intent note <id> "..."\` to log notes (updates both remote map and local file)
429
- 4. When all ACs are checked: \`intent done <id>\`
394
+ - Run \`npx intentdocs note <id> "..."\` to log notes (updates both remote map and local file)
395
+ 4. When all ACs are checked: \`npx intentdocs done <id>\`
430
396
 
431
397
  ## If you already know the story ID
432
398
  The file is at \`.intent/stories/<full-story-id>.md\` \u2014 read it directly.
@@ -438,13 +404,13 @@ The file is at \`.intent/stories/<full-story-id>.md\` \u2014 read it directly.
438
404
 
439
405
  Use this when you've made a decision that future agents (or teammates) should know about.
440
406
 
441
- Run \`intent decide\` \u2014 the CLI will prompt for:
407
+ Run \`npx intentdocs decide\` \u2014 the CLI will prompt for:
442
408
  - Title: short, specific description of the decision
443
409
  - Description: what was decided and why (include trade-offs considered)
444
410
  - Category: architecture / product / technical / trade-off
445
411
 
446
412
  Decisions appear in the Memory section of the project page at intentdocs.com
447
- and are included in CLAUDE.md the next time you run \`intent sync --context\`.
413
+ and are included in CLAUDE.md the next time you run \`npx intentdocs sync --context\`.
448
414
 
449
415
  Good decisions to log:
450
416
  - "Chose X over Y because..."
@@ -457,7 +423,7 @@ Good decisions to log:
457
423
 
458
424
  Use this when you've written code that represents the right way to do something in this project.
459
425
 
460
- Run \`intent example\` \u2014 the CLI will prompt for:
426
+ Run \`npx intentdocs example\` \u2014 the CLI will prompt for:
461
427
  - Title: what the pattern is
462
428
  - Description: when to use it
463
429
  - Language: typescript / python / bash / other
@@ -465,7 +431,7 @@ Run \`intent example\` \u2014 the CLI will prompt for:
465
431
  - After code: the correct pattern to follow
466
432
 
467
433
  Examples appear in the Knowledge > Examples section of the project page
468
- and are included in CLAUDE.md as Reference Patterns the next time you run \`intent sync --context\`.`
434
+ and are included in CLAUDE.md as Reference Patterns the next time you run \`npx intentdocs sync --context\`.`
469
435
  );
470
436
  console.log(" \u2713 Created slash commands: /intent-propose, /intent-next, /intent-implement, /intent-review, /intent-document, /intent-test, /intent-status, /intent-done, /intent-sync, /intent-context, /intent-decide, /intent-example");
471
437
  registerMcpWithClaudeCode();
@@ -486,7 +452,7 @@ function registerMcpWithClaudeCode() {
486
452
  writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
487
453
  console.log(" \u2713 Registered MCP server in ~/.claude/settings.json \u2014 restart Claude Code to activate");
488
454
  }
489
- function setupCursor(syncToken) {
455
+ function setupCursor() {
490
456
  const cwd = process.cwd();
491
457
  const cursorRulesPath = join2(cwd, ".cursorrules");
492
458
  const cursorBlock = `
@@ -498,12 +464,12 @@ function setupCursor(syncToken) {
498
464
  3. **CONVENTIONS.md** \u2014 coding patterns, naming, file structure
499
465
 
500
466
  ## Workflow
501
- - Next story: \`intent next\`
502
- - Mark done: \`intent done <id>\`
503
- - Add notes: \`intent note <id> "..."\`
504
- - Log decisions: \`intent decide "Title" -d "Why"\`
505
- - Create stories: \`intent add "title" --activity "Name"\`
506
- - Refresh context: \`intent sync\`
467
+ - Next story: \`npx intentdocs next\`
468
+ - Mark done: \`npx intentdocs done <id>\`
469
+ - Add notes: \`npx intentdocs note <id> "..."\`
470
+ - Log decisions: \`npx intentdocs decide "Title" -d "Why"\`
471
+ - Create stories: \`npx intentdocs add "title" --activity "Name"\`
472
+ - Refresh context: \`npx intentdocs sync\`
507
473
 
508
474
  ## The acceptance-criteria loop
509
475
  - Each "Done when" criterion carries a priority (\`must\`/\`should\`) and a
@@ -514,7 +480,7 @@ function setupCursor(syncToken) {
514
480
  - For a failing \`must\` criterion: fix and re-check. If the same \`must\`
515
481
  fails 3 times, call \`raise_blocker\` with what you attempted, what's
516
482
  failing, and the single decision needed \u2014 then stop.
517
- - Never call \`mark_done\`/\`intent done\` while a \`must\` criterion is still
483
+ - Never call \`mark_done\`/\`npx intentdocs done\` while a \`must\` criterion is still
518
484
  failing or unreported \u2014 both warn and require an explicit override.
519
485
 
520
486
  ## Rules
@@ -614,8 +580,6 @@ _Linting, formatting, style preferences._
614
580
  }
615
581
 
616
582
  export {
617
- captureCli,
618
- shutdownCliAnalytics,
619
583
  sync,
620
584
  setup
621
585
  };
@@ -3,14 +3,14 @@ import chalk from "chalk";
3
3
  function isPlanGated(status) {
4
4
  return status === 402 || status === 403;
5
5
  }
6
- var UPGRADE_MESSAGE_PLAIN = "This feature requires a Pro plan or your own Anthropic key.\n Upgrade: https://intentdocs.com/pricing\n Or add your key: intent keys set";
6
+ var UPGRADE_MESSAGE_PLAIN = "This feature requires a Pro plan or your own Anthropic key.\n Upgrade: https://intentdocs.com/pricing\n Or add your key: npx intentdocs keys set";
7
7
  function printUpgradeMessage() {
8
8
  console.log();
9
9
  console.log(
10
10
  ` ${chalk.yellow("This feature requires a Pro plan or your own Anthropic key.")}`
11
11
  );
12
12
  console.log(` Upgrade: ${chalk.cyan.underline("https://intentdocs.com/pricing")}`);
13
- console.log(` Or add your key: ${chalk.cyan("intent keys set")}`);
13
+ console.log(` Or add your key: ${chalk.cyan("npx intentdocs keys set")}`);
14
14
  console.log();
15
15
  }
16
16
 
@@ -0,0 +1,11 @@
1
+ // src/lib/api-base.ts
2
+ var API_BASE = "https://www.intentdocs.com";
3
+ function canonicalApiBase(base) {
4
+ const trimmed = base.trim().replace(/\/+$/, "");
5
+ return /^https?:\/\/intentdocs\.com$/i.test(trimmed) ? API_BASE : trimmed;
6
+ }
7
+
8
+ export {
9
+ API_BASE,
10
+ canonicalApiBase
11
+ };
@@ -1,18 +1,41 @@
1
1
  // src/lib/prompt.ts
2
2
  import { createInterface } from "readline";
3
3
  var rl = null;
4
+ function stdinExhausted() {
5
+ return process.stdin.readableEnded === true || process.stdin.destroyed === true;
6
+ }
7
+ function isInteractive() {
8
+ return process.stdin.isTTY === true;
9
+ }
4
10
  function getRL() {
5
11
  if (!rl) {
6
- rl = createInterface({
12
+ const iface = createInterface({
7
13
  input: process.stdin,
8
14
  output: process.stdout
9
15
  });
16
+ iface.on("close", () => {
17
+ if (rl === iface) rl = null;
18
+ });
19
+ rl = iface;
10
20
  }
11
21
  return rl;
12
22
  }
13
23
  function ask(question) {
24
+ if (stdinExhausted()) return Promise.resolve("");
14
25
  return new Promise((resolve) => {
15
- getRL().question(question, (answer) => {
26
+ const iface = getRL();
27
+ let settled = false;
28
+ const onClose = () => {
29
+ if (!settled) {
30
+ settled = true;
31
+ resolve("");
32
+ }
33
+ };
34
+ iface.once("close", onClose);
35
+ iface.question(question, (answer) => {
36
+ if (settled) return;
37
+ settled = true;
38
+ iface.removeListener("close", onClose);
16
39
  resolve(answer.trim());
17
40
  });
18
41
  });
@@ -53,7 +76,7 @@ ${question}
53
76
  const answer = await ask(`
54
77
  Choice (1-${options.length}): `);
55
78
  const idx = parseInt(answer, 10) - 1;
56
- if (idx < 0 || idx >= options.length) return 0;
79
+ if (Number.isNaN(idx) || idx < 0 || idx >= options.length) return 0;
57
80
  return idx;
58
81
  }
59
82
  function closePrompt() {
@@ -70,6 +93,7 @@ function pausePrompt() {
70
93
  }
71
94
 
72
95
  export {
96
+ isInteractive,
73
97
  ask,
74
98
  askMultiline,
75
99
  confirm,