@thinkingsage/kanon 0.8.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 +410 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/bridge/mcp-server.cjs +14171 -0
- package/package.json +98 -0
- package/src/adapters/capabilities.ts +178 -0
- package/src/adapters/claude-code.ts +110 -0
- package/src/adapters/cline.ts +98 -0
- package/src/adapters/codex.ts +173 -0
- package/src/adapters/copilot.ts +106 -0
- package/src/adapters/cursor.ts +97 -0
- package/src/adapters/degradation.ts +95 -0
- package/src/adapters/index.ts +324 -0
- package/src/adapters/kiro-frontmatter.ts +139 -0
- package/src/adapters/kiro-inclusion.ts +86 -0
- package/src/adapters/kiro.ts +412 -0
- package/src/adapters/qdeveloper.ts +115 -0
- package/src/adapters/types.ts +81 -0
- package/src/adapters/windsurf.ts +96 -0
- package/src/admin.ts +283 -0
- package/src/asset-conventions.ts +118 -0
- package/src/attribution-backfill.ts +319 -0
- package/src/attribution-report.ts +95 -0
- package/src/attribution.ts +239 -0
- package/src/backends/github.ts +194 -0
- package/src/backends/http.ts +122 -0
- package/src/backends/index.ts +39 -0
- package/src/backends/local.ts +47 -0
- package/src/backends/s3.ts +157 -0
- package/src/backends/types.ts +59 -0
- package/src/base-cache.ts +270 -0
- package/src/browse-ui.ts +3754 -0
- package/src/browse.ts +1038 -0
- package/src/build.ts +1108 -0
- package/src/catalog.ts +204 -0
- package/src/cli-deprecated.ts +29 -0
- package/src/cli.ts +773 -0
- package/src/collection-admin.ts +287 -0
- package/src/collection-builder.ts +464 -0
- package/src/collections.ts +116 -0
- package/src/compatibility.ts +105 -0
- package/src/config.ts +743 -0
- package/src/eval/rubrics/kiro-progressive-steering.ts +841 -0
- package/src/eval.ts +1169 -0
- package/src/file-writer.ts +61 -0
- package/src/format-registry.ts +141 -0
- package/src/guild/auto-updater.ts +163 -0
- package/src/guild/backend-resolver.ts +49 -0
- package/src/guild/cli.ts +592 -0
- package/src/guild/collection-expander.ts +47 -0
- package/src/guild/global-cache.ts +247 -0
- package/src/guild/hook-generator.ts +100 -0
- package/src/guild/manifest.ts +154 -0
- package/src/guild/path-utils.ts +12 -0
- package/src/guild/sync.ts +622 -0
- package/src/guild/version-resolver.ts +42 -0
- package/src/help/metadata.ts +445 -0
- package/src/help/renderer.ts +265 -0
- package/src/help/typo-suggester.ts +25 -0
- package/src/hooks/expression.ts +493 -0
- package/src/hooks/pipeline.ts +141 -0
- package/src/import.ts +773 -0
- package/src/importers/claude-code.ts +134 -0
- package/src/importers/cline.ts +103 -0
- package/src/importers/codex.ts +140 -0
- package/src/importers/copilot.ts +103 -0
- package/src/importers/cursor.ts +105 -0
- package/src/importers/index.ts +390 -0
- package/src/importers/kiro.ts +110 -0
- package/src/importers/qdeveloper.ts +103 -0
- package/src/importers/types.ts +54 -0
- package/src/importers/windsurf.ts +104 -0
- package/src/install.ts +1005 -0
- package/src/manifest-admin.ts +306 -0
- package/src/mcp-bridge.ts +240 -0
- package/src/mutation/delta.ts +50 -0
- package/src/mutation/history.ts +66 -0
- package/src/mutation/operators.ts +524 -0
- package/src/mutation/runner.ts +332 -0
- package/src/new.ts +106 -0
- package/src/outcomes/collision.ts +127 -0
- package/src/outcomes/normalize.ts +208 -0
- package/src/outcomes/registry.ts +173 -0
- package/src/parser.ts +446 -0
- package/src/provenance-backfill-cli.ts +319 -0
- package/src/provenance-backfill.ts +520 -0
- package/src/publish.ts +354 -0
- package/src/reconcile-orchestrator.ts +502 -0
- package/src/reconcile-report-renderer.ts +176 -0
- package/src/resolve-body.ts +15 -0
- package/src/rosetta/builtins/compatibility-profiles.ts +297 -0
- package/src/rosetta/builtins/contracts.ts +1033 -0
- package/src/rosetta/builtins/pretty-printers/claude-code-native.ts +122 -0
- package/src/rosetta/builtins/pretty-printers/cline-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/codex-native.ts +127 -0
- package/src/rosetta/builtins/pretty-printers/copilot-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/cursor-native.ts +50 -0
- package/src/rosetta/builtins/pretty-printers/index.ts +81 -0
- package/src/rosetta/builtins/pretty-printers/kiro-native.ts +166 -0
- package/src/rosetta/builtins/pretty-printers/kiro-power.ts +108 -0
- package/src/rosetta/builtins/pretty-printers/kiro-skill.ts +88 -0
- package/src/rosetta/builtins/pretty-printers/qdeveloper-native.ts +51 -0
- package/src/rosetta/builtins/pretty-printers/superpowers.ts +97 -0
- package/src/rosetta/builtins/pretty-printers/windsurf-native.ts +50 -0
- package/src/rosetta/builtins/sources/claude-code-native.ts +348 -0
- package/src/rosetta/builtins/sources/cline-native.ts +176 -0
- package/src/rosetta/builtins/sources/codex-native.ts +343 -0
- package/src/rosetta/builtins/sources/copilot-native.ts +178 -0
- package/src/rosetta/builtins/sources/cursor-native.ts +176 -0
- package/src/rosetta/builtins/sources/index.ts +95 -0
- package/src/rosetta/builtins/sources/kiro-native.ts +462 -0
- package/src/rosetta/builtins/sources/kiro-power.ts +285 -0
- package/src/rosetta/builtins/sources/kiro-skill.ts +230 -0
- package/src/rosetta/builtins/sources/qdeveloper-native.ts +181 -0
- package/src/rosetta/builtins/sources/superpowers.ts +240 -0
- package/src/rosetta/builtins/sources/windsurf-native.ts +176 -0
- package/src/rosetta/builtins/targets/claude-code.ts +181 -0
- package/src/rosetta/builtins/targets/cline.ts +87 -0
- package/src/rosetta/builtins/targets/codex.ts +226 -0
- package/src/rosetta/builtins/targets/copilot.ts +103 -0
- package/src/rosetta/builtins/targets/cursor.ts +87 -0
- package/src/rosetta/builtins/targets/index.ts +60 -0
- package/src/rosetta/builtins/targets/kiro.ts +278 -0
- package/src/rosetta/builtins/targets/qdeveloper.ts +103 -0
- package/src/rosetta/builtins/targets/windsurf.ts +87 -0
- package/src/rosetta/canonical.ts +729 -0
- package/src/rosetta/compatibility.ts +432 -0
- package/src/rosetta/contracts.ts +329 -0
- package/src/rosetta/detector.ts +724 -0
- package/src/rosetta/diagnostics.ts +630 -0
- package/src/rosetta/engine-bootstrap.ts +103 -0
- package/src/rosetta/engine.ts +744 -0
- package/src/rosetta/index.ts +381 -0
- package/src/rosetta/inspection.ts +530 -0
- package/src/rosetta/plan.ts +448 -0
- package/src/rosetta/provenance-digest.ts +369 -0
- package/src/rosetta/reconcile.ts +812 -0
- package/src/rosetta/redaction.ts +467 -0
- package/src/rosetta/registry.ts +712 -0
- package/src/rosetta/renderers.ts +571 -0
- package/src/rosetta/request-guard.ts +335 -0
- package/src/rosetta/resolution.ts +419 -0
- package/src/rosetta/source-accounting.ts +233 -0
- package/src/rosetta/templates.ts +129 -0
- package/src/rosetta-cli.ts +717 -0
- package/src/rosetta-docs-generator.ts +793 -0
- package/src/rosetta-profiles-cli.ts +367 -0
- package/src/schemas.ts +1712 -0
- package/src/spec-coordination.ts +1141 -0
- package/src/temper.ts +747 -0
- package/src/template-bundle-loader.ts +312 -0
- package/src/template-engine.ts +53 -0
- package/src/translation-application-policy.ts +496 -0
- package/src/translation-orchestrator.ts +1013 -0
- package/src/translation-plan-applier.ts +473 -0
- package/src/tutorial.ts +305 -0
- package/src/validate.ts +1093 -0
- package/src/versioning.ts +553 -0
- package/src/wizard.ts +660 -0
- package/src/workspace.ts +237 -0
- package/templates/eval-contexts/claude-code.md.njk +6 -0
- package/templates/eval-contexts/cline.md.njk +6 -0
- package/templates/eval-contexts/copilot.md.njk +6 -0
- package/templates/eval-contexts/cursor.md.njk +6 -0
- package/templates/eval-contexts/kiro.md.njk +10 -0
- package/templates/eval-contexts/qdeveloper.md.njk +6 -0
- package/templates/eval-contexts/windsurf.md.njk +6 -0
- package/templates/harness-adapters/_base/attribution-footer.md.njk +17 -0
- package/templates/harness-adapters/_base/base.md.njk +16 -0
- package/templates/harness-adapters/claude-code/claude.md.njk +1 -0
- package/templates/harness-adapters/claude-code/mcp.json.njk +1 -0
- package/templates/harness-adapters/claude-code/settings.json.njk +1 -0
- package/templates/harness-adapters/claude-code/skill-library-index.md.njk +13 -0
- package/templates/harness-adapters/claude-code/skill.md.njk +19 -0
- package/templates/harness-adapters/cline/hook.sh.njk +4 -0
- package/templates/harness-adapters/cline/mcp.json.njk +1 -0
- package/templates/harness-adapters/cline/rule.md.njk +1 -0
- package/templates/harness-adapters/codex/agents-md.md.njk +6 -0
- package/templates/harness-adapters/codex/agents-pointer.md.njk +16 -0
- package/templates/harness-adapters/codex/skill.md.njk +27 -0
- package/templates/harness-adapters/copilot/agents.md.njk +1 -0
- package/templates/harness-adapters/copilot/instructions.md.njk +1 -0
- package/templates/harness-adapters/copilot/scoped.md.njk +6 -0
- package/templates/harness-adapters/cursor/mcp.json.njk +1 -0
- package/templates/harness-adapters/cursor/rule.md.njk +6 -0
- package/templates/harness-adapters/kiro/hook.json.njk +1 -0
- package/templates/harness-adapters/kiro/mcp.json.njk +1 -0
- package/templates/harness-adapters/kiro/power-steering.md.njk +3 -0
- package/templates/harness-adapters/kiro/power.md.njk +12 -0
- package/templates/harness-adapters/kiro/steering.md.njk +16 -0
- package/templates/harness-adapters/qdeveloper/agent.md.njk +1 -0
- package/templates/harness-adapters/qdeveloper/mcp.json.njk +1 -0
- package/templates/harness-adapters/qdeveloper/rule.md.njk +1 -0
- package/templates/harness-adapters/windsurf/mcp.json.njk +1 -0
- package/templates/harness-adapters/windsurf/rule.md.njk +1 -0
- package/templates/harness-adapters/windsurf/workflow.md.njk +1 -0
- package/templates/knowledge/hooks.yaml.njk +4 -0
- package/templates/knowledge/knowledge.md.njk +53 -0
- package/templates/knowledge/mcp-servers.yaml.njk +2 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance Backfill — CLI Command Handler
|
|
3
|
+
*
|
|
4
|
+
* `kanon rosetta backfill [upstream]` is the one-shot command that records
|
|
5
|
+
* `ProvenanceRecord`s for existing distilled artifacts (ADR-0049). It matches
|
|
6
|
+
* each distilled artifact to the current upstream by NAME, records the current
|
|
7
|
+
* `baseDigest`, writes the machine-managed provenance block into `knowledge.md`,
|
|
8
|
+
* and seeds the git-ignored base cache. Supports `--dry-run` to report what it
|
|
9
|
+
* would backfill without writing.
|
|
10
|
+
*
|
|
11
|
+
* This handler is the orchestration shell: it resolves config, locates the
|
|
12
|
+
* upstream source root and distilled knowledge directory, resolves the source
|
|
13
|
+
* revision, then delegates the per-artifact work to `backfillUpstream`
|
|
14
|
+
* (src/provenance-backfill.ts), which composes the pure Rosetta Stone helpers.
|
|
15
|
+
*
|
|
16
|
+
* Requirements: 18.1, 18.9
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { exists } from "node:fs/promises";
|
|
20
|
+
import { isAbsolute, resolve } from "node:path";
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
import type { Command } from "commander";
|
|
23
|
+
import { loadForgeConfig, type UpstreamConfig } from "./config";
|
|
24
|
+
import { loadKnowledgeArtifact } from "./parser";
|
|
25
|
+
import {
|
|
26
|
+
type BackfillResult,
|
|
27
|
+
type BackfillSourceFormat,
|
|
28
|
+
type BackfillUpstreamOptions,
|
|
29
|
+
backfillUpstream,
|
|
30
|
+
type DistilledArtifactLoader,
|
|
31
|
+
} from "./provenance-backfill";
|
|
32
|
+
import type { KnowledgeArtifact } from "./schemas";
|
|
33
|
+
|
|
34
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
35
|
+
// Options
|
|
36
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
37
|
+
|
|
38
|
+
interface BackfillCliOptions {
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
json?: boolean;
|
|
41
|
+
revision?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Source formats a path-based backfill can distill from. */
|
|
45
|
+
const BACKFILL_FORMATS: ReadonlySet<string> = new Set([
|
|
46
|
+
"kiro-power",
|
|
47
|
+
"kiro-skill",
|
|
48
|
+
"superpowers",
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
52
|
+
// Filesystem-backed distilled artifact loader
|
|
53
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default loader: parse a distilled artifact directory via the canonical parser.
|
|
57
|
+
* Returns undefined when the directory does not parse into a valid artifact so
|
|
58
|
+
* the backfill classifies it as a translation failure rather than throwing.
|
|
59
|
+
*/
|
|
60
|
+
const loadDistilledFromDisk: DistilledArtifactLoader = async (artifactDir) => {
|
|
61
|
+
const result = await loadKnowledgeArtifact(artifactDir);
|
|
62
|
+
if ("errors" in result) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return result.data as KnowledgeArtifact;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
69
|
+
// Source-revision resolution
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the upstream source revision to record in provenance. Prefers an
|
|
74
|
+
* explicit `--revision`; otherwise attempts to read the current subtree HEAD via
|
|
75
|
+
* git; otherwise falls back to a stable backfill marker so the (non-empty)
|
|
76
|
+
* schema field is always satisfied without failing the command on machines
|
|
77
|
+
* where git is unavailable.
|
|
78
|
+
*/
|
|
79
|
+
async function resolveSourceRevision(
|
|
80
|
+
explicit: string | undefined,
|
|
81
|
+
repoRoot: string,
|
|
82
|
+
): Promise<string> {
|
|
83
|
+
if (explicit && explicit.trim().length > 0) {
|
|
84
|
+
return explicit.trim();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const proc = Bun.spawn(["git", "rev-parse", "HEAD"], {
|
|
89
|
+
cwd: repoRoot,
|
|
90
|
+
stdout: "pipe",
|
|
91
|
+
stderr: "ignore",
|
|
92
|
+
});
|
|
93
|
+
const out = (await new Response(proc.stdout).text()).trim();
|
|
94
|
+
const code = await proc.exited;
|
|
95
|
+
if (code === 0 && out.length > 0) {
|
|
96
|
+
return `backfill:${out}`;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// git unavailable — fall through to the marker below.
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return "backfill:unknown";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
106
|
+
// Path resolution for one upstream
|
|
107
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
108
|
+
|
|
109
|
+
interface ResolvedUpstreamPaths {
|
|
110
|
+
readonly sourceFormat: BackfillSourceFormat;
|
|
111
|
+
readonly knowledgeDir: string;
|
|
112
|
+
readonly upstreamRoot: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Resolve the distilled knowledge directory and upstream source root for an
|
|
117
|
+
* upstream config entry, or return a diagnostic string explaining why it cannot
|
|
118
|
+
* be backfilled. `prefix` is relative to the repository root; `knowledgeDir` is
|
|
119
|
+
* relative to the kanon working directory.
|
|
120
|
+
*/
|
|
121
|
+
async function resolveUpstreamPaths(
|
|
122
|
+
upstream: UpstreamConfig,
|
|
123
|
+
repoRoot: string,
|
|
124
|
+
workingDir: string,
|
|
125
|
+
): Promise<ResolvedUpstreamPaths | string> {
|
|
126
|
+
const format = upstream.format ?? "auto";
|
|
127
|
+
if (!BACKFILL_FORMATS.has(format)) {
|
|
128
|
+
return `format "${format}" is not a path-based source format (expected kiro-power, kiro-skill, or superpowers)`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!upstream.knowledgeDir) {
|
|
132
|
+
return "no knowledgeDir configured for this upstream";
|
|
133
|
+
}
|
|
134
|
+
if (!upstream.prefix) {
|
|
135
|
+
return "no prefix (subtree path) configured for this upstream";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const knowledgeDir = isAbsolute(upstream.knowledgeDir)
|
|
139
|
+
? upstream.knowledgeDir
|
|
140
|
+
: resolve(workingDir, upstream.knowledgeDir);
|
|
141
|
+
const upstreamRoot = isAbsolute(upstream.prefix)
|
|
142
|
+
? upstream.prefix
|
|
143
|
+
: resolve(repoRoot, upstream.prefix);
|
|
144
|
+
|
|
145
|
+
if (!(await exists(knowledgeDir))) {
|
|
146
|
+
return `knowledge directory not found: ${knowledgeDir}`;
|
|
147
|
+
}
|
|
148
|
+
if (!(await exists(upstreamRoot))) {
|
|
149
|
+
return `upstream source root not found: ${upstreamRoot} (run the sync script first)`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
sourceFormat: format as BackfillSourceFormat,
|
|
154
|
+
knowledgeDir,
|
|
155
|
+
upstreamRoot,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
160
|
+
// Human-readable rendering
|
|
161
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
162
|
+
|
|
163
|
+
function renderResult(result: BackfillResult, dryRun: boolean): void {
|
|
164
|
+
const verb = dryRun ? "would backfill" : "backfilled";
|
|
165
|
+
console.log(
|
|
166
|
+
chalk.bold.cyan(`Provenance backfill — ${result.upstream}`) +
|
|
167
|
+
(dryRun ? chalk.dim(" (dry run)") : ""),
|
|
168
|
+
);
|
|
169
|
+
console.log(chalk.dim("─".repeat(50)));
|
|
170
|
+
|
|
171
|
+
for (const entry of result.entries) {
|
|
172
|
+
switch (entry.outcome) {
|
|
173
|
+
case "backfilled": {
|
|
174
|
+
const digest = entry.baseDigest
|
|
175
|
+
? chalk.dim(` ${entry.baseDigest.slice(0, 19)}…`)
|
|
176
|
+
: "";
|
|
177
|
+
console.log(` ${chalk.green("✓")} ${chalk.bold(entry.name)}${digest}`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case "skipped-has-provenance":
|
|
181
|
+
console.log(
|
|
182
|
+
` ${chalk.dim("•")} ${entry.name} ${chalk.dim("(already has provenance)")}`,
|
|
183
|
+
);
|
|
184
|
+
break;
|
|
185
|
+
case "unmatched":
|
|
186
|
+
console.log(
|
|
187
|
+
` ${chalk.yellow("⚠")} ${entry.name} ${chalk.dim("(no upstream match)")}`,
|
|
188
|
+
);
|
|
189
|
+
break;
|
|
190
|
+
case "translation-failed":
|
|
191
|
+
console.log(
|
|
192
|
+
` ${chalk.red("✗")} ${entry.name} ${chalk.dim(`(${entry.detail ?? "translation failed"})`)}`,
|
|
193
|
+
);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
console.log();
|
|
199
|
+
console.log(
|
|
200
|
+
chalk.green(` ${result.backfilledCount} ${verb}`) +
|
|
201
|
+
chalk.dim(
|
|
202
|
+
`, ${result.skippedCount} skipped, ${result.unmatchedCount} unmatched, ${result.failedCount} failed`,
|
|
203
|
+
),
|
|
204
|
+
);
|
|
205
|
+
console.log();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
209
|
+
// Command handler
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Handler for `kanon rosetta backfill [upstream]`. Backfills one named upstream
|
|
214
|
+
* or every configured `upstreams` entry when no name is given.
|
|
215
|
+
*/
|
|
216
|
+
async function backfillCommand(
|
|
217
|
+
upstreamName: string | undefined,
|
|
218
|
+
options: BackfillCliOptions,
|
|
219
|
+
): Promise<void> {
|
|
220
|
+
const config = await loadForgeConfig();
|
|
221
|
+
const upstreams = config.upstreams ?? {};
|
|
222
|
+
|
|
223
|
+
const names = upstreamName ? [upstreamName] : Object.keys(upstreams).sort();
|
|
224
|
+
|
|
225
|
+
if (upstreamName && !upstreams[upstreamName]) {
|
|
226
|
+
console.error(
|
|
227
|
+
chalk.red(`Error: Upstream "${upstreamName}" not found in config.`),
|
|
228
|
+
);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (names.length === 0) {
|
|
233
|
+
console.error(
|
|
234
|
+
chalk.yellow("No upstreams configured in kanon.config.yaml."),
|
|
235
|
+
);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const workingDir = process.cwd();
|
|
240
|
+
const repoRoot = resolve(workingDir, "..");
|
|
241
|
+
const dryRun = Boolean(options.dryRun);
|
|
242
|
+
|
|
243
|
+
const results: BackfillResult[] = [];
|
|
244
|
+
let hadError = false;
|
|
245
|
+
|
|
246
|
+
for (const name of names) {
|
|
247
|
+
const upstream = upstreams[name];
|
|
248
|
+
const resolved = await resolveUpstreamPaths(upstream, repoRoot, workingDir);
|
|
249
|
+
|
|
250
|
+
if (typeof resolved === "string") {
|
|
251
|
+
if (!options.json) {
|
|
252
|
+
console.error(chalk.yellow(` ⚠ ${name} — skipped: ${resolved}`));
|
|
253
|
+
}
|
|
254
|
+
hadError = true;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const sourceRevision = await resolveSourceRevision(
|
|
259
|
+
options.revision,
|
|
260
|
+
repoRoot,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const opts: BackfillUpstreamOptions = {
|
|
264
|
+
upstream: name,
|
|
265
|
+
knowledgeDir: resolved.knowledgeDir,
|
|
266
|
+
upstreamRoot: resolved.upstreamRoot,
|
|
267
|
+
sourceFormat: resolved.sourceFormat,
|
|
268
|
+
sourceRevision,
|
|
269
|
+
dryRun,
|
|
270
|
+
workspaceRoot: workingDir,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const result = await backfillUpstream(opts, loadDistilledFromDisk);
|
|
274
|
+
results.push(result);
|
|
275
|
+
|
|
276
|
+
if (result.failedCount > 0) {
|
|
277
|
+
hadError = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (options.json) {
|
|
282
|
+
console.log(JSON.stringify({ dryRun, upstreams: results }, null, 2));
|
|
283
|
+
} else {
|
|
284
|
+
for (const result of results) {
|
|
285
|
+
renderResult(result, dryRun);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (hadError) {
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
295
|
+
// Registration
|
|
296
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Register the `kanon rosetta backfill` subcommand on the rosetta command group.
|
|
300
|
+
*/
|
|
301
|
+
export function registerBackfillCommand(rosettaCmd: Command): void {
|
|
302
|
+
rosettaCmd
|
|
303
|
+
.command("backfill [upstream]")
|
|
304
|
+
.description(
|
|
305
|
+
"Backfill provenance for existing distilled artifacts by matching to current upstream by name",
|
|
306
|
+
)
|
|
307
|
+
.option(
|
|
308
|
+
"--dry-run",
|
|
309
|
+
"Report what would be backfilled without writing files",
|
|
310
|
+
)
|
|
311
|
+
.option("--json", "Output as JSON")
|
|
312
|
+
.option(
|
|
313
|
+
"--revision <rev>",
|
|
314
|
+
"Upstream revision to record in provenance (default: current git HEAD)",
|
|
315
|
+
)
|
|
316
|
+
.action((upstream: string | undefined, opts: BackfillCliOptions) =>
|
|
317
|
+
backfillCommand(upstream, opts),
|
|
318
|
+
);
|
|
319
|
+
}
|