@delfini/cli 0.1.1 → 0.2.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.
@@ -10,7 +10,7 @@ import {
10
10
  normalizeDocScope,
11
11
  validateAndReconcile,
12
12
  validateDocScopeEntry
13
- } from "./chunk-MUW24ZC4.js";
13
+ } from "./chunk-LJKEHO6F.js";
14
14
 
15
15
  // src/cli.ts
16
16
  init_esm_shims();
@@ -170,6 +170,199 @@ import { dirname, join as join2, resolve } from "path";
170
170
  import { createInterface } from "readline/promises";
171
171
  import { fileURLToPath } from "url";
172
172
 
173
+ // src/doc-scope.ts
174
+ init_esm_shims();
175
+ import { promises as fs } from "fs";
176
+ import path from "path";
177
+ import { glob } from "tinyglobby";
178
+ var DOC_SCOPE_RELATIVE_PATH = ".claude/skills/delfini/doc-scope.json";
179
+ var DOC_SCOPE_VERSION = 1;
180
+ var DOC_SCOPE_VERSION_MISMATCH_MESSAGE = "your doc-scope.json is for a newer @delfini/cli; please upgrade.";
181
+ var REPO_ROOT_REL = ".";
182
+ var DocScopeVersionMismatchError = class extends Error {
183
+ code = "DOC_SCOPE_VERSION_MISMATCH";
184
+ constructor(message = DOC_SCOPE_VERSION_MISMATCH_MESSAGE) {
185
+ super(message);
186
+ this.name = "DocScopeVersionMismatchError";
187
+ }
188
+ };
189
+ var DocScopeCorruptError = class extends Error {
190
+ code = "DOC_SCOPE_CORRUPT";
191
+ constructor(message) {
192
+ super(message);
193
+ this.name = "DocScopeCorruptError";
194
+ }
195
+ };
196
+ var DocScopeValidationError = class extends Error {
197
+ code = "DOC_SCOPE_VALIDATION";
198
+ constructor(message) {
199
+ super(message);
200
+ this.name = "DocScopeValidationError";
201
+ }
202
+ };
203
+ var docScopeSchemaV1 = external_exports.object({
204
+ version: external_exports.literal(1),
205
+ doc_scope: external_exports.array(external_exports.string().min(1))
206
+ });
207
+ var versionProbeSchema = external_exports.object({
208
+ version: external_exports.number().int().positive()
209
+ });
210
+ async function readDocScope(repoRoot) {
211
+ const root = repoRoot ?? await getRepoRoot();
212
+ const target = path.join(root, DOC_SCOPE_RELATIVE_PATH);
213
+ let raw;
214
+ try {
215
+ raw = await fs.readFile(target, "utf8");
216
+ } catch (err) {
217
+ if (isNoEntError(err)) return null;
218
+ throw err;
219
+ }
220
+ let parsed;
221
+ try {
222
+ parsed = JSON.parse(raw);
223
+ } catch (err) {
224
+ throw new DocScopeCorruptError(
225
+ `${DOC_SCOPE_RELATIVE_PATH} is malformed: ${err.message}`
226
+ );
227
+ }
228
+ const probe = versionProbeSchema.safeParse(parsed);
229
+ if (probe.success && probe.data.version > DOC_SCOPE_VERSION) {
230
+ throw new DocScopeVersionMismatchError();
231
+ }
232
+ const result = docScopeSchemaV1.safeParse(parsed);
233
+ if (!result.success) {
234
+ throw new DocScopeCorruptError(
235
+ `${DOC_SCOPE_RELATIVE_PATH} is malformed: ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
236
+ );
237
+ }
238
+ return result.data;
239
+ }
240
+ async function writeDocScope(paths, options) {
241
+ const root = options?.repoRoot ?? await getRepoRoot();
242
+ if (!Array.isArray(paths) || paths.length === 0) {
243
+ throw new DocScopeValidationError("at least one path is required");
244
+ }
245
+ const errors = [];
246
+ for (const entry of paths) {
247
+ const err = validateDocScopeEntry(entry, REPO_ROOT_REL);
248
+ if (err !== null) errors.push(err);
249
+ }
250
+ if (errors.length > 0) {
251
+ throw new DocScopeValidationError(
252
+ `${DOC_SCOPE_RELATIVE_PATH}: invalid path(s):
253
+ ${errors.map((e) => ` - ${e}`).join("\n")}`
254
+ );
255
+ }
256
+ const normalised = normalizeDocScope(paths);
257
+ if (normalised.length === 0) {
258
+ throw new DocScopeValidationError(
259
+ `${DOC_SCOPE_RELATIVE_PATH}: every entry collapses to an empty scope after normalisation (e.g. '.', './', 'docs/..') \u2014 provide at least one concrete path`
260
+ );
261
+ }
262
+ const target = path.join(root, DOC_SCOPE_RELATIVE_PATH);
263
+ await fs.mkdir(path.dirname(target), { recursive: true });
264
+ const payload = { version: DOC_SCOPE_VERSION, doc_scope: normalised };
265
+ const json = `${JSON.stringify(payload, null, 2)}
266
+ `;
267
+ await fs.writeFile(target, json, "utf8");
268
+ }
269
+ async function docScopeExists(repoRoot) {
270
+ const root = repoRoot ?? await getRepoRoot();
271
+ const target = path.join(root, DOC_SCOPE_RELATIVE_PATH);
272
+ try {
273
+ const st = await fs.stat(target);
274
+ return st.isFile();
275
+ } catch {
276
+ return false;
277
+ }
278
+ }
279
+ async function deleteDocScope(repoRoot) {
280
+ const root = repoRoot ?? await getRepoRoot();
281
+ const target = path.join(root, DOC_SCOPE_RELATIVE_PATH);
282
+ try {
283
+ await fs.unlink(target);
284
+ } catch (err) {
285
+ if (!isNoEntError(err)) throw err;
286
+ }
287
+ }
288
+ async function expandDocScope(paths, repoRoot) {
289
+ const root = repoRoot ?? await getRepoRoot();
290
+ const normalisedRoot = path.resolve(root);
291
+ const found = /* @__PURE__ */ new Set();
292
+ const missing = [];
293
+ for (const rawEntry of paths) {
294
+ if (typeof rawEntry !== "string") continue;
295
+ const normalised = normalizeDocScope([rawEntry]);
296
+ if (normalised.length === 0) {
297
+ if (rawEntry.trim().length > 0) missing.push(rawEntry);
298
+ continue;
299
+ }
300
+ const entry = normalised[0];
301
+ if (validateDocScopeEntry(entry, REPO_ROOT_REL) !== null) {
302
+ missing.push(rawEntry);
303
+ continue;
304
+ }
305
+ if (classifyEntry(entry) === "glob") {
306
+ const matches = await glob(entry, {
307
+ cwd: root,
308
+ absolute: true,
309
+ onlyFiles: true,
310
+ dot: false,
311
+ // Case-folding parity with the engine predicate (`nocase: true`).
312
+ caseSensitiveMatch: false,
313
+ // Migrating from fast-glob — disable tinyglobby's directory-pattern
314
+ // auto-expansion so a glob like `packages/*/README.md` keeps exact
315
+ // fast-glob semantics.
316
+ expandDirectories: false
317
+ });
318
+ const inRoot = matches.filter((m) => isInsideRoot(m, normalisedRoot));
319
+ if (inRoot.length === 0) {
320
+ missing.push(rawEntry);
321
+ } else {
322
+ for (const m of inRoot) found.add(m);
323
+ }
324
+ continue;
325
+ }
326
+ const absolute = path.resolve(root, entry);
327
+ let stat;
328
+ try {
329
+ stat = await fs.stat(absolute);
330
+ } catch (err) {
331
+ if (isNoEntError(err)) {
332
+ missing.push(rawEntry);
333
+ continue;
334
+ }
335
+ throw err;
336
+ }
337
+ if (stat.isDirectory()) {
338
+ const children = await glob("**/*.md", {
339
+ cwd: absolute,
340
+ absolute: true,
341
+ onlyFiles: true,
342
+ caseSensitiveMatch: false,
343
+ dot: false,
344
+ expandDirectories: false
345
+ });
346
+ for (const c of children) {
347
+ if (isInsideRoot(c, normalisedRoot)) found.add(c);
348
+ }
349
+ } else if (stat.isFile()) {
350
+ if (isInsideRoot(absolute, normalisedRoot)) found.add(absolute);
351
+ } else {
352
+ missing.push(rawEntry);
353
+ }
354
+ }
355
+ const files = Array.from(found).sort();
356
+ return { files, missingPaths: missing };
357
+ }
358
+ function isNoEntError(err) {
359
+ return typeof err === "object" && err !== null && err.code === "ENOENT";
360
+ }
361
+ function isInsideRoot(absolute, normalisedRoot) {
362
+ const resolved = path.resolve(absolute);
363
+ return resolved === normalisedRoot || resolved.startsWith(normalisedRoot + path.sep);
364
+ }
365
+
173
366
  // src/trace.ts
174
367
  init_esm_shims();
175
368
  import {
@@ -264,8 +457,17 @@ var CLAUDE_MD_FILENAME = "CLAUDE.md";
264
457
  var SUPPORTED_TOOL = "CLAUDE";
265
458
  var TEMPLATES_DIR = resolveTemplatesDir();
266
459
  function resolveTemplatesDir() {
267
- const here = dirname(fileURLToPath(import.meta.url));
268
- return resolve(here, "..", "..", "templates");
460
+ let dir = dirname(fileURLToPath(import.meta.url));
461
+ for (let i = 0; i < 5; i++) {
462
+ const candidate = resolve(dir, "templates");
463
+ if (existsSync2(join2(candidate, "SKILL.md"))) {
464
+ return candidate;
465
+ }
466
+ const parent = dirname(dir);
467
+ if (parent === dir) break;
468
+ dir = parent;
469
+ }
470
+ throw new Error("templates/ directory not found relative to the CLI module");
269
471
  }
270
472
  async function runInstall(targetPath, options) {
271
473
  const tool = options?.tool ?? SUPPORTED_TOOL;
@@ -276,9 +478,74 @@ async function runInstall(targetPath, options) {
276
478
  const resolvedTarget = resolve(process.cwd(), targetPath);
277
479
  const repoRoot = await getRepoRoot(resolvedTarget);
278
480
  writeSkillTemplate(repoRoot, logger);
481
+ await applyDocScope(repoRoot, logger, options?.provideDocScope);
279
482
  await applyAutoInvokeDecision(repoRoot, logger, options?.confirmAutoInvoke);
280
483
  appendGitignoreLine(repoRoot, logger);
281
484
  }
485
+ function parseScopeInput(answer) {
486
+ return answer.split(/[\s,]+/u).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
487
+ }
488
+ function sanitiseScope(paths) {
489
+ return paths.map((entry) => entry.trim()).filter((entry) => entry.length > 0);
490
+ }
491
+ async function applyDocScope(repoRoot, logger, provideDocScope) {
492
+ const target = join2(repoRoot, DOC_SCOPE_RELATIVE_PATH);
493
+ if (provideDocScope) {
494
+ const paths2 = sanitiseScope(await provideDocScope());
495
+ if (paths2.length === 0) {
496
+ log(logger, `doc-scope.json \u2192 ${target} (no paths provided, no change)`);
497
+ return;
498
+ }
499
+ await persistDocScope(repoRoot, logger, target, paths2);
500
+ return;
501
+ }
502
+ if (await docScopeExists(repoRoot)) {
503
+ log(logger, `doc-scope.json \u2192 ${target} (already configured, no change)`);
504
+ return;
505
+ }
506
+ if (!process.stdin.isTTY) {
507
+ log(
508
+ logger,
509
+ `doc-scope.json \u2192 ${target} (non-interactive shell: scope prompt skipped, no change)`
510
+ );
511
+ return;
512
+ }
513
+ const paths = await promptDocScope();
514
+ if (paths.length === 0) {
515
+ log(
516
+ logger,
517
+ `doc-scope.json \u2192 ${target} (no paths provided, no change \u2014 first /delfini run will prompt)`
518
+ );
519
+ return;
520
+ }
521
+ await persistDocScope(repoRoot, logger, target, paths);
522
+ }
523
+ async function promptDocScope() {
524
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
525
+ try {
526
+ const answer = await rl.question(
527
+ "Which docs should Delfini track? Enter one or more paths \u2014 directories (recursive .md scan), files, or globs, space- or comma-separated (e.g. `docs/ specs/architecture.md packages/*/README.md`). Leave blank to skip: "
528
+ );
529
+ return parseScopeInput(answer);
530
+ } finally {
531
+ rl.close();
532
+ }
533
+ }
534
+ async function persistDocScope(repoRoot, logger, target, paths) {
535
+ try {
536
+ await writeDocScope(paths, { repoRoot });
537
+ log(logger, `doc-scope.json \u2192 ${target} (wrote ${paths.length} path(s))`);
538
+ } catch (err) {
539
+ if (err instanceof DocScopeValidationError) {
540
+ log(
541
+ logger,
542
+ `doc-scope.json \u2192 ${target} (skipped \u2014 ${err.message}). Fix the path(s) and re-run \`delfini install\`, edit the file directly, or set the scope on the first /delfini run.`
543
+ );
544
+ return;
545
+ }
546
+ throw err;
547
+ }
548
+ }
282
549
  function parseYesNo(answer) {
283
550
  const normalised = answer.trim().toLowerCase();
284
551
  return normalised === "y" || normalised === "yes";
@@ -394,8 +661,8 @@ function log(logger, message) {
394
661
 
395
662
  // src/commands/local-finalize.ts
396
663
  init_esm_shims();
397
- import { promises as fs } from "fs";
398
- import path from "path";
664
+ import { promises as fs2 } from "fs";
665
+ import path2 from "path";
399
666
  var TRACE_DIR_RELATIVE = ".delfini-trace";
400
667
  var ANALYSIS_INPUT_FILENAME = "analysis-input.json";
401
668
  var REPORT_FILENAME = "report.md";
@@ -416,10 +683,10 @@ async function runLocalFinalize(options) {
416
683
  const stderr = options.stderr ?? process.stderr;
417
684
  const stdout = options.stdout ?? process.stdout;
418
685
  const repoRoot = options.repoRoot ?? await getRepoRoot();
419
- const findingsPath = path.isAbsolute(options.findingsPath) ? options.findingsPath : path.join(repoRoot, options.findingsPath);
686
+ const findingsPath = path2.isAbsolute(options.findingsPath) ? options.findingsPath : path2.join(repoRoot, options.findingsPath);
420
687
  let findingsContent;
421
688
  try {
422
- findingsContent = await fs.readFile(findingsPath, "utf8");
689
+ findingsContent = await fs2.readFile(findingsPath, "utf8");
423
690
  } catch (err) {
424
691
  return emitSchemaValidationError(stderr, [
425
692
  {
@@ -439,10 +706,10 @@ async function runLocalFinalize(options) {
439
706
  }
440
707
  ]);
441
708
  }
442
- const analysisInputPath = path.join(repoRoot, TRACE_DIR_RELATIVE, ANALYSIS_INPUT_FILENAME);
709
+ const analysisInputPath = path2.join(repoRoot, TRACE_DIR_RELATIVE, ANALYSIS_INPUT_FILENAME);
443
710
  let docs;
444
711
  try {
445
- const raw = await fs.readFile(analysisInputPath, "utf8");
712
+ const raw = await fs2.readFile(analysisInputPath, "utf8");
446
713
  const parsed = JSON.parse(raw);
447
714
  if (!Array.isArray(parsed.docs)) {
448
715
  return emitSchemaValidationError(stderr, [
@@ -657,201 +924,6 @@ import path3 from "path";
657
924
  import { fileURLToPath as fileURLToPath2 } from "url";
658
925
  import { promisify } from "util";
659
926
  import simpleGit3 from "simple-git";
660
-
661
- // src/doc-scope.ts
662
- init_esm_shims();
663
- import { promises as fs2 } from "fs";
664
- import path2 from "path";
665
- import { glob } from "tinyglobby";
666
- var DOC_SCOPE_RELATIVE_PATH = ".claude/skills/delfini/doc-scope.json";
667
- var DOC_SCOPE_VERSION = 1;
668
- var DOC_SCOPE_VERSION_MISMATCH_MESSAGE = "your doc-scope.json is for a newer @delfini/cli; please upgrade.";
669
- var REPO_ROOT_REL = ".";
670
- var DocScopeVersionMismatchError = class extends Error {
671
- code = "DOC_SCOPE_VERSION_MISMATCH";
672
- constructor(message = DOC_SCOPE_VERSION_MISMATCH_MESSAGE) {
673
- super(message);
674
- this.name = "DocScopeVersionMismatchError";
675
- }
676
- };
677
- var DocScopeCorruptError = class extends Error {
678
- code = "DOC_SCOPE_CORRUPT";
679
- constructor(message) {
680
- super(message);
681
- this.name = "DocScopeCorruptError";
682
- }
683
- };
684
- var DocScopeValidationError = class extends Error {
685
- code = "DOC_SCOPE_VALIDATION";
686
- constructor(message) {
687
- super(message);
688
- this.name = "DocScopeValidationError";
689
- }
690
- };
691
- var docScopeSchemaV1 = external_exports.object({
692
- version: external_exports.literal(1),
693
- doc_scope: external_exports.array(external_exports.string().min(1))
694
- });
695
- var versionProbeSchema = external_exports.object({
696
- version: external_exports.number().int().positive()
697
- });
698
- async function readDocScope(repoRoot) {
699
- const root = repoRoot ?? await getRepoRoot();
700
- const target = path2.join(root, DOC_SCOPE_RELATIVE_PATH);
701
- let raw;
702
- try {
703
- raw = await fs2.readFile(target, "utf8");
704
- } catch (err) {
705
- if (isNoEntError(err)) return null;
706
- throw err;
707
- }
708
- let parsed;
709
- try {
710
- parsed = JSON.parse(raw);
711
- } catch (err) {
712
- throw new DocScopeCorruptError(
713
- `${DOC_SCOPE_RELATIVE_PATH} is malformed: ${err.message}`
714
- );
715
- }
716
- const probe = versionProbeSchema.safeParse(parsed);
717
- if (probe.success && probe.data.version > DOC_SCOPE_VERSION) {
718
- throw new DocScopeVersionMismatchError();
719
- }
720
- const result = docScopeSchemaV1.safeParse(parsed);
721
- if (!result.success) {
722
- throw new DocScopeCorruptError(
723
- `${DOC_SCOPE_RELATIVE_PATH} is malformed: ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
724
- );
725
- }
726
- return result.data;
727
- }
728
- async function writeDocScope(paths, options) {
729
- const root = options?.repoRoot ?? await getRepoRoot();
730
- if (!Array.isArray(paths) || paths.length === 0) {
731
- throw new DocScopeValidationError("at least one path is required");
732
- }
733
- const errors = [];
734
- for (const entry of paths) {
735
- const err = validateDocScopeEntry(entry, REPO_ROOT_REL);
736
- if (err !== null) errors.push(err);
737
- }
738
- if (errors.length > 0) {
739
- throw new DocScopeValidationError(
740
- `${DOC_SCOPE_RELATIVE_PATH}: invalid path(s):
741
- ${errors.map((e) => ` - ${e}`).join("\n")}`
742
- );
743
- }
744
- const normalised = normalizeDocScope(paths);
745
- if (normalised.length === 0) {
746
- throw new DocScopeValidationError(
747
- `${DOC_SCOPE_RELATIVE_PATH}: every entry collapses to an empty scope after normalisation (e.g. '.', './', 'docs/..') \u2014 provide at least one concrete path`
748
- );
749
- }
750
- const target = path2.join(root, DOC_SCOPE_RELATIVE_PATH);
751
- await fs2.mkdir(path2.dirname(target), { recursive: true });
752
- const payload = { version: DOC_SCOPE_VERSION, doc_scope: normalised };
753
- const json = `${JSON.stringify(payload, null, 2)}
754
- `;
755
- await fs2.writeFile(target, json, "utf8");
756
- }
757
- async function docScopeExists(repoRoot) {
758
- const root = repoRoot ?? await getRepoRoot();
759
- const target = path2.join(root, DOC_SCOPE_RELATIVE_PATH);
760
- try {
761
- const st = await fs2.stat(target);
762
- return st.isFile();
763
- } catch {
764
- return false;
765
- }
766
- }
767
- async function deleteDocScope(repoRoot) {
768
- const root = repoRoot ?? await getRepoRoot();
769
- const target = path2.join(root, DOC_SCOPE_RELATIVE_PATH);
770
- try {
771
- await fs2.unlink(target);
772
- } catch (err) {
773
- if (!isNoEntError(err)) throw err;
774
- }
775
- }
776
- async function expandDocScope(paths, repoRoot) {
777
- const root = repoRoot ?? await getRepoRoot();
778
- const normalisedRoot = path2.resolve(root);
779
- const found = /* @__PURE__ */ new Set();
780
- const missing = [];
781
- for (const rawEntry of paths) {
782
- if (typeof rawEntry !== "string") continue;
783
- const normalised = normalizeDocScope([rawEntry]);
784
- if (normalised.length === 0) {
785
- if (rawEntry.trim().length > 0) missing.push(rawEntry);
786
- continue;
787
- }
788
- const entry = normalised[0];
789
- if (validateDocScopeEntry(entry, REPO_ROOT_REL) !== null) {
790
- missing.push(rawEntry);
791
- continue;
792
- }
793
- if (classifyEntry(entry) === "glob") {
794
- const matches = await glob(entry, {
795
- cwd: root,
796
- absolute: true,
797
- onlyFiles: true,
798
- dot: false,
799
- // Case-folding parity with the engine predicate (`nocase: true`).
800
- caseSensitiveMatch: false,
801
- // Migrating from fast-glob — disable tinyglobby's directory-pattern
802
- // auto-expansion so a glob like `packages/*/README.md` keeps exact
803
- // fast-glob semantics.
804
- expandDirectories: false
805
- });
806
- const inRoot = matches.filter((m) => isInsideRoot(m, normalisedRoot));
807
- if (inRoot.length === 0) {
808
- missing.push(rawEntry);
809
- } else {
810
- for (const m of inRoot) found.add(m);
811
- }
812
- continue;
813
- }
814
- const absolute = path2.resolve(root, entry);
815
- let stat;
816
- try {
817
- stat = await fs2.stat(absolute);
818
- } catch (err) {
819
- if (isNoEntError(err)) {
820
- missing.push(rawEntry);
821
- continue;
822
- }
823
- throw err;
824
- }
825
- if (stat.isDirectory()) {
826
- const children = await glob("**/*.md", {
827
- cwd: absolute,
828
- absolute: true,
829
- onlyFiles: true,
830
- caseSensitiveMatch: false,
831
- dot: false,
832
- expandDirectories: false
833
- });
834
- for (const c of children) {
835
- if (isInsideRoot(c, normalisedRoot)) found.add(c);
836
- }
837
- } else if (stat.isFile()) {
838
- if (isInsideRoot(absolute, normalisedRoot)) found.add(absolute);
839
- } else {
840
- missing.push(rawEntry);
841
- }
842
- }
843
- const files = Array.from(found).sort();
844
- return { files, missingPaths: missing };
845
- }
846
- function isNoEntError(err) {
847
- return typeof err === "object" && err !== null && err.code === "ENOENT";
848
- }
849
- function isInsideRoot(absolute, normalisedRoot) {
850
- const resolved = path2.resolve(absolute);
851
- return resolved === normalisedRoot || resolved.startsWith(normalisedRoot + path2.sep);
852
- }
853
-
854
- // src/commands/local-prepare.ts
855
927
  var execFileAsync = promisify(execFile);
856
928
  var UNTRACKED_DIFF_MAX_BUFFER = 64 * 1024 * 1024;
857
929
  var PROMPT_TOKEN_BUDGET = 15e4;
@@ -1179,10 +1251,16 @@ async function main(argv) {
1179
1251
  });
1180
1252
  program.command("install <path>").description(
1181
1253
  "Scaffold .claude/skills/delfini/SKILL.md + CLAUDE.md auto-invoke + .gitignore append"
1182
- ).option("--tool <agent>", "Coding agent target (only 'CLAUDE' supported in V1)", "CLAUDE").option("--auto-invoke", "append the CLAUDE.md auto-invoke block without prompting").option("--no-auto-invoke", "strip the CLAUDE.md auto-invoke block without prompting").action(async (targetPath, opts) => {
1183
- const confirmAutoInvoke = opts.autoInvoke === void 0 ? void 0 : () => Promise.resolve(opts.autoInvoke);
1184
- await runInstall(targetPath, { tool: opts.tool, confirmAutoInvoke });
1185
- });
1254
+ ).option("--tool <agent>", "Coding agent target (only 'CLAUDE' supported in V1)", "CLAUDE").option("--auto-invoke", "append the CLAUDE.md auto-invoke block without prompting").option("--no-auto-invoke", "strip the CLAUDE.md auto-invoke block without prompting").option(
1255
+ "--scope <paths>",
1256
+ "Seed doc-scope.json with these paths (space- or comma-separated; overwrites any existing scope) without prompting. Omit to be prompted interactively on a TTY."
1257
+ ).action(
1258
+ async (targetPath, opts) => {
1259
+ const confirmAutoInvoke = opts.autoInvoke === void 0 ? void 0 : () => Promise.resolve(opts.autoInvoke);
1260
+ const provideDocScope = opts.scope === void 0 ? void 0 : () => Promise.resolve(parseScopeInput(opts.scope));
1261
+ await runInstall(targetPath, { tool: opts.tool, confirmAutoInvoke, provideDocScope });
1262
+ }
1263
+ );
1186
1264
  program.command("local-prepare").description(
1187
1265
  "Compute diff + doc-scope + prompt + token-budget gate; write .delfini-trace/"
1188
1266
  ).option("--scope <paths>", "Comma-separated doc-scope paths (overrides doc-scope.json)").option("--base <ref>", "Diff base ref (default: git merge-base HEAD origin/main)").option(
@@ -1256,13 +1334,6 @@ export {
1256
1334
  RepoRootNotFoundError,
1257
1335
  getRepoRoot,
1258
1336
  runDiffStatus,
1259
- ensureTraceDir,
1260
- appendToGitignore,
1261
- writeTraceFile,
1262
- writeRetryAttemptFile,
1263
- InstallToolNotSupportedError,
1264
- runInstall,
1265
- runLocalFinalize,
1266
1337
  DOC_SCOPE_RELATIVE_PATH,
1267
1338
  DOC_SCOPE_VERSION,
1268
1339
  DocScopeVersionMismatchError,
@@ -1273,6 +1344,13 @@ export {
1273
1344
  docScopeExists,
1274
1345
  deleteDocScope,
1275
1346
  expandDocScope,
1347
+ ensureTraceDir,
1348
+ appendToGitignore,
1349
+ writeTraceFile,
1350
+ writeRetryAttemptFile,
1351
+ InstallToolNotSupportedError,
1352
+ runInstall,
1353
+ runLocalFinalize,
1276
1354
  PROMPT_TOKEN_BUDGET,
1277
1355
  runLocalPrepare,
1278
1356
  main
@@ -31,11 +31,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  mod
32
32
  ));
33
33
 
34
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.9_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
34
+ // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.15_tsx@4.22.4_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
35
35
  import path from "path";
36
36
  import { fileURLToPath } from "url";
37
37
  var init_esm_shims = __esm({
38
- "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.9_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
38
+ "../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.15_tsx@4.22.4_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
39
39
  "use strict";
40
40
  }
41
41
  });