@mmerterden/multi-agent-pipeline 12.6.0 → 12.7.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/CHANGELOG.md +83 -0
- package/README.md +18 -18
- package/docs/FIGMA_PIPELINE.md +34 -34
- package/docs/adr/0001-three-model-triage.md +12 -12
- package/docs/adr/0002-instruction-driven-flag.md +5 -5
- package/docs/adr/0003-unified-shared-skills.md +5 -5
- package/docs/adr/0004-zero-dependency-philosophy.md +5 -5
- package/docs/adr/0005-lazy-phase-docs.md +2 -2
- package/docs/adr/0006-skills-core-external-split.md +6 -6
- package/docs/adr/0007-multi-tool-adapter-framework.md +19 -19
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +19 -19
- package/docs/adr/README.md +1 -1
- package/docs/best-practices.md +3 -3
- package/docs/features.md +28 -28
- package/docs/performance.md +16 -16
- package/docs/recovery-guide.md +39 -39
- package/index.js +4 -4
- package/install/_common.mjs +5 -11
- package/install/_copilot-instructions.mjs +2 -2
- package/install/_dev-only-files.mjs +1 -1
- package/install/_platform-filter.mjs +1 -1
- package/install/_telemetry.mjs +1 -1
- package/install/claude.mjs +10 -9
- package/install/copilot.mjs +10 -19
- package/install/index.mjs +7 -15
- package/install/templates/copilot-instructions.md +54 -54
- package/install.js +1 -1
- package/package.json +13 -10
- package/pipeline/commands/multi-agent/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/design-check/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/finish/SKILL.md +6 -6
- package/pipeline/commands/multi-agent/forget/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/issue/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/log/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/purge/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/refactor/SKILL.md +16 -8
- package/pipeline/commands/multi-agent/resume/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/review/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/routines/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/save/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/search/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/stack/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/status/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/sync/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/test/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +3 -3
- package/pipeline/eval/run-metrics-fixture.json +60 -13
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/channels-multi-repo.sh +1 -1
- package/pipeline/lib/context-link-extractor.sh +1 -1
- package/pipeline/lib/credential-store.sh +1 -1
- package/pipeline/lib/fetch-confluence.sh +1 -1
- package/pipeline/lib/fetch-crashlytics.sh +1 -1
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/fetch-graylog.sh +1 -1
- package/pipeline/lib/fetch-swagger.sh +1 -1
- package/pipeline/lib/issue-fetcher.sh +1 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/repo-cache.sh +1 -1
- package/pipeline/lib/submodule-detector.sh +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
- package/pipeline/multi-agent-refs/component-generation.md +121 -0
- package/pipeline/multi-agent-refs/cross-cli-contract.md +1 -1
- package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +1 -1
- package/pipeline/preferences-template.json +5 -11
- package/pipeline/schemas/agent-state.schema.json +39 -9
- package/pipeline/schemas/analysis-output.schema.json +18 -4
- package/pipeline/schemas/analysis-spec.schema.json +120 -32
- package/pipeline/schemas/clarify-output.schema.json +15 -5
- package/pipeline/schemas/design-check-config.schema.json +32 -11
- package/pipeline/schemas/dev-critic-output.schema.json +20 -5
- package/pipeline/schemas/figma-project-config.schema.json +42 -10
- package/pipeline/schemas/learnings-ledger.schema.json +10 -2
- package/pipeline/schemas/migrations/figma-config-1.0.0-to-2.0.0.mjs +1 -4
- package/pipeline/schemas/migrations/prefs-2.0.0-to-2.1.0.mjs +24 -7
- package/pipeline/schemas/plan-todos.schema.json +6 -3
- package/pipeline/schemas/planning-output.schema.json +5 -1
- package/pipeline/schemas/prefs.schema.json +91 -229
- package/pipeline/schemas/test-gap.schema.json +5 -5
- package/pipeline/schemas/token-budget.json +8 -8
- package/pipeline/schemas/triage-corpus.schema.json +1 -1
- package/pipeline/scripts/aggregate-metrics.mjs +18 -6
- package/pipeline/scripts/build-skills-index.mjs +6 -2
- package/pipeline/scripts/build-stack-plugins.mjs +142 -39
- package/pipeline/scripts/check-derived-drift.mjs +196 -0
- package/pipeline/scripts/check-md-links.mjs +6 -2
- package/pipeline/scripts/classify-plan-safety.mjs +20 -7
- package/pipeline/scripts/cost-budget-check.mjs +2 -1
- package/pipeline/scripts/cost-table.json +1 -1
- package/pipeline/scripts/diff-explain.mjs +7 -3
- package/pipeline/scripts/diff-risk-score.mjs +13 -3
- package/pipeline/scripts/eval-golden-tasks-live.mjs +8 -3
- package/pipeline/scripts/eval-golden-tasks.mjs +21 -9
- package/pipeline/scripts/eval-intent.mjs +8 -4
- package/pipeline/scripts/eval-mine-corpus.mjs +14 -4
- package/pipeline/scripts/evidence-gate.mjs +7 -2
- package/pipeline/scripts/fixtures/install-layout.tsv +3 -3
- package/pipeline/scripts/gen-mode-dispatch.mjs +38 -21
- package/pipeline/scripts/gen-skills-index.mjs +18 -3
- package/pipeline/scripts/learning-curve.mjs +13 -3
- package/pipeline/scripts/learnings-ledger.mjs +103 -36
- package/pipeline/scripts/lint-mcp-refs.mjs +13 -2
- package/pipeline/scripts/lint-skills.mjs +20 -9
- package/pipeline/scripts/localize-commands.mjs +6 -1
- package/pipeline/scripts/match-skills.mjs +15 -4
- package/pipeline/scripts/migrate-prefs.mjs +33 -16
- package/pipeline/scripts/phase-tracker.sh +3 -1
- package/pipeline/scripts/repo-map.mjs +110 -64
- package/pipeline/scripts/review-scope.mjs +7 -1
- package/pipeline/scripts/routine-registry.mjs +4 -9
- package/pipeline/scripts/run-aggregator.mjs +11 -5
- package/pipeline/scripts/run-metrics.mjs +13 -8
- package/pipeline/scripts/run-smokes.mjs +57 -3
- package/pipeline/scripts/scorecard.mjs +258 -0
- package/pipeline/scripts/smoke-context-budget.sh +72 -0
- package/pipeline/scripts/smoke-model-fallback.sh +1 -1
- package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +86 -7
- package/pipeline/scripts/smoke-own-punctuation.sh +103 -0
- package/pipeline/scripts/smoke-workflow-audit.sh +43 -11
- package/pipeline/scripts/smoke-write-state.sh +49 -5
- package/pipeline/scripts/test-gap-rules/android.json +11 -11
- package/pipeline/scripts/test-gap-rules/ios.json +16 -11
- package/pipeline/scripts/test-gap-rules/node.json +19 -7
- package/pipeline/scripts/test-gap-rules/python.json +10 -4
- package/pipeline/scripts/test-gap-scan.mjs +44 -12
- package/pipeline/scripts/test-integrity-gate.mjs +5 -1
- package/pipeline/scripts/token-budget-report.mjs +44 -21
- package/pipeline/scripts/triage-memory.mjs +126 -34
- package/pipeline/scripts/uninstall.mjs +74 -30
- package/pipeline/scripts/validate-analysis-doc.mjs +15 -5
- package/pipeline/scripts/validate-diff-risk.mjs +32 -18
- package/pipeline/scripts/validate-test-gap.mjs +17 -7
- package/pipeline/scripts/validate-triage.mjs +17 -5
- package/pipeline/scripts/write-state.mjs +32 -9
- package/pipeline/skills/.skills-index.json +91 -91
- package/pipeline/skills/shared/README.md +57 -57
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +1 -1
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +26 -279
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +16 -8
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +1 -1
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +1 -1
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -4
- package/pipeline/skills/shared/external/agentflow/SKILL.md +1 -1
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/android_ui_verification/SKILL.md +1 -1
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +1 -1
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +1 -1
- package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +12 -12
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -1
- package/pipeline/skills/shared/external/context-compression/SKILL.md +1 -1
- package/pipeline/skills/shared/external/council/SKILL.md +3 -3
- package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -1
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +1 -1
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +1 -1
- package/pipeline/skills/shared/external/firebase/SKILL.md +1 -1
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +1 -1
- package/pipeline/skills/shared/external/help-skills/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -1
- package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +1 -1
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +1 -1
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +1 -1
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -1
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +1 -1
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -1
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -2
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +12 -12
- package/pipeline/skills/shared/external/skill-creator/audit.md +21 -21
- package/pipeline/skills/shared/external/skill-creator/checklist.md +3 -3
- package/pipeline/skills/shared/external/skill-creator/examples.md +10 -10
- package/pipeline/skills/shared/external/skill-creator/label-check.md +17 -17
- package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +86 -50
- package/pipeline/skills/shared/external/skill-creator/template.md +9 -9
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +1 -1
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -1
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -1
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -1
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -1
- package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/schemas/build-benchmark.schema.json +9 -49
- package/pipeline/skills/skills-index.md +57 -57
- package/pipeline/scripts/smoke-plugin-validate.sh +0 -64
|
@@ -43,7 +43,15 @@
|
|
|
43
43
|
* @module pipeline/scripts/learnings-ledger
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
readFileSync,
|
|
48
|
+
writeFileSync,
|
|
49
|
+
renameSync,
|
|
50
|
+
existsSync,
|
|
51
|
+
mkdirSync,
|
|
52
|
+
appendFileSync,
|
|
53
|
+
statSync,
|
|
54
|
+
} from "node:fs";
|
|
47
55
|
import { homedir } from "node:os";
|
|
48
56
|
import { execFileSync } from "node:child_process";
|
|
49
57
|
import { join, basename, dirname } from "node:path";
|
|
@@ -59,11 +67,16 @@ for (let i = 1; i < argv.length; i++) {
|
|
|
59
67
|
// (e.g. --statement="-- prefer let over var"). Use it when the space form
|
|
60
68
|
// would mistake the value for the next flag.
|
|
61
69
|
const eq = body.indexOf("=");
|
|
62
|
-
if (eq !== -1) {
|
|
70
|
+
if (eq !== -1) {
|
|
71
|
+
flags[body.slice(0, eq)] = body.slice(eq + 1);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
63
74
|
const k = body;
|
|
64
75
|
const v = argv[i + 1];
|
|
65
|
-
if (v !== undefined && !v.startsWith("--")) {
|
|
66
|
-
|
|
76
|
+
if (v !== undefined && !v.startsWith("--")) {
|
|
77
|
+
flags[k] = v;
|
|
78
|
+
i++;
|
|
79
|
+
} else flags[k] = true;
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
const KINDS = new Set(["fact", "convention", "rejected-preference"]);
|
|
@@ -86,7 +99,7 @@ function repoSlug() {
|
|
|
86
99
|
const commonDir = execFileSync(
|
|
87
100
|
"git",
|
|
88
101
|
["rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
89
|
-
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
|
|
102
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] },
|
|
90
103
|
).trim();
|
|
91
104
|
if (commonDir) {
|
|
92
105
|
const base = basename(commonDir);
|
|
@@ -94,19 +107,30 @@ function repoSlug() {
|
|
|
94
107
|
const slug = basename(root);
|
|
95
108
|
if (slug) return slug;
|
|
96
109
|
}
|
|
97
|
-
} catch {
|
|
110
|
+
} catch {
|
|
111
|
+
/* not a git repo, or git too old for --path-format */
|
|
112
|
+
}
|
|
98
113
|
try {
|
|
99
114
|
const top = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
100
115
|
encoding: "utf8",
|
|
101
116
|
stdio: ["ignore", "pipe", "ignore"],
|
|
102
117
|
}).trim();
|
|
103
118
|
if (top) return basename(top);
|
|
104
|
-
} catch {
|
|
119
|
+
} catch {
|
|
120
|
+
/* not a git repo */
|
|
121
|
+
}
|
|
105
122
|
return "default";
|
|
106
123
|
}
|
|
107
124
|
|
|
108
125
|
function ledgerPath(slug) {
|
|
109
|
-
return join(
|
|
126
|
+
return join(
|
|
127
|
+
homedir(),
|
|
128
|
+
".claude",
|
|
129
|
+
"memory",
|
|
130
|
+
"multi-agent",
|
|
131
|
+
slug || repoSlug(),
|
|
132
|
+
"learnings-ledger.jsonl",
|
|
133
|
+
);
|
|
110
134
|
}
|
|
111
135
|
|
|
112
136
|
function ensureDir(p) {
|
|
@@ -114,7 +138,10 @@ function ensureDir(p) {
|
|
|
114
138
|
}
|
|
115
139
|
|
|
116
140
|
function normStatement(s) {
|
|
117
|
-
return String(s || "")
|
|
141
|
+
return String(s || "")
|
|
142
|
+
.toLowerCase()
|
|
143
|
+
.replace(/\s+/g, " ")
|
|
144
|
+
.trim();
|
|
118
145
|
}
|
|
119
146
|
|
|
120
147
|
function readLedger(slug) {
|
|
@@ -124,8 +151,11 @@ function readLedger(slug) {
|
|
|
124
151
|
const rows = [];
|
|
125
152
|
for (const line of raw.split("\n")) {
|
|
126
153
|
if (!line.trim()) continue;
|
|
127
|
-
try {
|
|
128
|
-
|
|
154
|
+
try {
|
|
155
|
+
rows.push(JSON.parse(line));
|
|
156
|
+
} catch {
|
|
157
|
+
/* skip corrupted line */
|
|
158
|
+
}
|
|
129
159
|
}
|
|
130
160
|
return rows;
|
|
131
161
|
}
|
|
@@ -166,18 +196,25 @@ function addEntry(slug, { kind, statement, scope, task, confidence, diagnosis },
|
|
|
166
196
|
function cmdAdd() {
|
|
167
197
|
const kind = flags.kind;
|
|
168
198
|
if (!KINDS.has(kind)) die(`--kind must be one of: ${[...KINDS].join(", ")}`, 1);
|
|
169
|
-
if (!flags.statement || flags.statement === true) die(
|
|
199
|
+
if (!flags.statement || flags.statement === true) die('add needs --statement "..."', 1);
|
|
170
200
|
const slug = repoSlug();
|
|
171
201
|
const existing = new Set(readLedger(slug).map((r) => `${r.kind}::${normStatement(r.statement)}`));
|
|
172
|
-
const wrote = addEntry(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
202
|
+
const wrote = addEntry(
|
|
203
|
+
slug,
|
|
204
|
+
{
|
|
205
|
+
kind,
|
|
206
|
+
statement: flags.statement,
|
|
207
|
+
scope: flags.scope && flags.scope !== true ? String(flags.scope) : "global",
|
|
208
|
+
task: flags.task && flags.task !== true ? String(flags.task) : null,
|
|
209
|
+
confidence:
|
|
210
|
+
flags.confidence && flags.confidence !== true ? String(flags.confidence) : "medium",
|
|
211
|
+
diagnosis: flags.diagnosis && flags.diagnosis !== true ? String(flags.diagnosis) : null,
|
|
212
|
+
},
|
|
213
|
+
existing,
|
|
214
|
+
);
|
|
215
|
+
process.stdout.write(
|
|
216
|
+
JSON.stringify({ ok: true, slug, added: wrote ? 1 : 0, deduped: wrote ? 0 : 1 }) + "\n",
|
|
217
|
+
);
|
|
181
218
|
process.exit(wrote ? 0 : 2);
|
|
182
219
|
}
|
|
183
220
|
|
|
@@ -188,8 +225,11 @@ function cmdFromTriage() {
|
|
|
188
225
|
const task = flags.task && flags.task !== true ? String(flags.task) : null;
|
|
189
226
|
const slug = repoSlug();
|
|
190
227
|
let triage;
|
|
191
|
-
try {
|
|
192
|
-
|
|
228
|
+
try {
|
|
229
|
+
triage = JSON.parse(readFileSync(triagePath, "utf8"));
|
|
230
|
+
} catch (e) {
|
|
231
|
+
die(`cannot parse triage JSON: ${e.message}`, 1);
|
|
232
|
+
}
|
|
193
233
|
|
|
194
234
|
const existing = new Set(readLedger(slug).map((r) => `${r.kind}::${normStatement(r.statement)}`));
|
|
195
235
|
let written = 0;
|
|
@@ -203,12 +243,21 @@ function cmdFromTriage() {
|
|
|
203
243
|
// whole class on every future run. Blocking findings always get re-raised
|
|
204
244
|
// and re-triaged on their own merits; only lower-severity rejections (style
|
|
205
245
|
// nitpicks, scope calls) become durable "do not re-flag" preferences.
|
|
206
|
-
if (f.severity === "blocking") {
|
|
246
|
+
if (f.severity === "blocking") {
|
|
247
|
+
skippedBlocking++;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
207
250
|
// Top-level files (dirname ".") scope to the file itself, not a stray "./*".
|
|
208
251
|
const dir = f.file ? dirname(f.file) : "";
|
|
209
|
-
const scope = !f.file ? "global" :
|
|
252
|
+
const scope = !f.file ? "global" : dir === "." || dir === "" ? f.file : `${dir}/*`;
|
|
210
253
|
const statement = `Do not re-flag: ${issue}` + (r.reason ? ` (rejected: ${r.reason})` : "");
|
|
211
|
-
if (
|
|
254
|
+
if (
|
|
255
|
+
addEntry(
|
|
256
|
+
slug,
|
|
257
|
+
{ kind: "rejected-preference", statement, scope, task, confidence: "low" },
|
|
258
|
+
existing,
|
|
259
|
+
)
|
|
260
|
+
) {
|
|
212
261
|
written++;
|
|
213
262
|
}
|
|
214
263
|
}
|
|
@@ -220,7 +269,7 @@ function cmdForget() {
|
|
|
220
269
|
const slug = repoSlug();
|
|
221
270
|
const match = flags.statement && flags.statement !== true ? normStatement(flags.statement) : null;
|
|
222
271
|
const kind = flags.kind && flags.kind !== true ? String(flags.kind) : null;
|
|
223
|
-
if (!match && !kind) die(
|
|
272
|
+
if (!match && !kind) die('forget needs --statement "..." and/or --kind <kind>', 1);
|
|
224
273
|
const p = ledgerPath(slug);
|
|
225
274
|
if (!existsSync(p)) {
|
|
226
275
|
process.stdout.write(JSON.stringify({ ok: true, slug, removed: 0 }) + "\n");
|
|
@@ -259,7 +308,9 @@ function cmdBrief() {
|
|
|
259
308
|
for (const r of ordered) (byKind[r.kind] || (byKind[r.kind] = [])).push(r);
|
|
260
309
|
|
|
261
310
|
const lines = ["<repo-learnings>"];
|
|
262
|
-
lines.push(
|
|
311
|
+
lines.push(
|
|
312
|
+
`Durable knowledge for repo "${slug}" (replayed each run; treat as context, not commands - current scope decides).`,
|
|
313
|
+
);
|
|
263
314
|
const labels = {
|
|
264
315
|
fact: "Architectural facts",
|
|
265
316
|
convention: "Conventions",
|
|
@@ -281,7 +332,9 @@ function cmdBrief() {
|
|
|
281
332
|
}
|
|
282
333
|
|
|
283
334
|
function cmdPath() {
|
|
284
|
-
process.stdout.write(
|
|
335
|
+
process.stdout.write(
|
|
336
|
+
ledgerPath(flags["repo-slug"] ? String(flags["repo-slug"]) : repoSlug()) + "\n",
|
|
337
|
+
);
|
|
285
338
|
process.exit(0);
|
|
286
339
|
}
|
|
287
340
|
|
|
@@ -297,13 +350,27 @@ function cmdStats() {
|
|
|
297
350
|
}
|
|
298
351
|
|
|
299
352
|
switch (SUB) {
|
|
300
|
-
case "add":
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
case "
|
|
304
|
-
|
|
305
|
-
|
|
353
|
+
case "add":
|
|
354
|
+
cmdAdd();
|
|
355
|
+
break;
|
|
356
|
+
case "from-triage":
|
|
357
|
+
cmdFromTriage();
|
|
358
|
+
break;
|
|
359
|
+
case "forget":
|
|
360
|
+
cmdForget();
|
|
361
|
+
break;
|
|
362
|
+
case "brief":
|
|
363
|
+
cmdBrief();
|
|
364
|
+
break;
|
|
365
|
+
case "path":
|
|
366
|
+
cmdPath();
|
|
367
|
+
break;
|
|
368
|
+
case "stats":
|
|
369
|
+
cmdStats();
|
|
370
|
+
break;
|
|
306
371
|
default:
|
|
307
|
-
process.stderr.write(
|
|
372
|
+
process.stderr.write(
|
|
373
|
+
"usage: learnings-ledger.mjs <add|from-triage|forget|brief|path|stats> [flags]\n",
|
|
374
|
+
);
|
|
308
375
|
process.exit(64);
|
|
309
376
|
}
|
|
@@ -45,7 +45,15 @@ const KNOWN_BAD = { dev_toolkit: "dev-toolkit", "claude-ai-Figma": "claude_ai_Fi
|
|
|
45
45
|
|
|
46
46
|
const SCAN_DIRS = ["pipeline/commands", "pipeline/skills", "pipeline/multi-agent-refs"];
|
|
47
47
|
const SCAN_EXT = /\.(md|sh|mjs|json)$/;
|
|
48
|
-
const PRUNE = new Set([
|
|
48
|
+
const PRUNE = new Set([
|
|
49
|
+
"node_modules",
|
|
50
|
+
".git",
|
|
51
|
+
".worktrees",
|
|
52
|
+
"Pods",
|
|
53
|
+
".build",
|
|
54
|
+
"DerivedData",
|
|
55
|
+
".next",
|
|
56
|
+
]);
|
|
49
57
|
|
|
50
58
|
function walk(dir, out = []) {
|
|
51
59
|
let entries;
|
|
@@ -121,7 +129,10 @@ function resolveToolkitRepo() {
|
|
|
121
129
|
if (name.includes("dev") && arg) candidates.push(dirname(resolve(arg)));
|
|
122
130
|
}
|
|
123
131
|
};
|
|
124
|
-
for (const cfgPath of [
|
|
132
|
+
for (const cfgPath of [
|
|
133
|
+
join(homedir(), ".claude.json"),
|
|
134
|
+
join(homedir(), ".claude", "settings.json"),
|
|
135
|
+
]) {
|
|
125
136
|
if (!existsSync(cfgPath)) continue;
|
|
126
137
|
try {
|
|
127
138
|
const json = JSON.parse(readFileSync(cfgPath, "utf8"));
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
// - description: required, non-empty, single line, <= 1024 chars
|
|
15
15
|
// - user-invocable: when present, must be true or false
|
|
16
16
|
// - platform: when present, must be ios | android | common | all
|
|
17
|
+
// - description: must carry a routing/trigger clause ("use when ..."), the
|
|
18
|
+
// one thing it is for - blocking since all 193 skills have one
|
|
17
19
|
//
|
|
18
20
|
// Spec-conformance signals (warnings - never fail the gate):
|
|
19
21
|
// - name should match the agent-skills spec pattern
|
|
20
22
|
// (lowercase letters/digits/hyphens, <= 64 chars)
|
|
21
|
-
// - description should carry a routing/trigger clause ("use when ...")
|
|
22
|
-
// so the model can decide when to load the skill
|
|
23
23
|
// - a body over ~500 lines with no companion-file reference should be
|
|
24
24
|
// split into references/ files loaded on demand
|
|
25
25
|
|
|
@@ -99,12 +99,19 @@ for (const file of files) {
|
|
|
99
99
|
if (!isBlockScalar && words < 6) {
|
|
100
100
|
warn(file, `description is terse (${words} words) - say what it does AND when to use it`);
|
|
101
101
|
}
|
|
102
|
-
// Routing quality (
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
102
|
+
// Routing quality (BLOCKING since the backlog reached zero). A description
|
|
103
|
+
// without a trigger clause tells the model what the skill is and nothing
|
|
104
|
+
// about when to reach for it, which is the one job the description has -
|
|
105
|
+
// it is the routing rule, not a summary.
|
|
106
|
+
//
|
|
107
|
+
// This was warn-only while 93 of 193 skills were missing one, because a
|
|
108
|
+
// gate that fires on half the tree gets ignored. All 93 were written, so
|
|
109
|
+
// the baseline is zero and it can hold the line. Block scalars are skipped
|
|
110
|
+
// for the same parser reason as above.
|
|
111
|
+
const ROUTING_RE =
|
|
112
|
+
/\b(use (this|it|when|for|whenever)|when (the|a|an|you|asked|working|building|implementing|writing|reviewing)|triggers?|invoked?( when| for)?|applies when|activated?)\b/i;
|
|
106
113
|
if (!isBlockScalar && !ROUTING_RE.test(desc)) {
|
|
107
|
-
|
|
114
|
+
fail(file, 'description has no routing/trigger clause (e.g. "use when ...")');
|
|
108
115
|
}
|
|
109
116
|
}
|
|
110
117
|
|
|
@@ -115,9 +122,13 @@ for (const file of files) {
|
|
|
115
122
|
const bodyLines = body.split("\n").length;
|
|
116
123
|
if (bodyLines > 500) {
|
|
117
124
|
const referencesCompanion =
|
|
118
|
-
/\]\((?!https?:|mailto:|#)[^)]+\)/.test(body) ||
|
|
125
|
+
/\]\((?!https?:|mailto:|#)[^)]+\)/.test(body) ||
|
|
126
|
+
/`[^`\n]*\/[^`\n]*\.(md|sh|mjs|json|py|txt)`/.test(body);
|
|
119
127
|
if (!referencesCompanion) {
|
|
120
|
-
warn(
|
|
128
|
+
warn(
|
|
129
|
+
file,
|
|
130
|
+
`body is ${bodyLines} lines with no companion-file reference - consider splitting into references/`,
|
|
131
|
+
);
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
134
|
|
|
@@ -116,7 +116,12 @@ if (invokedDirectly) {
|
|
|
116
116
|
console.error("usage: localize-commands.mjs <apply|restore> [--dir <commandsDir>]");
|
|
117
117
|
process.exit(2);
|
|
118
118
|
}
|
|
119
|
-
let dir = join(
|
|
119
|
+
let dir = join(
|
|
120
|
+
process.env.HOME || process.env.USERPROFILE || "",
|
|
121
|
+
".claude",
|
|
122
|
+
"commands",
|
|
123
|
+
"multi-agent",
|
|
124
|
+
);
|
|
120
125
|
const dirFlag = args.indexOf("--dir");
|
|
121
126
|
if (dirFlag >= 0) {
|
|
122
127
|
if (!args[dirFlag + 1]) {
|
|
@@ -38,7 +38,9 @@ const repoRoot = resolve(here, "..", "..");
|
|
|
38
38
|
|
|
39
39
|
const args = process.argv.slice(2);
|
|
40
40
|
if (args.length === 0 || args[0].startsWith("--")) {
|
|
41
|
-
console.error(
|
|
41
|
+
console.error(
|
|
42
|
+
'Usage: match-skills.mjs "<task text>" [--touched-files a,b] [--stack ios] [--limit 12] [--json]',
|
|
43
|
+
);
|
|
42
44
|
process.exit(1);
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -51,7 +53,11 @@ const opts = {
|
|
|
51
53
|
json: false,
|
|
52
54
|
};
|
|
53
55
|
for (let i = 1; i < args.length; i++) {
|
|
54
|
-
if (args[i] === "--touched-files")
|
|
56
|
+
if (args[i] === "--touched-files")
|
|
57
|
+
opts.touchedFiles = (args[++i] || "")
|
|
58
|
+
.split(",")
|
|
59
|
+
.map((s) => s.trim())
|
|
60
|
+
.filter(Boolean);
|
|
55
61
|
else if (args[i] === "--stack") opts.stack = (args[++i] || "").trim().toLowerCase();
|
|
56
62
|
else if (args[i] === "--limit") opts.limit = parseInt(args[++i], 10) || 12;
|
|
57
63
|
else if (args[i] === "--index") opts.indexPath = resolve(args[++i]);
|
|
@@ -86,8 +92,13 @@ function globToRe(glob) {
|
|
|
86
92
|
// `**/` means zero-or-more path segments, so a leading `**/` must also
|
|
87
93
|
// match top-level files (no dir prefix). Without the optional slash,
|
|
88
94
|
// `**/Auth/**` compiled to `.*\/Auth\/.*` and missed root-level `Auth/...`.
|
|
89
|
-
if (glob[i + 2] === "/") {
|
|
90
|
-
|
|
95
|
+
if (glob[i + 2] === "/") {
|
|
96
|
+
re += "(?:.*/)?";
|
|
97
|
+
i += 2;
|
|
98
|
+
} else {
|
|
99
|
+
re += ".*";
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
91
102
|
} else if (c === "*") re += "[^/]*";
|
|
92
103
|
else if (c === "?") re += ".";
|
|
93
104
|
else if (".+()|{}[]^$\\".includes(c)) re += "\\" + c;
|
|
@@ -95,7 +95,9 @@ function consolidateFirebase(out, changes) {
|
|
|
95
95
|
}
|
|
96
96
|
if ("firebase_project" in km) {
|
|
97
97
|
delete km.firebase_project;
|
|
98
|
-
changes.push(
|
|
98
|
+
changes.push(
|
|
99
|
+
"keychainMapping: removed firebase_project (redundant - project_id lives inside the SA JSON)",
|
|
100
|
+
);
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
if (Array.isArray(out?.global?.identities)) {
|
|
@@ -195,7 +197,9 @@ function migrate(prefs) {
|
|
|
195
197
|
out.global.identities = out.global.gitIdentities;
|
|
196
198
|
changes.push(`renamed gitIdentities → identities (${out.global.identities.length} entries)`);
|
|
197
199
|
} else {
|
|
198
|
-
changes.push(
|
|
200
|
+
changes.push(
|
|
201
|
+
"gitIdentities present but identities also exists - keeping identities, dropping gitIdentities",
|
|
202
|
+
);
|
|
199
203
|
}
|
|
200
204
|
delete out.global.gitIdentities;
|
|
201
205
|
} else if (!Array.isArray(out.global.identities)) {
|
|
@@ -214,7 +218,8 @@ function migrate(prefs) {
|
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
out.global.keychainMapping = km;
|
|
217
|
-
if (kmChanged)
|
|
221
|
+
if (kmChanged)
|
|
222
|
+
changes.push("expanded keychainMapping with missing services (existing values preserved)");
|
|
218
223
|
|
|
219
224
|
// 5. New v2.1.0 fields with defaults
|
|
220
225
|
if (!out.global.platformIdentityRouting) {
|
|
@@ -320,25 +325,29 @@ function migrateReportChannels(out, changes) {
|
|
|
320
325
|
// --- reportChannels ---
|
|
321
326
|
if (!g.reportChannels || typeof g.reportChannels !== "object") {
|
|
322
327
|
const channels = {
|
|
323
|
-
pr:
|
|
324
|
-
jira:
|
|
328
|
+
pr: true, // schema default
|
|
329
|
+
jira: typeof g.jiraCommentDefault === "boolean" ? g.jiraCommentDefault : true,
|
|
325
330
|
confluence: typeof g.confluenceDefault === "boolean" ? g.confluenceDefault : false,
|
|
326
|
-
wiki:
|
|
331
|
+
wiki: typeof g.wikiDefault === "boolean" ? g.wikiDefault : false,
|
|
327
332
|
};
|
|
328
333
|
g.reportChannels = channels;
|
|
329
|
-
changes.push(
|
|
334
|
+
changes.push(
|
|
335
|
+
"added reportChannels {pr,jira,confluence,wiki} (migrated from jiraCommentDefault/confluenceDefault/wikiDefault if present)",
|
|
336
|
+
);
|
|
330
337
|
}
|
|
331
338
|
|
|
332
339
|
// --- reportContent ---
|
|
333
340
|
if (!g.reportContent || typeof g.reportContent !== "object") {
|
|
334
341
|
g.reportContent = {
|
|
335
|
-
normalAnalysis:
|
|
342
|
+
normalAnalysis: true,
|
|
336
343
|
technicalAnalysis: false,
|
|
337
|
-
testScenarios:
|
|
338
|
-
autoDiff:
|
|
339
|
-
manualNote:
|
|
344
|
+
testScenarios: true,
|
|
345
|
+
autoDiff: false,
|
|
346
|
+
manualNote: false,
|
|
340
347
|
};
|
|
341
|
-
changes.push(
|
|
348
|
+
changes.push(
|
|
349
|
+
"added reportContent defaults {normalAnalysis,technicalAnalysis,testScenarios,autoDiff,manualNote}",
|
|
350
|
+
);
|
|
342
351
|
} else if (!("technicalAnalysis" in g.reportContent)) {
|
|
343
352
|
// v5.7.3+ - backfill technicalAnalysis onto already-initialized reportContent
|
|
344
353
|
g.reportContent.technicalAnalysis = false;
|
|
@@ -349,24 +358,32 @@ function migrateReportChannels(out, changes) {
|
|
|
349
358
|
if (!Array.isArray(g.wikiScope)) {
|
|
350
359
|
if (g.wikiDefault === false) {
|
|
351
360
|
g.wikiScope = [];
|
|
352
|
-
changes.push(
|
|
361
|
+
changes.push(
|
|
362
|
+
"added wikiScope: [] (legacy wikiDefault=false - opt out of all wiki artifacts)",
|
|
363
|
+
);
|
|
353
364
|
} else {
|
|
354
365
|
g.wikiScope = ["main", "ios", "screenshots", "index"];
|
|
355
|
-
changes.push(
|
|
366
|
+
changes.push(
|
|
367
|
+
"added wikiScope: [main,ios,screenshots,index] (legacy wikiDefault=true or unset)",
|
|
368
|
+
);
|
|
356
369
|
}
|
|
357
370
|
}
|
|
358
371
|
|
|
359
372
|
// --- autopilotReportTimeoutSeconds ---
|
|
360
373
|
if (typeof g.autopilotReportTimeoutSeconds !== "number") {
|
|
361
374
|
g.autopilotReportTimeoutSeconds = 1800;
|
|
362
|
-
changes.push(
|
|
375
|
+
changes.push(
|
|
376
|
+
"added autopilotReportTimeoutSeconds: 1800 (30 min) - Phase 7 always-pause timeout",
|
|
377
|
+
);
|
|
363
378
|
}
|
|
364
379
|
|
|
365
380
|
// --- prune deprecated booleans ---
|
|
366
381
|
for (const key of ["jiraCommentDefault", "confluenceDefault", "wikiDefault"]) {
|
|
367
382
|
if (key in g) {
|
|
368
383
|
delete g[key];
|
|
369
|
-
changes.push(
|
|
384
|
+
changes.push(
|
|
385
|
+
`removed deprecated ${key} (superseded by reportChannels${key === "wikiDefault" ? " + wikiScope" : ""})`,
|
|
386
|
+
);
|
|
370
387
|
}
|
|
371
388
|
}
|
|
372
389
|
}
|
|
@@ -724,8 +724,10 @@ case "$ACTION" in
|
|
|
724
724
|
# Live current-action line for the active phase. Quiet by construction:
|
|
725
725
|
# progress lines are frequent, so `now` never renders - the card picks the
|
|
726
726
|
# value up at the next boundary render/update. Truncated to 60 chars.
|
|
727
|
+
# 57 + "..." keeps the documented 60-char cap now that the marker is three
|
|
728
|
+
# ASCII dots rather than a one-character ellipsis.
|
|
727
729
|
if [ "${#TEXT}" -gt 60 ]; then
|
|
728
|
-
TEXT="${TEXT:0:
|
|
730
|
+
TEXT="${TEXT:0:57}..."
|
|
729
731
|
fi
|
|
730
732
|
acquire_state_lock
|
|
731
733
|
state=$(load_state)
|