repo-harness 0.8.3 → 0.8.5
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 +17 -14
- package/CLAUDE.md +17 -14
- package/README.es.md +3 -3
- package/README.fr.md +3 -3
- package/README.ja.md +3 -3
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/assets/reference-configs/global-working-rules.md +8 -2
- package/assets/skill-version.json +10 -2
- package/assets/templates/helpers/sprint-backlog.sh +16 -1
- package/assets/templates/helpers/workstream-sync.sh +45 -6
- package/package.json +1 -1
- package/scripts/AGENTS.md +68 -0
- package/scripts/CLAUDE.md +68 -0
- package/scripts/check-tarball-install-smoke.sh +27 -0
- package/scripts/inspect-project-state.ts +12 -0
- package/scripts/lib/project-init-lib.sh +29 -4
- package/scripts/sprint-backlog.sh +16 -1
- package/scripts/workstream-sync.sh +45 -6
- package/src/cli/commands/global-runtime.ts +81 -0
- package/src/cli/commands/init.ts +50 -12
- package/src/cli/hook/minimal-change-context.ts +1 -0
- package/assets/templates/AGENTS.md +0 -13
- package/assets/templates/CLAUDE.md +0 -13
package/AGENTS.md
CHANGED
|
@@ -63,35 +63,38 @@ bash scripts/migrate-project-template.sh --repo . --dry-run
|
|
|
63
63
|
<!-- BEGIN ARCHITECTURE CONTRACT -->
|
|
64
64
|
## Architecture Contract
|
|
65
65
|
|
|
66
|
-
- Functional block:
|
|
67
|
-
- Capability ID: `
|
|
68
|
-
- Matched prefix:
|
|
69
|
-
- Architecture domain: `
|
|
70
|
-
- Architecture capability: `
|
|
71
|
-
- Architecture module: `docs/architecture/modules/
|
|
72
|
-
- Last architecture event: 2026-
|
|
73
|
-
- Last changed path:
|
|
66
|
+
- Functional block: `scripts/inspect-project-state.ts`
|
|
67
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
68
|
+
- Matched prefix: `scripts/inspect-project-state.ts`
|
|
69
|
+
- Architecture domain: `workflow-engine`
|
|
70
|
+
- Architecture capability: `inspection-migration`
|
|
71
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
72
|
+
- Last architecture event: 2026-07-03T15:44:54+0800
|
|
73
|
+
- Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
|
|
74
74
|
- Severity: high
|
|
75
|
-
- Change type:
|
|
75
|
+
- Change type: architecture-closeout
|
|
76
76
|
- Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
|
|
77
|
-
- Entrypoints:
|
|
77
|
+
- Entrypoints: `scripts/inspect-project-state.ts`
|
|
78
78
|
- Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
|
|
79
79
|
- Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
|
|
80
|
-
- Runtime path:
|
|
80
|
+
- Runtime path: `scripts/inspect-project-state.ts`
|
|
81
81
|
- LSP/tooling profile: `typescript-lsp`
|
|
82
82
|
- Verification: Use root required checks plus local commands recorded in this capability contract.
|
|
83
83
|
- Latest snapshot: `(none yet)`
|
|
84
|
-
- Semantic diagram source: `docs/architecture/modules/
|
|
84
|
+
- Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
85
85
|
- Latest human diagram: `(none yet)`
|
|
86
86
|
- Pending architecture request: `(none)`
|
|
87
87
|
|
|
88
88
|
## Active Workstreams
|
|
89
89
|
|
|
90
|
-
-
|
|
90
|
+
- `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
|
|
91
|
+
- status: active
|
|
92
|
+
- current_slice: completed-20260703-architecture-closeout
|
|
93
|
+
- source_plan: (none)
|
|
91
94
|
|
|
92
95
|
## Current Session Projection
|
|
93
96
|
|
|
94
|
-
- Durable progress lives under `tasks/workstreams/
|
|
97
|
+
- Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
|
|
95
98
|
- `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
|
|
96
99
|
- `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
|
|
97
100
|
<!-- END ARCHITECTURE CONTRACT -->
|
package/CLAUDE.md
CHANGED
|
@@ -63,35 +63,38 @@ bash scripts/migrate-project-template.sh --repo . --dry-run
|
|
|
63
63
|
<!-- BEGIN ARCHITECTURE CONTRACT -->
|
|
64
64
|
## Architecture Contract
|
|
65
65
|
|
|
66
|
-
- Functional block:
|
|
67
|
-
- Capability ID: `
|
|
68
|
-
- Matched prefix:
|
|
69
|
-
- Architecture domain: `
|
|
70
|
-
- Architecture capability: `
|
|
71
|
-
- Architecture module: `docs/architecture/modules/
|
|
72
|
-
- Last architecture event: 2026-
|
|
73
|
-
- Last changed path:
|
|
66
|
+
- Functional block: `scripts/inspect-project-state.ts`
|
|
67
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
68
|
+
- Matched prefix: `scripts/inspect-project-state.ts`
|
|
69
|
+
- Architecture domain: `workflow-engine`
|
|
70
|
+
- Architecture capability: `inspection-migration`
|
|
71
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
72
|
+
- Last architecture event: 2026-07-03T15:44:54+0800
|
|
73
|
+
- Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
|
|
74
74
|
- Severity: high
|
|
75
|
-
- Change type:
|
|
75
|
+
- Change type: architecture-closeout
|
|
76
76
|
- Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
|
|
77
|
-
- Entrypoints:
|
|
77
|
+
- Entrypoints: `scripts/inspect-project-state.ts`
|
|
78
78
|
- Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
|
|
79
79
|
- Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
|
|
80
|
-
- Runtime path:
|
|
80
|
+
- Runtime path: `scripts/inspect-project-state.ts`
|
|
81
81
|
- LSP/tooling profile: `typescript-lsp`
|
|
82
82
|
- Verification: Use root required checks plus local commands recorded in this capability contract.
|
|
83
83
|
- Latest snapshot: `(none yet)`
|
|
84
|
-
- Semantic diagram source: `docs/architecture/modules/
|
|
84
|
+
- Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
85
85
|
- Latest human diagram: `(none yet)`
|
|
86
86
|
- Pending architecture request: `(none)`
|
|
87
87
|
|
|
88
88
|
## Active Workstreams
|
|
89
89
|
|
|
90
|
-
-
|
|
90
|
+
- `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
|
|
91
|
+
- status: active
|
|
92
|
+
- current_slice: completed-20260703-architecture-closeout
|
|
93
|
+
- source_plan: (none)
|
|
91
94
|
|
|
92
95
|
## Current Session Projection
|
|
93
96
|
|
|
94
|
-
- Durable progress lives under `tasks/workstreams/
|
|
97
|
+
- Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
|
|
95
98
|
- `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
|
|
96
99
|
- `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
|
|
97
100
|
<!-- END ARCHITECTURE CONTRACT -->
|
package/README.es.md
CHANGED
|
@@ -85,7 +85,7 @@ artifacts.
|
|
|
85
85
|
## Novedades
|
|
86
86
|
|
|
87
87
|
Las notas de versión viven en [`docs/CHANGELOG.md`](docs/CHANGELOG.md). La línea
|
|
88
|
-
actual es `0.8.
|
|
88
|
+
actual es `0.8.5`.
|
|
89
89
|
|
|
90
90
|
## Cómo funciona
|
|
91
91
|
|
|
@@ -419,8 +419,8 @@ Guards habituales:
|
|
|
419
419
|
|
|
420
420
|
## Release actual
|
|
421
421
|
|
|
422
|
-
- npm package: `repo-harness@0.8.
|
|
423
|
-
- Generated workflow stamp: `repo-harness@0.8.
|
|
422
|
+
- npm package: `repo-harness@0.8.5`
|
|
423
|
+
- Generated workflow stamp: `repo-harness@0.8.5+template@0.8.5`
|
|
424
424
|
- GitHub repository: `Ancienttwo/repo-harness`
|
|
425
425
|
- Release history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
|
|
426
426
|
|
package/README.fr.md
CHANGED
|
@@ -85,7 +85,7 @@ l'emportent.
|
|
|
85
85
|
## Nouveautés
|
|
86
86
|
|
|
87
87
|
Les notes de version vivent dans [`docs/CHANGELOG.md`](docs/CHANGELOG.md). La
|
|
88
|
-
ligne actuelle est `0.8.
|
|
88
|
+
ligne actuelle est `0.8.5`.
|
|
89
89
|
|
|
90
90
|
## Comment ça marche
|
|
91
91
|
|
|
@@ -424,8 +424,8 @@ Guards courants :
|
|
|
424
424
|
|
|
425
425
|
## Release actuelle
|
|
426
426
|
|
|
427
|
-
- npm package : `repo-harness@0.8.
|
|
428
|
-
- Generated workflow stamp : `repo-harness@0.8.
|
|
427
|
+
- npm package : `repo-harness@0.8.5`
|
|
428
|
+
- Generated workflow stamp : `repo-harness@0.8.5+template@0.8.5`
|
|
429
429
|
- GitHub repository : `Ancienttwo/repo-harness`
|
|
430
430
|
- Release history : [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
|
|
431
431
|
|
package/README.ja.md
CHANGED
|
@@ -75,7 +75,7 @@ review、checks、handoff と食い違う場合は、source artifacts を優先
|
|
|
75
75
|
## What's New
|
|
76
76
|
|
|
77
77
|
リリースノートは [`docs/CHANGELOG.md`](docs/CHANGELOG.md) にあります。現在の
|
|
78
|
-
ラインは `0.8.
|
|
78
|
+
ラインは `0.8.5` です。
|
|
79
79
|
|
|
80
80
|
## 仕組み
|
|
81
81
|
|
|
@@ -398,8 +398,8 @@ hook がブロックしたときは、まず terminal の構造化された出
|
|
|
398
398
|
|
|
399
399
|
## 現在の Release
|
|
400
400
|
|
|
401
|
-
- npm package:`repo-harness@0.8.
|
|
402
|
-
- Generated workflow stamp:`repo-harness@0.8.
|
|
401
|
+
- npm package:`repo-harness@0.8.5`
|
|
402
|
+
- Generated workflow stamp:`repo-harness@0.8.5+template@0.8.5`
|
|
403
403
|
- GitHub repository:`Ancienttwo/repo-harness`
|
|
404
404
|
- Release history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
|
|
405
405
|
|
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ active plan, contract, review, checks, or handoff, the source artifacts win.
|
|
|
79
79
|
## What's New
|
|
80
80
|
|
|
81
81
|
Release notes live in [`docs/CHANGELOG.md`](docs/CHANGELOG.md). The current line
|
|
82
|
-
is `0.8.
|
|
82
|
+
is `0.8.5`.
|
|
83
83
|
|
|
84
84
|
## How It Works
|
|
85
85
|
|
|
@@ -599,8 +599,8 @@ Most common guards:
|
|
|
599
599
|
|
|
600
600
|
## Current Release
|
|
601
601
|
|
|
602
|
-
- npm package: `repo-harness@0.8.
|
|
603
|
-
- Generated workflow stamp: `repo-harness@0.8.
|
|
602
|
+
- npm package: `repo-harness@0.8.5`
|
|
603
|
+
- Generated workflow stamp: `repo-harness@0.8.5+template@0.8.5`
|
|
604
604
|
- GitHub repository: `Ancienttwo/repo-harness`
|
|
605
605
|
- Release history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
|
|
606
606
|
|
package/README.zh-CN.md
CHANGED
|
@@ -69,7 +69,7 @@ review、checks 或 handoff 冲突,以 source artifacts 为准。
|
|
|
69
69
|
|
|
70
70
|
## What's New
|
|
71
71
|
|
|
72
|
-
Release notes 见 [`docs/CHANGELOG.md`](docs/CHANGELOG.md),当前版本线是 `0.8.
|
|
72
|
+
Release notes 见 [`docs/CHANGELOG.md`](docs/CHANGELOG.md),当前版本线是 `0.8.5`。
|
|
73
73
|
|
|
74
74
|
## 工作原理
|
|
75
75
|
|
|
@@ -445,8 +445,8 @@ hook block 工作时,先看 terminal 里的结构化输出。核心字段是
|
|
|
445
445
|
|
|
446
446
|
## 当前 Release
|
|
447
447
|
|
|
448
|
-
- npm package:`repo-harness@0.8.
|
|
449
|
-
- Generated workflow stamp:`repo-harness@0.8.
|
|
448
|
+
- npm package:`repo-harness@0.8.5`
|
|
449
|
+
- Generated workflow stamp:`repo-harness@0.8.5+template@0.8.5`
|
|
450
450
|
- GitHub repository:`Ancienttwo/repo-harness`
|
|
451
451
|
- Release history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
|
|
452
452
|
|
|
@@ -29,6 +29,14 @@ Before changing behavior, infer why the current shape exists: compatibility boun
|
|
|
29
29
|
|
|
30
30
|
Do not introduce a new abstraction unless it removes real complexity, matches an existing local pattern, or protects a cross-module invariant.
|
|
31
31
|
|
|
32
|
+
## No Compatibility Fallbacks in Product Code
|
|
33
|
+
|
|
34
|
+
Do not add fallback, compatibility, heuristic, defensive, or "best effort" code paths unless the current task or a human-approved migration/release contract explicitly demands that path. Prefer fail-closed behavior with a clear error over silently inventing output.
|
|
35
|
+
|
|
36
|
+
When the source of truth is an LLM/provider/external authority/user input contract, do not re-derive the same semantic data with local deterministic rules, regexes, multilingual pattern lists, shadow parsers, or compatibility shims. If the authoritative value is missing, malformed, unauthenticated, or unavailable, surface that failure and stop; do not synthesize a replacement to make the flow continue.
|
|
37
|
+
|
|
38
|
+
Product-logic compatibility is harmful by default. Do not preserve old product semantics, accept multiple semantic shapes, infer missing fields, or translate one domain meaning into another unless the user explicitly requested that compatibility in the current task or a human-approved migration/release contract names it. Compatibility for old wire formats, legacy clients, or migration windows is allowed only when it is explicit, covered by tests, and bounded by a removal or ownership path. Validation, security checks, data-safety checks, and error handling remain required, but they must reject or report invalid states instead of changing semantics.
|
|
39
|
+
|
|
32
40
|
## Reporting
|
|
33
41
|
|
|
34
42
|
For small tasks, keep P1/P2/P3 internal and report only the conclusion.
|
|
@@ -43,12 +51,10 @@ Reports must be concise and grounded in files, commands, runtime behavior, obser
|
|
|
43
51
|
|
|
44
52
|
## Completion Summary Rule
|
|
45
53
|
|
|
46
|
-
For non-trivial completed tasks, include a short `下一刀` section at the end of the final delivery report unless there is genuinely no meaningful follow-up.
|
|
47
54
|
For non-trivial completed tasks, include a short `下一刀` section only when verified state shows a concrete next bottleneck, unresolved risk, failing check, deployment gap, review gap, or active-plan item that materially affects the user's stated goal.
|
|
48
55
|
|
|
49
56
|
Do not manufacture follow-up work just to keep slicing. If the task is reasonably complete and the remaining work would be speculative, low-value polish, or over-engineering, omit `下一刀` and stop at the completion report.
|
|
50
57
|
|
|
51
|
-
The recommendation is not a question. It must be one concrete, bounded next slice derived from verified state: active plan, todo, handoff, failing checks, review gaps, deployment state, unresolved risk, or observed system behavior.
|
|
52
58
|
When included, the recommendation is not a question. It must be one concrete, bounded next slice derived from verified state: active plan, todo, handoff, failing checks, review gaps, deployment state, unresolved risk, or observed system behavior.
|
|
53
59
|
|
|
54
60
|
Format:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.8.
|
|
3
|
-
"templateVersion": "0.8.
|
|
2
|
+
"version": "0.8.5",
|
|
3
|
+
"templateVersion": "0.8.5",
|
|
4
4
|
"skillName": "repo-harness",
|
|
5
5
|
"contractId": "tasks-first-harness-v1",
|
|
6
6
|
"compatibility": {
|
|
@@ -179,6 +179,14 @@
|
|
|
179
179
|
{
|
|
180
180
|
"version": "0.8.3",
|
|
181
181
|
"description": "Keeps adopt and migration helper runtime package-only, removes local compatibility wrapper generation, and refreshes dependency lines to latest"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"version": "0.8.4",
|
|
185
|
+
"description": "Lets package-dispatched workstream sync resolve bundled helper siblings when downstream repos do not vendor legacy scripts"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"version": "0.8.5",
|
|
189
|
+
"description": "Repairs workspace-source Bun global installs that hit DependencyLoop by reinstalling from a packed tarball and adds packaged sprint-backlog target-root smoke coverage"
|
|
182
190
|
}
|
|
183
191
|
],
|
|
184
192
|
"generatedProjectStamp": {
|
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
if
|
|
5
|
+
if [[ -n "${REPO_HARNESS_TARGET_REPO_ROOT:-}" ]]; then
|
|
6
|
+
if [[ "$REPO_HARNESS_TARGET_REPO_ROOT" != /* ]]; then
|
|
7
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must be an absolute path" >&2
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
if ! REPO_ROOT="$(cd "$REPO_HARNESS_TARGET_REPO_ROOT" 2>/dev/null && pwd -P)"; then
|
|
11
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT does not resolve to a directory" >&2
|
|
12
|
+
exit 2
|
|
13
|
+
fi
|
|
14
|
+
CURRENT_ROOT="$(pwd -P)"
|
|
15
|
+
if [[ "$REPO_ROOT" != "$CURRENT_ROOT" ]]; then
|
|
16
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must match the current helper cwd" >&2
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
cd "$REPO_ROOT"
|
|
20
|
+
elif REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
|
|
6
21
|
cd "$REPO_ROOT"
|
|
7
22
|
else
|
|
8
23
|
cd "$SCRIPT_DIR/.."
|
|
@@ -83,6 +83,47 @@ validate_block() {
|
|
|
83
83
|
[[ -e "$block" ]]
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
helper_sibling() {
|
|
87
|
+
local helper_name="$1"
|
|
88
|
+
local helper_dir=""
|
|
89
|
+
if [[ -n "${REPO_HARNESS_HELPER_SOURCE_PATH:-}" ]]; then
|
|
90
|
+
helper_dir="$(dirname "$REPO_HARNESS_HELPER_SOURCE_PATH")"
|
|
91
|
+
fi
|
|
92
|
+
if [[ -n "$helper_dir" && -f "$helper_dir/$helper_name" ]]; then
|
|
93
|
+
printf '%s\n' "$helper_dir/$helper_name"
|
|
94
|
+
return 0
|
|
95
|
+
fi
|
|
96
|
+
return 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
capability_resolver() {
|
|
100
|
+
local sibling=""
|
|
101
|
+
if command -v bun >/dev/null 2>&1 && [[ -f "scripts/capability-resolver.ts" ]]; then
|
|
102
|
+
bun scripts/capability-resolver.ts "$@"
|
|
103
|
+
return $?
|
|
104
|
+
fi
|
|
105
|
+
sibling="$(helper_sibling capability-resolver.ts || true)"
|
|
106
|
+
if command -v bun >/dev/null 2>&1 && [[ -n "$sibling" ]]; then
|
|
107
|
+
bun "$sibling" "$@"
|
|
108
|
+
return $?
|
|
109
|
+
fi
|
|
110
|
+
return 127
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
context_contract_sync() {
|
|
114
|
+
local sibling=""
|
|
115
|
+
if [[ -x "scripts/context-contract-sync.sh" ]]; then
|
|
116
|
+
bash "scripts/context-contract-sync.sh" "$@"
|
|
117
|
+
return $?
|
|
118
|
+
fi
|
|
119
|
+
sibling="$(helper_sibling context-contract-sync.sh || true)"
|
|
120
|
+
if [[ -n "$sibling" ]]; then
|
|
121
|
+
bash "$sibling" "$@"
|
|
122
|
+
return $?
|
|
123
|
+
fi
|
|
124
|
+
return 127
|
|
125
|
+
}
|
|
126
|
+
|
|
86
127
|
while [[ $# -gt 0 ]]; do
|
|
87
128
|
case "$1" in
|
|
88
129
|
--block)
|
|
@@ -139,12 +180,12 @@ if ! validate_block "$functional_block"; then
|
|
|
139
180
|
exit 2
|
|
140
181
|
fi
|
|
141
182
|
|
|
142
|
-
if
|
|
143
|
-
echo "workstream-sync:
|
|
183
|
+
if ! command -v bun >/dev/null 2>&1 || ! capability_resolver list --format json >/dev/null 2>&1; then
|
|
184
|
+
echo "workstream-sync: capability-resolver.ts and bun are required" >&2
|
|
144
185
|
exit 2
|
|
145
186
|
fi
|
|
146
187
|
|
|
147
|
-
if ! resolver_json="$(
|
|
188
|
+
if ! resolver_json="$(capability_resolver match --path "$functional_block" --format json 2>&1)"; then
|
|
148
189
|
echo "$resolver_json" >&2
|
|
149
190
|
exit 1
|
|
150
191
|
fi
|
|
@@ -257,8 +298,6 @@ fi
|
|
|
257
298
|
event_json="{\"ts\":\"$(json_escape "$iso_timestamp")\",\"file_path\":\"$(json_escape "$workstream_file")\",\"severity\":\"medium\",\"functional_block\":\"$(json_escape "$functional_block")\",\"capability_id\":\"$(json_escape "$capability_id")\",\"matched_prefix\":\"$(json_escape "$matched_prefix")\",\"architecture_domain\":\"$(json_escape "$architecture_domain")\",\"architecture_capability\":\"$(json_escape "$architecture_capability")\",\"architecture_module\":\"$(json_escape "$architecture_module")\",\"workstream_dir\":\"$(json_escape "$workstream_dir")\",\"contract_agents\":\"$(json_escape "$contract_agents")\",\"contract_claude\":\"$(json_escape "$contract_claude")\",\"active_workstream\":\"$(json_escape "$workstream_file")\",\"change_type\":\"workstream-sync\",\"spawn_recommended\":false,\"contract_sync_required\":true,\"request_file\":\"$(json_escape "$request_file")\"}"
|
|
258
299
|
printf '%s\n' "$event_json" >> "$event_file"
|
|
259
300
|
|
|
260
|
-
|
|
261
|
-
bash "$helper_dir/context-contract-sync.sh" sync-event --json "$event_json"
|
|
262
|
-
fi
|
|
301
|
+
context_contract_sync sync-event --json "$event_json" >/dev/null 2>&1 || true
|
|
263
302
|
|
|
264
303
|
echo "[WorkstreamSync] Ensured $workstream_file for $capability_id."
|
package/package.json
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Functional Block Agent Context
|
|
2
|
+
|
|
3
|
+
Keep this file focused on the local contract for this primary functional block.
|
|
4
|
+
|
|
5
|
+
<!-- BEGIN CAPABILITY CONTEXT -->
|
|
6
|
+
## Capability Context
|
|
7
|
+
|
|
8
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
9
|
+
- Domain: `workflow-engine`
|
|
10
|
+
- Name: `inspection-migration`
|
|
11
|
+
- Primary prefix: `scripts/inspect-project-state.ts`
|
|
12
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
13
|
+
- Workstream: `tasks/workstreams/workflow-engine/inspection-migration`
|
|
14
|
+
|
|
15
|
+
## Positioning
|
|
16
|
+
|
|
17
|
+
Owns the workflow-engine-inspection-migration capability boundary declared in .ai/context/capabilities.json.
|
|
18
|
+
|
|
19
|
+
## Source Map
|
|
20
|
+
|
|
21
|
+
- Primary prefix: `scripts/inspect-project-state.ts` (entrypoint)
|
|
22
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md` (design-source)
|
|
23
|
+
- Workstream: `tasks/workstreams/workflow-engine/inspection-migration` (durable-progress)
|
|
24
|
+
|
|
25
|
+
## Refresh Hints
|
|
26
|
+
|
|
27
|
+
- `bun test tests/migration-script.test.ts tests/create-project-dirs.runtime.test.ts tests/workflow-contract.test.ts`
|
|
28
|
+
- `bash scripts/migrate-project-template.sh --repo . --dry-run`
|
|
29
|
+
<!-- END CAPABILITY CONTEXT -->
|
|
30
|
+
|
|
31
|
+
<!-- BEGIN ARCHITECTURE CONTRACT -->
|
|
32
|
+
## Architecture Contract
|
|
33
|
+
|
|
34
|
+
- Functional block: `scripts/inspect-project-state.ts`
|
|
35
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
36
|
+
- Matched prefix: `scripts/inspect-project-state.ts`
|
|
37
|
+
- Architecture domain: `workflow-engine`
|
|
38
|
+
- Architecture capability: `inspection-migration`
|
|
39
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
40
|
+
- Last architecture event: 2026-07-03T15:45:36+0800
|
|
41
|
+
- Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
|
|
42
|
+
- Severity: high
|
|
43
|
+
- Change type: architecture-closeout
|
|
44
|
+
- Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
|
|
45
|
+
- Entrypoints: `scripts/inspect-project-state.ts`
|
|
46
|
+
- Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
|
|
47
|
+
- Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
|
|
48
|
+
- Runtime path: `scripts/inspect-project-state.ts`
|
|
49
|
+
- LSP/tooling profile: `typescript-lsp`
|
|
50
|
+
- Verification: Use root required checks plus local commands recorded in this capability contract.
|
|
51
|
+
- Latest snapshot: `(none yet)`
|
|
52
|
+
- Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
53
|
+
- Latest human diagram: `(none yet)`
|
|
54
|
+
- Pending architecture request: `(none)`
|
|
55
|
+
|
|
56
|
+
## Active Workstreams
|
|
57
|
+
|
|
58
|
+
- `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
|
|
59
|
+
- status: active
|
|
60
|
+
- current_slice: completed-20260703-architecture-closeout
|
|
61
|
+
- source_plan: (none)
|
|
62
|
+
|
|
63
|
+
## Current Session Projection
|
|
64
|
+
|
|
65
|
+
- Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
|
|
66
|
+
- `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
|
|
67
|
+
- `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
|
|
68
|
+
<!-- END ARCHITECTURE CONTRACT -->
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Functional Block Agent Context
|
|
2
|
+
|
|
3
|
+
Keep this file focused on the local contract for this primary functional block.
|
|
4
|
+
|
|
5
|
+
<!-- BEGIN CAPABILITY CONTEXT -->
|
|
6
|
+
## Capability Context
|
|
7
|
+
|
|
8
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
9
|
+
- Domain: `workflow-engine`
|
|
10
|
+
- Name: `inspection-migration`
|
|
11
|
+
- Primary prefix: `scripts/inspect-project-state.ts`
|
|
12
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
13
|
+
- Workstream: `tasks/workstreams/workflow-engine/inspection-migration`
|
|
14
|
+
|
|
15
|
+
## Positioning
|
|
16
|
+
|
|
17
|
+
Owns the workflow-engine-inspection-migration capability boundary declared in .ai/context/capabilities.json.
|
|
18
|
+
|
|
19
|
+
## Source Map
|
|
20
|
+
|
|
21
|
+
- Primary prefix: `scripts/inspect-project-state.ts` (entrypoint)
|
|
22
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md` (design-source)
|
|
23
|
+
- Workstream: `tasks/workstreams/workflow-engine/inspection-migration` (durable-progress)
|
|
24
|
+
|
|
25
|
+
## Refresh Hints
|
|
26
|
+
|
|
27
|
+
- `bun test tests/migration-script.test.ts tests/create-project-dirs.runtime.test.ts tests/workflow-contract.test.ts`
|
|
28
|
+
- `bash scripts/migrate-project-template.sh --repo . --dry-run`
|
|
29
|
+
<!-- END CAPABILITY CONTEXT -->
|
|
30
|
+
|
|
31
|
+
<!-- BEGIN ARCHITECTURE CONTRACT -->
|
|
32
|
+
## Architecture Contract
|
|
33
|
+
|
|
34
|
+
- Functional block: `scripts/inspect-project-state.ts`
|
|
35
|
+
- Capability ID: `workflow-engine-inspection-migration`
|
|
36
|
+
- Matched prefix: `scripts/inspect-project-state.ts`
|
|
37
|
+
- Architecture domain: `workflow-engine`
|
|
38
|
+
- Architecture capability: `inspection-migration`
|
|
39
|
+
- Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
40
|
+
- Last architecture event: 2026-07-03T15:45:36+0800
|
|
41
|
+
- Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
|
|
42
|
+
- Severity: high
|
|
43
|
+
- Change type: architecture-closeout
|
|
44
|
+
- Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
|
|
45
|
+
- Entrypoints: `scripts/inspect-project-state.ts`
|
|
46
|
+
- Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
|
|
47
|
+
- Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
|
|
48
|
+
- Runtime path: `scripts/inspect-project-state.ts`
|
|
49
|
+
- LSP/tooling profile: `typescript-lsp`
|
|
50
|
+
- Verification: Use root required checks plus local commands recorded in this capability contract.
|
|
51
|
+
- Latest snapshot: `(none yet)`
|
|
52
|
+
- Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
|
|
53
|
+
- Latest human diagram: `(none yet)`
|
|
54
|
+
- Pending architecture request: `(none)`
|
|
55
|
+
|
|
56
|
+
## Active Workstreams
|
|
57
|
+
|
|
58
|
+
- `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
|
|
59
|
+
- status: active
|
|
60
|
+
- current_slice: completed-20260703-architecture-closeout
|
|
61
|
+
- source_plan: (none)
|
|
62
|
+
|
|
63
|
+
## Current Session Projection
|
|
64
|
+
|
|
65
|
+
- Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
|
|
66
|
+
- `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
|
|
67
|
+
- `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
|
|
68
|
+
<!-- END ARCHITECTURE CONTRACT -->
|
|
@@ -79,6 +79,33 @@ if ! "$CLI" run check-task-workflow --help >/dev/null; then
|
|
|
79
79
|
echo "[tarball-smoke] ERROR: packaged 'repo-harness run check-task-workflow --help' failed (run dispatcher / helper lookup / bin startup broken)" >&2
|
|
80
80
|
exit 1
|
|
81
81
|
fi
|
|
82
|
+
|
|
83
|
+
mkdir -p "$TARGET_REPO/plans/sprints" "$TARGET_REPO/.ai/harness/sprint"
|
|
84
|
+
cat > "$TARGET_REPO/plans/sprints/20991231-2359-tarball-root.sprint.md" <<'SPRINT_EOF'
|
|
85
|
+
# Sprint: Tarball Root
|
|
86
|
+
|
|
87
|
+
> **Status**: Approved
|
|
88
|
+
|
|
89
|
+
## Backlog
|
|
90
|
+
|
|
91
|
+
| # | Status | Task | Mode | Acceptance | Plan |
|
|
92
|
+
|---|--------|------|------|------------|------|
|
|
93
|
+
| 1 | [ ] | task-a | inline | packaged helper reads target repo | (pending) |
|
|
94
|
+
| 2 | [ ] | task-b | inline | packaged helper reads target repo | (pending) |
|
|
95
|
+
| 3 | [ ] | task-c | inline | packaged helper reads target repo | (pending) |
|
|
96
|
+
| 4 | [ ] | task-d | inline | packaged helper reads target repo | (pending) |
|
|
97
|
+
| 5 | [ ] | task-e | inline | packaged helper reads target repo | (pending) |
|
|
98
|
+
SPRINT_EOF
|
|
99
|
+
printf '%s' 'plans/sprints/20991231-2359-tarball-root.sprint.md' > "$TARGET_REPO/.ai/harness/sprint/active-sprint"
|
|
100
|
+
|
|
101
|
+
(cd "$TARGET_REPO" && "$CLI" run sprint-backlog status) >"$TMP_DIR/sprint-status.txt"
|
|
102
|
+
if ! grep -qx 'sprint: plans/sprints/20991231-2359-tarball-root.sprint.md' "$TMP_DIR/sprint-status.txt" \
|
|
103
|
+
|| ! grep -qx 'tasks_total: 5' "$TMP_DIR/sprint-status.txt"; then
|
|
104
|
+
echo "[tarball-smoke] ERROR: packaged sprint-backlog helper did not read the target repo sprint state" >&2
|
|
105
|
+
cat "$TMP_DIR/sprint-status.txt" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
82
109
|
printf '{"prompt":"review release readiness"}\n' | "$HOOK" prompt-guard-decide >/dev/null
|
|
83
110
|
|
|
84
111
|
FAKE_HOME="$TMP_DIR/home"
|
|
@@ -175,6 +175,15 @@ export function inspectRepo(repo: string): InspectionResult {
|
|
|
175
175
|
if (hasAnyPath(repo, generatedClaudeHookPaths)) {
|
|
176
176
|
driftSignals.push("stale-generated-claude-hook-shims");
|
|
177
177
|
}
|
|
178
|
+
const rootClaudeFile = join(repo, "CLAUDE.md");
|
|
179
|
+
const rootAgentsFile = join(repo, "AGENTS.md");
|
|
180
|
+
if (
|
|
181
|
+
existsSync(rootClaudeFile) &&
|
|
182
|
+
existsSync(rootAgentsFile) &&
|
|
183
|
+
readFileSync(rootClaudeFile, "utf-8") !== readFileSync(rootAgentsFile, "utf-8")
|
|
184
|
+
) {
|
|
185
|
+
driftSignals.push("root-agent-context-divergent");
|
|
186
|
+
}
|
|
178
187
|
|
|
179
188
|
if (driftSignals.includes("missing-runtime-contract-manifest")) {
|
|
180
189
|
requiredDecisions.push("Install runtime workflow contract manifest");
|
|
@@ -200,6 +209,9 @@ export function inspectRepo(repo: string): InspectionResult {
|
|
|
200
209
|
if (driftSignals.includes("stale-generated-claude-hook-shims")) {
|
|
201
210
|
requiredDecisions.push("Remove manifest-owned generated .claude/hooks shims and keep .ai/hooks as source of truth");
|
|
202
211
|
}
|
|
212
|
+
if (driftSignals.includes("root-agent-context-divergent")) {
|
|
213
|
+
requiredDecisions.push("Root CLAUDE.md and AGENTS.md have diverged; reconcile by hand — repo-harness never overwrites user-authored root files.");
|
|
214
|
+
}
|
|
203
215
|
|
|
204
216
|
const upgradeSignals = new Set(driftSignals);
|
|
205
217
|
if (hasCustomClaudeHooks(repo)) {
|
|
@@ -2160,19 +2160,44 @@ pi_root_context_content() {
|
|
|
2160
2160
|
cat <<'EOF_ROOT_CONTEXT'
|
|
2161
2161
|
# Repo Agent Context
|
|
2162
2162
|
|
|
2163
|
-
This is the root routing contract for Claude Code and Codex.
|
|
2163
|
+
This is the root routing contract for Claude Code and Codex. Keep it short:
|
|
2164
|
+
load this first, then follow the repo-owned artifacts it names.
|
|
2164
2165
|
|
|
2165
2166
|
## Root Workflow Contract
|
|
2166
2167
|
|
|
2167
2168
|
- Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
|
|
2169
|
+
- Prefer repo-local workflow artifacts over tool-specific chat memory.
|
|
2168
2170
|
- Treat `docs/spec.md` as stable product truth, `tasks/current.md` as a derived status snapshot, and `tasks/todos.md` as the deferred-goal ledger; current execution stays in the active plan's `## Task Breakdown`.
|
|
2169
|
-
- Treat `docs/researches/`, `tasks/lessons.md`,
|
|
2170
|
-
- Use `.ai/context/context-map.json` and `.ai/context/capabilities.json` to discover functional-block contracts.
|
|
2171
|
+
- Treat `docs/researches/`, `tasks/lessons.md`, `tasks/notes/`, `.ai/harness/policy.json`, and `.ai/harness/handoff/current.md` as durable workflow context.
|
|
2172
|
+
- Use `.ai/context/context-map.json` and `.ai/context/capabilities.json` to discover functional-block contracts before adding local agent files.
|
|
2171
2173
|
- Do not infer local `CLAUDE.md` or `AGENTS.md` files from broad physical layouts such as `apps/*`, `packages/*`, or `services/*`.
|
|
2172
2174
|
- Put capability-specific ownership, entrypoints, and verification commands in explicitly selected functional-block contracts.
|
|
2173
2175
|
- Keep root context concise; route deep implementation detail into plans, task notes, research, workstreams, or architecture docs.
|
|
2174
2176
|
- Treat `_ref/` as ignored external reference material and `_ops/` as ignored local operations state.
|
|
2175
|
-
|
|
2177
|
+
|
|
2178
|
+
## Agent Context Scaffolding
|
|
2179
|
+
|
|
2180
|
+
- Before creating or changing agent context files, inspect existing high-context files, repo manifests, CI workflows, Makefiles, generated outputs, generators, and high-risk directories.
|
|
2181
|
+
- Treat scanners as leads, not authority. Verify commands, ownership, and generated-file boundaries against actual repo files before writing instructions.
|
|
2182
|
+
- Choose the smallest instruction stack that changes behavior: root context for repo-wide routing, scoped context only where local rules differ, and no nested file for ordinary implementation directories.
|
|
2183
|
+
- Preserve existing high-context files unless the user explicitly approved a rewrite; add pointers or scoped complements instead of normalizing names.
|
|
2184
|
+
- Pair every prohibition with the concrete alternative: source of truth, helper, generator, command, or verification surface.
|
|
2185
|
+
|
|
2186
|
+
## Decision Protocol
|
|
2187
|
+
|
|
2188
|
+
- For non-trivial engineering work, complete P1/P2/P3 before design decisions or code edits: P1 map the real system boundary, P2 trace one concrete data/control path, and P3 state the design rationale and invariant being preserved.
|
|
2189
|
+
- For planning requests, produce one decision-complete recommendation with scope, non-scope, tradeoffs, tests, rollback/failure handling, and the most fragile assumption; do not implement until the user approves.
|
|
2190
|
+
- If the user says `implement this plan`, first check for obvious repo drift, then execute the approved plan without re-litigating the direction.
|
|
2191
|
+
- For bug hunts, trace the failing path and name the root cause before changing code.
|
|
2192
|
+
- For bundles of requests, classify items before accepting scope; do not treat every item as automatic implementation work.
|
|
2193
|
+
- Do not add fallback, compatibility, or "best effort" product code that re-derives an authority's semantics (LLM/provider/external/user-input) with local rules, regexes, or shadow parsers; fail closed with a clear error unless the current task or a human-approved migration/release contract explicitly requires that path.
|
|
2194
|
+
|
|
2195
|
+
## Execution And Verification
|
|
2196
|
+
|
|
2197
|
+
- Prefer existing repo patterns, scripts, and standard-library/platform features before adding dependencies, files, or abstractions.
|
|
2198
|
+
- Preserve user-authored files; do not overwrite existing `CLAUDE.md` or `AGENTS.md` except when explicitly applying an approved scaffold or syncing the controlled architecture block.
|
|
2199
|
+
- After substantive changes, run focused checks for the touched area plus `bash scripts/check-task-sync.sh` and `bash scripts/check-task-workflow.sh --strict` when those scripts exist.
|
|
2200
|
+
- Report what changed, why it was the smallest coherent change, verification evidence, and any concrete residual risk.
|
|
2176
2201
|
EOF_ROOT_CONTEXT
|
|
2177
2202
|
}
|
|
2178
2203
|
|
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
if
|
|
5
|
+
if [[ -n "${REPO_HARNESS_TARGET_REPO_ROOT:-}" ]]; then
|
|
6
|
+
if [[ "$REPO_HARNESS_TARGET_REPO_ROOT" != /* ]]; then
|
|
7
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must be an absolute path" >&2
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
if ! REPO_ROOT="$(cd "$REPO_HARNESS_TARGET_REPO_ROOT" 2>/dev/null && pwd -P)"; then
|
|
11
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT does not resolve to a directory" >&2
|
|
12
|
+
exit 2
|
|
13
|
+
fi
|
|
14
|
+
CURRENT_ROOT="$(pwd -P)"
|
|
15
|
+
if [[ "$REPO_ROOT" != "$CURRENT_ROOT" ]]; then
|
|
16
|
+
echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must match the current helper cwd" >&2
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
cd "$REPO_ROOT"
|
|
20
|
+
elif REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
|
|
6
21
|
cd "$REPO_ROOT"
|
|
7
22
|
else
|
|
8
23
|
cd "$SCRIPT_DIR/.."
|
|
@@ -83,6 +83,47 @@ validate_block() {
|
|
|
83
83
|
[[ -e "$block" ]]
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
helper_sibling() {
|
|
87
|
+
local helper_name="$1"
|
|
88
|
+
local helper_dir=""
|
|
89
|
+
if [[ -n "${REPO_HARNESS_HELPER_SOURCE_PATH:-}" ]]; then
|
|
90
|
+
helper_dir="$(dirname "$REPO_HARNESS_HELPER_SOURCE_PATH")"
|
|
91
|
+
fi
|
|
92
|
+
if [[ -n "$helper_dir" && -f "$helper_dir/$helper_name" ]]; then
|
|
93
|
+
printf '%s\n' "$helper_dir/$helper_name"
|
|
94
|
+
return 0
|
|
95
|
+
fi
|
|
96
|
+
return 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
capability_resolver() {
|
|
100
|
+
local sibling=""
|
|
101
|
+
if command -v bun >/dev/null 2>&1 && [[ -f "scripts/capability-resolver.ts" ]]; then
|
|
102
|
+
bun scripts/capability-resolver.ts "$@"
|
|
103
|
+
return $?
|
|
104
|
+
fi
|
|
105
|
+
sibling="$(helper_sibling capability-resolver.ts || true)"
|
|
106
|
+
if command -v bun >/dev/null 2>&1 && [[ -n "$sibling" ]]; then
|
|
107
|
+
bun "$sibling" "$@"
|
|
108
|
+
return $?
|
|
109
|
+
fi
|
|
110
|
+
return 127
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
context_contract_sync() {
|
|
114
|
+
local sibling=""
|
|
115
|
+
if [[ -x "scripts/context-contract-sync.sh" ]]; then
|
|
116
|
+
bash "scripts/context-contract-sync.sh" "$@"
|
|
117
|
+
return $?
|
|
118
|
+
fi
|
|
119
|
+
sibling="$(helper_sibling context-contract-sync.sh || true)"
|
|
120
|
+
if [[ -n "$sibling" ]]; then
|
|
121
|
+
bash "$sibling" "$@"
|
|
122
|
+
return $?
|
|
123
|
+
fi
|
|
124
|
+
return 127
|
|
125
|
+
}
|
|
126
|
+
|
|
86
127
|
while [[ $# -gt 0 ]]; do
|
|
87
128
|
case "$1" in
|
|
88
129
|
--block)
|
|
@@ -139,12 +180,12 @@ if ! validate_block "$functional_block"; then
|
|
|
139
180
|
exit 2
|
|
140
181
|
fi
|
|
141
182
|
|
|
142
|
-
if
|
|
143
|
-
echo "workstream-sync:
|
|
183
|
+
if ! command -v bun >/dev/null 2>&1 || ! capability_resolver list --format json >/dev/null 2>&1; then
|
|
184
|
+
echo "workstream-sync: capability-resolver.ts and bun are required" >&2
|
|
144
185
|
exit 2
|
|
145
186
|
fi
|
|
146
187
|
|
|
147
|
-
if ! resolver_json="$(
|
|
188
|
+
if ! resolver_json="$(capability_resolver match --path "$functional_block" --format json 2>&1)"; then
|
|
148
189
|
echo "$resolver_json" >&2
|
|
149
190
|
exit 1
|
|
150
191
|
fi
|
|
@@ -257,8 +298,6 @@ fi
|
|
|
257
298
|
event_json="{\"ts\":\"$(json_escape "$iso_timestamp")\",\"file_path\":\"$(json_escape "$workstream_file")\",\"severity\":\"medium\",\"functional_block\":\"$(json_escape "$functional_block")\",\"capability_id\":\"$(json_escape "$capability_id")\",\"matched_prefix\":\"$(json_escape "$matched_prefix")\",\"architecture_domain\":\"$(json_escape "$architecture_domain")\",\"architecture_capability\":\"$(json_escape "$architecture_capability")\",\"architecture_module\":\"$(json_escape "$architecture_module")\",\"workstream_dir\":\"$(json_escape "$workstream_dir")\",\"contract_agents\":\"$(json_escape "$contract_agents")\",\"contract_claude\":\"$(json_escape "$contract_claude")\",\"active_workstream\":\"$(json_escape "$workstream_file")\",\"change_type\":\"workstream-sync\",\"spawn_recommended\":false,\"contract_sync_required\":true,\"request_file\":\"$(json_escape "$request_file")\"}"
|
|
258
299
|
printf '%s\n' "$event_json" >> "$event_file"
|
|
259
300
|
|
|
260
|
-
|
|
261
|
-
bash "$helper_dir/context-contract-sync.sh" sync-event --json "$event_json"
|
|
262
|
-
fi
|
|
301
|
+
context_contract_sync sync-event --json "$event_json" >/dev/null 2>&1 || true
|
|
263
302
|
|
|
264
303
|
echo "[WorkstreamSync] Ensured $workstream_file for $capability_id."
|
|
@@ -129,6 +129,34 @@ function packageVersion(sourceRoot: string): string | null {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function packageName(sourceRoot: string): string | null {
|
|
133
|
+
try {
|
|
134
|
+
const pkg = JSON.parse(readFileSync(join(sourceRoot, "package.json"), "utf-8"));
|
|
135
|
+
return typeof pkg.name === "string" ? pkg.name : null;
|
|
136
|
+
} catch (_error) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isBunDependencyLoop(step: GlobalRuntimeStep): boolean {
|
|
142
|
+
return /DependencyLoop|dependency loop/i.test(`${step.stdout ?? ""}\n${step.stderr ?? ""}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function parsePackedTarballFilename(stdout: string): string | null {
|
|
146
|
+
try {
|
|
147
|
+
const parsed = JSON.parse(stdout);
|
|
148
|
+
const entry = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
149
|
+
return typeof entry?.filename === "string" ? entry.filename : null;
|
|
150
|
+
} catch (_error) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function appendOutput(...values: Array<string | undefined>): string | undefined {
|
|
156
|
+
const output = values.filter((value) => value && value.trim()).join("\n");
|
|
157
|
+
return output || undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
132
160
|
function bunGlobalPackageRoot(env?: NodeJS.ProcessEnv): string | null {
|
|
133
161
|
const bunInstall = env?.BUN_INSTALL ?? process.env.BUN_INSTALL;
|
|
134
162
|
const home = env?.HOME ?? process.env.HOME ?? process.env.USERPROFILE;
|
|
@@ -149,6 +177,7 @@ function isBunGlobalPackageSource(sourceRoot: string, env?: NodeJS.ProcessEnv):
|
|
|
149
177
|
|
|
150
178
|
function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, installSpec?: string): GlobalRuntimeStep {
|
|
151
179
|
const version = packageVersion(sourceRoot);
|
|
180
|
+
const name = packageName(sourceRoot);
|
|
152
181
|
if (installSpec === undefined && isBunGlobalPackageSource(sourceRoot, env)) {
|
|
153
182
|
return {
|
|
154
183
|
step: "install repo-harness CLI",
|
|
@@ -160,6 +189,9 @@ function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, in
|
|
|
160
189
|
}
|
|
161
190
|
const spec = installSpec ?? (existsSync(join(sourceRoot, "package.json")) ? sourceRoot : "repo-harness");
|
|
162
191
|
const step = runProcess("bun", ["add", "-g", spec], cwd, env);
|
|
192
|
+
if (installSpec === undefined && name === "repo-harness" && step.status === "failed" && isBunDependencyLoop(step)) {
|
|
193
|
+
return installCliFromPackedTarball(sourceRoot, cwd, env, version, step);
|
|
194
|
+
}
|
|
163
195
|
return withStepName(
|
|
164
196
|
step,
|
|
165
197
|
"install repo-harness CLI",
|
|
@@ -167,6 +199,55 @@ function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, in
|
|
|
167
199
|
);
|
|
168
200
|
}
|
|
169
201
|
|
|
202
|
+
function installCliFromPackedTarball(
|
|
203
|
+
sourceRoot: string,
|
|
204
|
+
cwd: string,
|
|
205
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
206
|
+
version: string | null,
|
|
207
|
+
dependencyLoopStep: GlobalRuntimeStep,
|
|
208
|
+
): GlobalRuntimeStep {
|
|
209
|
+
const packDir = join(homeDir(env), ".repo-harness", "packages");
|
|
210
|
+
const detailPrefix = version ? `version=${version}; ` : "";
|
|
211
|
+
mkdirSync(packDir, { recursive: true });
|
|
212
|
+
|
|
213
|
+
const pack = runProcess("npm", ["pack", "--json", "--pack-destination", packDir], sourceRoot, env);
|
|
214
|
+
if (pack.status !== "ok") {
|
|
215
|
+
return withStepName(
|
|
216
|
+
{
|
|
217
|
+
...pack,
|
|
218
|
+
stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr),
|
|
219
|
+
},
|
|
220
|
+
"install repo-harness CLI",
|
|
221
|
+
`${detailPrefix}dependency-loop repair pack failed`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const filename = parsePackedTarballFilename(pack.stdout ?? "");
|
|
225
|
+
if (filename === null) {
|
|
226
|
+
return {
|
|
227
|
+
step: "install repo-harness CLI",
|
|
228
|
+
status: "failed",
|
|
229
|
+
command: pack.command,
|
|
230
|
+
detail: `${detailPrefix}dependency-loop repair pack output invalid`,
|
|
231
|
+
stdout: dependencyLoopStep.stdout,
|
|
232
|
+
stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr, "npm pack --json did not return a tarball filename"),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const remove = runProcess("bun", ["remove", "-g", "repo-harness"], cwd, env);
|
|
236
|
+
if (remove.status !== "ok") {
|
|
237
|
+
return withStepName(
|
|
238
|
+
{
|
|
239
|
+
...remove,
|
|
240
|
+
stdout: appendOutput(dependencyLoopStep.stdout, remove.stdout),
|
|
241
|
+
stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr, remove.stderr),
|
|
242
|
+
},
|
|
243
|
+
"install repo-harness CLI",
|
|
244
|
+
`${detailPrefix}dependency-loop repair remove failed`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const add = runProcess("bun", ["add", "-g", join(packDir, filename)], cwd, env);
|
|
248
|
+
return withStepName(add, "install repo-harness CLI", `${detailPrefix}repaired=packed-tarball`);
|
|
249
|
+
}
|
|
250
|
+
|
|
170
251
|
function syncRuntimeSkill(sourceRoot: string, env?: NodeJS.ProcessEnv): GlobalRuntimeStep {
|
|
171
252
|
const script = join(sourceRoot, "scripts", "sync-codex-installed-copies.sh");
|
|
172
253
|
if (!existsSync(script)) {
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -40,6 +40,8 @@ const WAZA_SHARED_RULES = ["anti-patterns.md", "chinese.md", "durable-context.md
|
|
|
40
40
|
const GBRAIN_INSTALL_ARGS = ["install", "-g", "github:garrytan/gbrain"] as const;
|
|
41
41
|
const GLOBAL_RULES_BEGIN = "<!-- BEGIN: repo-harness global-working-rules -->";
|
|
42
42
|
const GLOBAL_RULES_END = "<!-- END: repo-harness global-working-rules -->";
|
|
43
|
+
const GLOBAL_RULES_SELF_NOTE =
|
|
44
|
+
"<!-- repo-harness manages this block; edits inside are overwritten on sync. Keep personal rules outside the markers. -->";
|
|
43
45
|
|
|
44
46
|
export type InitBrainMode = "manifest-only" | "install-gbrain-cli" | "skip";
|
|
45
47
|
export type ReportingLanguagePreset = "follow" | "zh-CN" | "en" | "custom";
|
|
@@ -234,16 +236,42 @@ function renderGlobalRules(sourceRoot: string, instruction: string): string {
|
|
|
234
236
|
/^- Use the user's language for reports; keep technical terms in English\.$/m,
|
|
235
237
|
`- ${instruction}`,
|
|
236
238
|
);
|
|
237
|
-
return `${GLOBAL_RULES_BEGIN}\n${rendered.trim()}\n${GLOBAL_RULES_END}\n`;
|
|
239
|
+
return `${GLOBAL_RULES_BEGIN}\n${GLOBAL_RULES_SELF_NOTE}\n${rendered.trim()}\n${GLOBAL_RULES_END}\n`;
|
|
238
240
|
}
|
|
239
241
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
type ManagedBlockStatus = "written" | "blocked-unbalanced" | "skipped-legacy";
|
|
243
|
+
|
|
244
|
+
interface MergedManagedBlock {
|
|
245
|
+
content: string;
|
|
246
|
+
status: ManagedBlockStatus;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function countOccurrences(haystack: string, needle: string): number {
|
|
250
|
+
let count = 0;
|
|
251
|
+
let index = haystack.indexOf(needle);
|
|
252
|
+
while (index !== -1) {
|
|
253
|
+
count += 1;
|
|
254
|
+
index = haystack.indexOf(needle, index + needle.length);
|
|
255
|
+
}
|
|
256
|
+
return count;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function mergeManagedBlock(current: string, block: string): MergedManagedBlock {
|
|
260
|
+
const beginCount = countOccurrences(current, GLOBAL_RULES_BEGIN);
|
|
261
|
+
const endCount = countOccurrences(current, GLOBAL_RULES_END);
|
|
262
|
+
|
|
263
|
+
if (beginCount > 0 || endCount > 0) {
|
|
264
|
+
const start = current.indexOf(GLOBAL_RULES_BEGIN);
|
|
265
|
+
const end = current.indexOf(GLOBAL_RULES_END);
|
|
266
|
+
const balanced = beginCount === 1 && endCount === 1 && start >= 0 && end >= start;
|
|
267
|
+
if (!balanced) {
|
|
268
|
+
return { content: current, status: "blocked-unbalanced" };
|
|
269
|
+
}
|
|
244
270
|
const afterEnd = end + GLOBAL_RULES_END.length;
|
|
245
|
-
|
|
271
|
+
const merged = `${current.slice(0, start)}${block.trimEnd()}${current.slice(afterEnd).replace(/^\n?/, "\n")}`;
|
|
272
|
+
return { content: merged, status: "written" };
|
|
246
273
|
}
|
|
274
|
+
|
|
247
275
|
if (
|
|
248
276
|
/^# Global Working Rules\s*$/m.test(current) ||
|
|
249
277
|
(
|
|
@@ -253,10 +281,10 @@ function mergeManagedBlock(current: string, block: string): string {
|
|
|
253
281
|
current.includes("### P3: Design Decision")
|
|
254
282
|
)
|
|
255
283
|
) {
|
|
256
|
-
return current;
|
|
284
|
+
return { content: current, status: "skipped-legacy" };
|
|
257
285
|
}
|
|
258
286
|
const trimmed = current.trimEnd();
|
|
259
|
-
return `${trimmed}${trimmed ? "\n\n" : ""}${block}
|
|
287
|
+
return { content: `${trimmed}${trimmed ? "\n\n" : ""}${block}`, status: "written" };
|
|
260
288
|
}
|
|
261
289
|
|
|
262
290
|
export function writeGlobalContextFiles(
|
|
@@ -276,19 +304,29 @@ export function writeGlobalContextFiles(
|
|
|
276
304
|
if (target === "claude" || target === "both") targets.push(join(home, ".claude", "CLAUDE.md"));
|
|
277
305
|
|
|
278
306
|
const changes: string[] = [];
|
|
307
|
+
let blocked = false;
|
|
279
308
|
for (const filePath of targets) {
|
|
280
309
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
281
310
|
const current = existsSync(filePath) ? readFileSync(filePath, "utf-8") : "";
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
311
|
+
const merged = mergeManagedBlock(current, block);
|
|
312
|
+
if (merged.status === "blocked-unbalanced") {
|
|
313
|
+
blocked = true;
|
|
314
|
+
changes.push(`blocked:${filePath} (unbalanced repo-harness markers; repair manually, then re-run)`);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (merged.status === "skipped-legacy") {
|
|
318
|
+
changes.push(`skipped-legacy:${filePath} (unmanaged Global Working Rules present; add the repo-harness markers to enable managed sync)`);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (merged.content === current) {
|
|
284
322
|
changes.push(`unchanged:${filePath}`);
|
|
285
323
|
continue;
|
|
286
324
|
}
|
|
287
|
-
writeFileSync(filePath,
|
|
325
|
+
writeFileSync(filePath, merged.content, "utf-8");
|
|
288
326
|
changes.push(`${current ? "updated" : "created"}:${filePath}`);
|
|
289
327
|
}
|
|
290
328
|
|
|
291
|
-
return { step: "global working rules", status: "ok", detail: changes.join(", ") };
|
|
329
|
+
return { step: "global working rules", status: blocked ? "failed" : "ok", detail: changes.join(", ") };
|
|
292
330
|
}
|
|
293
331
|
|
|
294
332
|
/**
|
|
@@ -14,6 +14,7 @@ const SESSION_CONTEXT = [
|
|
|
14
14
|
'3. Prefer the smallest direct implementation over new wrappers or extension points.',
|
|
15
15
|
'4. Delete or shrink obsolete code before adding layers.',
|
|
16
16
|
'5. Preserve explicit requirements, security, validation, data safety, error handling, accessibility, and runnable tests.',
|
|
17
|
+
'6. No compatibility fallbacks in product code: do not re-derive an LLM/provider/authority-owned value with local rules or regexes; if the authoritative value is missing or malformed, fail closed with a clear error instead of synthesizing a replacement.',
|
|
17
18
|
'Before completion, justify each new dependency, file, and abstraction.',
|
|
18
19
|
].join('\n');
|
|
19
20
|
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Functional Block Agent Context
|
|
2
|
-
|
|
3
|
-
Keep this file focused on the local contract for this primary functional block.
|
|
4
|
-
|
|
5
|
-
## Local Context Contract
|
|
6
|
-
|
|
7
|
-
- Describe only the ownership, boundaries, stable entrypoints, and local verification commands for this functional block.
|
|
8
|
-
- Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
|
|
9
|
-
- Record the local LSP/tooling profile here when it differs from the repo default.
|
|
10
|
-
- Route deep implementation detail into nearby docs instead of inflating root agent context files.
|
|
11
|
-
- Treat `.ai/context/context-map.json` as the index of discoverable context files.
|
|
12
|
-
- Do not keep pushing context files deeper by default; add lower-level files only for a separately owned functional block with its own commands and invariants.
|
|
13
|
-
- Prefer repo-local workflow artifacts over tool-specific chat memory.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Functional Block Agent Context
|
|
2
|
-
|
|
3
|
-
Keep this file focused on the local contract for this primary functional block.
|
|
4
|
-
|
|
5
|
-
## Local Context Contract
|
|
6
|
-
|
|
7
|
-
- Describe only the ownership, boundaries, stable entrypoints, and local verification commands for this functional block.
|
|
8
|
-
- Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
|
|
9
|
-
- Record the local LSP/tooling profile here when it differs from the repo default.
|
|
10
|
-
- Route deep implementation detail into nearby docs instead of inflating root agent context files.
|
|
11
|
-
- Treat `.ai/context/context-map.json` as the index of discoverable context files.
|
|
12
|
-
- Do not keep pushing context files deeper by default; add lower-level files only for a separately owned functional block with its own commands and invariants.
|
|
13
|
-
- Prefer repo-local workflow artifacts over tool-specific chat memory.
|