intentdocs 0.12.0 → 0.12.2
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 +6 -0
- package/assets/hero.svg +352 -0
- package/dist/{chunk-SDXDVNNP.js → chunk-2NSRHMTH.js} +1 -1
- package/dist/{chunk-5GATVQEI.js → chunk-2VM54R5K.js} +1 -1
- package/dist/{chunk-Q6BSSJK5.js → chunk-7ONMS2RJ.js} +2 -2
- package/dist/{chunk-RGFGTIIH.js → chunk-HWMSGXLQ.js} +9 -0
- package/dist/{pull-MDI63WI7.js → chunk-JDK3RCQU.js} +31 -10
- package/dist/{ci-CWPLSRCQ.js → ci-LG4NM2DU.js} +2 -2
- package/dist/{complexity-HLJTXY55.js → complexity-6XVLG3EH.js} +1 -1
- package/dist/{import-prd-FQI4J45M.js → import-prd-DTO5LTWA.js} +1 -1
- package/dist/index.js +78 -49
- package/dist/{log-VTIAG4PC.js → log-ELEPANI3.js} +1 -1
- package/dist/{map-extract-4C44YGGD.js → map-extract-MUGIIXTP.js} +1 -1
- package/dist/{map-import-TSSDU766.js → map-import-TDBELC77.js} +1 -1
- package/dist/pull-6GAAR6NP.js +17 -0
- package/dist/{push-7LJ654MJ.js → push-62T2TMKN.js} +25 -4
- package/dist/{research-L27DLYXC.js → research-XMUAQOVB.js} +1 -1
- package/dist/{scope-ORIFXV4P.js → scope-PFHPW6Y6.js} +2 -2
- package/dist/{setup-W4PKG6GB.js → setup-5ZNAOKQK.js} +2 -2
- package/package.json +5 -3
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
checkoutConfig,
|
|
6
6
|
hasConfig,
|
|
7
7
|
writeConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HWMSGXLQ.js";
|
|
9
9
|
import {
|
|
10
10
|
ask,
|
|
11
11
|
closePrompt,
|
|
@@ -196,7 +196,7 @@ async function scope(projectId) {
|
|
|
196
196
|
" Configure your AI tool (Claude Code / Cursor) with intentdocs agent workflows?"
|
|
197
197
|
);
|
|
198
198
|
if (wantSetup) {
|
|
199
|
-
const { setup } = await import("./setup-
|
|
199
|
+
const { setup } = await import("./setup-5ZNAOKQK.js");
|
|
200
200
|
await setup();
|
|
201
201
|
return;
|
|
202
202
|
}
|
|
@@ -442,6 +442,14 @@ function newFeature(key, remote) {
|
|
|
442
442
|
return `${[head, ...scenarios].join("\n\n")}
|
|
443
443
|
`;
|
|
444
444
|
}
|
|
445
|
+
function freeKeys(prefix, used, count) {
|
|
446
|
+
let top = 0;
|
|
447
|
+
for (const key of used) {
|
|
448
|
+
const m = new RegExp(`^${prefix}-(\\d+)$`).exec(key);
|
|
449
|
+
if (m) top = Math.max(top, Number(m[1]));
|
|
450
|
+
}
|
|
451
|
+
return Array.from({ length: count }, (_, i) => `${prefix}-${top + 1 + i}`);
|
|
452
|
+
}
|
|
445
453
|
|
|
446
454
|
// src/lib/config.ts
|
|
447
455
|
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
@@ -526,6 +534,7 @@ export {
|
|
|
526
534
|
classify,
|
|
527
535
|
renderFeature,
|
|
528
536
|
newFeature,
|
|
537
|
+
freeKeys,
|
|
529
538
|
checkoutConfig,
|
|
530
539
|
hasConfig,
|
|
531
540
|
readConfig,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
classify,
|
|
6
6
|
featureFiles,
|
|
7
7
|
findIntentDir,
|
|
8
|
+
freeKeys,
|
|
8
9
|
newFeature,
|
|
9
10
|
parseFeature,
|
|
10
11
|
readIntentFolder,
|
|
@@ -15,15 +16,13 @@ import {
|
|
|
15
16
|
specOfPushStory,
|
|
16
17
|
specOfStory,
|
|
17
18
|
writeSyncBase
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-HWMSGXLQ.js";
|
|
19
20
|
import {
|
|
20
21
|
choose,
|
|
21
22
|
closePrompt,
|
|
22
23
|
confirm,
|
|
23
24
|
isInteractive
|
|
24
25
|
} from "./chunk-WRRUCCVZ.js";
|
|
25
|
-
import "./chunk-XZE2XP6O.js";
|
|
26
|
-
import "./chunk-UYTVTYNB.js";
|
|
27
26
|
|
|
28
27
|
// src/commands/pull.ts
|
|
29
28
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
@@ -254,6 +253,8 @@ function planUnits(deps, response, base, nextBase, outcome) {
|
|
|
254
253
|
});
|
|
255
254
|
}
|
|
256
255
|
}
|
|
256
|
+
const synced = Object.keys(base.stories).length > 0;
|
|
257
|
+
const numberTaken = (key, mine, theirs) => synced && !(key in base.stories) && specOfPushStory(mine).title !== theirs.title;
|
|
257
258
|
const live = response.stories.filter((s) => s.key);
|
|
258
259
|
outcome.cancelled = live.filter((s) => s.cancelled_at && files.has(s.key)).map((s) => s.key);
|
|
259
260
|
for (const story of live.filter((s) => !s.cancelled_at)) {
|
|
@@ -261,7 +262,9 @@ function planUnits(deps, response, base, nextBase, outcome) {
|
|
|
261
262
|
const theirs = specOfStory(story, storymap.activities ?? []);
|
|
262
263
|
const mine = local.get(key);
|
|
263
264
|
const path = files.get(key);
|
|
264
|
-
if (mine && path) {
|
|
265
|
+
if (mine && path && numberTaken(key, mine, theirs)) {
|
|
266
|
+
outcome.numberTaken.push(key);
|
|
267
|
+
} else if (mine && path) {
|
|
265
268
|
const kind = classify(specOfPushStory(mine), theirs, base.stories[key]);
|
|
266
269
|
if (kind === null) nextBase.stories[key] = theirs;
|
|
267
270
|
else if (kind === "local") outcome.localOnly.push(key);
|
|
@@ -320,7 +323,7 @@ function planUnits(deps, response, base, nextBase, outcome) {
|
|
|
320
323
|
}
|
|
321
324
|
const statusChanges = [];
|
|
322
325
|
const notMoved = [];
|
|
323
|
-
for (const s of live.filter((s2) => !s2.cancelled_at && STATUSES.has(s2.status) && state.stories?.[s2.key])) {
|
|
326
|
+
for (const s of live.filter((s2) => !s2.cancelled_at && STATUSES.has(s2.status) && state.stories?.[s2.key] && !outcome.numberTaken.includes(s2.key))) {
|
|
324
327
|
const key = s.key;
|
|
325
328
|
const mine = state.stories[key].status ?? "todo";
|
|
326
329
|
const was = base.statuses[key];
|
|
@@ -345,7 +348,7 @@ function planUnits(deps, response, base, nextBase, outcome) {
|
|
|
345
348
|
}
|
|
346
349
|
});
|
|
347
350
|
}
|
|
348
|
-
for (const story of live.filter((s) => !s.cancelled_at && s.agent_plan && files.has(s.key) && local.has(s.key))) {
|
|
351
|
+
for (const story of live.filter((s) => !s.cancelled_at && s.agent_plan && files.has(s.key) && local.has(s.key) && !outcome.numberTaken.includes(s.key))) {
|
|
349
352
|
const key = story.key;
|
|
350
353
|
const plan = story.agent_plan;
|
|
351
354
|
if ((base.plans[key] ?? 0) >= plan.version) continue;
|
|
@@ -369,11 +372,23 @@ function planUnits(deps, response, base, nextBase, outcome) {
|
|
|
369
372
|
}
|
|
370
373
|
return units;
|
|
371
374
|
}
|
|
375
|
+
function numberTakenAdvice(keys, used) {
|
|
376
|
+
const prefix = keys[0].replace(/-\d+$/, "");
|
|
377
|
+
const next = freeKeys(prefix, used, keys.length);
|
|
378
|
+
return [
|
|
379
|
+
`
|
|
380
|
+
${keys.join(", ")} ${keys.length === 1 ? "is" : "are"} used by a different story in intentdocs, made since this folder last synced. Neither was changed.`,
|
|
381
|
+
" 1. Give the folder's " + (keys.length === 1 ? "story a number" : "stories numbers") + " that isn't taken: " + keys.map((k, i) => `${k} \u2192 ${next[i]}`).join(", ") + ".",
|
|
382
|
+
" Change it in the feature file's tag, storymap.yaml, state.yaml and any plans/<key>.v*.md.",
|
|
383
|
+
" 2. Run `intentdocs pull` to bring intentdocs' " + keys.join(", ") + " into the folder.",
|
|
384
|
+
" 3. Run `intentdocs push` to send the renumbered " + (keys.length === 1 ? "story" : "stories") + "."
|
|
385
|
+
];
|
|
386
|
+
}
|
|
372
387
|
async function runPull(deps) {
|
|
373
388
|
const response = await deps.listStories();
|
|
374
389
|
const base = deps.readSyncBase();
|
|
375
390
|
const nextBase = structuredClone(base);
|
|
376
|
-
const outcome = { units: [], written: [], localOnly: [], cancelled: [], statusNotMoved: [] };
|
|
391
|
+
const outcome = { units: [], written: [], localOnly: [], cancelled: [], statusNotMoved: [], numberTaken: [] };
|
|
377
392
|
outcome.units = planUnits(deps, response, base, nextBase, outcome);
|
|
378
393
|
const disk = new Files(deps.readFile);
|
|
379
394
|
for (const unit of outcome.units) {
|
|
@@ -394,11 +409,15 @@ Changed only in the repo, so nothing to pull: ${outcome.localOnly.join(", ")}. \
|
|
|
394
409
|
deps.log(`
|
|
395
410
|
intentdocs hasn't moved these since the last sync, so their status here is kept: ${outcome.statusNotMoved.join(", ")}.`);
|
|
396
411
|
if (outcome.cancelled.length) deps.log(`Cancelled in intentdocs, left as they are here: ${outcome.cancelled.join(", ")}.`);
|
|
412
|
+
if (outcome.numberTaken.length) {
|
|
413
|
+
const used = [...response.stories.map((s) => s.key ?? ""), ...featureFiles(findIntentDir(deps.cwd)).keys()];
|
|
414
|
+
for (const line of numberTakenAdvice(outcome.numberTaken, used)) deps.log(line);
|
|
415
|
+
}
|
|
397
416
|
const safe = outcome.units.filter((u) => u.kind === "web");
|
|
398
417
|
const risky = outcome.units.filter((u) => u.kind !== "web");
|
|
399
418
|
const apply = /* @__PURE__ */ new Set();
|
|
400
419
|
if (outcome.units.length === 0) {
|
|
401
|
-
if (!outcome.localOnly.length && !outcome.statusNotMoved.length) deps.log("\nThe repo already matches intentdocs.");
|
|
420
|
+
if (!outcome.localOnly.length && !outcome.statusNotMoved.length && !outcome.numberTaken.length) deps.log("\nThe repo already matches intentdocs.");
|
|
402
421
|
} else if (deps.yes) {
|
|
403
422
|
for (const u of safe) apply.add(u);
|
|
404
423
|
if (risky.length) deps.log(`
|
|
@@ -469,8 +488,10 @@ async function pull(opts = {}) {
|
|
|
469
488
|
closePrompt();
|
|
470
489
|
}
|
|
471
490
|
}
|
|
491
|
+
|
|
472
492
|
export {
|
|
473
493
|
PullError,
|
|
474
|
-
|
|
475
|
-
runPull
|
|
494
|
+
numberTakenAdvice,
|
|
495
|
+
runPull,
|
|
496
|
+
pull
|
|
476
497
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ci
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2VM54R5K.js";
|
|
4
4
|
import "./chunk-KPQ42YE6.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-HWMSGXLQ.js";
|
|
6
6
|
import "./chunk-WRRUCCVZ.js";
|
|
7
7
|
import "./chunk-XZE2XP6O.js";
|
|
8
8
|
import "./chunk-UYTVTYNB.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
login,
|
|
4
|
+
logout
|
|
5
|
+
} from "./chunk-64I7RLP3.js";
|
|
2
6
|
import {
|
|
3
7
|
appendToNotes
|
|
4
8
|
} from "./chunk-GFKZ5CRL.js";
|
|
@@ -8,11 +12,11 @@ import {
|
|
|
8
12
|
} from "./chunk-UQDMUKLP.js";
|
|
9
13
|
import {
|
|
10
14
|
ci
|
|
11
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2VM54R5K.js";
|
|
12
16
|
import {
|
|
13
17
|
setup,
|
|
14
18
|
sync
|
|
15
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-2NSRHMTH.js";
|
|
16
20
|
import {
|
|
17
21
|
criterionPriority,
|
|
18
22
|
criterionStatusLabel,
|
|
@@ -31,11 +35,7 @@ import {
|
|
|
31
35
|
} from "./chunk-KPQ42YE6.js";
|
|
32
36
|
import {
|
|
33
37
|
scope
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
login,
|
|
37
|
-
logout
|
|
38
|
-
} from "./chunk-64I7RLP3.js";
|
|
38
|
+
} from "./chunk-7ONMS2RJ.js";
|
|
39
39
|
import {
|
|
40
40
|
amendDecision,
|
|
41
41
|
apiFetch,
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
readConfig,
|
|
58
58
|
requireConfig,
|
|
59
59
|
writeConfig
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-HWMSGXLQ.js";
|
|
61
61
|
import {
|
|
62
62
|
ask,
|
|
63
63
|
closePrompt,
|
|
@@ -304,7 +304,7 @@ Connecting to "${map2.title}"${project.workspace ? ` in ${project.workspace.name
|
|
|
304
304
|
await offerAllowList((q) => ask2(rl, q));
|
|
305
305
|
const setUpCi = await ask2(rl, " Set up CI test reporting now? It creates a key and adds the workflow. (y/N): ");
|
|
306
306
|
if (/^y(es)?$/i.test(setUpCi.trim())) {
|
|
307
|
-
const { ci: ci2 } = await import("./ci-
|
|
307
|
+
const { ci: ci2 } = await import("./ci-LG4NM2DU.js");
|
|
308
308
|
await ci2();
|
|
309
309
|
} else {
|
|
310
310
|
console.log(" You can run `npx intentdocs ci` any time to turn it on.\n");
|
|
@@ -1411,21 +1411,50 @@ async function add(title, opts) {
|
|
|
1411
1411
|
}
|
|
1412
1412
|
|
|
1413
1413
|
// src/lib/banner.ts
|
|
1414
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1415
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
1416
|
+
import { fileURLToPath } from "url";
|
|
1414
1417
|
import chalk from "chalk";
|
|
1415
|
-
|
|
1416
|
-
|
|
1418
|
+
|
|
1419
|
+
// src/lib/wordmark.ts
|
|
1420
|
+
var WORDMARK = `\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
1421
|
+
\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
|
|
1422
|
+
\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
1423
|
+
\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551
|
|
1424
|
+
\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551
|
|
1425
|
+
\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D`;
|
|
1426
|
+
|
|
1427
|
+
// src/lib/banner.ts
|
|
1428
|
+
function packageVersion() {
|
|
1429
|
+
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
1430
|
+
for (let i = 0; i < 4; i++) {
|
|
1431
|
+
const file = join5(dir, "package.json");
|
|
1432
|
+
if (existsSync5(file)) {
|
|
1433
|
+
const pkg = JSON.parse(readFileSync5(file, "utf8"));
|
|
1434
|
+
if (pkg.name === "intentdocs" && pkg.version) return pkg.version;
|
|
1435
|
+
}
|
|
1436
|
+
dir = dirname2(dir);
|
|
1437
|
+
}
|
|
1438
|
+
return "";
|
|
1439
|
+
}
|
|
1440
|
+
var version = packageVersion();
|
|
1441
|
+
var block = chalk.hex("#5B85FF");
|
|
1442
|
+
var shadow = chalk.hex("#1B4FD8");
|
|
1417
1443
|
var muted = chalk.dim;
|
|
1418
1444
|
var white = chalk.white.bold;
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
${
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
`;
|
|
1445
|
+
function paint(line) {
|
|
1446
|
+
return line.replace(/█+|[^█]+/g, (run) => run[0] === "\u2588" ? block(run) : shadow(run));
|
|
1447
|
+
}
|
|
1448
|
+
function art(columns) {
|
|
1449
|
+
if (columns < 86) return ` ${white("intentdocs")}`;
|
|
1450
|
+
return WORDMARK.split("\n").map((line) => ` ${paint(line)}`).join("\n");
|
|
1451
|
+
}
|
|
1427
1452
|
function printBanner(subtitle) {
|
|
1428
|
-
console.log(
|
|
1453
|
+
console.log(`
|
|
1454
|
+
${art(process.stdout.columns ?? 80)}
|
|
1455
|
+
`);
|
|
1456
|
+
console.log(` ${muted(`your idea, built to spec by your AI agent${version ? ` \xB7 v${version}` : ""}`)}
|
|
1457
|
+
`);
|
|
1429
1458
|
if (subtitle) {
|
|
1430
1459
|
console.log(` ${white(subtitle)}`);
|
|
1431
1460
|
console.log(` ${muted("\u2500".repeat(subtitle.length))}
|
|
@@ -1634,19 +1663,19 @@ async function start() {
|
|
|
1634
1663
|
closePrompt();
|
|
1635
1664
|
return;
|
|
1636
1665
|
}
|
|
1637
|
-
const { scope: scope2 } = await import("./scope-
|
|
1666
|
+
const { scope: scope2 } = await import("./scope-PFHPW6Y6.js");
|
|
1638
1667
|
await scope2(projectId);
|
|
1639
1668
|
}
|
|
1640
1669
|
|
|
1641
1670
|
// src/commands/propose.ts
|
|
1642
|
-
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync4, readFileSync as
|
|
1643
|
-
import { join as
|
|
1671
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync4, readFileSync as readFileSync6, existsSync as existsSync6, appendFileSync as appendFileSync2 } from "fs";
|
|
1672
|
+
import { join as join6 } from "path";
|
|
1644
1673
|
function ensureChangesIgnored(cwd = process.cwd()) {
|
|
1645
|
-
const gitignorePath =
|
|
1646
|
-
if (!
|
|
1647
|
-
const covered =
|
|
1674
|
+
const gitignorePath = join6(cwd, ".gitignore");
|
|
1675
|
+
if (!existsSync6(gitignorePath)) return;
|
|
1676
|
+
const covered = readFileSync6(gitignorePath, "utf-8").split(/\r?\n/).some((line) => /^\/?intent-changes\/?(\*\*?)?$/.test(line.trim()));
|
|
1648
1677
|
if (covered) return;
|
|
1649
|
-
const gi =
|
|
1678
|
+
const gi = readFileSync6(gitignorePath, "utf-8");
|
|
1650
1679
|
appendFileSync2(gitignorePath, `${gi.endsWith("\n") || gi === "" ? "" : "\n"}
|
|
1651
1680
|
# intentdocs local change proposals
|
|
1652
1681
|
intent-changes/
|
|
@@ -1744,8 +1773,8 @@ async function propose(changeName, opts = {}) {
|
|
|
1744
1773
|
\u2717 Failed to create stories: ${err instanceof Error ? err.message : String(err)}`);
|
|
1745
1774
|
console.log(" Saving proposal locally anyway...");
|
|
1746
1775
|
}
|
|
1747
|
-
const changesDir =
|
|
1748
|
-
if (!
|
|
1776
|
+
const changesDir = join6(process.cwd(), "intent-changes", slug);
|
|
1777
|
+
if (!existsSync6(changesDir)) mkdirSync2(changesDir, { recursive: true });
|
|
1749
1778
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1750
1779
|
const proposalMd = [
|
|
1751
1780
|
`# Proposal: ${changeName}`,
|
|
@@ -1780,7 +1809,7 @@ async function propose(changeName, opts = {}) {
|
|
|
1780
1809
|
`_Add notes here as you build._`,
|
|
1781
1810
|
``
|
|
1782
1811
|
].join("\n");
|
|
1783
|
-
writeFileSync4(
|
|
1812
|
+
writeFileSync4(join6(changesDir, "proposal.md"), proposalMd);
|
|
1784
1813
|
console.log(` \u2713 Saved intent-changes/${slug}/proposal.md`);
|
|
1785
1814
|
ensureChangesIgnored();
|
|
1786
1815
|
console.log(`
|
|
@@ -1797,7 +1826,7 @@ async function propose(changeName, opts = {}) {
|
|
|
1797
1826
|
closePrompt();
|
|
1798
1827
|
}
|
|
1799
1828
|
function parseProposalFile(filePath) {
|
|
1800
|
-
const raw =
|
|
1829
|
+
const raw = readFileSync6(filePath, "utf-8");
|
|
1801
1830
|
const lines = raw.split("\n");
|
|
1802
1831
|
let changeName = "";
|
|
1803
1832
|
let problem = "";
|
|
@@ -1871,7 +1900,7 @@ function parseProposalFile(filePath) {
|
|
|
1871
1900
|
return { changeName, problem, solution, activity, priority, stories: stories2 };
|
|
1872
1901
|
}
|
|
1873
1902
|
async function proposeFromFile(filePath, config, nameOverride) {
|
|
1874
|
-
if (!
|
|
1903
|
+
if (!existsSync6(filePath)) {
|
|
1875
1904
|
console.error(`
|
|
1876
1905
|
File not found: ${filePath}
|
|
1877
1906
|
`);
|
|
@@ -1907,8 +1936,8 @@ async function proposeFromFile(filePath, config, nameOverride) {
|
|
|
1907
1936
|
\u2717 Failed to create stories: ${err instanceof Error ? err.message : String(err)}`);
|
|
1908
1937
|
console.log(" Saving proposal locally anyway...");
|
|
1909
1938
|
}
|
|
1910
|
-
const changesDir =
|
|
1911
|
-
if (!
|
|
1939
|
+
const changesDir = join6(process.cwd(), "intent-changes", slug);
|
|
1940
|
+
if (!existsSync6(changesDir)) mkdirSync2(changesDir, { recursive: true });
|
|
1912
1941
|
const proposalMd = [
|
|
1913
1942
|
`# Proposal: ${changeName}`,
|
|
1914
1943
|
``,
|
|
@@ -1939,7 +1968,7 @@ async function proposeFromFile(filePath, config, nameOverride) {
|
|
|
1939
1968
|
].join("\n");
|
|
1940
1969
|
})
|
|
1941
1970
|
].join("\n");
|
|
1942
|
-
writeFileSync4(
|
|
1971
|
+
writeFileSync4(join6(changesDir, "proposal.md"), proposalMd);
|
|
1943
1972
|
console.log(` \u2713 Saved intent-changes/${slug}/proposal.md`);
|
|
1944
1973
|
ensureChangesIgnored();
|
|
1945
1974
|
console.log(`
|
|
@@ -2971,9 +3000,9 @@ Registering intentdocs MCP with OpenClaw...`);
|
|
|
2971
3000
|
|
|
2972
3001
|
// src/index.ts
|
|
2973
3002
|
var require2 = createRequire2(import.meta.url);
|
|
2974
|
-
var { version } = require2("../package.json");
|
|
3003
|
+
var { version: version2 } = require2("../package.json");
|
|
2975
3004
|
var program = new Command();
|
|
2976
|
-
program.name("intentdocs").description("Write specs, map stories, ship with AI \u2014 from your terminal").version(
|
|
3005
|
+
program.name("intentdocs").description("Write specs, map stories, ship with AI \u2014 from your terminal").version(version2);
|
|
2977
3006
|
program.command("login").description("Log in to intentdocs (opens browser)").action(() => void login());
|
|
2978
3007
|
program.command("logout").description("Log out of intentdocs").action(() => void logout());
|
|
2979
3008
|
var keys = program.command("keys").description("Manage your Anthropic (sk-ant-), xAI (xai-), or OpenAI (sk- / sk-proj-) API key \u2014 unlock AI features on any plan");
|
|
@@ -3019,10 +3048,10 @@ program.command("projects").description("List the projects your token can reach
|
|
|
3019
3048
|
import("./projects-AYAYVFKL.js").then((m) => void m.projects());
|
|
3020
3049
|
});
|
|
3021
3050
|
program.command("push").description("Upload this repo's nikOS intent/ folder: log in, create the project, and link the repo").action(() => {
|
|
3022
|
-
import("./push-
|
|
3051
|
+
import("./push-62T2TMKN.js").then((m) => m.push());
|
|
3023
3052
|
});
|
|
3024
3053
|
program.command("pull").description("Show web edits to this repo's feature files as a diff, then write the ones you agree to").option("-y, --yes", "write web changes without asking (never settles a story changed on both sides)").action((opts) => {
|
|
3025
|
-
import("./pull-
|
|
3054
|
+
import("./pull-6GAAR6NP.js").then((m) => m.pull(opts));
|
|
3026
3055
|
});
|
|
3027
3056
|
program.command("init [token]").description("Connect this project to a intentdocs story map").action((token) => void init(token));
|
|
3028
3057
|
program.command("sync").description("Refresh INTENT.md from the live story map").option("--context", "Refresh only the CLAUDE.md/AGENTS.md context file (not stories)").action((opts) => void sync(opts));
|
|
@@ -3037,36 +3066,36 @@ program.command("done <id>").description("Mark a story as done (accepts its key
|
|
|
3037
3066
|
program.command("stop <id>").description("Stop development of an in-progress story (resets to todo, signals agents to stop; accepts its key or an ID prefix)").action((id) => void stop(id));
|
|
3038
3067
|
program.command("add <title>").description("Create a new story").option("-a, --activity <activity>", "Activity to add the story under").option("-p, --priority <priority>", "Priority: must, should, could", "should").option("-e, --effort <effort>", "Effort: S, M, L, XL", "M").action((title, opts) => void add(title, opts));
|
|
3039
3068
|
var decide = program.command("decide [title]").description("Log an architectural or product decision").option("-d, --description <desc>", "Decision description").option("-c, --category <cat>", "Category: architecture, product, technical, trade-off", "technical").option("-s, --story <id>", "Link to a story (its key like PB-42, or an ID prefix)").action((title, opts) => {
|
|
3040
|
-
import("./log-
|
|
3069
|
+
import("./log-ELEPANI3.js").then((m) => void m.logDecision(title, opts));
|
|
3041
3070
|
});
|
|
3042
3071
|
decide.command("list").description("List logged decisions (id, category, title)").action(() => {
|
|
3043
|
-
import("./log-
|
|
3072
|
+
import("./log-ELEPANI3.js").then((m) => void m.listLoggedDecisions());
|
|
3044
3073
|
});
|
|
3045
3074
|
decide.command("amend <id>").description("Amend a logged decision's title, description, or category (accepts an ID prefix)").option("-t, --title <title>", "New title").option("-d, --description <desc>", "New description").option("-c, --category <cat>", "New category: architecture, product, technical, trade-off").action((id, opts) => {
|
|
3046
|
-
import("./log-
|
|
3075
|
+
import("./log-ELEPANI3.js").then((m) => void m.amendDecision(id, opts));
|
|
3047
3076
|
});
|
|
3048
3077
|
decide.command("delete <id>").alias("retract").description("Retract a logged decision \u2014 soft-deleted and audited, not removed (accepts an ID prefix)").option("-r, --reason <reason>", "Why this decision is being retracted").option("-y, --yes", "Skip the confirmation prompt (required when there's no TTY)").action((id, opts) => {
|
|
3049
|
-
import("./log-
|
|
3078
|
+
import("./log-ELEPANI3.js").then((m) => void m.deleteDecision(id, opts));
|
|
3050
3079
|
});
|
|
3051
3080
|
program.command("note <storyId> [note]").description("Add an implementation note to a story (appended to its notes)").action((storyId, note) => {
|
|
3052
|
-
import("./log-
|
|
3081
|
+
import("./log-ELEPANI3.js").then((m) => void m.logNote(storyId, note));
|
|
3053
3082
|
});
|
|
3054
3083
|
program.command("example").description("Add a few-shot reference pattern (before/after code) to the project").action(() => void example());
|
|
3055
3084
|
program.command("complexity [storyId]").description("Analyze story complexity with AI \u2014 scores, risks, effort estimates").action((id) => {
|
|
3056
|
-
import("./complexity-
|
|
3085
|
+
import("./complexity-6XVLG3EH.js").then((m) => void m.complexity(id));
|
|
3057
3086
|
});
|
|
3058
3087
|
program.command("research [query]").description("Research a topic with AI using your project context").action((query) => {
|
|
3059
|
-
import("./research-
|
|
3088
|
+
import("./research-XMUAQOVB.js").then((m) => void m.research(query));
|
|
3060
3089
|
});
|
|
3061
3090
|
program.command("import [file]").description("Import a PRD or spec into your story map as stories (reads standard input when no file is given; needs --yes then)").option("-y, --yes", "Import without asking for confirmation (required when reading from standard input)").action((file, opts) => {
|
|
3062
|
-
import("./import-prd-
|
|
3091
|
+
import("./import-prd-DTO5LTWA.js").then((m) => void m.importPrd(file, opts));
|
|
3063
3092
|
});
|
|
3064
3093
|
var map = program.command("map").description("Import or extract story maps from codebases");
|
|
3065
3094
|
map.command("extract").description("Output a prompt for your coding agent to extract a story map from an existing codebase").action(() => {
|
|
3066
|
-
import("./map-extract-
|
|
3095
|
+
import("./map-extract-MUGIIXTP.js").then((m) => void m.mapExtract());
|
|
3067
3096
|
});
|
|
3068
3097
|
map.command("import <file>").description("Import a storymap.json file generated by your coding agent").option("--yes", "Skip confirmation prompt").action((file, opts) => {
|
|
3069
|
-
import("./map-import-
|
|
3098
|
+
import("./map-import-TDBELC77.js").then((m) => void m.mapImport(file, opts));
|
|
3070
3099
|
});
|
|
3071
3100
|
map.command("schema").description("Print the JSON Schema for storymap.json").action(() => {
|
|
3072
3101
|
import("./map-schema-5BEIJM2J.js").then((m) => void m.mapSchema());
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PullError,
|
|
3
|
+
numberTakenAdvice,
|
|
4
|
+
pull,
|
|
5
|
+
runPull
|
|
6
|
+
} from "./chunk-JDK3RCQU.js";
|
|
7
|
+
import "./chunk-KTGQO3AE.js";
|
|
8
|
+
import "./chunk-HWMSGXLQ.js";
|
|
9
|
+
import "./chunk-WRRUCCVZ.js";
|
|
10
|
+
import "./chunk-XZE2XP6O.js";
|
|
11
|
+
import "./chunk-UYTVTYNB.js";
|
|
12
|
+
export {
|
|
13
|
+
PullError,
|
|
14
|
+
numberTakenAdvice,
|
|
15
|
+
pull,
|
|
16
|
+
runPull
|
|
17
|
+
};
|
|
@@ -2,17 +2,23 @@ import {
|
|
|
2
2
|
login
|
|
3
3
|
} from "./chunk-64I7RLP3.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
numberTakenAdvice
|
|
6
|
+
} from "./chunk-JDK3RCQU.js";
|
|
7
|
+
import {
|
|
8
|
+
checkoutMismatch,
|
|
9
|
+
listStories
|
|
6
10
|
} from "./chunk-KTGQO3AE.js";
|
|
7
11
|
import {
|
|
8
12
|
checkoutConfig,
|
|
13
|
+
featureFiles,
|
|
14
|
+
findIntentDir,
|
|
9
15
|
readConfig,
|
|
10
16
|
readIntentFolder,
|
|
11
17
|
readSyncBase,
|
|
12
18
|
specOfPushStory,
|
|
13
19
|
writeConfig,
|
|
14
20
|
writeSyncBase
|
|
15
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HWMSGXLQ.js";
|
|
16
22
|
import {
|
|
17
23
|
choose,
|
|
18
24
|
closePrompt,
|
|
@@ -36,12 +42,13 @@ var PUSH_ENDPOINTS = {
|
|
|
36
42
|
projectMaps: (projectId) => `/api/cli/projects/${encodeURIComponent(projectId)}/maps`
|
|
37
43
|
};
|
|
38
44
|
var PushApiError = class extends Error {
|
|
39
|
-
constructor(message, status, code = null, problems = [], projectId = null) {
|
|
45
|
+
constructor(message, status, code = null, problems = [], projectId = null, keys = []) {
|
|
40
46
|
super(message);
|
|
41
47
|
this.status = status;
|
|
42
48
|
this.code = code;
|
|
43
49
|
this.problems = problems;
|
|
44
50
|
this.projectId = projectId;
|
|
51
|
+
this.keys = keys;
|
|
45
52
|
this.name = "PushApiError";
|
|
46
53
|
}
|
|
47
54
|
};
|
|
@@ -56,7 +63,8 @@ async function call(fetcher, path, init, what) {
|
|
|
56
63
|
res.status,
|
|
57
64
|
typeof body.error === "string" ? body.error : null,
|
|
58
65
|
Array.isArray(body.problems) ? body.problems : [],
|
|
59
|
-
body.project_id ?? null
|
|
66
|
+
body.project_id ?? null,
|
|
67
|
+
Array.isArray(body.keys) ? body.keys.filter((k) => typeof k === "string") : []
|
|
60
68
|
);
|
|
61
69
|
}
|
|
62
70
|
return await res.json();
|
|
@@ -169,6 +177,13 @@ function openBrowser(url) {
|
|
|
169
177
|
const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
170
178
|
exec(cmd);
|
|
171
179
|
}
|
|
180
|
+
async function numberTakenSteps(keys, localKeys, remoteKeys) {
|
|
181
|
+
const remote = await remoteKeys().catch(() => []);
|
|
182
|
+
return [
|
|
183
|
+
...numberTakenAdvice(keys, [...keys, ...localKeys, ...remote]).slice(1),
|
|
184
|
+
" Changes to stories intentdocs already had may have been saved; pushing again is safe."
|
|
185
|
+
];
|
|
186
|
+
}
|
|
172
187
|
async function push() {
|
|
173
188
|
const deps = {
|
|
174
189
|
cwd: process.cwd(),
|
|
@@ -201,6 +216,11 @@ async function push() {
|
|
|
201
216
|
if (err instanceof PushError) {
|
|
202
217
|
console.error(`\u2717 ${err.message}`);
|
|
203
218
|
for (const d of err.details) console.error(` - ${d}`);
|
|
219
|
+
} else if (err instanceof PushApiError && err.code === "NUMBER_TAKEN" && err.keys.length) {
|
|
220
|
+
console.error(`\u2717 ${err.message}`);
|
|
221
|
+
const config = readConfig();
|
|
222
|
+
const remote = async () => config?.mapId ? (await listStories(config)).stories.map((s) => s.key ?? "") : [];
|
|
223
|
+
for (const line of await numberTakenSteps(err.keys, featureFiles(findIntentDir(deps.cwd)).keys(), remote)) console.error(line);
|
|
204
224
|
} else if (err instanceof PushApiError) {
|
|
205
225
|
console.error(`\u2717 ${err.message}`);
|
|
206
226
|
for (const p of err.problems) console.error(` - ${p}`);
|
|
@@ -214,6 +234,7 @@ async function push() {
|
|
|
214
234
|
}
|
|
215
235
|
export {
|
|
216
236
|
PushError,
|
|
237
|
+
numberTakenSteps,
|
|
217
238
|
push,
|
|
218
239
|
pushNotes,
|
|
219
240
|
runPush
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectCheckout,
|
|
3
3
|
scope
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7ONMS2RJ.js";
|
|
5
5
|
import "./chunk-KTGQO3AE.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-HWMSGXLQ.js";
|
|
7
7
|
import "./chunk-WRRUCCVZ.js";
|
|
8
8
|
import "./chunk-XZE2XP6O.js";
|
|
9
9
|
import "./chunk-UYTVTYNB.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
setup
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2NSRHMTH.js";
|
|
4
4
|
import "./chunk-BNEU6TLJ.js";
|
|
5
5
|
import "./chunk-LQTPZL2Y.js";
|
|
6
6
|
import "./chunk-KPQ42YE6.js";
|
|
7
7
|
import "./chunk-KTGQO3AE.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-HWMSGXLQ.js";
|
|
9
9
|
import "./chunk-WRRUCCVZ.js";
|
|
10
10
|
import "./chunk-XZE2XP6O.js";
|
|
11
11
|
import "./chunk-UYTVTYNB.js";
|