create-claude-cabinet 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/lib/CLAUDE.md +240 -0
- package/lib/cli.js +202 -349
- package/lib/copy.js +75 -1
- package/lib/engagement-server-setup.js +1 -17
- package/lib/engagement-setup.js +1 -1
- package/lib/installer-gate.js +135 -0
- package/lib/metadata.js +20 -0
- package/lib/modules.js +292 -0
- package/lib/mux-setup.js +1 -17
- package/lib/project-context.js +16 -96
- package/lib/settings-merge.js +148 -9
- package/lib/site-audit-setup.js +23 -7
- package/lib/verify-setup.js +20 -9
- package/lib/watchtower-setup.js +1 -5
- package/package.json +1 -1
- package/templates/CLAUDE.md +1159 -0
- package/templates/briefing/_briefing-template.md +6 -11
- package/templates/cabinet/eval-protocol.md +27 -10
- package/templates/cabinet/watchtower-contracts.md +124 -0
- package/templates/cabinet/worktree-invocation-contract.md +59 -0
- package/templates/engagement/__tests__/checklist-visibility.test.mjs +76 -0
- package/templates/engagement/engagement-checklist.mjs +26 -2
- package/templates/engagement/engagement-schema.md +8 -6
- package/templates/engagement/pib-db-patches/pib-db-lib.mjs +102 -18
- package/templates/engagement/pib-db-patches/pib-db-schema.sql +1 -1
- package/templates/engagement/pib-db-patches/pib-db.mjs +4 -1
- package/templates/engagement/sql-constants.mjs +9 -1
- package/templates/engagement-server/__tests__/cross-tenant-auth.test.mjs +87 -0
- package/templates/engagement-server/server.mjs +65 -40
- package/templates/hooks/action-completion-gate.sh +10 -0
- package/templates/hooks/action-quality-gate.sh +10 -0
- package/templates/hooks/skill-telemetry.sh +10 -5
- package/templates/hooks/skill-tool-telemetry.sh +11 -5
- package/templates/mcp/pib-db.json +1 -1
- package/templates/mux/__tests__/mux-fail-loud.fixture.sh +4 -5
- package/templates/mux/__tests__/worktree-lifecycle.fixture.sh +214 -0
- package/templates/mux/__tests__/worktree-lifecycle.test.mjs +44 -0
- package/templates/mux/__tests__/worktree-status-clean.fixture.sh +245 -0
- package/templates/mux/__tests__/worktree-status-clean.test.mjs +89 -0
- package/templates/mux/bin/mux +44 -28
- package/templates/mux/config/worktree-cleanup.sh +57 -12
- package/templates/mux/config/worktree-dirty-check.sh +72 -2
- package/templates/mux/config/worktree-session-health.sh +401 -17
- package/templates/rules/enforcement-pipeline.md +0 -12
- package/templates/scripts/__tests__/api-usage-idle-gate.test.mjs +81 -0
- package/templates/scripts/__tests__/assessment-recalibration.test.mjs +387 -0
- package/templates/scripts/__tests__/batch-disposition.test.mjs +19 -0
- package/templates/scripts/__tests__/branch-diverged-reconcile.test.mjs +374 -0
- package/templates/scripts/__tests__/bsql-loader-verify.test.mjs +47 -0
- package/templates/scripts/__tests__/completion-review-reconcile.test.mjs +173 -0
- package/templates/scripts/__tests__/cross-ring-reader.test.mjs +12 -4
- package/templates/scripts/__tests__/detector-registry.test.mjs +152 -0
- package/templates/scripts/__tests__/draft-surfacing.test.mjs +433 -0
- package/templates/scripts/__tests__/generated-state-classification.test.mjs +228 -0
- package/templates/scripts/__tests__/inbox-assessment.test.mjs +341 -0
- package/templates/scripts/__tests__/memory-reachability.test.mjs +150 -0
- package/templates/scripts/__tests__/mirror-parity.test.mjs +54 -0
- package/templates/scripts/__tests__/resolve-project-slug.test.mjs +186 -0
- package/templates/scripts/__tests__/ring1-pib-error-surfacing.test.mjs +69 -0
- package/templates/scripts/__tests__/ring1-stale-open-counts.test.mjs +143 -0
- package/templates/scripts/__tests__/ring3-attribution.test.mjs +267 -0
- package/templates/scripts/__tests__/ring3-completion-filter.test.mjs +176 -0
- package/templates/scripts/__tests__/ring3-coverage-debt.test.mjs +377 -0
- package/templates/scripts/__tests__/ring3-last-session-pointer.test.mjs +80 -0
- package/templates/scripts/__tests__/ring3-thread-capture.test.mjs +213 -0
- package/templates/scripts/__tests__/watchtower-status-ring4.test.mjs +89 -0
- package/templates/scripts/audit-coherence-check.mjs +127 -0
- package/templates/scripts/audit-synth.mjs +117 -0
- package/templates/scripts/load-triage-history.js +23 -2
- package/templates/scripts/merge-findings.js +13 -3
- package/templates/scripts/patterns-scope-check.mjs +122 -0
- package/templates/scripts/pib-db-lib.mjs +116 -18
- package/templates/scripts/pib-db-mcp-server.mjs +2 -1
- package/templates/scripts/pib-db.mjs +2 -1
- package/templates/scripts/review-server.mjs +7 -12
- package/templates/scripts/triage-server.mjs +7 -8
- package/templates/scripts/watchtower-cross-ring-reader.mjs +38 -7
- package/templates/scripts/watchtower-inbox-assessment.mjs +857 -0
- package/templates/scripts/watchtower-lib.mjs +550 -9
- package/templates/scripts/watchtower-queue.mjs +197 -2
- package/templates/scripts/watchtower-ring1.mjs +567 -106
- package/templates/scripts/watchtower-ring2.mjs +213 -15
- package/templates/scripts/watchtower-ring3-close.mjs +679 -90
- package/templates/scripts/watchtower-status.sh +17 -0
- package/templates/scripts/work-tracker-server.mjs +26 -22
- package/templates/skills/audit/SKILL.md +24 -8
- package/templates/skills/audit/phases/structural-checks.md +22 -0
- package/templates/skills/briefing/SKILL.md +8 -0
- package/templates/skills/cabinet-accessibility/SKILL.md +1 -1
- package/templates/skills/cabinet-anthropic-insider/SKILL.md +29 -8
- package/templates/skills/cabinet-process-therapist/SKILL.md +45 -3
- package/templates/skills/cc-publish/SKILL.md +41 -7
- package/templates/skills/debrief/phases/audit-pattern-capture.md +13 -0
- package/templates/skills/inbox/SKILL.md +124 -6
- package/templates/skills/orient/SKILL.md +4 -0
- package/templates/skills/pulse/SKILL.md +10 -8
- package/templates/skills/session-handoff/SKILL.md +6 -8
- package/templates/skills/spring-clean/SKILL.md +1 -1
- package/templates/skills/spring-clean/phases/execute-decisions.md +1 -1
- package/templates/skills/validate/phases/validators.md +86 -0
- package/templates/skills/watchtower/SKILL.md +18 -26
- package/templates/watchtower/config.json.template +2 -1
- package/templates/workflows/deliberative-audit.js +258 -87
- package/templates/workflows/execute-group-complete.js +16 -2
- package/templates/workflows/execute-group-implement.js +16 -2
package/lib/cli.js
CHANGED
|
@@ -3,9 +3,9 @@ const path = require('path');
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const crypto = require('crypto');
|
|
6
|
-
const { copyTemplates, recordSkip, isProjectOwnedSeed,
|
|
7
|
-
const { mergeSettings, healUserSettings, mergeWatchtowerHooks, mergeMuxHooks, mergeBashCompressHooks } = require('./settings-merge');
|
|
8
|
-
const { create: createMetadata, read: readMetadata, readFrozenModules, setFrozenModules } = require('./metadata');
|
|
6
|
+
const { copyTemplates, recordSkip, isProjectOwnedSeed, classifyFileOwnership } = require('./copy');
|
|
7
|
+
const { mergeSettings, healUserSettings, mergeWatchtowerHooks, mergeMuxHooks, mergeBashCompressHooks, mergeCcDevHooks, mergeSkillOverrides } = require('./settings-merge');
|
|
8
|
+
const { create: createMetadata, read: readMetadata, readFrozenModules, setFrozenModules, readMcpOptOut } = require('./metadata');
|
|
9
9
|
const { setupDb, shouldSkipInit, readBundledSchemaVersion } = require('./db-setup');
|
|
10
10
|
const { setupVerifyRuntime } = require('./verify-setup');
|
|
11
11
|
const { setupSiteAuditRuntime } = require('./site-audit-setup');
|
|
@@ -442,281 +442,10 @@ function generateAgentWrappers(projectDir) {
|
|
|
442
442
|
return wanted.size;
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
// MODULES
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
// before v0.27.2 (test/manifest-integrity guards against recurrence).
|
|
450
|
-
//
|
|
451
|
-
// Intentional orphans (maintainer-only, must NOT ship to consumers) are
|
|
452
|
-
// allowlisted in test/manifest-integrity. Currently: skills/cc-publish
|
|
453
|
-
// (CC-source-repo release tooling, like scripts/migrate-all-consumers.js).
|
|
454
|
-
const MODULES = {
|
|
455
|
-
'session-loop': {
|
|
456
|
-
name: 'Session Loop (orient + debrief)',
|
|
457
|
-
description: 'The briefing cycle. Claude starts each session informed, ends by preparing the next briefing.',
|
|
458
|
-
mandatory: true,
|
|
459
|
-
templates: [
|
|
460
|
-
'skills/orient',
|
|
461
|
-
'skills/orient-quick',
|
|
462
|
-
'skills/debrief',
|
|
463
|
-
'skills/debrief-quick',
|
|
464
|
-
'skills/session-handoff',
|
|
465
|
-
// Instruction phases — always ship, overriding the default skip-phases rule in copy.js
|
|
466
|
-
'skills/debrief/phases/audit-pattern-capture.md',
|
|
467
|
-
'skills/debrief/phases/methodology-capture.md',
|
|
468
|
-
'skills/debrief/phases/record-lessons.md',
|
|
469
|
-
'skills/debrief/phases/upstream-feedback.md',
|
|
470
|
-
'skills/debrief/phases/qa-handoff-sweep.md',
|
|
471
|
-
// Reversibility scaffolding (act:6fa60c7d) — standalone classic copies
|
|
472
|
-
// of orient/debrief, kept invokable so the orient/debrief retirement is
|
|
473
|
-
// reversible during the watchtower transition. They do NOT delegate to
|
|
474
|
-
// the live orient/debrief (which will change at retirement); they ARE
|
|
475
|
-
// the old skills under a new name. orient-classic ships SKILL.md only
|
|
476
|
-
// (its phases use skeleton defaults, like live orient); debrief-classic
|
|
477
|
-
// ships its SKILL.md + the same instruction phases as live debrief.
|
|
478
|
-
'skills/orient-classic',
|
|
479
|
-
'skills/debrief-classic',
|
|
480
|
-
'skills/debrief-classic/phases/audit-pattern-capture.md',
|
|
481
|
-
'skills/debrief-classic/phases/methodology-capture.md',
|
|
482
|
-
'skills/debrief-classic/phases/record-lessons.md',
|
|
483
|
-
'skills/debrief-classic/phases/upstream-feedback.md',
|
|
484
|
-
'skills/debrief-classic/phases/qa-handoff-sweep.md',
|
|
485
|
-
'skills/menu',
|
|
486
|
-
],
|
|
487
|
-
},
|
|
488
|
-
'hooks': {
|
|
489
|
-
name: 'Git Guardrails + Telemetry',
|
|
490
|
-
description: 'Block destructive git ops (force push, hard reset). Track skill usage via JSONL telemetry.',
|
|
491
|
-
mandatory: false,
|
|
492
|
-
default: true,
|
|
493
|
-
lean: true,
|
|
494
|
-
templates: ['hooks/git-guardrails.sh', 'hooks/cc-upstream-guard.sh', 'hooks/skill-telemetry.sh', 'hooks/skill-tool-telemetry.sh', 'hooks/work-tracker-guard.sh', 'hooks/action-quality-gate.sh', 'hooks/action-completion-gate.sh', 'hooks/memory-index-guard.sh', 'scripts/cc-drift-check.cjs', 'scripts/skill-usage.mjs'],
|
|
495
|
-
},
|
|
496
|
-
'work-tracking': {
|
|
497
|
-
name: 'Work Tracking (pib-db or markdown)',
|
|
498
|
-
description: 'Track work items for orient/debrief. Default: SQLite (pib-db). Also supports markdown (tasks.md) or external systems. Choice made during /onboard.',
|
|
499
|
-
mandatory: false,
|
|
500
|
-
default: true,
|
|
501
|
-
lean: false,
|
|
502
|
-
templates: ['scripts/pib-db.mjs', 'scripts/pib-db-path.mjs', 'scripts/pib-db-lib.mjs', 'scripts/pib-db-mcp-server.mjs', 'scripts/pib-db-schema.sql', 'scripts/work-tracker-server.mjs', 'scripts/work-tracker-ui.html', 'skills/work-tracker', 'skills/spring-clean'],
|
|
503
|
-
needsDb: true,
|
|
504
|
-
},
|
|
505
|
-
'planning': {
|
|
506
|
-
name: 'Planning + Execution (plan + execute)',
|
|
507
|
-
description: 'Structured planning with cabinet critique — members weigh in before you build.',
|
|
508
|
-
mandatory: false,
|
|
509
|
-
default: true,
|
|
510
|
-
lean: true,
|
|
511
|
-
templates: ['skills/plan', 'skills/execute', 'skills/execute/phases/post-impl-checklist.md', 'skills/debrief/phases/checklist-feedback.md', 'skills/checklist-discover', 'skills/generate-plan-groups', 'skills/execute-group', 'workflows/execute-group-implement.js', 'workflows/execute-group-complete.js', 'skills/investigate', 'cabinet/checkpoint-protocol.md', 'cabinet/worktree-invocation-contract.md', 'cabinet/elicitation-methods.md', 'cabinet/qa-dimensions-template.yaml', 'cabinet/checklist-stats-schema.md', 'scripts/qa-dimensions-validator.cjs', 'skills/orient/phases/checklist-status.md', 'skills/audit/phases/checklist-pruning.md'],
|
|
512
|
-
},
|
|
513
|
-
'compliance': {
|
|
514
|
-
name: 'Compliance Stack (rules + enforcement)',
|
|
515
|
-
description: 'Scoped instructions that load by path. Enforcement pipeline for promoting patterns to rules.',
|
|
516
|
-
mandatory: false,
|
|
517
|
-
default: true,
|
|
518
|
-
lean: false,
|
|
519
|
-
templates: ['rules/enforcement-pipeline.md', 'rules/maintainability.md', 'rules/markdown-prose.md', 'rules/verify-before-asserting.md', 'rules/plan-before-bulk-or-irreversible-actions.md', 'rules/acknowledge-when-corrected.md', 'skills/unwrap', 'memory/patterns/_pattern-template.md', 'memory/patterns/pattern-intelligence-first.md'],
|
|
520
|
-
},
|
|
521
|
-
'memory': {
|
|
522
|
-
name: 'Built-In Memory (cc-remember + reader + validator)',
|
|
523
|
-
description: 'Curated write/validate layer over Claude Code\'s built-in file memory. /cc-remember writes indexed memories, /memory browses them, validate-memory.mjs guards MEMORY.md integrity. Replaced the retired omega engine in v0.27.',
|
|
524
|
-
mandatory: false,
|
|
525
|
-
default: true,
|
|
526
|
-
// lean:true is load-bearing — it keeps the skill triad, scripts, and
|
|
527
|
-
// rule installing together as an atomic unit. compliance is lean:false,
|
|
528
|
-
// so the memory-capture rule must NOT live there or lean installs get a
|
|
529
|
-
// partial, incoherent set.
|
|
530
|
-
lean: true,
|
|
531
|
-
templates: [
|
|
532
|
-
'skills/cc-remember',
|
|
533
|
-
'skills/memory',
|
|
534
|
-
'rules/memory-capture.md',
|
|
535
|
-
'cabinet/memory-lifecycle-contract.md',
|
|
536
|
-
'scripts/write-memory-file.mjs',
|
|
537
|
-
'scripts/validate-memory.mjs',
|
|
538
|
-
// project-context.cjs ships as a co-located sibling: the two .mjs
|
|
539
|
-
// scripts require('./project-context.cjs') and consumers have no lib/.
|
|
540
|
-
'scripts/project-context.cjs',
|
|
541
|
-
],
|
|
542
|
-
},
|
|
543
|
-
'audit': {
|
|
544
|
-
name: 'Audit Loop (audit + triage + cabinet)',
|
|
545
|
-
description: '27 expert cabinet members review your project. Convene the full cabinet or just one committee.',
|
|
546
|
-
mandatory: false,
|
|
547
|
-
default: true,
|
|
548
|
-
lean: true,
|
|
549
|
-
templates: [
|
|
550
|
-
'skills/audit', 'skills/pulse', 'skills/triage-audit', 'skills/cabinet',
|
|
551
|
-
'cabinet', 'briefing',
|
|
552
|
-
'skills/cabinet-accessibility', 'skills/cabinet-anti-confirmation',
|
|
553
|
-
'skills/cabinet-architecture', 'skills/cabinet-automation',
|
|
554
|
-
'skills/cabinet-boundary-man',
|
|
555
|
-
'skills/cabinet-anthropic-insider', 'skills/cabinet-cc-health',
|
|
556
|
-
'skills/cabinet-data-integrity',
|
|
557
|
-
'skills/cabinet-debugger', 'skills/cabinet-deployment',
|
|
558
|
-
'skills/cabinet-historian',
|
|
559
|
-
'skills/cabinet-organized-mind', 'skills/cabinet-process-therapist',
|
|
560
|
-
'skills/cabinet-qa', 'skills/cabinet-record-keeper',
|
|
561
|
-
'skills/cabinet-roster-check', 'skills/cabinet-security',
|
|
562
|
-
'skills/cabinet-seo',
|
|
563
|
-
'skills/cabinet-small-screen', 'skills/cabinet-speed-freak',
|
|
564
|
-
'skills/cabinet-system-advocate', 'skills/cabinet-technical-debt',
|
|
565
|
-
'skills/cabinet-usability', 'skills/cabinet-workflow-cop',
|
|
566
|
-
'skills/cabinet-framework-quality', 'skills/cabinet-goal-alignment',
|
|
567
|
-
'skills/cabinet-information-design', 'skills/cabinet-mantine-quality',
|
|
568
|
-
'skills/cabinet-ui-experimentalist', 'skills/cabinet-user-advocate',
|
|
569
|
-
'skills/cabinet-vision',
|
|
570
|
-
'skills/cabinet-narrative-architect', 'skills/cabinet-interactive-storyteller',
|
|
571
|
-
'skills/cabinet-elegance',
|
|
572
|
-
'scripts/merge-findings.js', 'scripts/load-triage-history.js',
|
|
573
|
-
'scripts/pib-db-path.mjs', // load-triage-history.js imports it (declared cross-module dep; also shipped by work-tracking)
|
|
574
|
-
'scripts/triage-server.mjs', 'scripts/triage-ui.html',
|
|
575
|
-
'scripts/finding-schema.json', 'scripts/resolve-committees.cjs',
|
|
576
|
-
'scripts/review-server.mjs', 'scripts/review-ui.html',
|
|
577
|
-
'workflows/deliberative-audit.js', 'cabinet/critique-contract.md',
|
|
578
|
-
],
|
|
579
|
-
},
|
|
580
|
-
'lifecycle': {
|
|
581
|
-
name: 'Lifecycle (onboard + seed + cc-upgrade + link)',
|
|
582
|
-
description: 'Onboarding prepares the briefings. Seed proposes new cabinet members when you adopt new tech.',
|
|
583
|
-
mandatory: false,
|
|
584
|
-
default: true,
|
|
585
|
-
lean: true,
|
|
586
|
-
templates: ['skills/onboard', 'skills/seed', 'skills/cc-upgrade', 'skills/cc-link', 'skills/cc-unlink', 'skills/cc-extract', 'skills/cc-feedback', 'cabinet/elicitation-methods.md'],
|
|
587
|
-
},
|
|
588
|
-
'validate': {
|
|
589
|
-
name: 'Validate',
|
|
590
|
-
description: 'Structural validation checks with unified summary. Define your own validators.',
|
|
591
|
-
mandatory: false,
|
|
592
|
-
default: true,
|
|
593
|
-
lean: false,
|
|
594
|
-
templates: ['skills/validate', 'scripts/skill-validator.sh'],
|
|
595
|
-
},
|
|
596
|
-
'verify': {
|
|
597
|
-
name: 'Verification Harness (Cucumber + Playwright)',
|
|
598
|
-
description: 'Walkthrough verification with human-in-the-loop verdict pauses. Replaces flat AC lists with re-runnable user-journey scenarios. Includes /verify skeleton skill + cabinet-verify npm runtime + opt-in integration phases for /plan, /execute, /debrief.',
|
|
599
|
-
mandatory: false,
|
|
600
|
-
default: false,
|
|
601
|
-
lean: false,
|
|
602
|
-
templates: [
|
|
603
|
-
'skills/verify',
|
|
604
|
-
'skills/plan/phases/verify-plan.md',
|
|
605
|
-
'skills/execute/phases/verify-emit.md',
|
|
606
|
-
'skills/debrief/phases/verify-coverage.md',
|
|
607
|
-
'skills/orient/phases/verify-backfill.md',
|
|
608
|
-
],
|
|
609
|
-
postInstall: 'verify-setup',
|
|
610
|
-
},
|
|
611
|
-
'site-audit': {
|
|
612
|
-
name: 'Site Audit (deployed-site quality)',
|
|
613
|
-
description: '14-check audit for deployed websites: performance, accessibility (3 engines), security, SEO, DNS, privacy, sustainability. Standalone HTML report + comparison mode.',
|
|
614
|
-
mandatory: false,
|
|
615
|
-
default: false,
|
|
616
|
-
lean: false,
|
|
617
|
-
templates: [
|
|
618
|
-
'skills/cc-site-audit',
|
|
619
|
-
'site-audit-runtime',
|
|
620
|
-
],
|
|
621
|
-
postInstall: 'site-audit-setup',
|
|
622
|
-
},
|
|
623
|
-
engagement: {
|
|
624
|
-
name: 'Engagement management (with secure credential handoff)',
|
|
625
|
-
description: 'Ongoing client-engagement management built on pib-db: per-recipient packets (rendered projections of the work backlog), role-gated billing, client feedback flowing back as events, and secure credential handoff (encrypted capture via OS dialog, pluggable email/MCP/file transport). Three primary skills across consultant and client sides, plus redirect stubs. Requires work-tracking (the pib-db adapter is the engine\'s data source).',
|
|
626
|
-
mandatory: false,
|
|
627
|
-
default: false,
|
|
628
|
-
lean: false,
|
|
629
|
-
requires: ['work-tracking'],
|
|
630
|
-
postInstall: 'engagement-setup',
|
|
631
|
-
templates: [
|
|
632
|
-
'skills/collab-client',
|
|
633
|
-
'skills/collab-consultant',
|
|
634
|
-
'skills/engagement-help',
|
|
635
|
-
'skills/engagement-create',
|
|
636
|
-
'skills/setup-accounts',
|
|
637
|
-
'skills/guide',
|
|
638
|
-
'engagement',
|
|
639
|
-
],
|
|
640
|
-
},
|
|
641
|
-
watchtower: {
|
|
642
|
-
name: 'Watchtower (continuous background state)',
|
|
643
|
-
description: 'Replaces orient/debrief with continuous background processing. Three rings (mechanical cron, Claude intelligence, session-aware), ambient state injection via SessionStart hook, and an inbox for extracted knowledge and signals. Sessions start informed with minimal context cost.',
|
|
644
|
-
mandatory: false,
|
|
645
|
-
default: false,
|
|
646
|
-
lean: false,
|
|
647
|
-
templates: [
|
|
648
|
-
'scripts/watchtower-validate.mjs',
|
|
649
|
-
'cabinet/watchtower-contracts.md',
|
|
650
|
-
'scripts/watchtower-lib.mjs',
|
|
651
|
-
'scripts/watchtower-queue.mjs',
|
|
652
|
-
'scripts/watchtower-routines.mjs',
|
|
653
|
-
'scripts/watchtower-hook-runner.mjs',
|
|
654
|
-
'scripts/watchtower-phase-shim.mjs',
|
|
655
|
-
'scripts/watchtower-sync.mjs',
|
|
656
|
-
'scripts/watchtower-advisories.mjs',
|
|
657
|
-
'cabinet/advisories-state-schema.md',
|
|
658
|
-
'skills/inbox',
|
|
659
|
-
'hooks/watchtower-session-start.sh',
|
|
660
|
-
'scripts/watchtower-build-context.mjs',
|
|
661
|
-
'scripts/watchtower-snapshot.mjs',
|
|
662
|
-
'scripts/watchtower-narrative-corpus.mjs',
|
|
663
|
-
'scripts/watchtower-cross-ring-reader.mjs',
|
|
664
|
-
'scripts/watchtower-ring1.mjs',
|
|
665
|
-
'scripts/watchtower-ring1-runner.sh',
|
|
666
|
-
'skills/watchtower',
|
|
667
|
-
'watchtower/com.claude-cabinet.watchtower-ring1.plist',
|
|
668
|
-
'watchtower/watchtower-ring1.service',
|
|
669
|
-
'watchtower/watchtower-ring1.timer',
|
|
670
|
-
'scripts/watchtower-ring2.mjs',
|
|
671
|
-
'scripts/watchtower-ring2-runner.sh',
|
|
672
|
-
'watchtower/com.claude-cabinet.watchtower-ring2-fast.plist',
|
|
673
|
-
'watchtower/com.claude-cabinet.watchtower-ring2-slow.plist',
|
|
674
|
-
'watchtower/watchtower-ring2-fast.service',
|
|
675
|
-
'watchtower/watchtower-ring2-fast.timer',
|
|
676
|
-
'watchtower/watchtower-ring2-slow.service',
|
|
677
|
-
'watchtower/watchtower-ring2-slow.timer',
|
|
678
|
-
'hooks/watchtower-session-end.sh',
|
|
679
|
-
'scripts/watchtower-ring3-close.mjs',
|
|
680
|
-
'scripts/watchtower-ring4.mjs',
|
|
681
|
-
'scripts/watchtower-ring4-runner.sh',
|
|
682
|
-
'scripts/watchtower-status.sh',
|
|
683
|
-
'skills/briefing',
|
|
684
|
-
'skills/threads',
|
|
685
|
-
'skills/catch-up',
|
|
686
|
-
'skills/qa-handoff',
|
|
687
|
-
'skills/qa-drain',
|
|
688
|
-
'skills/close',
|
|
689
|
-
],
|
|
690
|
-
},
|
|
691
|
-
mux: {
|
|
692
|
-
name: 'Mux (tmux project manager)',
|
|
693
|
-
description: 'Multi-project terminal manager. Desks (tmux sessions), auto-worktrees, trail logging, sticky notes, portal color-switching, and an MCP server for Claude. Installs to user-level paths (~/.local/bin/, ~/.config/mux/).',
|
|
694
|
-
mandatory: false,
|
|
695
|
-
default: false,
|
|
696
|
-
lean: false,
|
|
697
|
-
postInstall: 'mux-setup',
|
|
698
|
-
templates: ['skills/orient/phases/dx-captures.md', 'skills/dx-feedback'],
|
|
699
|
-
},
|
|
700
|
-
'engagement-server': {
|
|
701
|
-
name: 'Engagement Server',
|
|
702
|
-
description: 'Central multi-engagement API server. Deploys once to Railway/Fly, serves all client engagements. User-level infrastructure.',
|
|
703
|
-
mandatory: false,
|
|
704
|
-
default: false,
|
|
705
|
-
lean: false,
|
|
706
|
-
requires: ['engagement', 'work-tracking'],
|
|
707
|
-
postInstall: 'engagement-server-setup',
|
|
708
|
-
templates: [],
|
|
709
|
-
},
|
|
710
|
-
'bash-compress': {
|
|
711
|
-
name: 'Bash Output Compression Hook',
|
|
712
|
-
description: 'PostToolUse hook that compresses noisy Bash stdout (git status walls, npm/yarn install output, find/ls dumps) to reclaim context in long sessions. Off by default. stderr and error/warning lines pass through verbatim; every rewrite carries a visible [compressed] marker; fail-open on any error. Requires the hooks module (it wires into .claude/settings.json).',
|
|
713
|
-
mandatory: false,
|
|
714
|
-
default: false,
|
|
715
|
-
lean: false,
|
|
716
|
-
requires: ['hooks'],
|
|
717
|
-
templates: ['hooks/bash-output-compress.sh'],
|
|
718
|
-
},
|
|
719
|
-
};
|
|
445
|
+
// The MODULES manifest (the module → template-path registry) lives in its
|
|
446
|
+
// own file so this ~2000-line orchestrator stays navigable (architecture-0005).
|
|
447
|
+
// Re-exported below for back-compat with importers of `require('../lib/cli').MODULES`.
|
|
448
|
+
const { MODULES } = require('./modules');
|
|
720
449
|
|
|
721
450
|
/** Recursively collect all relative file paths under a directory. */
|
|
722
451
|
function walkDir(dir, base) {
|
|
@@ -822,6 +551,35 @@ function computeRemovals({ existingManifest, allManifest, selectedModules, templ
|
|
|
822
551
|
return { toRemove, kept };
|
|
823
552
|
}
|
|
824
553
|
|
|
554
|
+
// Merge CC-shipped MCP server entries into a consumer's .mcp.json mcpServers
|
|
555
|
+
// object, honoring the .ccrc.json `mcpOptOut` list (act:b770c323). Pure and
|
|
556
|
+
// mutating-in-place on `existing` (the caller serializes the parent object):
|
|
557
|
+
// - incoming keys NOT opted out are set/overwritten (the prior Object.assign
|
|
558
|
+
// behavior) and reported in `added`;
|
|
559
|
+
// - incoming keys the consumer opted out are never added (`skipped`);
|
|
560
|
+
// - an opted-out key already present in `existing` is DELETED (`removed`) —
|
|
561
|
+
// self-heal toward the declared intent, but ONLY for keys CC itself ships
|
|
562
|
+
// (in `incoming`), so a consumer's hand-added servers are never touched.
|
|
563
|
+
function mergeMcpServers(existing, incoming = {}, optOut = []) {
|
|
564
|
+
const optedOut = new Set(optOut);
|
|
565
|
+
const added = [];
|
|
566
|
+
const removed = [];
|
|
567
|
+
const skipped = [];
|
|
568
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
569
|
+
if (optedOut.has(key)) {
|
|
570
|
+
skipped.push(key);
|
|
571
|
+
if (Object.prototype.hasOwnProperty.call(existing, key)) {
|
|
572
|
+
delete existing[key];
|
|
573
|
+
removed.push(key);
|
|
574
|
+
}
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
existing[key] = value;
|
|
578
|
+
added.push(key);
|
|
579
|
+
}
|
|
580
|
+
return { added, removed, skipped };
|
|
581
|
+
}
|
|
582
|
+
|
|
825
583
|
// Signals that a directory contains a real project (not just empty)
|
|
826
584
|
const PROJECT_SIGNALS = [
|
|
827
585
|
'package.json', 'Cargo.toml', 'requirements.txt', 'pyproject.toml',
|
|
@@ -961,6 +719,42 @@ function printHelp() {
|
|
|
961
719
|
`);
|
|
962
720
|
}
|
|
963
721
|
|
|
722
|
+
// --- advisories-state gitignore seeding (act:c008862c) ---
|
|
723
|
+
// .claude/cabinet/advisories-state.json is machine-written runtime state
|
|
724
|
+
// (the advisory pass rewrites it), so tracked it churns every commit and
|
|
725
|
+
// reads as authored work in mux worktrees. FRESH installs (no prior
|
|
726
|
+
// .ccrc.json) seed a .gitignore entry so it never enters git; existing
|
|
727
|
+
// installs are left untouched — untracking a live consumer repo is
|
|
728
|
+
// operator-gated — but a TRACKED copy is reported so the consumer walk
|
|
729
|
+
// surfaces it. Pure and injectable for tests.
|
|
730
|
+
const ADVISORIES_STATE_PATH = '.claude/cabinet/advisories-state.json';
|
|
731
|
+
function seedAdvisoriesGitignore(projectDir, { fresh, dryRun, exec } = {}) {
|
|
732
|
+
const run = exec || ((cmd) => require('child_process').execSync(cmd, { cwd: projectDir, stdio: 'pipe' }));
|
|
733
|
+
try {
|
|
734
|
+
run(`git ls-files --error-unmatch ${ADVISORIES_STATE_PATH}`);
|
|
735
|
+
return { status: 'tracked-reported' };
|
|
736
|
+
} catch { /* not tracked — fall through */ }
|
|
737
|
+
if (!fresh) return { status: 'skipped-existing-install' };
|
|
738
|
+
try {
|
|
739
|
+
run('git rev-parse --git-dir');
|
|
740
|
+
} catch {
|
|
741
|
+
return { status: 'skipped-no-git' };
|
|
742
|
+
}
|
|
743
|
+
try {
|
|
744
|
+
// Already ignored by ANY rule (exact line or a covering glob like this
|
|
745
|
+
// repo's `.claude/cabinet/*`) — nothing to add.
|
|
746
|
+
run(`git check-ignore -q ${ADVISORIES_STATE_PATH}`);
|
|
747
|
+
return { status: 'already-present' };
|
|
748
|
+
} catch { /* not ignored — seed below */ }
|
|
749
|
+
const giPath = path.join(projectDir, '.gitignore');
|
|
750
|
+
let content = '';
|
|
751
|
+
try { content = fs.readFileSync(giPath, 'utf8'); } catch { /* no .gitignore yet */ }
|
|
752
|
+
if (dryRun) return { status: 'would-seed' };
|
|
753
|
+
const nl = content && !content.endsWith('\n') ? '\n' : '';
|
|
754
|
+
fs.appendFileSync(giPath, `${nl}# machine-written advisory-dismissal state (CC)\n${ADVISORIES_STATE_PATH}\n`);
|
|
755
|
+
return { status: 'seeded' };
|
|
756
|
+
}
|
|
757
|
+
|
|
964
758
|
async function run() {
|
|
965
759
|
const flags = parseArgs(process.argv);
|
|
966
760
|
|
|
@@ -1463,69 +1257,88 @@ async function run() {
|
|
|
1463
1257
|
const incoming = fs.readFileSync(srcPath, 'utf8');
|
|
1464
1258
|
const incomingHash = hashContent(incoming);
|
|
1465
1259
|
const mPath = manifestPath(tmpl);
|
|
1260
|
+
const destExists = fs.existsSync(destPath);
|
|
1261
|
+
const existingContent = destExists ? fs.readFileSync(destPath, 'utf8') : null;
|
|
1262
|
+
// Instruction phases explicitly listed in MODULES are CC-owned and must
|
|
1263
|
+
// always overwrite (they're not customizable); other phase files are
|
|
1264
|
+
// preserved when the operator has edited them.
|
|
1265
|
+
const isPhaseFile = tmpl.includes('/phases/') || tmpl.includes('\\phases\\');
|
|
1266
|
+
const isInstructionPhase = isPhaseFile && mod.templates.includes(tmpl);
|
|
1267
|
+
|
|
1268
|
+
// Single decision spine — the ownership cascade lives in copy.js
|
|
1269
|
+
// (classifyFileOwnership) so this branch can't drift from the directory
|
|
1270
|
+
// walk. The leak this closes: the hand-inlined copy here was missing
|
|
1271
|
+
// the project-owned-seed guard (elegance-0002, act:a6377c82).
|
|
1272
|
+
const decision = classifyFileOwnership({
|
|
1273
|
+
relPath: tmpl,
|
|
1274
|
+
destExists,
|
|
1275
|
+
existingContent,
|
|
1276
|
+
incoming,
|
|
1277
|
+
isPhaseFile,
|
|
1278
|
+
isInstructionPhase,
|
|
1279
|
+
frozen,
|
|
1280
|
+
isCcOwned: Boolean(existingManifest[mPath]),
|
|
1281
|
+
skipConflicts: flags.yes || dirState === 'existing-install',
|
|
1282
|
+
});
|
|
1466
1283
|
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1284
|
+
switch (decision.action) {
|
|
1285
|
+
case 'seed':
|
|
1286
|
+
// Project-owned seed (act:2001bf54): seed if absent, NEVER
|
|
1287
|
+
// overwrite, ALWAYS omit from the manifest.
|
|
1288
|
+
if (!destExists) {
|
|
1289
|
+
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
1290
|
+
totalCopied++;
|
|
1291
|
+
} else {
|
|
1292
|
+
totalSkipped++;
|
|
1293
|
+
}
|
|
1294
|
+
recordSkip(allManifest, mPath);
|
|
1295
|
+
continue;
|
|
1296
|
+
case 'preserve-phase':
|
|
1297
|
+
console.log(` Preserved customized phase: ${tmpl}`);
|
|
1298
|
+
totalSkipped++;
|
|
1299
|
+
recordSkip(allManifest, mPath);
|
|
1300
|
+
continue;
|
|
1301
|
+
case 'skip-identical':
|
|
1470
1302
|
totalSkipped++;
|
|
1471
1303
|
recordSkip(allManifest, mPath, { identical: true, incomingHash });
|
|
1472
1304
|
continue;
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
console.log(`
|
|
1305
|
+
case 'freeze-hold':
|
|
1306
|
+
totalSkipped++;
|
|
1307
|
+
frozenCounts[modKey] = (frozenCounts[modKey] || 0) + 1;
|
|
1308
|
+
allManifest[mPath] = decision.manifestHash;
|
|
1309
|
+
console.log(` ❄ Frozen (held): ${path.relative(projectDir, destPath)}`);
|
|
1310
|
+
continue;
|
|
1311
|
+
case 'overwrite':
|
|
1312
|
+
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
1313
|
+
totalOverwritten++;
|
|
1314
|
+
// Log single-file overwrites too — the directory path (copy.js)
|
|
1315
|
+
// already does. Without this, scripts/ updates are invisible in
|
|
1316
|
+
// install output, masking whether a changed script propagated.
|
|
1317
|
+
console.log(` Updated: ${path.relative(projectDir, destPath)}`);
|
|
1318
|
+
allManifest[mPath] = incomingHash;
|
|
1319
|
+
continue;
|
|
1320
|
+
case 'skip-omit':
|
|
1486
1321
|
totalSkipped++;
|
|
1487
|
-
//
|
|
1488
|
-
//
|
|
1322
|
+
// Project-created file → omit from manifest entirely. Ownership
|
|
1323
|
+
// classification is manifest-PRESENCE-based, so recording ANY hash
|
|
1324
|
+
// here would mark the file upstream-owned and the NEXT install
|
|
1325
|
+
// would silently overwrite it (act:bf21c95b).
|
|
1489
1326
|
recordSkip(allManifest, mPath);
|
|
1490
1327
|
continue;
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
if (
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
// decision.omit → project-owned; fall through.
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
if (flags.yes || dirState === 'existing-install') {
|
|
1510
|
-
// If file is in the old manifest, it's upstream-managed — overwrite.
|
|
1511
|
-
// If not, it's project-created — skip.
|
|
1512
|
-
if (existingManifest[mPath]) {
|
|
1513
|
-
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
1514
|
-
totalOverwritten++;
|
|
1515
|
-
// Log single-file overwrites too — the directory path (copy.js)
|
|
1516
|
-
// already does. Without this, scripts/ updates are invisible in
|
|
1517
|
-
// install output, masking whether a changed script propagated.
|
|
1518
|
-
console.log(` Updated: ${path.relative(projectDir, destPath)}`);
|
|
1519
|
-
allManifest[mPath] = incomingHash;
|
|
1520
|
-
} else {
|
|
1521
|
-
totalSkipped++;
|
|
1522
|
-
// Project-created file → omit from manifest entirely. Ownership
|
|
1523
|
-
// classification is manifest-PRESENCE-based, so recording ANY
|
|
1524
|
-
// hash here would mark the file upstream-owned and the NEXT
|
|
1525
|
-
// install would silently overwrite it (act:bf21c95b).
|
|
1526
|
-
recordSkip(allManifest, mPath);
|
|
1527
|
-
}
|
|
1528
|
-
} else {
|
|
1328
|
+
case 'freeze-hold-new':
|
|
1329
|
+
// New file in a frozen module: hold it back (don't create) so the
|
|
1330
|
+
// module stays internally consistent at its pinned version. Report
|
|
1331
|
+
// only — never a manifest entry (no on-disk content to hash).
|
|
1332
|
+
frozenCounts[modKey] = (frozenCounts[modKey] || 0) + 1;
|
|
1333
|
+
console.log(` ❄ Frozen (held new): ${path.relative(projectDir, destPath)}`);
|
|
1334
|
+
continue;
|
|
1335
|
+
case 'copy-new':
|
|
1336
|
+
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
1337
|
+
totalCopied++;
|
|
1338
|
+
allManifest[mPath] = incomingHash;
|
|
1339
|
+
continue;
|
|
1340
|
+
case 'prompt':
|
|
1341
|
+
default: {
|
|
1529
1342
|
const response = await prompts({
|
|
1530
1343
|
type: 'select',
|
|
1531
1344
|
name: 'action',
|
|
@@ -1546,19 +1359,8 @@ async function run() {
|
|
|
1546
1359
|
// the manifest so it is never mistaken for upstream content.
|
|
1547
1360
|
recordSkip(allManifest, mPath);
|
|
1548
1361
|
}
|
|
1549
|
-
}
|
|
1550
|
-
} else {
|
|
1551
|
-
// New file in a frozen module: hold it back (don't create) so the
|
|
1552
|
-
// module stays internally consistent at its pinned version. Report
|
|
1553
|
-
// only — never a manifest entry (no on-disk content to hash).
|
|
1554
|
-
if (frozen) {
|
|
1555
|
-
frozenCounts[modKey] = (frozenCounts[modKey] || 0) + 1;
|
|
1556
|
-
console.log(` ❄ Frozen (held new): ${path.relative(projectDir, destPath)}`);
|
|
1557
1362
|
continue;
|
|
1558
1363
|
}
|
|
1559
|
-
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
1560
|
-
totalCopied++;
|
|
1561
|
-
allManifest[mPath] = incomingHash;
|
|
1562
1364
|
}
|
|
1563
1365
|
}
|
|
1564
1366
|
}
|
|
@@ -1619,6 +1421,27 @@ async function run() {
|
|
|
1619
1421
|
mergeBashCompressHooks(settingsPath);
|
|
1620
1422
|
console.log(' ⚙️ Registered bash-output compression PostToolUse hook');
|
|
1621
1423
|
}
|
|
1424
|
+
|
|
1425
|
+
// Repo-local maintainer hooks — no-op unless this IS the CC source repo
|
|
1426
|
+
// (dogfood). Registers the node --check PostToolUse gate durably so a
|
|
1427
|
+
// reinstall can't silently regenerate it away (architecture-0004).
|
|
1428
|
+
if (mergeCcDevHooks(projectDir)) {
|
|
1429
|
+
console.log(' ⚙️ Registered repo-local node --check PostToolUse hook (CC source repo)');
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// cabinet-* skills are ~half the skill-listing budget and are spawned by
|
|
1433
|
+
// agentType (name), never auto-invoked by description — so set them
|
|
1434
|
+
// "name-only" to free budget for the routing skills that need full trigger
|
|
1435
|
+
// keywords (act:bee0fa16). Only-if-absent, so a user override is preserved.
|
|
1436
|
+
if (selectedModules.includes('audit')) {
|
|
1437
|
+
const cabinetSkills = (MODULES.audit.templates || [])
|
|
1438
|
+
.map((t) => (t.match(/^skills\/(cabinet-[^/]+)$/) || [])[1])
|
|
1439
|
+
.filter(Boolean);
|
|
1440
|
+
const added = mergeSkillOverrides(projectDir, cabinetSkills);
|
|
1441
|
+
if (added > 0) {
|
|
1442
|
+
console.log(` ⚙️ Set ${added} cabinet-* skill${added === 1 ? '' : 's'} to name-only (frees skill-listing budget)`);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1622
1445
|
}
|
|
1623
1446
|
|
|
1624
1447
|
// --- Heal user-level ~/.claude/settings.json ---
|
|
@@ -1648,9 +1471,22 @@ async function run() {
|
|
|
1648
1471
|
existing = {};
|
|
1649
1472
|
}
|
|
1650
1473
|
if (!existing.mcpServers) existing.mcpServers = {};
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1474
|
+
const optOut = readMcpOptOut(projectDir);
|
|
1475
|
+
const { added, removed, skipped } = mergeMcpServers(existing.mcpServers, mcpConfig.mcpServers, optOut);
|
|
1476
|
+
// Only write when this merge actually contributed or healed something —
|
|
1477
|
+
// an all-opted-out install must not reformat a consumer's .mcp.json.
|
|
1478
|
+
if (added.length > 0 || removed.length > 0) {
|
|
1479
|
+
fs.writeFileSync(mcpJsonPath, JSON.stringify(existing, null, 2) + '\n');
|
|
1480
|
+
}
|
|
1481
|
+
if (added.length > 0) {
|
|
1482
|
+
console.log(` 🔌 Merged ${added.join(', ')} MCP server into .mcp.json`);
|
|
1483
|
+
}
|
|
1484
|
+
if (skipped.length > 0) {
|
|
1485
|
+
console.log(` ⏭ MCP registration declined by .ccrc.json mcpOptOut: ${skipped.join(', ')}`);
|
|
1486
|
+
}
|
|
1487
|
+
if (removed.length > 0) {
|
|
1488
|
+
console.log(` 🧹 Removed opted-out MCP entr${removed.length === 1 ? 'y' : 'ies'} from .mcp.json: ${removed.join(', ')}`);
|
|
1489
|
+
}
|
|
1654
1490
|
}
|
|
1655
1491
|
} catch (err) {
|
|
1656
1492
|
console.log(` ⚠ MCP config merge failed: ${err.message}`);
|
|
@@ -1874,6 +1710,23 @@ async function run() {
|
|
|
1874
1710
|
}
|
|
1875
1711
|
}
|
|
1876
1712
|
|
|
1713
|
+
// --- Seed advisories-state gitignore (fresh installs only; act:c008862c) ---
|
|
1714
|
+
try {
|
|
1715
|
+
const seedResult = seedAdvisoriesGitignore(projectDir, {
|
|
1716
|
+
fresh: dirState !== 'existing-install',
|
|
1717
|
+
dryRun: !!flags.dryRun,
|
|
1718
|
+
});
|
|
1719
|
+
if (seedResult.status === 'seeded') {
|
|
1720
|
+
console.log(' 🙈 Gitignored .claude/cabinet/advisories-state.json (machine-written state)');
|
|
1721
|
+
} else if (seedResult.status === 'would-seed') {
|
|
1722
|
+
console.log(' [dry run] Would gitignore .claude/cabinet/advisories-state.json');
|
|
1723
|
+
} else if (seedResult.status === 'tracked-reported') {
|
|
1724
|
+
console.log(' ℹ .claude/cabinet/advisories-state.json is TRACKED in this repo — left untouched. Untracking (git rm --cached) is an operator call; tracked, it churns every commit.');
|
|
1725
|
+
}
|
|
1726
|
+
} catch (err) {
|
|
1727
|
+
console.log(` ⚠ advisories-state gitignore seeding skipped: ${err.message}`);
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1877
1730
|
// --- Write metadata ---
|
|
1878
1731
|
if (!flags.dryRun) {
|
|
1879
1732
|
createMetadata(projectDir, {
|
|
@@ -1967,4 +1820,4 @@ async function run() {
|
|
|
1967
1820
|
console.log('');
|
|
1968
1821
|
}
|
|
1969
1822
|
|
|
1970
|
-
module.exports = { run, MODULES, generateAgentWrappers, generateSkillIndex, expandFrozenClosure, computeRemovals, manifestPath };
|
|
1823
|
+
module.exports = { run, MODULES, generateAgentWrappers, generateSkillIndex, expandFrozenClosure, computeRemovals, mergeMcpServers, manifestPath, seedAdvisoriesGitignore };
|