@moretea-labs/forge 1.7.0 → 1.7.1
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/AGENTS.md +2 -0
- package/CHANGELOG.md +13 -0
- package/CLAUDE.md +2 -0
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/docs/architecture/CURRENT.md +12 -4
- package/docs/forge-plugin-management.md +1 -1
- package/docs/operations/controller-performance-and-502.md +19 -0
- package/docs/operations/homebrew.md +2 -2
- package/package.json +5 -2
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-work-efficiency.ts +0 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1531
- package/scripts/check-architecture-sync.sh +2 -302
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-runtime-architecture.mjs +243 -16
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +0 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -702
- package/scripts/ensure-task-workflow.sh +1 -1192
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/lib/project-init-lib.sh +7 -2
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -33
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -771
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +3 -0
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -531
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -593
- package/scripts/verify-sprint.sh +1 -500
- package/scripts/workflow-contract.ts +4 -201
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/controller/check-runner.ts +7 -2
- package/src/cli/controller/context-pack.ts +46 -21
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +2 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/local-bridge/facade-api.ts +37 -47
- package/src/cli/local-bridge/server.ts +2 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -33
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +85 -89
- package/src/cli/mcp/server.ts +57 -13
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset.ts +2 -2
- package/src/cli/mcp/transports/http.ts +23 -0
- package/src/cli/repositories/command-classifier.ts +2 -2
- package/src/cli/repositories/command-executor.ts +24 -6
- package/src/cli/repositories/repository-snapshot.ts +5 -2
- package/src/cli/repositories/structured-git.ts +57 -3
- package/src/cli/repository/inspector.ts +11 -3
- package/src/runtime/context/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +9 -61
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +18 -25
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
- package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
- package/src/runtime/control-plane/facade/index.ts +2 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/types.ts +68 -5
- package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
- package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +18 -6
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/process-runtime/check-result.ts +53 -18
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
- package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
- package/src/runtime/execution/process-runtime/runtime.ts +10 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -12
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -13
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/router.ts +2 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +805 -1009
- package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
- package/src/runtime/plugins/browser-adapter.ts +256 -1083
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +18 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
- package/src/runtime/plugins/browser-runtime.ts +10 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
- package/src/runtime/plugins/external-adapter.ts +92 -58
- package/src/runtime/plugins/macos-capability-broker.ts +0 -8
- package/src/runtime/plugins/store.ts +66 -9
- package/src/runtime/plugins/types.ts +3 -1
- package/src/runtime/recovery/maintenance-executor.ts +61 -25
- package/src/runtime/root/package-connector-service.ts +46 -4
- package/src/runtime/root/package-runtime-release.ts +1 -1
- package/src/runtime/root/package-runtime-service.ts +33 -2
- package/src/runtime/root/release-manifest.ts +137 -16
- package/src/runtime/root/release-materialize.ts +109 -35
- package/src/runtime/root/types.ts +10 -0
- package/src/runtime/standalone-recovery/core.ts +425 -194
- package/src/runtime/standalone-recovery/entry.ts +1 -1
- package/src/runtime/standalone-recovery/installer.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +113 -87
- package/src/runtime/workflow/schedules/settlement.ts +26 -23
- package/src/runtime/workflow/schedules/store.ts +79 -10
|
@@ -1,117 +1,4 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
cat <<'USAGE_EOF'
|
|
6
|
-
Usage: scripts/check-deploy-sql-order.sh [--quiet] [--root deploy/sql]
|
|
7
|
-
|
|
8
|
-
Validates deployment SQL assets:
|
|
9
|
-
- deployment SQL files must live directly under deploy/sql/
|
|
10
|
-
- filenames must start with a 4-digit numeric prefix
|
|
11
|
-
- prefixes must be strictly ascending in filename order
|
|
12
|
-
- if tests/sql/control_plane_invariants.sql exists, it must reference every deployment SQL file
|
|
13
|
-
|
|
14
|
-
Example: deploy/sql/0001_create_tables.sql
|
|
15
|
-
USAGE_EOF
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
quiet=0
|
|
19
|
-
sql_root="deploy/sql"
|
|
20
|
-
invariant_file="tests/sql/control_plane_invariants.sql"
|
|
21
|
-
|
|
22
|
-
while [[ $# -gt 0 ]]; do
|
|
23
|
-
case "$1" in
|
|
24
|
-
--quiet)
|
|
25
|
-
quiet=1
|
|
26
|
-
shift
|
|
27
|
-
;;
|
|
28
|
-
--root)
|
|
29
|
-
sql_root="${2:-}"
|
|
30
|
-
if [[ -z "$sql_root" ]]; then
|
|
31
|
-
echo "--root requires a path" >&2
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
shift 2
|
|
35
|
-
;;
|
|
36
|
-
--help|-h)
|
|
37
|
-
usage
|
|
38
|
-
exit 0
|
|
39
|
-
;;
|
|
40
|
-
*)
|
|
41
|
-
echo "Unknown argument: $1" >&2
|
|
42
|
-
usage
|
|
43
|
-
exit 1
|
|
44
|
-
;;
|
|
45
|
-
esac
|
|
46
|
-
done
|
|
47
|
-
|
|
48
|
-
sql_root="${sql_root%/}"
|
|
49
|
-
deploy_root="${sql_root%%/sql}"
|
|
50
|
-
issues=0
|
|
51
|
-
|
|
52
|
-
report_issue() {
|
|
53
|
-
echo "[deploy-sql] $1"
|
|
54
|
-
issues=$((issues + 1))
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if [[ "$sql_root" != "deploy/sql" ]]; then
|
|
58
|
-
report_issue "SQL root must be deploy/sql; got: $sql_root"
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
if [[ ! -d "$sql_root" ]]; then
|
|
62
|
-
report_issue "Missing SQL directory: $sql_root"
|
|
63
|
-
else
|
|
64
|
-
if [[ -d "$deploy_root" ]]; then
|
|
65
|
-
while IFS= read -r file; do
|
|
66
|
-
[[ -z "$file" ]] && continue
|
|
67
|
-
if [[ "$file" != "$sql_root/"* ]]; then
|
|
68
|
-
report_issue "Deploy SQL file must live under $sql_root/: $file"
|
|
69
|
-
continue
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
rel="${file#"$sql_root"/}"
|
|
73
|
-
if [[ "$rel" == */* ]]; then
|
|
74
|
-
report_issue "SQL file must be a direct child of $sql_root/: $file"
|
|
75
|
-
fi
|
|
76
|
-
done < <(find "$deploy_root" -type f -name '*.sql' | sort)
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
previous_number=-1
|
|
80
|
-
previous_file=""
|
|
81
|
-
while IFS= read -r file; do
|
|
82
|
-
[[ -z "$file" ]] && continue
|
|
83
|
-
base="$(basename "$file")"
|
|
84
|
-
|
|
85
|
-
if [[ ! "$base" =~ ^([0-9]{4})[_-].+\.sql$ ]]; then
|
|
86
|
-
report_issue "SQL filename must start with a 4-digit prefix: $file (example: deploy/sql/0001_create_tables.sql)"
|
|
87
|
-
continue
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
number="${BASH_REMATCH[1]}"
|
|
91
|
-
number_value=$((10#$number))
|
|
92
|
-
if (( previous_number >= 0 && number_value <= previous_number )); then
|
|
93
|
-
report_issue "SQL prefixes must be strictly ascending: $previous_file before $file"
|
|
94
|
-
fi
|
|
95
|
-
|
|
96
|
-
previous_number="$number_value"
|
|
97
|
-
previous_file="$file"
|
|
98
|
-
done < <(find "$sql_root" -maxdepth 1 -type f -name '*.sql' | sort)
|
|
99
|
-
|
|
100
|
-
if [[ -f "$invariant_file" ]]; then
|
|
101
|
-
while IFS= read -r file; do
|
|
102
|
-
[[ -z "$file" ]] && continue
|
|
103
|
-
base="$(basename "$file")"
|
|
104
|
-
if ! grep -Fq "$file" "$invariant_file" && ! grep -Fq "$base" "$invariant_file"; then
|
|
105
|
-
report_issue "SQL migration must be referenced by $invariant_file: $file"
|
|
106
|
-
fi
|
|
107
|
-
done < <(find "$sql_root" -maxdepth 1 -type f -name '*.sql' | sort)
|
|
108
|
-
fi
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
if (( issues > 0 )); then
|
|
112
|
-
exit 1
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
if (( quiet == 0 )); then
|
|
116
|
-
echo "[deploy-sql] OK"
|
|
117
|
-
fi
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
4
|
+
exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "check-deploy-sql-order.sh" "$@"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync, existsSync, lstatSync, readdirSync } from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { dirname, extname, normalize, resolve } from 'node:path';
|
|
4
5
|
|
|
5
6
|
const root = resolve(new URL('..', import.meta.url).pathname);
|
|
6
7
|
const failures = [];
|
|
@@ -52,6 +53,105 @@ function sourceFiles(directory) {
|
|
|
52
53
|
return files;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
function relativeStaticTypeScriptDependencyGraph(directory = 'src') {
|
|
57
|
+
let ts;
|
|
58
|
+
try {
|
|
59
|
+
ts = createRequire(import.meta.url)('typescript');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
failures.push(`TypeScript dependency is required for architecture import-cycle analysis: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
|
+
return new Map();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const files = sourceFiles(directory).sort();
|
|
66
|
+
const known = new Set(files);
|
|
67
|
+
const graph = new Map(files.map((path) => [path, new Set()]));
|
|
68
|
+
|
|
69
|
+
function resolveTypeScriptImport(fromPath, specifier) {
|
|
70
|
+
if (!specifier.startsWith('.')) return undefined;
|
|
71
|
+
const base = normalize(`${dirname(fromPath)}/${specifier}`).replaceAll('\\', '/');
|
|
72
|
+
const extension = extname(base);
|
|
73
|
+
const withoutRuntimeExtension = ['.js', '.mjs', '.cjs'].includes(extension)
|
|
74
|
+
? base.slice(0, -extension.length)
|
|
75
|
+
: base;
|
|
76
|
+
const candidates = extension === '.ts'
|
|
77
|
+
? [base]
|
|
78
|
+
: [withoutRuntimeExtension, `${withoutRuntimeExtension}.ts`, `${withoutRuntimeExtension}/index.ts`];
|
|
79
|
+
return candidates.find((candidate) => known.has(candidate));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const path of files) {
|
|
83
|
+
const sourceFile = ts.createSourceFile(path, text(path), ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
84
|
+
for (const statement of sourceFile.statements) {
|
|
85
|
+
let specifier;
|
|
86
|
+
if ((ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement))
|
|
87
|
+
&& statement.moduleSpecifier
|
|
88
|
+
&& ts.isStringLiteralLike(statement.moduleSpecifier)) {
|
|
89
|
+
specifier = statement.moduleSpecifier.text;
|
|
90
|
+
} else if (ts.isImportEqualsDeclaration(statement)
|
|
91
|
+
&& ts.isExternalModuleReference(statement.moduleReference)
|
|
92
|
+
&& statement.moduleReference.expression
|
|
93
|
+
&& ts.isStringLiteralLike(statement.moduleReference.expression)) {
|
|
94
|
+
specifier = statement.moduleReference.expression.text;
|
|
95
|
+
}
|
|
96
|
+
if (!specifier) continue;
|
|
97
|
+
const target = resolveTypeScriptImport(path, specifier);
|
|
98
|
+
if (target) graph.get(path).add(target);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return graph;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function stronglyConnectedComponents(graph) {
|
|
105
|
+
let index = 0;
|
|
106
|
+
const indices = new Map();
|
|
107
|
+
const lowLinks = new Map();
|
|
108
|
+
const stack = [];
|
|
109
|
+
const onStack = new Set();
|
|
110
|
+
const components = [];
|
|
111
|
+
|
|
112
|
+
function visit(node) {
|
|
113
|
+
indices.set(node, index);
|
|
114
|
+
lowLinks.set(node, index);
|
|
115
|
+
index += 1;
|
|
116
|
+
stack.push(node);
|
|
117
|
+
onStack.add(node);
|
|
118
|
+
|
|
119
|
+
for (const target of graph.get(node) ?? []) {
|
|
120
|
+
if (!indices.has(target)) {
|
|
121
|
+
visit(target);
|
|
122
|
+
lowLinks.set(node, Math.min(lowLinks.get(node), lowLinks.get(target)));
|
|
123
|
+
} else if (onStack.has(target)) {
|
|
124
|
+
lowLinks.set(node, Math.min(lowLinks.get(node), indices.get(target)));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (lowLinks.get(node) !== indices.get(node)) return;
|
|
129
|
+
const component = [];
|
|
130
|
+
while (stack.length) {
|
|
131
|
+
const member = stack.pop();
|
|
132
|
+
onStack.delete(member);
|
|
133
|
+
component.push(member);
|
|
134
|
+
if (member === node) break;
|
|
135
|
+
}
|
|
136
|
+
components.push(component.sort());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const node of [...graph.keys()].sort()) {
|
|
140
|
+
if (!indices.has(node)) visit(node);
|
|
141
|
+
}
|
|
142
|
+
return components;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function requireAcyclicProductionTypeScript() {
|
|
146
|
+
const graph = relativeStaticTypeScriptDependencyGraph('src');
|
|
147
|
+
const cyclic = stronglyConnectedComponents(graph).filter((component) =>
|
|
148
|
+
component.length > 1 || (component.length === 1 && graph.get(component[0])?.has(component[0])),
|
|
149
|
+
);
|
|
150
|
+
for (const component of cyclic) {
|
|
151
|
+
failures.push(`production TypeScript import cycle: ${component.join(' -> ')}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
55
155
|
const allowedArchitectureRootMarkdown = new Set(['CURRENT.md', 'EVOLUTION.md', 'history.md', 'index.md']);
|
|
56
156
|
const architectureRootMarkdown = readdirSync(resolve(root, 'docs/architecture'), { withFileTypes: true })
|
|
57
157
|
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
@@ -96,6 +196,26 @@ const required = [
|
|
|
96
196
|
'src/runtime/execution/thin-harness/index.ts',
|
|
97
197
|
'src/runtime/execution/thin-harness/execution-router.ts',
|
|
98
198
|
'src/runtime/control-plane/routing/route-policy.ts',
|
|
199
|
+
'src/runtime/control-plane/routing/workspace-admission.ts',
|
|
200
|
+
'src/runtime/control-plane/facade/requirement-authority.ts',
|
|
201
|
+
'src/runtime/control-plane/facade/repository-work-admission.ts',
|
|
202
|
+
'src/runtime/control-plane/execution/retained-work-resume.ts',
|
|
203
|
+
'src/runtime/control-plane/execution/work-handle-authority.ts',
|
|
204
|
+
'src/runtime/control-plane/execution/work-verification-context.ts',
|
|
205
|
+
'src/runtime/control-plane/execution/work-verification-service.ts',
|
|
206
|
+
'src/runtime/control-plane/execution/repository-work-attribution.ts',
|
|
207
|
+
'src/runtime/control-plane/execution/work-completion-authority.ts',
|
|
208
|
+
'src/runtime/control-plane/execution/work-evidence-policy.ts',
|
|
209
|
+
'src/runtime/control-plane/execution/work-execution-support.ts',
|
|
210
|
+
'src/runtime/control-plane/execution/work-finalization-service.ts',
|
|
211
|
+
'src/runtime/control-plane/execution/work-preparation-service.ts',
|
|
212
|
+
'src/runtime/control-plane/execution/work-operation-service.ts',
|
|
213
|
+
'src/runtime/control-plane/facade/work-state-machine.ts',
|
|
214
|
+
'src/runtime/evidence/process-check-execution.ts',
|
|
215
|
+
'src/runtime/context/semantic-navigation-contract.ts',
|
|
216
|
+
'src/cli/mcp/tool-contract.ts',
|
|
217
|
+
'src/cli/github/contracts.ts',
|
|
218
|
+
'src/runtime/gateway/mcp/runtime-tool-definitions.ts',
|
|
99
219
|
'docs/architecture/CURRENT.md',
|
|
100
220
|
'src/runtime/resources/leases/store.ts',
|
|
101
221
|
'src/runtime/evidence/event-ledger.ts',
|
|
@@ -124,19 +244,33 @@ const required = [
|
|
|
124
244
|
'src/cli/index.ts',
|
|
125
245
|
];
|
|
126
246
|
for (const path of required) text(path);
|
|
247
|
+
requireAcyclicProductionTypeScript();
|
|
248
|
+
for (const path of sourceFiles('src/runtime/control-plane')) {
|
|
249
|
+
forbid(path, /(?:from\s+['"]|import\s*\(\s*['"])(?:\.\.\/)+gateway\//, 'control-plane domain/application code must not depend on Gateway transport');
|
|
250
|
+
}
|
|
127
251
|
requireText('src/runtime/control-plane/routing/route-policy.ts', "export function decideRoute");
|
|
128
252
|
requireText('src/runtime/control-plane/routing/route-policy.ts', 'inputFingerprint');
|
|
129
253
|
requireText('src/runtime/control-plane/routing/route-policy.ts', 'policyVersion');
|
|
130
|
-
requireText('src/runtime/
|
|
131
|
-
requireText('src/runtime/
|
|
132
|
-
requireText('src/runtime/
|
|
133
|
-
requireText('src/runtime/
|
|
134
|
-
|
|
254
|
+
requireText('src/runtime/control-plane/execution/work-verification-service.ts', 'runPersistedCheckViaProcessRuntime({');
|
|
255
|
+
requireText('src/runtime/control-plane/execution/work-verification-service.ts', 'interactiveWaitMs: input.interactiveWaitMs ?? 0');
|
|
256
|
+
requireText('src/runtime/control-plane/execution/work-verification-service.ts', 'checkContentRevision');
|
|
257
|
+
requireText('src/runtime/control-plane/execution/work-verification-service.ts', 'observedGitHead');
|
|
258
|
+
requireText('src/runtime/gateway/mcp/runtime-tools.ts', 'executeWorkVerification({');
|
|
259
|
+
requireText('src/cli/local-bridge/facade-api.ts', 'executeWorkVerification({');
|
|
260
|
+
forbid(
|
|
261
|
+
'src/cli/local-bridge/facade-api.ts',
|
|
262
|
+
/runControllerCheck\s*\(/,
|
|
263
|
+
'Local Bridge Work verification must use the canonical persisted Work verification service',
|
|
264
|
+
);
|
|
265
|
+
forbid(
|
|
135
266
|
'src/runtime/gateway/mcp/runtime-tools.ts',
|
|
136
|
-
|
|
137
|
-
'
|
|
267
|
+
/function\s+classifyTerminalCheckEvidence\s*\(/,
|
|
268
|
+
'terminal Check evidence classification belongs to Process Runtime, not the Gateway transport',
|
|
269
|
+
);
|
|
270
|
+
forbid(
|
|
271
|
+
'src/runtime/control-plane/execution/work-verification-service.ts',
|
|
138
272
|
/runControllerCheck\s*\(/,
|
|
139
|
-
'route
|
|
273
|
+
'route Work verification through persisted Process Runtime instead of synchronous check execution',
|
|
140
274
|
);
|
|
141
275
|
for (const adapter of [
|
|
142
276
|
'src/cli/controller/work-mode.ts',
|
|
@@ -152,6 +286,52 @@ for (const path of sourceFiles('src')) {
|
|
|
152
286
|
forbid(path, /requirePlanForGoalWorkloop\s*:\s*true/, 'never restore mandatory Plan gating in production');
|
|
153
287
|
}
|
|
154
288
|
if (routeAuthorityCount !== 1) failures.push(`exactly one decideRoute authority is required; found ${routeAuthorityCount}`);
|
|
289
|
+
forbid(
|
|
290
|
+
'src/runtime/control-plane/facade/goal-workloop.ts',
|
|
291
|
+
/function\s+(?:evaluateWorkCompletionEvidence|evaluateWorkImplementationEvidence|verificationRecordAppliesToCurrentWorkspace)\s*\(/,
|
|
292
|
+
'keep Work evidence policy in the canonical work-evidence-policy module instead of reimplementing it in the facade',
|
|
293
|
+
);
|
|
294
|
+
requireText('src/runtime/control-plane/facade/goal-workloop.ts', "from '../execution/work-evidence-policy'");
|
|
295
|
+
for (const path of sourceFiles('src/runtime/control-plane')) {
|
|
296
|
+
if (path === 'src/runtime/control-plane/facade/work-contract-store.ts' || path === 'src/runtime/control-plane/execution/work-completion-authority.ts') continue;
|
|
297
|
+
forbid(
|
|
298
|
+
path,
|
|
299
|
+
/\brecordWorkCompletionReceipt\s*\(/,
|
|
300
|
+
'route Work completion through the canonical work-completion-authority instead of writing terminal receipts directly',
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
requireText('src/runtime/control-plane/execution/work-finalization-service.ts', 'completeWorkWithReceipt(');
|
|
304
|
+
forbid(
|
|
305
|
+
'src/runtime/plugins/browser-handoff-host.ts',
|
|
306
|
+
/browser\/sessions|saveBrowserSession|writeBrowserSession|sessionPath/,
|
|
307
|
+
'Browser handoff sidecars must return interaction results and never write BrowserSession authority directly',
|
|
308
|
+
);
|
|
309
|
+
forbid(
|
|
310
|
+
'src/runtime/plugins/browser-adapter.ts',
|
|
311
|
+
/BROWSER_POST_DISPATCH_REPLAY_SAFE_ACTIONS|POST_DISPATCH_REPLAY_SAFE_ACTIONS/,
|
|
312
|
+
'Browser replay safety must come from Browser Runtime transaction policy, not an adapter-local allowlist',
|
|
313
|
+
);
|
|
314
|
+
requireText('src/runtime/plugins/browser-runtime.ts', 'browserActionCanReplayAfterDispatch');
|
|
315
|
+
forbid(
|
|
316
|
+
'src/runtime/gateway/mcp/runtime-tools.ts',
|
|
317
|
+
/\b(?:createRequirement|resumeRetainedCancelledWorkContract)\s*\(/,
|
|
318
|
+
'keep Requirement admission and retained-cancelled Work lifecycle authority out of the MCP transport',
|
|
319
|
+
);
|
|
320
|
+
forbid(
|
|
321
|
+
'src/runtime/gateway/mcp/runtime-tools.ts',
|
|
322
|
+
/\b(?:updateWorkContract|writeWorkHandle)\s*\(/,
|
|
323
|
+
'keep WorkContract/WorkHandle persistence policy out of the MCP transport',
|
|
324
|
+
);
|
|
325
|
+
forbid(
|
|
326
|
+
'src/runtime/gateway/mcp/execution-tools.ts',
|
|
327
|
+
/\bcreateWorkContract\s*\(/,
|
|
328
|
+
'route compatibility work preparation through canonical Work admission authority',
|
|
329
|
+
);
|
|
330
|
+
forbid(
|
|
331
|
+
'src/cli/mcp/legacy-tool-service.ts',
|
|
332
|
+
/\bcreateWorkContract\s*\(/,
|
|
333
|
+
'keep the legacy MCP surface as translation over canonical Work admission authority',
|
|
334
|
+
);
|
|
155
335
|
requireMissing('src/runtime/control-plane/daemon-entry.ts');
|
|
156
336
|
requireMissing('scripts/smoke-runtime-control-plane.ts');
|
|
157
337
|
requireMissing('src/cli/controller/lifecycle.ts');
|
|
@@ -386,7 +566,14 @@ requireText('src/runtime/gateway/mcp/execution-tools.ts', 'isDurableWorkOperatio
|
|
|
386
566
|
requireText('src/runtime/gateway/mcp/execution-tools.ts', "'work_execute'");
|
|
387
567
|
requireText('src/runtime/gateway/mcp/execution-tools.ts', "'work_validate'");
|
|
388
568
|
requireText('src/runtime/gateway/mcp/execution-tools.ts', "'work_finalize'");
|
|
389
|
-
requireText('src/runtime/execution/workers/executor.ts', '
|
|
569
|
+
requireText('src/runtime/execution/workers/executor.ts', 'executeWork(runtimeContext');
|
|
570
|
+
requireText('src/runtime/execution/workers/executor.ts', 'validateWork(runtimeContext');
|
|
571
|
+
requireText('src/runtime/execution/workers/executor.ts', 'finalizeWork(runtimeContext');
|
|
572
|
+
forbid(
|
|
573
|
+
'src/runtime/execution/workers/executor.ts',
|
|
574
|
+
/gateway\/mcp\/execution-tools|callExecutionTool\s*\(/,
|
|
575
|
+
'Execution Worker must invoke control-plane Work application services directly, never MCP transport',
|
|
576
|
+
);
|
|
390
577
|
requireText('src/runtime/execution/workers/executor.ts', '__from_durable_worker');
|
|
391
578
|
requireText('src/runtime/gateway/mcp/runtime-tools.ts', 'managedProcessOperationDigest');
|
|
392
579
|
forbid(
|
|
@@ -582,14 +769,50 @@ forbidBetween(
|
|
|
582
769
|
requireText('src/runtime/control-plane/execution/session-store.ts', 'lastValidatedAt: now');
|
|
583
770
|
requireText('src/runtime/control-plane/execution/validation.ts', 'warnings.push');
|
|
584
771
|
requireText('src/runtime/control-plane/execution/work-handle-store.ts', "failed: ['validating', 'editing', 'committed', 'merged', 'cleaned', 'failed_terminal_cleanup']");
|
|
585
|
-
requireText('src/runtime/gateway/mcp/execution-tools.ts', '
|
|
586
|
-
requireText('src/runtime/gateway/mcp/execution-tools.ts', '
|
|
587
|
-
|
|
772
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', "from '../../control-plane/execution/work-finalization-service'");
|
|
773
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', "from '../../control-plane/execution/work-preparation-service'");
|
|
774
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', "from '../../control-plane/execution/work-operation-service'");
|
|
775
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', 'Compatibility exports: implementation authority lives in control-plane execution.');
|
|
776
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', 'resetFinalizationStagesForRequest,');
|
|
777
|
+
requireText('src/runtime/gateway/mcp/execution-tools.ts', 'selectDefaultWorkValidationChecks');
|
|
778
|
+
requireText('src/runtime/gateway/mcp/runtime-tools.ts', "callExecutionTool(ctx, 'work_finalize'");
|
|
779
|
+
forbid(
|
|
780
|
+
'src/runtime/gateway/mcp/runtime-tools.ts',
|
|
781
|
+
/repositoryGit(?:Commit|FinishWorkflow|MergeBranch|DeleteBranch|RebaseOnto)\s*\(/,
|
|
782
|
+
'rh_work facade finalization must delegate to the canonical Work finalization application service instead of performing Git delivery itself',
|
|
783
|
+
);
|
|
784
|
+
forbid(
|
|
588
785
|
'src/runtime/gateway/mcp/execution-tools.ts',
|
|
589
|
-
|
|
590
|
-
'
|
|
786
|
+
/function\s+finalizeWork\s*\(/,
|
|
787
|
+
'MCP execution transport must delegate Work finalization to the control-plane application service',
|
|
788
|
+
);
|
|
789
|
+
forbid(
|
|
790
|
+
'src/runtime/gateway/mcp/execution-tools.ts',
|
|
791
|
+
/function\s+(?:prepareWork|adoptExistingWorkHead)\s*\(/,
|
|
792
|
+
'MCP execution transport must delegate Work preparation/adoption to the control-plane application service',
|
|
793
|
+
);
|
|
794
|
+
forbid(
|
|
795
|
+
'src/runtime/gateway/mcp/execution-tools.ts',
|
|
796
|
+
/function\s+(?:executeWork|validateWork)\s*\(/,
|
|
797
|
+
'MCP execution transport must delegate Work execute/validate operations to the control-plane application service',
|
|
798
|
+
);
|
|
799
|
+
forbid(
|
|
800
|
+
'src/runtime/gateway/mcp/execution-tools.ts',
|
|
801
|
+
/(?:ensureManagedWorkspace|admitPreparedRepositoryWorkContract)\s*\(/,
|
|
802
|
+
'MCP execution transport must not own managed-workspace or WorkContract preparation admission',
|
|
803
|
+
);
|
|
804
|
+
requireText('src/runtime/control-plane/execution/work-preparation-service.ts', 'export function prepareWork(');
|
|
805
|
+
requireText('src/runtime/control-plane/execution/work-preparation-service.ts', 'function adoptExistingWorkHead(');
|
|
806
|
+
requireText('src/runtime/control-plane/execution/work-operation-service.ts', 'export async function executeWork(');
|
|
807
|
+
requireText('src/runtime/control-plane/execution/work-operation-service.ts', 'export async function validateWork(');
|
|
808
|
+
requireText('src/runtime/control-plane/execution/work-finalization-service.ts', 'resetFinalizationStagesForRequest');
|
|
809
|
+
requireText('src/runtime/control-plane/execution/work-finalization-service.ts', 'finalizationComplete');
|
|
810
|
+
forbidBetween(
|
|
811
|
+
'src/runtime/control-plane/execution/work-finalization-service.ts',
|
|
812
|
+
'export async function finalizeWork(',
|
|
813
|
+
'// WORK_FINALIZATION_SERVICE_END',
|
|
591
814
|
/withControllerLock\([\s\S]{0,900}?(?:repositoryGitCommit|repositoryGitFinishWorkflow|runCleanup|repositoryGitDeleteBranch)/,
|
|
592
|
-
'
|
|
815
|
+
'Work finalization must not hold the controller lock while committing, merging, deleting branches, or removing worktrees',
|
|
593
816
|
);
|
|
594
817
|
requireText('src/runtime/workflow/schedules/types.ts', "'repository-event'");
|
|
595
818
|
requireText('src/runtime/workflow/schedules/types.ts', "'dependency-checkpoint'");
|
|
@@ -614,6 +837,10 @@ for (const path of [
|
|
|
614
837
|
forbid(path, /\b(?:spawnSync|execSync|execFileSync)\s*\(/, 'the non-blocking Gateway/Controller hot-path rule');
|
|
615
838
|
}
|
|
616
839
|
|
|
840
|
+
requireText('scripts/run-governed-gate.ts', "label: 'source duplication'");
|
|
841
|
+
requireText('scripts/run-governed-gate.ts', "args: ['scripts/check-source-duplication.mjs']");
|
|
842
|
+
requireText('scripts/run-governed-gate.ts', "label: 'controller UI bundle'");
|
|
843
|
+
requireText('scripts/run-governed-gate.ts', "args: ['run', 'check:controller-ui']");
|
|
617
844
|
requireText('docs/architecture/CURRENT.md', '## State ownership');
|
|
618
845
|
requireText('docs/architecture/CURRENT.md', '## Runtime and MCP boundary');
|
|
619
846
|
requireText('docs/architecture/CURRENT.md', '## Testing and verification');
|
|
@@ -1,193 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Validates that version numbers are consistent across:
|
|
6
|
-
* - package.json
|
|
7
|
-
* - assets/skill-version.json
|
|
8
|
-
*
|
|
9
|
-
* Also checks if a generated project needs migration.
|
|
10
|
-
*/
|
|
2
|
+
export * from "../assets/templates/helpers/check-skill-version";
|
|
3
|
+
import { runTrackedForgeHelper } from "./lib/run-forge-helper";
|
|
11
4
|
|
|
12
|
-
import
|
|
13
|
-
import { join, dirname } from "path";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
15
|
-
import { resolveAgenticDevRoot } from "./workflow-contract.ts";
|
|
16
|
-
|
|
17
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
-
const __dirname = dirname(__filename);
|
|
19
|
-
const REPO_ROOT = __dirname.endsWith("/.ai/harness/scripts")
|
|
20
|
-
? join(__dirname, "../../..")
|
|
21
|
-
: __dirname.endsWith("/assets/templates/helpers")
|
|
22
|
-
? join(__dirname, "../../..")
|
|
23
|
-
: join(__dirname, "..");
|
|
24
|
-
|
|
25
|
-
export interface ConsistencyResult {
|
|
26
|
-
consistent: boolean;
|
|
27
|
-
packageJsonVersion: string | null;
|
|
28
|
-
skillVersionJsonVersion: string;
|
|
29
|
-
templateVersionJsonVersion: string;
|
|
30
|
-
skillVersionSource: string;
|
|
31
|
-
warnings: string[];
|
|
32
|
-
errors: string[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface MigrationCheckResult {
|
|
36
|
-
needsMigration: boolean;
|
|
37
|
-
currentSkillVersion: string;
|
|
38
|
-
projectSkillVersion: string | null;
|
|
39
|
-
projectTemplatVersion: string | null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Check version consistency across the version sources this repo owns.
|
|
44
|
-
*/
|
|
45
|
-
export function checkConsistency(repoRoot: string = REPO_ROOT): ConsistencyResult {
|
|
46
|
-
const errors: string[] = [];
|
|
47
|
-
const warnings: string[] = [];
|
|
48
|
-
|
|
49
|
-
// Read package.json
|
|
50
|
-
const pkgPath = join(repoRoot, "package.json");
|
|
51
|
-
if (!existsSync(pkgPath)) {
|
|
52
|
-
throw new Error(`package.json not found at ${pkgPath}`);
|
|
53
|
-
}
|
|
54
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
55
|
-
const packageJsonVersion =
|
|
56
|
-
typeof pkg.version === "string" && pkg.version.length > 0
|
|
57
|
-
? (pkg.version as string)
|
|
58
|
-
: null;
|
|
59
|
-
|
|
60
|
-
// Read the local source manifest when this script runs inside forge;
|
|
61
|
-
// generated projects resolve the upstream skill root instead.
|
|
62
|
-
const localSvPath = join(repoRoot, "assets", "skill-version.json");
|
|
63
|
-
const svPath = existsSync(localSvPath)
|
|
64
|
-
? localSvPath
|
|
65
|
-
: join(resolveAgenticDevRoot(repoRoot), "assets", "skill-version.json");
|
|
66
|
-
if (!existsSync(svPath)) {
|
|
67
|
-
throw new Error(`skill-version.json not found at ${svPath}`);
|
|
68
|
-
}
|
|
69
|
-
const sv = JSON.parse(readFileSync(svPath, "utf-8"));
|
|
70
|
-
const skillVersionJsonVersion = sv.version as string;
|
|
71
|
-
const templateVersionJsonVersion = sv.templateVersion as string;
|
|
72
|
-
const usingLocalSkillManifest = svPath === localSvPath;
|
|
73
|
-
|
|
74
|
-
const packageCoreVersion = packageJsonVersion?.split("-", 1)[0] ?? null;
|
|
75
|
-
const isForgePackage =
|
|
76
|
-
pkg.name === "forge" ||
|
|
77
|
-
pkg.name === "@moretea-labs/forge-controller" ||
|
|
78
|
-
pkg.name === "@moretea-labs/forge";
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
usingLocalSkillManifest &&
|
|
82
|
-
isForgePackage &&
|
|
83
|
-
packageCoreVersion !== null &&
|
|
84
|
-
packageCoreVersion !== skillVersionJsonVersion
|
|
85
|
-
) {
|
|
86
|
-
errors.push(
|
|
87
|
-
`package.json core version (${packageCoreVersion}) must match assets/skill-version.json version (${skillVersionJsonVersion})`
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (usingLocalSkillManifest && templateVersionJsonVersion !== skillVersionJsonVersion) {
|
|
92
|
-
errors.push(
|
|
93
|
-
`assets/skill-version.json templateVersion (${templateVersionJsonVersion}) must match version (${skillVersionJsonVersion})`
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!usingLocalSkillManifest && packageJsonVersion !== null) {
|
|
98
|
-
warnings.push(
|
|
99
|
-
`package.json.version (${packageJsonVersion}) belongs to the target repo; workflow stamp uses upstream forge skill-version.json`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
consistent: errors.length === 0,
|
|
105
|
-
packageJsonVersion,
|
|
106
|
-
skillVersionJsonVersion,
|
|
107
|
-
templateVersionJsonVersion,
|
|
108
|
-
skillVersionSource: svPath,
|
|
109
|
-
warnings,
|
|
110
|
-
errors,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Check if a generated project needs migration.
|
|
116
|
-
*/
|
|
117
|
-
export function checkProjectNeedsMigration(
|
|
118
|
-
projectPath: string,
|
|
119
|
-
repoRoot: string = REPO_ROOT
|
|
120
|
-
): MigrationCheckResult {
|
|
121
|
-
const localSvPath = join(repoRoot, "assets", "skill-version.json");
|
|
122
|
-
const svPath = existsSync(localSvPath)
|
|
123
|
-
? localSvPath
|
|
124
|
-
: join(resolveAgenticDevRoot(repoRoot), "assets", "skill-version.json");
|
|
125
|
-
const sv = JSON.parse(readFileSync(svPath, "utf-8"));
|
|
126
|
-
const currentSkillVersion = sv.version as string;
|
|
127
|
-
|
|
128
|
-
const stampPath = join(projectPath, ".claude", ".skill-version");
|
|
129
|
-
if (!existsSync(stampPath)) {
|
|
130
|
-
return {
|
|
131
|
-
needsMigration: true,
|
|
132
|
-
currentSkillVersion,
|
|
133
|
-
projectSkillVersion: null,
|
|
134
|
-
projectTemplatVersion: null,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const stampContent = readFileSync(stampPath, "utf-8");
|
|
139
|
-
const skillVersionMatch = stampContent.match(/^skill_version=(.+)$/m);
|
|
140
|
-
const templateVersionMatch = stampContent.match(/^template_version=(.+)$/m);
|
|
141
|
-
|
|
142
|
-
const projectSkillVersion = skillVersionMatch?.[1] ?? null;
|
|
143
|
-
const projectTemplatVersion = templateVersionMatch?.[1] ?? null;
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
needsMigration: projectSkillVersion !== currentSkillVersion,
|
|
147
|
-
currentSkillVersion,
|
|
148
|
-
projectSkillVersion,
|
|
149
|
-
projectTemplatVersion,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// CLI entry point
|
|
154
|
-
if (import.meta.main) {
|
|
155
|
-
const args = process.argv.slice(2);
|
|
156
|
-
const projectIdx = args.indexOf("--project");
|
|
157
|
-
const projectPath = projectIdx !== -1 ? args[projectIdx + 1] : null;
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
const result = checkConsistency();
|
|
161
|
-
|
|
162
|
-
if (result.consistent) {
|
|
163
|
-
console.log(
|
|
164
|
-
`Workflow version check passed: forge=${result.skillVersionJsonVersion}, template=${result.templateVersionJsonVersion}`
|
|
165
|
-
);
|
|
166
|
-
console.log(`Workflow version source: ${result.skillVersionSource}`);
|
|
167
|
-
for (const warning of result.warnings) {
|
|
168
|
-
console.log(`Warning: ${warning}`);
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
console.error("Version consistency check FAILED:");
|
|
172
|
-
for (const error of result.errors) {
|
|
173
|
-
console.error(` - ${error}`);
|
|
174
|
-
}
|
|
175
|
-
process.exit(1);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (projectPath) {
|
|
179
|
-
const migration = checkProjectNeedsMigration(projectPath);
|
|
180
|
-
if (migration.needsMigration) {
|
|
181
|
-
console.log(
|
|
182
|
-
`Project at ${projectPath} needs migration: ` +
|
|
183
|
-
`${migration.projectSkillVersion ?? "(no stamp)"} → ${migration.currentSkillVersion}`
|
|
184
|
-
);
|
|
185
|
-
} else {
|
|
186
|
-
console.log(`Project at ${projectPath} is up to date (${migration.currentSkillVersion})`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
191
|
-
process.exit(1);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
5
|
+
if (import.meta.main) runTrackedForgeHelper("check-skill-version.ts");
|