@sdd-method/sdd-cli 1.41.0 → 1.43.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 +4 -57
- package/dist/author-bin.d.ts +3 -0
- package/dist/author-bin.d.ts.map +1 -0
- package/dist/author-bin.js +8 -0
- package/dist/author-bin.js.map +1 -0
- package/dist/author-program.d.ts +8 -0
- package/dist/author-program.d.ts.map +1 -0
- package/dist/author-program.js +99 -0
- package/dist/author-program.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-harness.d.ts +11 -8
- package/dist/lib/agent-harness.d.ts.map +1 -1
- package/dist/lib/agent-harness.js +17 -8
- package/dist/lib/agent-harness.js.map +1 -1
- package/dist/lib/api-surface/index.js +2 -2
- package/dist/lib/api-surface/index.js.map +1 -1
- package/dist/lib/briefing/index.d.ts +1 -1
- package/dist/lib/briefing/index.d.ts.map +1 -1
- package/dist/lib/briefing/index.js +1 -1
- package/dist/lib/briefing/index.js.map +1 -1
- package/dist/lib/briefing/render.d.ts +18 -1
- package/dist/lib/briefing/render.d.ts.map +1 -1
- package/dist/lib/briefing/render.js +17 -8
- package/dist/lib/briefing/render.js.map +1 -1
- package/dist/lib/catalogue/aggregation-manifest-loader.js +4 -4
- package/dist/lib/catalogue/aggregation-manifest-loader.js.map +1 -1
- package/dist/lib/catalogue/cli-version.d.ts +1 -1
- package/dist/lib/catalogue/cli-version.d.ts.map +1 -1
- package/dist/lib/catalogue/cli-version.js +3 -3
- package/dist/lib/catalogue/cli-version.js.map +1 -1
- package/dist/lib/catalogue/freshness.d.ts +27 -0
- package/dist/lib/catalogue/freshness.d.ts.map +1 -0
- package/dist/lib/catalogue/freshness.js +70 -0
- package/dist/lib/catalogue/freshness.js.map +1 -0
- package/dist/lib/catalogue/graph-run.js +1 -1
- package/dist/lib/catalogue/graph-run.js.map +1 -1
- package/dist/lib/ci-binding/index.d.ts +63 -0
- package/dist/lib/ci-binding/index.d.ts.map +1 -0
- package/dist/lib/ci-binding/index.js +220 -0
- package/dist/lib/ci-binding/index.js.map +1 -0
- package/dist/lib/ci-binding/module.d.ts +36 -0
- package/dist/lib/ci-binding/module.d.ts.map +1 -0
- package/dist/lib/ci-binding/module.js +204 -0
- package/dist/lib/ci-binding/module.js.map +1 -0
- package/dist/lib/context-pull/index.d.ts +45 -0
- package/dist/lib/context-pull/index.d.ts.map +1 -0
- package/dist/lib/context-pull/index.js +191 -0
- package/dist/lib/context-pull/index.js.map +1 -0
- package/dist/lib/context-pull/resolve.d.ts +46 -0
- package/dist/lib/context-pull/resolve.d.ts.map +1 -0
- package/dist/lib/context-pull/resolve.js +70 -0
- package/dist/lib/context-pull/resolve.js.map +1 -0
- package/dist/lib/context-pull/retired-mcp-setup.d.ts +7 -0
- package/dist/lib/context-pull/retired-mcp-setup.d.ts.map +1 -0
- package/dist/lib/context-pull/retired-mcp-setup.js +7 -0
- package/dist/lib/context-pull/retired-mcp-setup.js.map +1 -0
- package/dist/lib/hooks-seed/entries.d.ts +15 -0
- package/dist/lib/hooks-seed/entries.d.ts.map +1 -1
- package/dist/lib/hooks-seed/entries.js +30 -1
- package/dist/lib/hooks-seed/entries.js.map +1 -1
- package/dist/lib/hooks-seed/index.d.ts +4 -9
- package/dist/lib/hooks-seed/index.d.ts.map +1 -1
- package/dist/lib/hooks-seed/index.js +4 -7
- package/dist/lib/hooks-seed/index.js.map +1 -1
- package/dist/lib/hooks-seed/merge.d.ts +7 -0
- package/dist/lib/hooks-seed/merge.d.ts.map +1 -1
- package/dist/lib/hooks-seed/merge.js +31 -0
- package/dist/lib/hooks-seed/merge.js.map +1 -1
- package/dist/lib/init/app.d.ts +0 -1
- package/dist/lib/init/app.d.ts.map +1 -1
- package/dist/lib/init/app.js +3 -7
- package/dist/lib/init/app.js.map +1 -1
- package/dist/lib/init/ci-workflow.d.ts +6 -8
- package/dist/lib/init/ci-workflow.d.ts.map +1 -1
- package/dist/lib/init/ci-workflow.js +57 -120
- package/dist/lib/init/ci-workflow.js.map +1 -1
- package/dist/lib/init/integration.d.ts +0 -1
- package/dist/lib/init/integration.d.ts.map +1 -1
- package/dist/lib/init/integration.js +3 -7
- package/dist/lib/init/integration.js.map +1 -1
- package/dist/lib/init/platform.d.ts +2 -10
- package/dist/lib/init/platform.d.ts.map +1 -1
- package/dist/lib/init/platform.js +12 -15
- package/dist/lib/init/platform.js.map +1 -1
- package/dist/lib/lock-file.d.ts +20 -0
- package/dist/lib/lock-file.d.ts.map +1 -1
- package/dist/lib/lock-file.js +25 -1
- package/dist/lib/lock-file.js.map +1 -1
- package/dist/lib/mcp/build-info.d.ts.map +1 -1
- package/dist/lib/mcp/build-info.js +3 -3
- package/dist/lib/mcp/build-info.js.map +1 -1
- package/dist/lib/pack/index.js +2 -2
- package/dist/lib/pack/index.js.map +1 -1
- package/dist/lib/pack/validate.js +2 -2
- package/dist/lib/pack/validate.js.map +1 -1
- package/dist/lib/package-version.d.ts +23 -0
- package/dist/lib/package-version.d.ts.map +1 -1
- package/dist/lib/package-version.js +47 -10
- package/dist/lib/package-version.js.map +1 -1
- package/dist/lib/plan/index.d.ts.map +1 -1
- package/dist/lib/plan/index.js +4 -4
- package/dist/lib/plan/index.js.map +1 -1
- package/dist/lib/plan/read-sdd.js +1 -1
- package/dist/lib/plan/render-template.d.ts +8 -0
- package/dist/lib/plan/render-template.d.ts.map +1 -1
- package/dist/lib/plan/render-template.js +27 -3
- package/dist/lib/plan/render-template.js.map +1 -1
- package/dist/lib/sdd-index/repo-config.d.ts +1 -1
- package/dist/lib/sdd-index/repo-config.js +1 -1
- package/dist/lib/sdd-reader.d.ts +35 -0
- package/dist/lib/sdd-reader.d.ts.map +1 -0
- package/dist/lib/sdd-reader.js +91 -0
- package/dist/lib/sdd-reader.js.map +1 -0
- package/dist/lib/sync/briefing-merge.d.ts +1 -1
- package/dist/lib/sync/briefing-merge.d.ts.map +1 -1
- package/dist/lib/sync/briefing-merge.js +50 -34
- package/dist/lib/sync/briefing-merge.js.map +1 -1
- package/dist/lib/sync/diff.js +1 -1
- package/dist/lib/sync/diff.js.map +1 -1
- package/dist/lib/sync/index.d.ts +16 -6
- package/dist/lib/sync/index.d.ts.map +1 -1
- package/dist/lib/sync/index.js +89 -116
- package/dist/lib/sync/index.js.map +1 -1
- package/dist/lib/sync/settings-merge.d.ts +26 -48
- package/dist/lib/sync/settings-merge.d.ts.map +1 -1
- package/dist/lib/sync/settings-merge.js +70 -162
- package/dist/lib/sync/settings-merge.js.map +1 -1
- package/dist/lib/validate/bundle-coherence.js +2 -2
- package/dist/lib/validate/bundle-coherence.js.map +1 -1
- package/dist/lib/validate/plan.d.ts +25 -0
- package/dist/lib/validate/plan.d.ts.map +1 -0
- package/dist/lib/validate/plan.js +54 -0
- package/dist/lib/validate/plan.js.map +1 -0
- package/dist/maintain-bin.d.ts +3 -0
- package/dist/maintain-bin.d.ts.map +1 -0
- package/dist/maintain-bin.js +8 -0
- package/dist/maintain-bin.js.map +1 -0
- package/dist/maintain-program.d.ts +8 -0
- package/dist/maintain-program.d.ts.map +1 -0
- package/dist/maintain-program.js +94 -0
- package/dist/maintain-program.js.map +1 -0
- package/dist/maintain-version.json +4 -0
- package/dist/verbs/catalogue-check.d.ts +10 -0
- package/dist/verbs/catalogue-check.d.ts.map +1 -0
- package/dist/verbs/catalogue-check.js +28 -0
- package/dist/verbs/catalogue-check.js.map +1 -0
- package/dist/verbs/catalogue-maintain.d.ts +6 -0
- package/dist/verbs/catalogue-maintain.d.ts.map +1 -0
- package/dist/verbs/catalogue-maintain.js +110 -0
- package/dist/verbs/catalogue-maintain.js.map +1 -0
- package/dist/verbs/catalogue.d.ts +5 -0
- package/dist/verbs/catalogue.d.ts.map +1 -1
- package/dist/verbs/catalogue.js +16 -80
- package/dist/verbs/catalogue.js.map +1 -1
- package/dist/verbs/context.d.ts +3 -0
- package/dist/verbs/context.d.ts.map +1 -0
- package/dist/verbs/context.js +39 -0
- package/dist/verbs/context.js.map +1 -0
- package/dist/verbs/pack-build.d.ts +3 -0
- package/dist/verbs/pack-build.d.ts.map +1 -0
- package/dist/verbs/pack-build.js +31 -0
- package/dist/verbs/pack-build.js.map +1 -0
- package/dist/verbs/pack.d.ts.map +1 -1
- package/dist/verbs/pack.js +2 -25
- package/dist/verbs/pack.js.map +1 -1
- package/dist/verbs/sync.d.ts.map +1 -1
- package/dist/verbs/sync.js +21 -0
- package/dist/verbs/sync.js.map +1 -1
- package/dist/verbs/validate.d.ts.map +1 -1
- package/dist/verbs/validate.js +26 -0
- package/dist/verbs/validate.js.map +1 -1
- package/dist/verify-program.d.ts +6 -1
- package/dist/verify-program.d.ts.map +1 -1
- package/dist/verify-program.js +12 -5
- package/dist/verify-program.js.map +1 -1
- package/dist/verify-version.json +2 -2
- package/package.json +6 -5
- package/scripts/author-acceptance.mjs +170 -0
- package/scripts/author-version.json +4 -0
- package/scripts/build-persona-package.mjs +309 -0
- package/scripts/copy-yaml-assets.mjs +4 -2
- package/scripts/dagger-parity.sh +74 -0
- package/scripts/maintain-acceptance.mjs +240 -0
- package/scripts/maintain-version.json +4 -0
- package/scripts/release-gate.mjs +9 -0
- package/scripts/verify-version.json +2 -2
- package/scripts/vitest-tmpdir.mjs +26 -0
- package/scripts/build-verify-package.mjs +0 -210
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Method Validation Dagger module (M-ADR 0219 §4.1–§4.3): the ONLY definition of the
|
|
3
|
+
* method-managed validation job. `sync` writes these files into every SDD at MODULE_DIR, with the
|
|
4
|
+
* exact verify-cli and maintain-cli versions released alongside this sdd-cli substituted in, and
|
|
5
|
+
* every CI host's wrapper (./index.ts) just calls the module.
|
|
6
|
+
*
|
|
7
|
+
* The module's source lives here, as text, rather than as files beside the package: sync runs from
|
|
8
|
+
* three packages (sdd-cli, maintain-cli, and the persona builds' import closure), and a string
|
|
9
|
+
* travels with whichever one imports it, where an asset directory would have to be copied into each.
|
|
10
|
+
* `scripts/dagger-parity.sh` renders it from the built package, so the parity harness runs exactly
|
|
11
|
+
* what sync writes.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { getMaintainCliVersion, getVerifyCliVersion } from "../package-version.js";
|
|
15
|
+
/** Where the module lives in an SDD (M-ADR 0219 §4.3, ruled 2026-10-16). */
|
|
16
|
+
export const MODULE_DIR = ".dagger/method-validation";
|
|
17
|
+
/**
|
|
18
|
+
* The Dagger engine the module declares and every wrapper installs, pinned to one value so the CLI a
|
|
19
|
+
* wrapper installs and the engine the module asks for can never disagree (M-ADR 0219 §6). An engine
|
|
20
|
+
* upgrade is a release concern: change it here, run scripts/dagger-parity.sh, release.
|
|
21
|
+
*/
|
|
22
|
+
export const DAGGER_VERSION = "0.21.10";
|
|
23
|
+
/** The command every host wrapper runs. */
|
|
24
|
+
export const MODULE_CALL = `dagger call -m ${MODULE_DIR} method-validation --source .`;
|
|
25
|
+
const VERIFY_PIN = "@@VERIFY_CLI_VERSION@@";
|
|
26
|
+
// The module's SDK import, substituted at render: written literally, the persona builds' import-closure
|
|
27
|
+
// scan would read this text as an import of the CLI's own and refuse a dependency it does not declare.
|
|
28
|
+
const DAGGER_SDK = "@@DAGGER_SDK@@";
|
|
29
|
+
const MAINTAIN_PIN = "@@MAINTAIN_CLI_VERSION@@";
|
|
30
|
+
// The module's own source. String.raw keeps it byte-for-byte, so it holds no backtick; its only
|
|
31
|
+
// substitutions are the three markers above, which renderModuleFiles replaces.
|
|
32
|
+
const INDEX_TS = String.raw `/**
|
|
33
|
+
* Method Validation (M-ADR 0219): the method-managed validation job, as one Dagger module. Every CI
|
|
34
|
+
* host calls it, and none keeps a step list of its own. Written by sdd-cli sync and method-managed:
|
|
35
|
+
* sync refuses to overwrite an edited copy without --allow-overwrite.
|
|
36
|
+
*
|
|
37
|
+
* Run it anywhere a container engine runs:
|
|
38
|
+
* dagger call -m .dagger/method-validation method-validation --source .
|
|
39
|
+
*
|
|
40
|
+
* The steps are the method's job plan, read at run time from "sdd-verify validate --list". Every
|
|
41
|
+
* step runs even after an earlier one fails, so one red step never hides the verdicts after it. The
|
|
42
|
+
* job fails only when a non-advisory step fails; the catalogue freshness step is advisory.
|
|
43
|
+
*/
|
|
44
|
+
import { dag, Container, Directory, File, object, func, ReturnType } from ${DAGGER_SDK}
|
|
45
|
+
|
|
46
|
+
// Pinned, so a run is reproducible and every tool the validators shell out to is named here.
|
|
47
|
+
const NODE_IMAGE = "node:20-bookworm"
|
|
48
|
+
const YQ_VERSION = "v4.44.3"
|
|
49
|
+
|
|
50
|
+
interface PlanStep {
|
|
51
|
+
id: string
|
|
52
|
+
title: string
|
|
53
|
+
tool: "sdd-verify" | "sdd-maintain" | "bash"
|
|
54
|
+
args: string[]
|
|
55
|
+
advisory: boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@object()
|
|
59
|
+
export class MethodValidation {
|
|
60
|
+
/**
|
|
61
|
+
* The toolchain: Node, git, bash, python3, ripgrep, a pinned yq, and the exact-pinned verify and
|
|
62
|
+
* maintain CLIs. A tarball, when given, replaces the published package (a release candidate).
|
|
63
|
+
*/
|
|
64
|
+
@func()
|
|
65
|
+
toolchain(
|
|
66
|
+
verifyVersion: string = "${VERIFY_PIN}",
|
|
67
|
+
maintainVersion: string = "${MAINTAIN_PIN}",
|
|
68
|
+
verifyTarball?: File,
|
|
69
|
+
maintainTarball?: File,
|
|
70
|
+
): Container {
|
|
71
|
+
let c = dag
|
|
72
|
+
.container()
|
|
73
|
+
.from(NODE_IMAGE)
|
|
74
|
+
.withExec(["sh", "-c", "apt-get update -qq && apt-get install -y -qq ripgrep python3 >/dev/null"])
|
|
75
|
+
.withExec([
|
|
76
|
+
"sh",
|
|
77
|
+
"-c",
|
|
78
|
+
"curl -fsSL -o /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/" +
|
|
79
|
+
YQ_VERSION +
|
|
80
|
+
"/yq_linux_$(dpkg --print-architecture) && chmod +x /usr/local/bin/yq",
|
|
81
|
+
])
|
|
82
|
+
const pkgs: string[] = []
|
|
83
|
+
if (verifyTarball) {
|
|
84
|
+
c = c.withFile("/pkgs/verify-cli.tgz", verifyTarball)
|
|
85
|
+
pkgs.push("/pkgs/verify-cli.tgz")
|
|
86
|
+
} else pkgs.push("@sdd-method/verify-cli@" + verifyVersion)
|
|
87
|
+
if (maintainTarball) {
|
|
88
|
+
c = c.withFile("/pkgs/maintain-cli.tgz", maintainTarball)
|
|
89
|
+
pkgs.push("/pkgs/maintain-cli.tgz")
|
|
90
|
+
} else pkgs.push("@sdd-method/maintain-cli@" + maintainVersion)
|
|
91
|
+
return c.withExec(["npm", "install", "-g", "--silent", ...pkgs])
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run Method Validation on an SDD repository. Returns a step-by-step report, and throws (so the
|
|
96
|
+
* CI host's job fails) when any non-advisory step failed.
|
|
97
|
+
*/
|
|
98
|
+
@func()
|
|
99
|
+
async methodValidation(
|
|
100
|
+
source: Directory,
|
|
101
|
+
verifyVersion: string = "${VERIFY_PIN}",
|
|
102
|
+
maintainVersion: string = "${MAINTAIN_PIN}",
|
|
103
|
+
verifyTarball?: File,
|
|
104
|
+
maintainTarball?: File,
|
|
105
|
+
): Promise<string> {
|
|
106
|
+
const base = this.toolchain(verifyVersion, maintainVersion, verifyTarball, maintainTarball)
|
|
107
|
+
.withMountedDirectory("/src", source)
|
|
108
|
+
.withWorkdir("/src")
|
|
109
|
+
const versions = (await base.withExec(["sh", "-c", "sdd-verify --version; sdd-maintain --version"]).stdout()).split("\n")
|
|
110
|
+
const plan = JSON.parse(await base.withExec(["sdd-verify", "validate", "--list"]).stdout()) as {
|
|
111
|
+
profile: string
|
|
112
|
+
steps: PlanStep[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const lines = ["Method Validation: profile " + plan.profile + "; sdd-verify " + versions[0] + ", sdd-maintain " + versions[1]]
|
|
116
|
+
let failed = 0
|
|
117
|
+
for (const step of plan.steps) {
|
|
118
|
+
const ran = base.withExec([step.tool, ...step.args], { expect: ReturnType.Any })
|
|
119
|
+
const code = await ran.exitCode()
|
|
120
|
+
const verdict = code === 0 ? "PASS" : step.advisory ? "ADVISORY" : "FAIL"
|
|
121
|
+
if (code !== 0 && !step.advisory) failed++
|
|
122
|
+
lines.push(verdict.padEnd(8) + " exit " + code + " " + step.id + " (" + step.title + ")")
|
|
123
|
+
if (code !== 0) {
|
|
124
|
+
const out = (await ran.stdout()) + (await ran.stderr())
|
|
125
|
+
lines.push(...out.trim().split("\n").slice(-6).map((l) => " " + l))
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
lines.push(failed === 0 ? "RESULT: PASS" : "RESULT: FAIL (" + failed + " failing step(s))")
|
|
129
|
+
const report = lines.join("\n")
|
|
130
|
+
if (failed > 0) throw new Error(report)
|
|
131
|
+
return report
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
const DAGGER_JSON = `{
|
|
136
|
+
"name": "method-validation",
|
|
137
|
+
"engineVersion": "v${DAGGER_VERSION}",
|
|
138
|
+
"sdk": {
|
|
139
|
+
"source": "typescript"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
`;
|
|
143
|
+
const PACKAGE_JSON = `{
|
|
144
|
+
"type": "module",
|
|
145
|
+
"dependencies": {
|
|
146
|
+
"typescript": "5.9.3"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
const TSCONFIG_JSON = `{
|
|
151
|
+
"compilerOptions": {
|
|
152
|
+
"target": "ES2022",
|
|
153
|
+
"moduleResolution": "Node",
|
|
154
|
+
"experimentalDecorators": true,
|
|
155
|
+
"strict": true,
|
|
156
|
+
"skipLibCheck": true,
|
|
157
|
+
"paths": {
|
|
158
|
+
"@dagger.io/dagger": ["./sdk/index.ts"],
|
|
159
|
+
"@dagger.io/dagger/telemetry": ["./sdk/telemetry.ts"]
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
`;
|
|
164
|
+
const YARN_LOCK = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
165
|
+
# yarn lockfile v1
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
typescript@5.9.3:
|
|
169
|
+
version "5.9.3"
|
|
170
|
+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
|
|
171
|
+
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
|
172
|
+
`;
|
|
173
|
+
// The SDK Dagger generates at run time stays out of the SDD's history.
|
|
174
|
+
const GITIGNORE = `/sdk
|
|
175
|
+
/**/node_modules/**
|
|
176
|
+
/**/.pnpm-store/**
|
|
177
|
+
/.env
|
|
178
|
+
`;
|
|
179
|
+
/**
|
|
180
|
+
* The module's files, relative to MODULE_DIR, in a fixed order. Pins default to the versions released
|
|
181
|
+
* with this sdd-cli (M-ADR 0218 §4.6); the parity harness passes candidate versions.
|
|
182
|
+
*/
|
|
183
|
+
export function renderModuleFiles(pins = { verify: getVerifyCliVersion(), maintain: getMaintainCliVersion() }) {
|
|
184
|
+
return [
|
|
185
|
+
[".gitignore", GITIGNORE],
|
|
186
|
+
["dagger.json", DAGGER_JSON],
|
|
187
|
+
["package.json", PACKAGE_JSON],
|
|
188
|
+
["src/index.ts", INDEX_TS.split(VERIFY_PIN).join(pins.verify).split(MAINTAIN_PIN).join(pins.maintain).split(DAGGER_SDK).join('"@dagger.io' + '/dagger"')],
|
|
189
|
+
["tsconfig.json", TSCONFIG_JSON],
|
|
190
|
+
["yarn.lock", YARN_LOCK],
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* sha256 over the module's files as they stand (null content = absent), in the render's order, so
|
|
195
|
+
* sync can tell a module nobody touched from an edited one (M-ADR 0218 §4.7, as for the wrapper).
|
|
196
|
+
*/
|
|
197
|
+
export function moduleSha256(files) {
|
|
198
|
+
const h = createHash("sha256");
|
|
199
|
+
for (const [rel, content] of files) {
|
|
200
|
+
h.update(rel).update("\0").update(content === null ? "\u0001absent" : content).update("\0");
|
|
201
|
+
}
|
|
202
|
+
return h.digest("hex");
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../src/lib/ci-binding/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,UAAU,+BAA+B,CAAC;AAEvF,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAC5C,wGAAwG;AACxG,uGAAuG;AACvG,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAEhD,gGAAgG;AAChG,+EAA+E;AAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;4EAYiD,UAAU;;;;;;;;;;;;;;;;;;;;;;+BAsBvD,UAAU;iCACR,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAkCd,UAAU;iCACR,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgC5C,CAAC;AAEF,MAAM,WAAW,GAAG;;uBAEG,cAAc;;;;;CAKpC,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;CAMpB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;;;;;CAarB,CAAC;AAEF,MAAM,SAAS,GAAG;;;;;;;;CAQjB,CAAC;AAEF,uEAAuE;AACvE,MAAM,SAAS,GAAG;;;;CAIjB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAA6C,EAAE,MAAM,EAAE,mBAAmB,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE,EAAE;IAEjH,OAAO;QACL,CAAC,YAAY,EAAE,SAAS,CAAC;QACzB,CAAC,aAAa,EAAE,WAAW,CAAC;QAC5B,CAAC,cAAc,EAAE,YAAY,CAAC;QAC9B,CAAC,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,CAAC;QACzJ,CAAC,eAAe,EAAE,aAAa,CAAC;QAChC,CAAC,WAAW,EAAE,SAAS,CAAC;KACzB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAqC;IAChE,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC;QACnC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sdd-cli context pull` — write the code-repo briefing into a code repository from its upstream
|
|
3
|
+
* SDD (M-ADR 0220 §4.5, re-homing M-ADR 0150 §4.4 Phase D).
|
|
4
|
+
*
|
|
5
|
+
* The successor to the code-repo half of `generate-claude-md.sh`. No dynamic content is baked
|
|
6
|
+
* in: the briefing points at the SDD's files. A sibling verb to `generate-briefing`, not an extension of it:
|
|
7
|
+
* `generate-briefing` needs the target to be an SDD (marker, lock, synced
|
|
8
|
+
* templates), and a code repository is none of those. They share the
|
|
9
|
+
* placeholder substitution and the wrapper's marker-block merge.
|
|
10
|
+
*
|
|
11
|
+
* What it writes, and nothing else (M-ADR 0218 §4.3 item 9, a MAINTAIN verb):
|
|
12
|
+
* agent-instructions.md whole file, method-managed
|
|
13
|
+
* CLAUDE.md, AGENTS.md the method-managed block only; adopter content survives (AGENTS.md is
|
|
14
|
+
* the pointer, M-ADR 0220 §4.6, when the SDD's baseline carries it)
|
|
15
|
+
* Templates are read from the SDD, which carries them via its baseline bundle. MCP_SETUP.md is no
|
|
16
|
+
* longer written (M-ADR 0220 §4.5); a copy this verb wrote earlier is removed when it still
|
|
17
|
+
* matches the method's last render, and left with a notice when it does not.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentHarness } from "../agent-harness.js";
|
|
20
|
+
export declare const CODE_REPO_BRIEFING_ROOT = "orchestration/templates/briefing/code-repo";
|
|
21
|
+
export declare const MCP_SETUP_REL_PATH = "MCP_SETUP.md";
|
|
22
|
+
export interface ContextPullOptions {
|
|
23
|
+
/** The code repository to write into. */
|
|
24
|
+
readonly codeRepo: string;
|
|
25
|
+
readonly agentHarness: AgentHarness;
|
|
26
|
+
readonly allowOverwrite: boolean;
|
|
27
|
+
readonly sddPath?: string | undefined;
|
|
28
|
+
readonly repoName?: string | undefined;
|
|
29
|
+
readonly searchRoots?: readonly string[] | undefined;
|
|
30
|
+
/** ISO date recorded as pull_date. Default: today (UTC). Pinned in tests for determinism. */
|
|
31
|
+
readonly pullDate?: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
export interface ContextPullResult {
|
|
34
|
+
readonly exitCode: number;
|
|
35
|
+
}
|
|
36
|
+
export declare function runContextPull(opts: ContextPullOptions, out?: (line: string) => void): Promise<ContextPullResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Remove an MCP_SETUP.md this verb wrote before M-ADR 0220, when it is byte-identical to the
|
|
39
|
+
* method's last template rendered with the values its own header records. Anything else is the
|
|
40
|
+
* adopter's now, and stays.
|
|
41
|
+
*/
|
|
42
|
+
export declare function retireMcpSetup(codeRepo: string): Promise<"absent" | "removed" | "kept">;
|
|
43
|
+
/** `{{name}}` substitution over an open variable set (the briefing renderer's is closed to four). */
|
|
44
|
+
export declare function substituteAll(template: string, vars: Readonly<Record<string, string>>): string;
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/context-pull/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAiBxD,eAAO,MAAM,uBAAuB,+CAA+C,CAAC;AACpF,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAMjD,MAAM,WAAW,kBAAkB;IACjC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACrD,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,EACxB,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAA2C,GACjE,OAAO,CAAC,iBAAiB,CAAC,CA2H5B;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC,CAiB7F;AAED,qGAAqG;AACrG,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAE9F"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sdd-cli context pull` — write the code-repo briefing into a code repository from its upstream
|
|
3
|
+
* SDD (M-ADR 0220 §4.5, re-homing M-ADR 0150 §4.4 Phase D).
|
|
4
|
+
*
|
|
5
|
+
* The successor to the code-repo half of `generate-claude-md.sh`. No dynamic content is baked
|
|
6
|
+
* in: the briefing points at the SDD's files. A sibling verb to `generate-briefing`, not an extension of it:
|
|
7
|
+
* `generate-briefing` needs the target to be an SDD (marker, lock, synced
|
|
8
|
+
* templates), and a code repository is none of those. They share the
|
|
9
|
+
* placeholder substitution and the wrapper's marker-block merge.
|
|
10
|
+
*
|
|
11
|
+
* What it writes, and nothing else (M-ADR 0218 §4.3 item 9, a MAINTAIN verb):
|
|
12
|
+
* agent-instructions.md whole file, method-managed
|
|
13
|
+
* CLAUDE.md, AGENTS.md the method-managed block only; adopter content survives (AGENTS.md is
|
|
14
|
+
* the pointer, M-ADR 0220 §4.6, when the SDD's baseline carries it)
|
|
15
|
+
* Templates are read from the SDD, which carries them via its baseline bundle. MCP_SETUP.md is no
|
|
16
|
+
* longer written (M-ADR 0220 §4.5); a copy this verb wrote earlier is removed when it still
|
|
17
|
+
* matches the method's last render, and left with a notice when it does not.
|
|
18
|
+
*/
|
|
19
|
+
import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
20
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
21
|
+
import { AGENT_INSTRUCTIONS_REL_PATH, AGENTS_POINTER, WRAPPER_BLOCK_BEGIN, WRAPPER_BLOCK_END, findUnresolvedPlaceholders, harnessWrapperOutputPath, resolveBriefingVariables, splitWrapperTemplate, } from "../briefing/index.js";
|
|
22
|
+
import { readLockFile } from "../lock-file.js";
|
|
23
|
+
import { readRepoKind } from "../repo-kind.js";
|
|
24
|
+
import { writeMarkedBlockFile } from "../sync/yaml-block-merge.js";
|
|
25
|
+
import { defaultSearchRoots, resolveCodeRepoName, resolveSdd } from "./resolve.js";
|
|
26
|
+
import { RETIRED_MCP_SETUP_TEMPLATE } from "./retired-mcp-setup.js";
|
|
27
|
+
export const CODE_REPO_BRIEFING_ROOT = "orchestration/templates/briefing/code-repo";
|
|
28
|
+
export const MCP_SETUP_REL_PATH = "MCP_SETUP.md";
|
|
29
|
+
const WRAPPER_TEMPLATE = {
|
|
30
|
+
"claude-code": "claude-code/CLAUDE.md.hbs",
|
|
31
|
+
};
|
|
32
|
+
export async function runContextPull(opts, out = (line) => process.stdout.write(line)) {
|
|
33
|
+
const codeRepo = resolve(opts.codeRepo);
|
|
34
|
+
if ((await readRepoKind(codeRepo)) !== null) {
|
|
35
|
+
out(fail(`${codeRepo} is an SDD repository (it has .sdd-repo-kind). context pull writes into a code repository; for an SDD use sdd-cli generate-briefing.`));
|
|
36
|
+
return { exitCode: 1 };
|
|
37
|
+
}
|
|
38
|
+
const repoName = resolveCodeRepoName(codeRepo, opts.repoName);
|
|
39
|
+
const outcome = await resolveSdd({
|
|
40
|
+
repoName,
|
|
41
|
+
sddPath: opts.sddPath,
|
|
42
|
+
searchRoots: opts.searchRoots ?? defaultSearchRoots(codeRepo),
|
|
43
|
+
codeRepo,
|
|
44
|
+
});
|
|
45
|
+
if (outcome.kind === "not-an-sdd") {
|
|
46
|
+
out(fail(`--sdd ${outcome.path} is not an SDD repository (no .sdd-repo-kind).`));
|
|
47
|
+
return { exitCode: 1 };
|
|
48
|
+
}
|
|
49
|
+
if (outcome.kind === "not-found") {
|
|
50
|
+
out(fail(`No SDD lists repository "${repoName}" in its catalogues/repositories.csv (searched ${outcome.searched.length} SDD(s) under ${(opts.searchRoots ?? defaultSearchRoots(codeRepo)).join(", ")}). Pass --sdd <path>, or --repo <id> if this repository is catalogued under another id.`));
|
|
51
|
+
return { exitCode: 1 };
|
|
52
|
+
}
|
|
53
|
+
if (outcome.kind === "ambiguous") {
|
|
54
|
+
out(fail(`Repository "${repoName}" is listed by ${outcome.candidates.length} SDDs: ${outcome.candidates.join(", ")}. Pass --sdd <path> to choose.`));
|
|
55
|
+
return { exitCode: 1 };
|
|
56
|
+
}
|
|
57
|
+
const sddRoot = outcome.sddRoot;
|
|
58
|
+
if (!outcome.catalogued) {
|
|
59
|
+
out(warn(`${basename(sddRoot)}'s catalogues/repositories.csv does not list "${repoName}"; continuing because --sdd was given.`));
|
|
60
|
+
}
|
|
61
|
+
// The SDD's own identity, profile and baseline, exactly as its own briefing renders them.
|
|
62
|
+
const lock = await readLockFile(sddRoot);
|
|
63
|
+
const forwardBase = lock?.bundles.find((b) => b.isForwardBase);
|
|
64
|
+
if (!forwardBase) {
|
|
65
|
+
out(fail(`${sddRoot} has no forward-base bundle in method-baseline.lock; sync it first.`));
|
|
66
|
+
return { exitCode: 1 };
|
|
67
|
+
}
|
|
68
|
+
const sdd = await resolveBriefingVariables({ targetRepo: sddRoot, baselineVersionOverride: forwardBase.bundleVersion });
|
|
69
|
+
const vars = {
|
|
70
|
+
repo_name: repoName,
|
|
71
|
+
sdd_name: sdd.sdd_name,
|
|
72
|
+
sdd_root: sddRoot,
|
|
73
|
+
repo_kind: sdd.repo_kind,
|
|
74
|
+
baseline_version: sdd.baseline_version,
|
|
75
|
+
pull_date: opts.pullDate ?? new Date().toISOString().slice(0, 10),
|
|
76
|
+
};
|
|
77
|
+
const aiTemplate = join(sddRoot, CODE_REPO_BRIEFING_ROOT, "agent-instructions.md.hbs");
|
|
78
|
+
const wrapperTemplate = join(sddRoot, CODE_REPO_BRIEFING_ROOT, WRAPPER_TEMPLATE[opts.agentHarness]);
|
|
79
|
+
for (const t of [aiTemplate, wrapperTemplate]) {
|
|
80
|
+
if (!(await exists(t))) {
|
|
81
|
+
out(fail(`${sddRoot} does not carry ${t.slice(sddRoot.length + 1)}: its method baseline predates context pull. Sync the SDD to a baseline that ships the code-repo templates.`));
|
|
82
|
+
return { exitCode: 1 };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// The AGENTS.md pointer (M-ADR 0220 §4.6) arrived later than the other code-repo templates: an SDD
|
|
86
|
+
// whose baseline does not carry it yet gets no pointer, and everything else proceeds.
|
|
87
|
+
const pointerTemplate = join(sddRoot, CODE_REPO_BRIEFING_ROOT, AGENTS_POINTER.templateRel);
|
|
88
|
+
const wrapperSources = [[harnessWrapperOutputPath(opts.agentHarness), wrapperTemplate]];
|
|
89
|
+
if (await exists(pointerTemplate))
|
|
90
|
+
wrapperSources.push([AGENTS_POINTER.outputRel, pointerTemplate]);
|
|
91
|
+
const rendered = {};
|
|
92
|
+
for (const [rel, path] of [[AGENT_INSTRUCTIONS_REL_PATH, aiTemplate], ...wrapperSources]) {
|
|
93
|
+
const content = substituteAll(await readFile(path, "utf8"), vars);
|
|
94
|
+
const unresolved = findUnresolvedPlaceholders(content);
|
|
95
|
+
if (unresolved.length > 0) {
|
|
96
|
+
out(fail(`${rel}: the SDD's template has placeholders this CLI does not know: ${unresolved.join(", ")}. Upgrade sdd-cli.`));
|
|
97
|
+
return { exitCode: 1 };
|
|
98
|
+
}
|
|
99
|
+
rendered[rel] = content;
|
|
100
|
+
}
|
|
101
|
+
// The wrappers first: they are the only writes that can be refused, and a refusal must leave
|
|
102
|
+
// nothing written, so every wrapper is checked before any is written.
|
|
103
|
+
const existingOf = {};
|
|
104
|
+
for (const [rel] of wrapperSources) {
|
|
105
|
+
const path = join(codeRepo, rel);
|
|
106
|
+
const existing = (await exists(path)) ? await readFile(path, "utf8") : null;
|
|
107
|
+
existingOf[rel] = existing;
|
|
108
|
+
const hasMarkers = existing !== null && existing.includes(WRAPPER_BLOCK_BEGIN) && existing.includes(WRAPPER_BLOCK_END);
|
|
109
|
+
if (existing !== null && !hasMarkers && !opts.allowOverwrite) {
|
|
110
|
+
// No markers: a pre-briefing-layer file (the bash generator wrote these whole) or adopter-authored.
|
|
111
|
+
out(fail(`${rel} exists without method-managed markers, so it is treated as adopter-authored. Nothing was written. Re-run with --allow-overwrite to replace it with the rendered wrapper (move anything worth keeping below its markers afterwards).`));
|
|
112
|
+
return { exitCode: 1 };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const changed = [];
|
|
116
|
+
for (const [rel] of wrapperSources) {
|
|
117
|
+
const path = join(codeRepo, rel);
|
|
118
|
+
const existing = existingOf[rel] ?? null;
|
|
119
|
+
const hasMarkers = existing !== null && existing.includes(WRAPPER_BLOCK_BEGIN) && existing.includes(WRAPPER_BLOCK_END);
|
|
120
|
+
if (existing !== null && !hasMarkers) {
|
|
121
|
+
await writeFile(path, rendered[rel], "utf8");
|
|
122
|
+
if (existing !== rendered[rel])
|
|
123
|
+
changed.push(rel);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const parts = splitWrapperTemplate(rendered[rel]);
|
|
127
|
+
const merge = await writeMarkedBlockFile(path, existing === null ? rendered[rel] : parts.block, { begin: WRAPPER_BLOCK_BEGIN, end: WRAPPER_BLOCK_END }, opts.allowOverwrite, existing === null ? undefined : { pre: parts.pre, post: parts.post });
|
|
128
|
+
if (merge.changed)
|
|
129
|
+
changed.push(rel);
|
|
130
|
+
}
|
|
131
|
+
for (const rel of [AGENT_INSTRUCTIONS_REL_PATH]) {
|
|
132
|
+
const path = join(codeRepo, rel);
|
|
133
|
+
const before = (await exists(path)) ? await readFile(path, "utf8") : null;
|
|
134
|
+
if (before !== rendered[rel]) {
|
|
135
|
+
await mkdir(dirname(path), { recursive: true });
|
|
136
|
+
await writeFile(path, rendered[rel], "utf8");
|
|
137
|
+
changed.push(rel);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const mcpSetup = await retireMcpSetup(codeRepo);
|
|
141
|
+
out(info(`Code repo "${repoName}" is specified by ${sdd.sdd_name} (${sdd.repo_kind}, ${sdd.baseline_version}) at ${sddRoot}.`));
|
|
142
|
+
out(info(changed.length > 0 ? `Wrote ${changed.join(", ")}.` : `Already current: ${[AGENT_INSTRUCTIONS_REL_PATH, ...wrapperSources.map(([rel]) => rel)].join(", ")}.`));
|
|
143
|
+
if (mcpSetup === "removed")
|
|
144
|
+
out(info(`Removed ${MCP_SETUP_REL_PATH}: the method no longer ships it (M-ADR 0220), and this copy was unedited.`));
|
|
145
|
+
if (mcpSetup === "kept")
|
|
146
|
+
out(info(`${MCP_SETUP_REL_PATH} is no longer written (M-ADR 0220). This copy differs from the method's last render, so it was left; delete it if nothing in it is yours.`));
|
|
147
|
+
return { exitCode: 0 };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Remove an MCP_SETUP.md this verb wrote before M-ADR 0220, when it is byte-identical to the
|
|
151
|
+
* method's last template rendered with the values its own header records. Anything else is the
|
|
152
|
+
* adopter's now, and stays.
|
|
153
|
+
*/
|
|
154
|
+
export async function retireMcpSetup(codeRepo) {
|
|
155
|
+
const path = join(codeRepo, MCP_SETUP_REL_PATH);
|
|
156
|
+
if (!(await exists(path)))
|
|
157
|
+
return "absent";
|
|
158
|
+
const text = await readFile(path, "utf8");
|
|
159
|
+
const repo = /^\* \*\*Emitted by:\*\* `sdd-cli context pull`, for code repo `([^`]*)`$/m.exec(text);
|
|
160
|
+
const upstream = /^\* \*\*Upstream SDD:\*\* `([^`]*)` at `([^`]*)`$/m.exec(text);
|
|
161
|
+
const baseline = /^\* \*\*Baseline version:\*\* `([^`]*)`$/m.exec(text);
|
|
162
|
+
if (!repo || !upstream || !baseline)
|
|
163
|
+
return "kept";
|
|
164
|
+
const render = substituteAll(RETIRED_MCP_SETUP_TEMPLATE, {
|
|
165
|
+
repo_name: repo[1],
|
|
166
|
+
upstream_sdd_name: upstream[1],
|
|
167
|
+
sdd_root: upstream[2],
|
|
168
|
+
sdd_method_baseline_version: baseline[1],
|
|
169
|
+
});
|
|
170
|
+
if (render !== text)
|
|
171
|
+
return "kept";
|
|
172
|
+
await rm(path);
|
|
173
|
+
return "removed";
|
|
174
|
+
}
|
|
175
|
+
/** `{{name}}` substitution over an open variable set (the briefing renderer's is closed to four). */
|
|
176
|
+
export function substituteAll(template, vars) {
|
|
177
|
+
return template.replace(/\{\{\s*([a-z_][a-z0-9_]*)\s*\}\}/g, (full, key) => (key in vars ? vars[key] : full));
|
|
178
|
+
}
|
|
179
|
+
async function exists(path) {
|
|
180
|
+
try {
|
|
181
|
+
await access(path);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const info = (m) => `[INFO] ${m}\n`;
|
|
189
|
+
const warn = (m) => `[WARN] ${m}\n`;
|
|
190
|
+
const fail = (m) => `[FAIL] ${m}\n`;
|
|
191
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/context-pull/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EACL,2BAA2B,EAC3B,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,CAAC,MAAM,uBAAuB,GAAG,4CAA4C,CAAC;AACpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAEjD,MAAM,gBAAgB,GAA2C;IAC/D,aAAa,EAAE,2BAA2B;CAC3C,CAAC;AAkBF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAwB,EACxB,MAA8B,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IAElE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC5C,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,sIAAsI,CAAC,CAAC,CAAC;QAC7J,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC;QAC/B,QAAQ;QACR,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC,QAAQ,CAAC;QAC7D,QAAQ;KACT,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAClC,GAAG,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,IAAI,gDAAgD,CAAC,CAAC,CAAC;QACjF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,4BAA4B,QAAQ,kDAAkD,OAAO,CAAC,QAAQ,CAAC,MAAM,iBAAiB,CAAC,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,yFAAyF,CAAC,CAAC,CAAC;QAChS,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,eAAe,QAAQ,kBAAkB,OAAO,CAAC,UAAU,CAAC,MAAM,UAAU,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACrJ,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,iDAAiD,QAAQ,wCAAwC,CAAC,CAAC,CAAC;IACnI,CAAC;IAED,0FAA0F;IAC1F,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAC/D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,qEAAqE,CAAC,CAAC,CAAC;QAC3F,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,wBAAwB,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,uBAAuB,EAAE,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC;IACxH,MAAM,IAAI,GAAqC;QAC7C,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;QACtC,SAAS,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAClE,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,CAAC,CAAC;IACvF,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACpG,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,mBAAmB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,6GAA6G,CAAC,CAAC,CAAC;YACjL,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IACD,mGAAmG;IACnG,sFAAsF;IACtF,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC;IAC3F,MAAM,cAAc,GAAuB,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;IAC5G,IAAI,MAAM,MAAM,CAAC,eAAe,CAAC;QAAE,cAAc,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC;IAEpG,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,2BAA2B,EAAE,UAAU,CAAC,EAAE,GAAG,cAAc,CAAU,EAAE,CAAC;QAClG,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,iEAAiE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC5H,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,6FAA6F;IAC7F,sEAAsE;IACtE,MAAM,UAAU,GAAkC,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5E,UAAU,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;QAC3B,MAAM,UAAU,GAAG,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QACvH,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YAC7D,oGAAoG;YACpG,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,sOAAsO,CAAC,CAAC,CAAC;YACxP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;QACzC,MAAM,UAAU,GAAG,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QACvH,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrC,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAE,EAAE,MAAM,CAAC,CAAC;YAC9C,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClD,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAE,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CACtC,IAAI,EACJ,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAChD,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,iBAAiB,EAAE,EACtD,IAAI,CAAC,cAAc,EACnB,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CACrE,CAAC;QACF,IAAI,KAAK,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,2BAA2B,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1E,IAAI,MAAM,KAAK,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAE,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAChD,GAAG,CAAC,IAAI,CAAC,cAAc,QAAQ,qBAAqB,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC,gBAAgB,QAAQ,OAAO,GAAG,CAAC,CAAC,CAAC;IAChI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB,CAAC,2BAA2B,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACxK,IAAI,QAAQ,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,CAAC,WAAW,kBAAkB,2EAA2E,CAAC,CAAC,CAAC;IAChJ,IAAI,QAAQ,KAAK,MAAM;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,kBAAkB,2IAA2I,CAAC,CAAC,CAAC;IACrM,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAChD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,2EAA2E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpG,MAAM,QAAQ,GAAG,oDAAoD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC;IACnD,MAAM,MAAM,GAAG,aAAa,CAAC,0BAA0B,EAAE;QACvD,SAAS,EAAE,IAAI,CAAC,CAAC,CAAE;QACnB,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAE;QAC/B,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAE;QACtB,2BAA2B,EAAE,QAAQ,CAAC,CAAC,CAAE;KAC1C,CAAC,CAAC;IACH,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACnC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;IACf,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAsC;IACpF,OAAO,QAAQ,CAAC,OAAO,CAAC,mCAAmC,EAAE,CAAC,IAAI,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACzH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;AAC5C,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;AAC5C,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-repo SDD-source resolution for `sdd-cli context pull` (M-ADR 0128 §1,
|
|
3
|
+
* M-ADR 0150 §4.4 Phase D).
|
|
4
|
+
*
|
|
5
|
+
* A code repository has no `.sdd-repo-kind`, no lock and no bundle, so nothing
|
|
6
|
+
* in it names the SDD that specifies it. The SDD names the code repository
|
|
7
|
+
* instead: every repository it owns is a row in its own
|
|
8
|
+
* `catalogues/repositories.csv`, keyed by id. Resolution is therefore a lookup
|
|
9
|
+
* in that direction: find the SDD whose catalogue lists this repository.
|
|
10
|
+
*
|
|
11
|
+
* Only the SDD's OWN catalogue counts, never `catalogues-aggregated/`: a
|
|
12
|
+
* platform root's aggregate lists every member's repositories too, so reading
|
|
13
|
+
* it would make every code repo resolve to two SDDs.
|
|
14
|
+
*/
|
|
15
|
+
export declare const REPOSITORIES_CATALOGUE = "catalogues/repositories.csv";
|
|
16
|
+
/** The code repository's id: `--repo` when given, else its git top-level's directory name. */
|
|
17
|
+
export declare function resolveCodeRepoName(codeRepo: string, override?: string): string;
|
|
18
|
+
export type ResolveOutcome = {
|
|
19
|
+
readonly kind: "resolved";
|
|
20
|
+
readonly sddRoot: string;
|
|
21
|
+
readonly catalogued: boolean;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "not-found";
|
|
24
|
+
readonly searched: readonly string[];
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: "ambiguous";
|
|
27
|
+
readonly candidates: readonly string[];
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: "not-an-sdd";
|
|
30
|
+
readonly path: string;
|
|
31
|
+
};
|
|
32
|
+
export interface ResolveSddOptions {
|
|
33
|
+
readonly repoName: string;
|
|
34
|
+
/** `--sdd`: an explicit SDD root. Skips discovery. */
|
|
35
|
+
readonly sddPath?: string | undefined;
|
|
36
|
+
/** Directories to discover SDDs under. Default: the code repository's parent. */
|
|
37
|
+
readonly searchRoots: readonly string[];
|
|
38
|
+
/** The code repository itself, excluded from candidates. */
|
|
39
|
+
readonly codeRepo: string;
|
|
40
|
+
}
|
|
41
|
+
/** Does this SDD's own repositories catalogue list `repoName`? */
|
|
42
|
+
export declare function catalogueListsRepo(sddRoot: string, repoName: string): Promise<boolean>;
|
|
43
|
+
export declare function resolveSdd(opts: ResolveSddOptions): Promise<ResolveOutcome>;
|
|
44
|
+
/** Default discovery root: the directory holding the code repository. */
|
|
45
|
+
export declare function defaultSearchRoots(codeRepo: string): string[];
|
|
46
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/context-pull/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,eAAO,MAAM,sBAAsB,gCAAgC,CAAC;AAEpE,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAK/E;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GACrF;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,kEAAkE;AAClE,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS5F;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAkBjF;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-repo SDD-source resolution for `sdd-cli context pull` (M-ADR 0128 §1,
|
|
3
|
+
* M-ADR 0150 §4.4 Phase D).
|
|
4
|
+
*
|
|
5
|
+
* A code repository has no `.sdd-repo-kind`, no lock and no bundle, so nothing
|
|
6
|
+
* in it names the SDD that specifies it. The SDD names the code repository
|
|
7
|
+
* instead: every repository it owns is a row in its own
|
|
8
|
+
* `catalogues/repositories.csv`, keyed by id. Resolution is therefore a lookup
|
|
9
|
+
* in that direction: find the SDD whose catalogue lists this repository.
|
|
10
|
+
*
|
|
11
|
+
* Only the SDD's OWN catalogue counts, never `catalogues-aggregated/`: a
|
|
12
|
+
* platform root's aggregate lists every member's repositories too, so reading
|
|
13
|
+
* it would make every code repo resolve to two SDDs.
|
|
14
|
+
*/
|
|
15
|
+
import { access } from "node:fs/promises";
|
|
16
|
+
import { spawnSync } from "node:child_process";
|
|
17
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
18
|
+
import { readCatalogueCsv } from "../catalogue/csv-reader.js";
|
|
19
|
+
import { discoverSddRepos } from "../list/discover.js";
|
|
20
|
+
import { readRepoKind } from "../repo-kind.js";
|
|
21
|
+
export const REPOSITORIES_CATALOGUE = "catalogues/repositories.csv";
|
|
22
|
+
/** The code repository's id: `--repo` when given, else its git top-level's directory name. */
|
|
23
|
+
export function resolveCodeRepoName(codeRepo, override) {
|
|
24
|
+
if (override !== undefined && override.trim() !== "")
|
|
25
|
+
return override.trim();
|
|
26
|
+
const top = spawnSync("git", ["-C", codeRepo, "rev-parse", "--show-toplevel"], { encoding: "utf8" });
|
|
27
|
+
if (top.status === 0 && top.stdout.trim() !== "")
|
|
28
|
+
return basename(top.stdout.trim());
|
|
29
|
+
return basename(resolve(codeRepo));
|
|
30
|
+
}
|
|
31
|
+
/** Does this SDD's own repositories catalogue list `repoName`? */
|
|
32
|
+
export async function catalogueListsRepo(sddRoot, repoName) {
|
|
33
|
+
const path = join(sddRoot, REPOSITORIES_CATALOGUE);
|
|
34
|
+
try {
|
|
35
|
+
await access(path);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const { rows } = await readCatalogueCsv(path);
|
|
41
|
+
return rows.some((r) => r["id"] === repoName);
|
|
42
|
+
}
|
|
43
|
+
export async function resolveSdd(opts) {
|
|
44
|
+
if (opts.sddPath !== undefined) {
|
|
45
|
+
const root = resolve(opts.sddPath);
|
|
46
|
+
if ((await readRepoKind(root)) === null)
|
|
47
|
+
return { kind: "not-an-sdd", path: root };
|
|
48
|
+
// An explicit --sdd is the caller's assertion, so an uncatalogued repository is reported
|
|
49
|
+
// (the caller may be wiring a repository the SDD has not catalogued yet), not refused.
|
|
50
|
+
return { kind: "resolved", sddRoot: root, catalogued: await catalogueListsRepo(root, opts.repoName) };
|
|
51
|
+
}
|
|
52
|
+
const self = resolve(opts.codeRepo);
|
|
53
|
+
const found = await discoverSddRepos(opts.searchRoots);
|
|
54
|
+
const searched = found.map((r) => r.path).filter((p) => resolve(p) !== self);
|
|
55
|
+
const matches = [];
|
|
56
|
+
for (const p of searched) {
|
|
57
|
+
if (await catalogueListsRepo(p, opts.repoName))
|
|
58
|
+
matches.push(p);
|
|
59
|
+
}
|
|
60
|
+
if (matches.length === 1)
|
|
61
|
+
return { kind: "resolved", sddRoot: matches[0], catalogued: true };
|
|
62
|
+
if (matches.length === 0)
|
|
63
|
+
return { kind: "not-found", searched };
|
|
64
|
+
return { kind: "ambiguous", candidates: matches };
|
|
65
|
+
}
|
|
66
|
+
/** Default discovery root: the directory holding the code repository. */
|
|
67
|
+
export function defaultSearchRoots(codeRepo) {
|
|
68
|
+
return [dirname(resolve(codeRepo))];
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/lib/context-pull/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last MCP_SETUP.md template the method shipped (sdd-method 52bbc36), kept so `context pull`
|
|
3
|
+
* can tell a copy it wrote from one an adopter edited after M-ADR 0220 §4.5 retired the file.
|
|
4
|
+
* The SDD's own baseline stops carrying the template, so the comparison cannot read it from there.
|
|
5
|
+
*/
|
|
6
|
+
export declare const RETIRED_MCP_SETUP_TEMPLATE: string;
|
|
7
|
+
//# sourceMappingURL=retired-mcp-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-mcp-setup.d.ts","sourceRoot":"","sources":["../../../src/lib/context-pull/retired-mcp-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAs4O,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last MCP_SETUP.md template the method shipped (sdd-method 52bbc36), kept so `context pull`
|
|
3
|
+
* can tell a copy it wrote from one an adopter edited after M-ADR 0220 §4.5 retired the file.
|
|
4
|
+
* The SDD's own baseline stops carrying the template, so the comparison cannot read it from there.
|
|
5
|
+
*/
|
|
6
|
+
export const RETIRED_MCP_SETUP_TEMPLATE = "# MCP_SETUP.md\n\n* **Source:** sdd-method-baseline\n* **Emitted by:** `sdd-cli context pull`, for code repo `{{repo_name}}`\n* **Upstream SDD:** `{{upstream_sdd_name}}` at `{{sdd_root}}`\n* **Baseline version:** `{{sdd_method_baseline_version}}`\n\nThis file is **method-shipped guidance for agents working in this code repo**. It tells the agent how to reach the upstream SDD's live context via MCP. Read it alongside `agent-instructions.md` at session start.\n\nPer M-ADR 0150 (MCP as the primary dynamic-context layer), the **primary dynamic-context surface** for this code repo is the upstream SDD's MCP server, not baked-in snapshot content. Prefer MCP queries over reading static files for anything that might have changed since the last `sdd-cli context pull`.\n\n## \u00a71 What MCP gives you here\n\nThis code repo (`{{repo_name}}`) consumes specifications from the upstream SDD `{{upstream_sdd_name}}`. The upstream SDD exposes a read-only MCP server (`sdd-mcp`) you can query for:\n\n* **Catalogue rows** \u2014 current capability inventory, service registry, contract list, feature tree, cross-SDD edges.\n* **Gate state** \u2014 lock-in recommendations, intent-quality scores, domain-architecture scores, contract-quality scores per capability.\n* **Plan progress** \u2014 active plans, phases shipped, deferred follow-ups.\n* **Spec lookups** \u2014 ADRs, capability specs, feature specs, traceability manifests.\n\nThe static briefing in this repo (`agent-instructions.md` and the harness wrapper) covers conventions and orientation that are stable across syncs. Anything that changes faster than syncs run \u2014 gate state, catalogue rows, lock-in status \u2014 belongs behind MCP.\n\n## \u00a72 Server identity\n\n* **Server name:** `sdd-mcp`\n* **Upstream SDD path:** `{{sdd_root}}`\n* **Transport:** stdio (per M-ADR 0128's three-MCP-server commitment)\n\n`{{sdd_root}}` is where the SDD was checked out when this file was written; adjust it if your checkout differs. The MCP server resolves the SDD root with this precedence (per sdd-cli):\n\n1. `SDD_REPO_PATH` environment variable.\n2. `--sdd-repo <path>` flag on `sdd-cli mcp serve`.\n3. A platform SDD serves itself: when the git root's own `.sdd-repo-kind` reads `platform-product`, that repository is the SDD, whatever its siblings carry (so a platform repo needs no `SDD_REPO_PATH`).\n4. Sibling-directory auto-discovery from the code repo.\n\n## \u00a73 Harness wiring\n\n### Claude Code (reference)\n\nAdd this fragment to `.claude/settings.json` in this code repo. If the SDD is checked out in a sibling directory, discovery finds it and the `--sdd-repo` argument can be dropped:\n\n```jsonc\n{\n \"mcpServers\": {\n \"sdd-mcp\": {\n \"command\": \"sdd-cli\",\n \"args\": [\"mcp\", \"serve\", \"--sdd-repo\", \"{{sdd_root}}\"]\n }\n }\n}\n```\n\nVerify the wiring: open this code repo in Claude Code; in a session, ask the agent \"list available MCP resources\". You should see `sdd://` URIs from `sdd-mcp`.\n\n### GitHub Copilot CLI\n\nCopilot CLI's MCP wiring uses `.github/copilot/mcp.json` (verify against the current Copilot CLI docs at the time of setup; this surface is evolving). Equivalent shape:\n\n```jsonc\n{\n \"servers\": {\n \"sdd-mcp\": {\n \"command\": \"sdd-cli\",\n \"args\": [\"mcp\", \"serve\", \"--sdd-repo\", \"{{sdd_root}}\"]\n }\n }\n}\n```\n\n### Other harnesses\n\nFor any other harness (OpenAI Codex CLI, OpenCode, a generic-stdio harness, or custom in-house): follow the adopter-responsibility flow per M-ADR 0141 \u00a74.5. Read the portable contract of each MCP resource (in the upstream SDD's `docs/method/methods/`) and instantiate against your harness's native MCP-client interface. Document the wiring in an adopter-side ADR or guide.\n\n## \u00a74 Resource surface \u2014 quick reference\n\nThe upstream `sdd-mcp` server exposes resources keyed by `sdd://` URIs. The most relevant for code-repo agents:\n\n| URI pattern | Returns | Typical use |\n|---|---|---|\n| `sdd://catalogue/{name}` | All rows from one catalogue (e.g. `services`, `capabilities`, `features`, `contracts`) | Discover what exists in the SDD |\n| `sdd://catalogue/metamodel` | The catalogue metamodel doc | Understand the entity / edge model |\n| `sdd://catalogue/schema` | Parsed schema (entities + columns + FK constraints) | Reason about data shape |\n| `sdd://gates/{gate}` | Current gate state per capability | Check whether your dependency has locked in |\n| `sdd://specs/{path}` | Spec content lookup | Read a specific feature / capability spec by ID |\n| `sdd://adrs/{id}` | ADR content + metadata | Cross-reference architectural decisions |\n\nNewly-added resource families ship via baseline sync; consult the upstream SDD's MCP setup docs for the current list.\n\nTools (callable via MCP `tools/call`): `find_producers`, `find_consumers`, `find_consumers_of_contract`, `find_dependencies`, `find_dependents`, `cascade_impact`, `query_edges_for_entity`, `find_orphan_rows`, `query_catalogue_coverage`, `find_products_by_category`, `find_related_specs`, `search_specs`, `list_adrs`, `query_gate_status`. Ask the server for `tools/list` for each tool's arguments.\n\n## \u00a75 Troubleshooting\n\n**`sdd-mcp` unreachable / \"Connection refused\"**\nThe MCP server is launched on-demand by the harness; if it isn't starting, check:\n1. `sdd-cli` is installed and on `$PATH` (`which sdd-cli` should resolve).\n2. The harness's MCP config exists and points at `sdd-cli mcp serve`.\n3. The `--sdd-repo` path (or the sibling the server discovers) is a real SDD root.\n\n**\"SDD root not found\" or \"manifest missing\"**\nThe SDD path doesn't resolve to a valid SDD. The path should contain `.sdd/sdd-manifest.yaml` (or the legacy `docs/method/foundations/` layout).\n\n**Version mismatch on resources**\nSome resource families require a minimum `sdd-cli` version. Check `npm list -g @sdd-method/sdd-cli`; upgrade via `npm install -g @sdd-method/sdd-cli@latest` if a resource returns \"unsupported by this server version\".\n\n**Permission denied**\nFor adopter-scoped resources (per M-ADR 0130), `platform-mcp` / `partner-mcp` enforce scope. If you're hitting permission errors, confirm you're querying the right MCP server for the resource (operator scope vs partner scope).\n\n## \u00a76 Fallback semantics \u2014 no silent stale-data\n\nIf `sdd-mcp` is unreachable for any reason, **the agent must report the error and continue with whatever static context exists in this code repo** \u2014 `CLAUDE.md` snapshot + the orientation in this file. **There is no silent fallback to stale baked-in dynamic state.** Per M-ADR 0128 \u00a71, falling back to stale data re-introduces exactly the problem MCP exists to fix.\n\nIf MCP-served dynamic context is unavailable, surface this back to the user explicitly. The user can choose to:\n\n* Proceed without dynamic context (accept the limitation).\n* Restart the MCP server / fix the connection.\n* Re-run `sdd-cli context pull` for a fresh static briefing, acknowledging it is still a point-in-time read.\n\n## Cross-references\n\n* Upstream SDD: `{{sdd_root}}`\n* M-ADR 0128 (MCP live-query infrastructure)\n* M-ADR 0150 (MCP as primary dynamic-context layer)\n* M-ADR 0130 (adopter MCP composition pattern \u2014 `platform-mcp` / `partner-mcp`)\n* M-ADR 0148 (the static-briefing layer this file complements)\n\n---\n\n<!-- This file is rewritten whole by sdd-cli context pull. Put repo-specific MCP guidance in the harness wrapper, below its method-managed markers. -->\n";
|
|
7
|
+
//# sourceMappingURL=retired-mcp-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-mcp-setup.js","sourceRoot":"","sources":["../../../src/lib/context-pull/retired-mcp-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAW,63OAA63O,CAAC"}
|