@claude-flow/cli 3.64.0 → 3.65.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.
Files changed (89) hide show
  1. package/.claude/helpers/helpers.manifest.json +2 -2
  2. package/catalog-manifest.json +2 -2
  3. package/dist/src/commands/cost.d.ts +18 -0
  4. package/dist/src/commands/cost.js +195 -0
  5. package/dist/src/commands/doctor-auto-approve.d.ts +9 -0
  6. package/dist/src/commands/doctor-auto-approve.js +32 -0
  7. package/dist/src/commands/doctor.js +21 -3
  8. package/dist/src/commands/hive-mind-worker.d.ts +2 -0
  9. package/dist/src/commands/hive-mind-worker.js +9 -3
  10. package/dist/src/commands/hive-mind.js +15 -1
  11. package/dist/src/commands/hooks.js +8 -2
  12. package/dist/src/commands/index.js +2 -0
  13. package/dist/src/commands/init.js +76 -2
  14. package/dist/src/commands/mods.js +13 -0
  15. package/dist/src/commands/plugins-paths.d.ts +13 -0
  16. package/dist/src/commands/plugins-paths.js +55 -0
  17. package/dist/src/commands/plugins-verify.d.ts +9 -0
  18. package/dist/src/commands/plugins-verify.js +92 -0
  19. package/dist/src/commands/plugins.js +13 -1
  20. package/dist/src/cost/attribution.d.ts +35 -0
  21. package/dist/src/cost/attribution.js +101 -0
  22. package/dist/src/cost/budget-file.d.ts +57 -0
  23. package/dist/src/cost/budget-file.js +113 -0
  24. package/dist/src/cost/litellm.d.ts +69 -0
  25. package/dist/src/cost/litellm.js +135 -0
  26. package/dist/src/init/executor.d.ts +7 -2
  27. package/dist/src/init/executor.js +64 -10
  28. package/dist/src/init/helper-commands.d.ts +16 -0
  29. package/dist/src/init/helper-commands.js +73 -0
  30. package/dist/src/init/risky-settings-gate.d.ts +39 -0
  31. package/dist/src/init/risky-settings-gate.js +130 -0
  32. package/dist/src/init/settings-risk-scanner.d.ts +35 -0
  33. package/dist/src/init/settings-risk-scanner.js +85 -0
  34. package/dist/src/init/types.d.ts +12 -0
  35. package/dist/src/mcp-tools/capability-brain.d.ts +1 -1
  36. package/dist/src/mcp-tools/capability-brain.js +1 -1
  37. package/dist/src/mcp-tools/hooks-tools.js +2 -1
  38. package/dist/src/memory/verified-guards.d.ts +70 -0
  39. package/dist/src/memory/verified-guards.js +101 -0
  40. package/dist/src/memory/verified-outcomes.d.ts +68 -3
  41. package/dist/src/memory/verified-outcomes.js +88 -19
  42. package/dist/src/memory/verified-reverify.d.ts +63 -0
  43. package/dist/src/memory/verified-reverify.js +174 -0
  44. package/dist/src/missions/schemas.d.ts +4 -4
  45. package/dist/src/mods/apply.d.ts +2 -0
  46. package/dist/src/mods/apply.js +68 -8
  47. package/dist/src/mods/command-registry/schema.d.ts +36 -36
  48. package/dist/src/mods/compact-snapshots.d.ts +21 -0
  49. package/dist/src/mods/compact-snapshots.js +45 -0
  50. package/dist/src/mods/headless-check.d.ts +58 -0
  51. package/dist/src/mods/headless-check.js +137 -0
  52. package/dist/src/mods/headless-plugins.d.ts +44 -0
  53. package/dist/src/mods/headless-plugins.js +92 -0
  54. package/dist/src/mods/install-trust.d.ts +28 -0
  55. package/dist/src/mods/install-trust.js +127 -0
  56. package/dist/src/mods/install.d.ts +19 -0
  57. package/dist/src/mods/install.js +38 -1
  58. package/dist/src/mods/plugin-paths.d.ts +60 -0
  59. package/dist/src/mods/plugin-paths.js +131 -0
  60. package/dist/src/mods/plugin-repair.d.ts +8 -0
  61. package/dist/src/mods/plugin-repair.js +7 -0
  62. package/dist/src/plugins/marketplace-trust/scan.d.ts +23 -0
  63. package/dist/src/plugins/marketplace-trust/scan.js +255 -0
  64. package/dist/src/plugins/marketplace-trust/signature.d.ts +53 -0
  65. package/dist/src/plugins/marketplace-trust/signature.js +140 -0
  66. package/dist/src/plugins/marketplace-trust/verify-status.d.ts +42 -0
  67. package/dist/src/plugins/marketplace-trust/verify-status.js +110 -0
  68. package/dist/src/services/headless-worker-executor.d.ts +2 -0
  69. package/dist/src/services/headless-worker-executor.js +13 -3
  70. package/package.json +2 -1
  71. package/plugins/ruflo-metaharness/.claude-plugin/plugin.json +8 -1
  72. package/plugins/ruflo-metaharness/CHANGELOG.md +6 -0
  73. package/plugins/ruflo-metaharness/README.md +14 -1
  74. package/plugins/ruflo-metaharness/agents/metaharness-architect.md +2 -0
  75. package/plugins/ruflo-metaharness/hooks/hooks.json +16 -2
  76. package/plugins/ruflo-metaharness/scripts/_redblue.mjs +12 -2
  77. package/plugins/ruflo-metaharness/scripts/_secret-env.cjs +50 -0
  78. package/plugins/ruflo-metaharness/scripts/_secret.mjs +35 -0
  79. package/plugins/ruflo-metaharness/scripts/smoke.sh +7 -7
  80. package/plugins/ruflo-metaharness/skills/harness-bench/SKILL.md +2 -1
  81. package/plugins/ruflo-metaharness/skills/harness-drift-from-history/SKILL.md +1 -1
  82. package/plugins/ruflo-metaharness/skills/harness-evolve/SKILL.md +2 -1
  83. package/plugins/ruflo-metaharness/skills/harness-gepa/SKILL.md +1 -1
  84. package/plugins/ruflo-metaharness/skills/harness-learn/SKILL.md +2 -1
  85. package/plugins/ruflo-metaharness/skills/harness-mint/SKILL.md +2 -1
  86. package/plugins/ruflo-metaharness/skills/harness-oia-audit/SKILL.md +1 -0
  87. package/plugins/ruflo-metaharness/skills/harness-score/SKILL.md +1 -1
  88. package/plugins/ruflo-metaharness/skills/harness-security-bench/SKILL.md +2 -1
  89. package/plugins/ruflo-metaharness/skills/harness-similarity/SKILL.md +1 -1
@@ -63,19 +63,19 @@ export declare const commandDefinitionSchema: z.ZodEffects<z.ZodObject<{
63
63
  path: z.ZodString;
64
64
  }, "strict", z.ZodTypeAny, {
65
65
  path: string;
66
- repository: string;
67
66
  commit: string;
67
+ repository: string;
68
68
  }, {
69
69
  path: string;
70
- repository: string;
71
70
  commit: string;
71
+ repository: string;
72
72
  }>;
73
73
  }, "strict", z.ZodTypeAny, {
74
74
  id: string;
75
75
  source: {
76
76
  path: string;
77
- repository: string;
78
77
  commit: string;
78
+ repository: string;
79
79
  };
80
80
  schemaVersion: 1;
81
81
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -100,8 +100,8 @@ export declare const commandDefinitionSchema: z.ZodEffects<z.ZodObject<{
100
100
  id: string;
101
101
  source: {
102
102
  path: string;
103
- repository: string;
104
103
  commit: string;
104
+ repository: string;
105
105
  };
106
106
  schemaVersion: 1;
107
107
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -126,8 +126,8 @@ export declare const commandDefinitionSchema: z.ZodEffects<z.ZodObject<{
126
126
  id: string;
127
127
  source: {
128
128
  path: string;
129
- repository: string;
130
129
  commit: string;
130
+ repository: string;
131
131
  };
132
132
  schemaVersion: 1;
133
133
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -152,8 +152,8 @@ export declare const commandDefinitionSchema: z.ZodEffects<z.ZodObject<{
152
152
  id: string;
153
153
  source: {
154
154
  path: string;
155
- repository: string;
156
155
  commit: string;
156
+ repository: string;
157
157
  };
158
158
  schemaVersion: 1;
159
159
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -190,18 +190,18 @@ export declare const inventorySourceSchema: z.ZodObject<{
190
190
  initCategory: z.ZodOptional<z.ZodString>;
191
191
  shippedIn: z.ZodArray<z.ZodString, "many">;
192
192
  }, "strict", z.ZodTypeAny, {
193
+ digest: string;
193
194
  sourcePath: string;
194
195
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
195
- digest: string;
196
196
  package: string;
197
197
  observedInvocation: string;
198
198
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
199
199
  shippedIn: string[];
200
200
  initCategory?: string | undefined;
201
201
  }, {
202
+ digest: string;
202
203
  sourcePath: string;
203
204
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
204
- digest: string;
205
205
  package: string;
206
206
  observedInvocation: string;
207
207
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -244,19 +244,19 @@ export declare const catalogEntrySchema: z.ZodObject<{
244
244
  path: z.ZodString;
245
245
  }, "strict", z.ZodTypeAny, {
246
246
  path: string;
247
- repository: string;
248
247
  commit: string;
248
+ repository: string;
249
249
  }, {
250
250
  path: string;
251
- repository: string;
252
251
  commit: string;
252
+ repository: string;
253
253
  }>;
254
254
  }, "strict", z.ZodTypeAny, {
255
255
  id: string;
256
256
  source: {
257
257
  path: string;
258
- repository: string;
259
258
  commit: string;
259
+ repository: string;
260
260
  };
261
261
  schemaVersion: 1;
262
262
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -281,8 +281,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
281
281
  id: string;
282
282
  source: {
283
283
  path: string;
284
- repository: string;
285
284
  commit: string;
285
+ repository: string;
286
286
  };
287
287
  schemaVersion: 1;
288
288
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -307,8 +307,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
307
307
  id: string;
308
308
  source: {
309
309
  path: string;
310
- repository: string;
311
310
  commit: string;
311
+ repository: string;
312
312
  };
313
313
  schemaVersion: 1;
314
314
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -333,8 +333,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
333
333
  id: string;
334
334
  source: {
335
335
  path: string;
336
- repository: string;
337
336
  commit: string;
337
+ repository: string;
338
338
  };
339
339
  schemaVersion: 1;
340
340
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -368,18 +368,18 @@ export declare const catalogEntrySchema: z.ZodObject<{
368
368
  initCategory: z.ZodOptional<z.ZodString>;
369
369
  shippedIn: z.ZodArray<z.ZodString, "many">;
370
370
  }, "strict", z.ZodTypeAny, {
371
+ digest: string;
371
372
  sourcePath: string;
372
373
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
373
- digest: string;
374
374
  package: string;
375
375
  observedInvocation: string;
376
376
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
377
377
  shippedIn: string[];
378
378
  initCategory?: string | undefined;
379
379
  }, {
380
+ digest: string;
380
381
  sourcePath: string;
381
382
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
382
- digest: string;
383
383
  package: string;
384
384
  observedInvocation: string;
385
385
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -389,9 +389,9 @@ export declare const catalogEntrySchema: z.ZodObject<{
389
389
  notes: z.ZodArray<z.ZodString, "many">;
390
390
  }, "strict", z.ZodTypeAny, {
391
391
  sources: {
392
+ digest: string;
392
393
  sourcePath: string;
393
394
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
394
- digest: string;
395
395
  package: string;
396
396
  observedInvocation: string;
397
397
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -404,8 +404,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
404
404
  id: string;
405
405
  source: {
406
406
  path: string;
407
- repository: string;
408
407
  commit: string;
408
+ repository: string;
409
409
  };
410
410
  schemaVersion: 1;
411
411
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -430,9 +430,9 @@ export declare const catalogEntrySchema: z.ZodObject<{
430
430
  notes: string[];
431
431
  }, {
432
432
  sources: {
433
+ digest: string;
433
434
  sourcePath: string;
434
435
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
435
- digest: string;
436
436
  package: string;
437
437
  observedInvocation: string;
438
438
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -445,8 +445,8 @@ export declare const catalogEntrySchema: z.ZodObject<{
445
445
  id: string;
446
446
  source: {
447
447
  path: string;
448
- repository: string;
449
448
  commit: string;
449
+ repository: string;
450
450
  };
451
451
  schemaVersion: 1;
452
452
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -510,19 +510,19 @@ export declare const commandCatalogSchema: z.ZodObject<{
510
510
  path: z.ZodString;
511
511
  }, "strict", z.ZodTypeAny, {
512
512
  path: string;
513
- repository: string;
514
513
  commit: string;
514
+ repository: string;
515
515
  }, {
516
516
  path: string;
517
- repository: string;
518
517
  commit: string;
518
+ repository: string;
519
519
  }>;
520
520
  }, "strict", z.ZodTypeAny, {
521
521
  id: string;
522
522
  source: {
523
523
  path: string;
524
- repository: string;
525
524
  commit: string;
525
+ repository: string;
526
526
  };
527
527
  schemaVersion: 1;
528
528
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -547,8 +547,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
547
547
  id: string;
548
548
  source: {
549
549
  path: string;
550
- repository: string;
551
550
  commit: string;
551
+ repository: string;
552
552
  };
553
553
  schemaVersion: 1;
554
554
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -573,8 +573,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
573
573
  id: string;
574
574
  source: {
575
575
  path: string;
576
- repository: string;
577
576
  commit: string;
577
+ repository: string;
578
578
  };
579
579
  schemaVersion: 1;
580
580
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -599,8 +599,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
599
599
  id: string;
600
600
  source: {
601
601
  path: string;
602
- repository: string;
603
602
  commit: string;
603
+ repository: string;
604
604
  };
605
605
  schemaVersion: 1;
606
606
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -634,18 +634,18 @@ export declare const commandCatalogSchema: z.ZodObject<{
634
634
  initCategory: z.ZodOptional<z.ZodString>;
635
635
  shippedIn: z.ZodArray<z.ZodString, "many">;
636
636
  }, "strict", z.ZodTypeAny, {
637
+ digest: string;
637
638
  sourcePath: string;
638
639
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
639
- digest: string;
640
640
  package: string;
641
641
  observedInvocation: string;
642
642
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
643
643
  shippedIn: string[];
644
644
  initCategory?: string | undefined;
645
645
  }, {
646
+ digest: string;
646
647
  sourcePath: string;
647
648
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
648
- digest: string;
649
649
  package: string;
650
650
  observedInvocation: string;
651
651
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -655,9 +655,9 @@ export declare const commandCatalogSchema: z.ZodObject<{
655
655
  notes: z.ZodArray<z.ZodString, "many">;
656
656
  }, "strict", z.ZodTypeAny, {
657
657
  sources: {
658
+ digest: string;
658
659
  sourcePath: string;
659
660
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
660
- digest: string;
661
661
  package: string;
662
662
  observedInvocation: string;
663
663
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -670,8 +670,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
670
670
  id: string;
671
671
  source: {
672
672
  path: string;
673
- repository: string;
674
673
  commit: string;
674
+ repository: string;
675
675
  };
676
676
  schemaVersion: 1;
677
677
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -696,9 +696,9 @@ export declare const commandCatalogSchema: z.ZodObject<{
696
696
  notes: string[];
697
697
  }, {
698
698
  sources: {
699
+ digest: string;
699
700
  sourcePath: string;
700
701
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
701
- digest: string;
702
702
  package: string;
703
703
  observedInvocation: string;
704
704
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -711,8 +711,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
711
711
  id: string;
712
712
  source: {
713
713
  path: string;
714
- repository: string;
715
714
  commit: string;
715
+ repository: string;
716
716
  };
717
717
  schemaVersion: 1;
718
718
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -739,9 +739,9 @@ export declare const commandCatalogSchema: z.ZodObject<{
739
739
  }, "strict", z.ZodTypeAny, {
740
740
  entries: {
741
741
  sources: {
742
+ digest: string;
742
743
  sourcePath: string;
743
744
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
744
- digest: string;
745
745
  package: string;
746
746
  observedInvocation: string;
747
747
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -754,8 +754,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
754
754
  id: string;
755
755
  source: {
756
756
  path: string;
757
- repository: string;
758
757
  commit: string;
758
+ repository: string;
759
759
  };
760
760
  schemaVersion: 1;
761
761
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -785,9 +785,9 @@ export declare const commandCatalogSchema: z.ZodObject<{
785
785
  }, {
786
786
  entries: {
787
787
  sources: {
788
+ digest: string;
788
789
  sourcePath: string;
789
790
  channel: "repo-project-commands" | "cli-init-template" | "marketplace-plugin" | "source-plugin" | "mod-registration";
790
- digest: string;
791
791
  package: string;
792
792
  observedInvocation: string;
793
793
  binding: "markdown-loader" | "mod-register" | "mod-middleware-on-markdown";
@@ -800,8 +800,8 @@ export declare const commandCatalogSchema: z.ZodObject<{
800
800
  id: string;
801
801
  source: {
802
802
  path: string;
803
- repository: string;
804
803
  commit: string;
804
+ repository: string;
805
805
  };
806
806
  schemaVersion: 1;
807
807
  kind: "help" | "query" | "prompt" | "workflow" | "mutation";
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ADR-505: `ruflo doctor` check for ruflo-mods compaction snapshots.
3
+ *
4
+ * The `compactSnapshot` option (default on) writes conversation text to
5
+ * `.claude-flow/sessions/compactions/`. `ruflo init` gitignores it through
6
+ * `.claude-flow/.gitignore` (`sessions/`); a project whose ignore rules lost
7
+ * that would commit transcripts. Warn-only: when snapshots exist and git does
8
+ * not ignore them. No snapshots, or not a git work tree, is a pass.
9
+ */
10
+ export declare const COMPACTIONS_DIR = ".claude-flow/sessions/compactions";
11
+ export type SnapshotHealth = {
12
+ status: 'pass' | 'warn';
13
+ message: string;
14
+ fix?: string;
15
+ };
16
+ /** `ignored`: git ignores the path; `not-ignored`: it would be committed; `no-git`: not a work tree or git missing. */
17
+ export type IgnoreState = 'ignored' | 'not-ignored' | 'no-git';
18
+ /** `git check-ignore -q`: exit 0 ignored, 1 not ignored, anything else (128: not a repo; ENOENT: no git) no answer. */
19
+ export declare function gitIgnoreState(root: string, relPath: string): IgnoreState;
20
+ export declare function compactSnapshotHealth(root: string, ignoreState?: (root: string, relPath: string) => IgnoreState): SnapshotHealth;
21
+ //# sourceMappingURL=compact-snapshots.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ADR-505: `ruflo doctor` check for ruflo-mods compaction snapshots.
3
+ *
4
+ * The `compactSnapshot` option (default on) writes conversation text to
5
+ * `.claude-flow/sessions/compactions/`. `ruflo init` gitignores it through
6
+ * `.claude-flow/.gitignore` (`sessions/`); a project whose ignore rules lost
7
+ * that would commit transcripts. Warn-only: when snapshots exist and git does
8
+ * not ignore them. No snapshots, or not a git work tree, is a pass.
9
+ */
10
+ import { execFileSync } from 'node:child_process';
11
+ import { readdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ export const COMPACTIONS_DIR = '.claude-flow/sessions/compactions';
14
+ /** `git check-ignore -q`: exit 0 ignored, 1 not ignored, anything else (128: not a repo; ENOENT: no git) no answer. */
15
+ export function gitIgnoreState(root, relPath) {
16
+ try {
17
+ execFileSync('git', ['check-ignore', '-q', '--', relPath], { cwd: root, stdio: 'ignore', timeout: 5000 });
18
+ return 'ignored';
19
+ }
20
+ catch (error) {
21
+ return error.status === 1 ? 'not-ignored' : 'no-git';
22
+ }
23
+ }
24
+ export function compactSnapshotHealth(root, ignoreState = gitIgnoreState) {
25
+ let files;
26
+ try {
27
+ files = readdirSync(join(root, COMPACTIONS_DIR)).filter((name) => name.endsWith('.jsonl'));
28
+ }
29
+ catch {
30
+ files = [];
31
+ }
32
+ if (files.length === 0)
33
+ return { status: 'pass', message: 'no compaction snapshots in this project' };
34
+ const sample = `${COMPACTIONS_DIR}/${files.sort()[0]}`;
35
+ const state = ignoreState(root, sample);
36
+ if (state === 'not-ignored') {
37
+ return {
38
+ status: 'warn',
39
+ message: `${files.length} compaction snapshot(s) in ${COMPACTIONS_DIR}/ hold conversation text and git does not ignore them`,
40
+ fix: 'add .claude-flow/ (or .claude-flow/sessions/) to .gitignore, or set the ruflo-mods compactSnapshot option to false',
41
+ };
42
+ }
43
+ return { status: 'pass', message: `${files.length} compaction snapshot(s), ${state === 'ignored' ? 'ignored by git' : 'not in a git work tree'}` };
44
+ }
45
+ //# sourceMappingURL=compact-snapshots.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * ADR-510 §2.4 — `ruflo doctor --component headless-plugins`: do ruflo mods
3
+ * actually run under `claude -p` on this machine?
4
+ *
5
+ * Runs `claude -p --plugin-dir <ruflo-mods> --output-format stream-json
6
+ * --verbose "reply ok"` in a throwaway project that has a `.claude-flow/`
7
+ * directory, then reports:
8
+ * - whether the init event lists ruflo-mods from that folder;
9
+ * - whether `plugin_errors` is empty (Claude Code omits the key when none);
10
+ * - whether the mod's session heartbeat (`.claude-flow/mods/session.json`)
11
+ * was written — the proof that its function hooks ran.
12
+ *
13
+ * The runner is injectable so tests never spawn `claude` or need a key.
14
+ * Without any model credential the check is skipped (warn), never spawned.
15
+ */
16
+ import { type PluginPaths } from './plugin-paths.js';
17
+ export declare const HEADLESS_TIMEOUT_MS = 60000;
18
+ export declare const HEARTBEAT: string;
19
+ export interface HeadlessRun {
20
+ exitCode: number | null;
21
+ stdout: string;
22
+ stderr: string;
23
+ timedOut?: boolean;
24
+ }
25
+ export type HeadlessRunner = (argv: string[], env: NodeJS.ProcessEnv, cwd: string, timeoutMs: number) => Promise<HeadlessRun>;
26
+ export interface HeadlessCheck {
27
+ name: string;
28
+ status: 'pass' | 'warn' | 'fail';
29
+ message: string;
30
+ fix?: string;
31
+ }
32
+ export interface HeadlessCheckDeps {
33
+ runner?: HeadlessRunner;
34
+ resolve?: () => PluginPaths;
35
+ env?: NodeJS.ProcessEnv;
36
+ home?: string;
37
+ /** Throwaway project dir factory (must be removable afterwards). */
38
+ makeProject?: () => string;
39
+ exists?: (path: string) => boolean;
40
+ timeoutMs?: number;
41
+ model?: string;
42
+ }
43
+ export declare const spawnHeadless: HeadlessRunner;
44
+ /** A model credential Claude Code could use; without one the check would only fail on auth. */
45
+ export declare function hasModelCredential(env: NodeJS.ProcessEnv, configDir: string, exists?: (p: string) => boolean): boolean;
46
+ interface InitEvent {
47
+ plugins?: Array<{
48
+ name?: string;
49
+ path?: string;
50
+ source?: string;
51
+ }>;
52
+ plugin_errors?: unknown[];
53
+ }
54
+ /** The `system/init` event of a stream-json run, if any. */
55
+ export declare function findInitEvent(stdout: string): InitEvent | null;
56
+ export declare function checkHeadlessPlugins(deps?: HeadlessCheckDeps): Promise<HeadlessCheck>;
57
+ export {};
58
+ //# sourceMappingURL=headless-check.d.ts.map
@@ -0,0 +1,137 @@
1
+ /**
2
+ * ADR-510 §2.4 — `ruflo doctor --component headless-plugins`: do ruflo mods
3
+ * actually run under `claude -p` on this machine?
4
+ *
5
+ * Runs `claude -p --plugin-dir <ruflo-mods> --output-format stream-json
6
+ * --verbose "reply ok"` in a throwaway project that has a `.claude-flow/`
7
+ * directory, then reports:
8
+ * - whether the init event lists ruflo-mods from that folder;
9
+ * - whether `plugin_errors` is empty (Claude Code omits the key when none);
10
+ * - whether the mod's session heartbeat (`.claude-flow/mods/session.json`)
11
+ * was written — the proof that its function hooks ran.
12
+ *
13
+ * The runner is injectable so tests never spawn `claude` or need a key.
14
+ * Without any model credential the check is skipped (warn), never spawned.
15
+ */
16
+ import { spawn } from 'node:child_process';
17
+ import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync } from 'node:fs';
18
+ import { homedir, tmpdir } from 'node:os';
19
+ import { join, resolve } from 'node:path';
20
+ import { ENABLE_ENV } from './install.js';
21
+ import { claudeConfigDir } from './plugin-resolve.js';
22
+ import { resolvePluginPaths } from './plugin-paths.js';
23
+ export const HEADLESS_TIMEOUT_MS = 60_000;
24
+ export const HEARTBEAT = join('.claude-flow', 'mods', 'session.json');
25
+ const PLUGIN = 'ruflo-mods';
26
+ const NAME = 'Headless plugins (ADR-510)';
27
+ export const spawnHeadless = (argv, env, cwd, timeoutMs) => new Promise((done) => {
28
+ let stdout = '';
29
+ let stderr = '';
30
+ let timedOut = false;
31
+ let child;
32
+ try {
33
+ child = spawn('claude', argv, { cwd, env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
34
+ }
35
+ catch (e) {
36
+ done({ exitCode: null, stdout: '', stderr: e instanceof Error ? e.message : String(e) });
37
+ return;
38
+ }
39
+ const timer = setTimeout(() => {
40
+ timedOut = true;
41
+ try {
42
+ child.kill('SIGTERM');
43
+ }
44
+ catch { /* already gone */ }
45
+ }, timeoutMs);
46
+ child.stdout?.on('data', (d) => { stdout += d.toString(); });
47
+ child.stderr?.on('data', (d) => { stderr += d.toString(); });
48
+ child.on('error', (e) => { clearTimeout(timer); done({ exitCode: null, stdout, stderr: e.message, timedOut }); });
49
+ child.on('close', (code) => { clearTimeout(timer); done({ exitCode: code, stdout, stderr, timedOut }); });
50
+ });
51
+ /** A model credential Claude Code could use; without one the check would only fail on auth. */
52
+ export function hasModelCredential(env, configDir, exists = existsSync) {
53
+ const keys = ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_BASE_URL', 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX'];
54
+ if (keys.some((k) => !!env[k]))
55
+ return true;
56
+ // macOS keeps the login in the keychain, which we cannot see from here.
57
+ if (process.platform === 'darwin')
58
+ return true;
59
+ return exists(join(configDir, '.credentials.json'));
60
+ }
61
+ /** The `system/init` event of a stream-json run, if any. */
62
+ export function findInitEvent(stdout) {
63
+ for (const line of stdout.split('\n')) {
64
+ const t = line.trim();
65
+ if (!t.startsWith('{'))
66
+ continue;
67
+ try {
68
+ const ev = JSON.parse(t);
69
+ if (ev.type === 'system' && ev.subtype === 'init')
70
+ return ev;
71
+ }
72
+ catch {
73
+ // not a JSON line
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+ const canonical = (p) => {
79
+ try {
80
+ return realpathSync(p);
81
+ }
82
+ catch {
83
+ return resolve(p);
84
+ }
85
+ };
86
+ export async function checkHeadlessPlugins(deps = {}) {
87
+ const env = deps.env ?? process.env;
88
+ const exists = deps.exists ?? existsSync;
89
+ const paths = (deps.resolve ?? (() => resolvePluginPaths([PLUGIN], { env, home: deps.home })))();
90
+ const mods = paths.resolved.find((p) => p.name === PLUGIN);
91
+ if (!mods) {
92
+ const why = paths.missing.find((m) => m.name === PLUGIN)?.reason ?? 'not found';
93
+ return { name: NAME, status: 'warn', message: `${PLUGIN} not found (${why}); headless workers run without it`, fix: 'ruflo mods install' };
94
+ }
95
+ const configDir = claudeConfigDir(env, deps.home ?? homedir());
96
+ if (!deps.runner && !hasModelCredential(env, configDir, exists)) {
97
+ return { name: NAME, status: 'warn', message: `skipped: no model credential for claude -p (${PLUGIN} resolves to ${mods.path})`, fix: 'set ANTHROPIC_API_KEY or run `claude login`, then re-run' };
98
+ }
99
+ const project = (deps.makeProject ?? (() => mkdtempSync(join(tmpdir(), 'ruflo-headless-'))))();
100
+ try {
101
+ mkdirSync(join(project, '.claude-flow'), { recursive: true });
102
+ const argv = ['-p', 'reply ok', '--plugin-dir', mods.path, '--output-format', 'stream-json', '--verbose', '--model', deps.model ?? 'haiku'];
103
+ const runEnv = { ...env, CLAUDE_ENTRYPOINT: 'worker' };
104
+ if (runEnv[ENABLE_ENV] === undefined)
105
+ runEnv[ENABLE_ENV] = '1';
106
+ delete runEnv.CLAUDE_SESSION_ID;
107
+ delete runEnv.CLAUDE_PARENT_SESSION_ID;
108
+ const run = await (deps.runner ?? spawnHeadless)(argv, runEnv, project, deps.timeoutMs ?? HEADLESS_TIMEOUT_MS);
109
+ if (run.timedOut) {
110
+ return { name: NAME, status: 'fail', message: `claude -p did not finish in ${(deps.timeoutMs ?? HEADLESS_TIMEOUT_MS) / 1000}s` };
111
+ }
112
+ const init = findInitEvent(run.stdout);
113
+ if (!init) {
114
+ const tail = (run.stderr || run.stdout).trim().split('\n').slice(-1)[0] ?? '';
115
+ return { name: NAME, status: 'fail', message: `no init event from claude -p (exit ${run.exitCode})${tail ? `: ${tail.slice(0, 200)}` : ''}`, fix: 'ruflo doctor -c claude' };
116
+ }
117
+ const want = canonical(mods.path);
118
+ const listed = (init.plugins ?? []).some((p) => p.name === PLUGIN && typeof p.path === 'string' && canonical(p.path) === want);
119
+ const errors = Array.isArray(init.plugin_errors) ? init.plugin_errors : [];
120
+ const heartbeat = exists(join(project, HEARTBEAT));
121
+ const facts = `init lists ${PLUGIN}: ${listed ? 'yes' : 'no'}; plugin_errors: ${errors.length === 0 ? 'none' : JSON.stringify(errors).slice(0, 200)}; heartbeat: ${heartbeat ? 'written' : 'absent'}`;
122
+ if (!listed || errors.length > 0) {
123
+ return { name: NAME, status: 'fail', message: `${facts} (${mods.path})`, fix: `claude -p --plugin-dir ${JSON.stringify(mods.path)} --output-format stream-json --verbose "reply ok"` };
124
+ }
125
+ if (!heartbeat) {
126
+ return { name: NAME, status: 'warn', message: `${facts}: the plugin loads but its function hooks did not run (Claude Code too old, or ${ENABLE_ENV}=0)` };
127
+ }
128
+ return { name: NAME, status: 'pass', message: `${facts} (${mods.source}: ${mods.path})` };
129
+ }
130
+ finally {
131
+ try {
132
+ rmSync(project, { recursive: true, force: true });
133
+ }
134
+ catch { /* best effort */ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=headless-check.js.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ADR-510 §2.2 — give a headless `claude -p` worker its ruflo plugins.
3
+ *
4
+ * Every place ruflo builds a `claude -p` command line passes its argv and env
5
+ * through `withHeadlessPlugins`. It appends `--plugin-dir <path>` per plugin
6
+ * in the worker profile (default: ruflo-mods) and sets
7
+ * `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1` unless the caller set it (a caller's
8
+ * `0` stays `0`). A caller's own `--plugin-dir` for the same plugin is never
9
+ * duplicated.
10
+ *
11
+ * A plugin that cannot be resolved does not stop the worker: it is logged once
12
+ * per process ("plugin <name> not found; worker runs without it") and returned
13
+ * in `missing` for the worker's status.
14
+ *
15
+ * Profile override: `RUFLO_HEADLESS_PLUGINS` is a comma list of plugin names;
16
+ * `none` (or an empty value) turns plugin loading off.
17
+ */
18
+ import { type ResolveOptions, type PluginPaths } from './plugin-paths.js';
19
+ export declare const DEFAULT_WORKER_PLUGINS: readonly string[];
20
+ export declare const PROFILE_ENV = "RUFLO_HEADLESS_PLUGINS";
21
+ export interface HeadlessPluginOptions extends ResolveOptions {
22
+ /** Plugin names to load; defaults to the env profile, else DEFAULT_WORKER_PLUGINS. */
23
+ profile?: readonly string[];
24
+ /** Where the once-per-process warning goes (default: stderr). */
25
+ warn?: (line: string) => void;
26
+ /** Injectable resolver, for tests. */
27
+ resolver?: (names: readonly string[], opts: ResolveOptions) => PluginPaths;
28
+ }
29
+ export interface HeadlessPluginResult<E> {
30
+ argv: string[];
31
+ env: E;
32
+ /** Plugins loaded via --plugin-dir by this call (not the caller's own). */
33
+ added: string[];
34
+ /** Plugins in the profile that could not be resolved. */
35
+ missing: string[];
36
+ }
37
+ /** For tests: forget which missing plugins were already logged. */
38
+ export declare function resetHeadlessPluginWarnings(): void;
39
+ /** The worker profile: explicit, else RUFLO_HEADLESS_PLUGINS, else ruflo-mods. */
40
+ export declare function workerProfile(env?: NodeJS.ProcessEnv, explicit?: readonly string[]): string[];
41
+ /** Every `--plugin-dir` value already in argv (both `--plugin-dir x` and `--plugin-dir=x`). */
42
+ export declare function existingPluginDirs(argv: readonly string[]): string[];
43
+ export declare function withHeadlessPlugins<E extends Record<string, string | undefined>>(argv: readonly string[], env: E, opts?: HeadlessPluginOptions): HeadlessPluginResult<E>;
44
+ //# sourceMappingURL=headless-plugins.d.ts.map