repo-harness 0.1.2 → 0.1.3

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.
Files changed (33) hide show
  1. package/README.md +57 -3
  2. package/README.zh-CN.md +31 -4
  3. package/SKILL.md +22 -0
  4. package/assets/hooks/post-bash.sh +116 -2
  5. package/assets/hooks/prompt-guard.sh +451 -135
  6. package/assets/initializer-question-pack.v4.json +207 -1
  7. package/assets/initializer-question-pack.v4.schema.json +40 -3
  8. package/assets/partials/04-project-structure.partial.md +10 -0
  9. package/assets/plan-map.json +44 -0
  10. package/assets/project-structures/ai-native-product-copilot.txt +21 -0
  11. package/assets/project-structures/ai-native-runtime-console.txt +25 -0
  12. package/assets/project-structures/ai-native-sidecar-kernel.txt +19 -0
  13. package/assets/reference-configs/external-tooling.md +14 -0
  14. package/assets/reference-configs/release-deploy.md +8 -0
  15. package/assets/skill-commands/repo-harness-scaffold/SKILL.md +13 -3
  16. package/assets/templates/helpers/check-deploy-sql-order.sh +12 -0
  17. package/assets/templates/helpers/plan-to-todo.sh +1 -0
  18. package/assets/templates/helpers/refresh-current-status.sh +6 -2
  19. package/assets/templates/tech-stack.template.md +14 -0
  20. package/docs/reference-configs/external-tooling.md +14 -0
  21. package/docs/reference-configs/hook-operations.md +9 -0
  22. package/docs/reference-configs/release-deploy.md +8 -0
  23. package/package.json +1 -1
  24. package/scripts/assemble-template.ts +140 -0
  25. package/scripts/check-deploy-sql-order.sh +12 -0
  26. package/scripts/initializer-question-pack.ts +28 -0
  27. package/scripts/plan-to-todo.sh +1 -0
  28. package/scripts/refresh-current-status.sh +6 -2
  29. package/src/cli/commands/prompt-guard-decision.ts +88 -0
  30. package/src/cli/commands/status.ts +1 -1
  31. package/src/cli/hook/prompt-guard-decision.ts +238 -0
  32. package/src/cli/hook-entry.ts +8 -1
  33. package/src/cli/index.ts +11 -1
package/README.md CHANGED
@@ -45,6 +45,16 @@ The design has three layers:
45
45
  the current repo's `.ai/hooks/*` scripts only when
46
46
  `.ai/harness/workflow-contract.json` exists.
47
47
 
48
+ For `UserPromptSubmit`, the public adapter contract stays
49
+ `repo-harness-hook UserPromptSubmit --route default`. The CLI route registry
50
+ dispatches that route to `.ai/hooks/prompt-guard.sh`. The shell hook remains the
51
+ repo-local adapter for host JSON parsing, workflow file reads, capture side
52
+ effects, quality gate rendering, and host-safe stdout/stderr. The prompt intent
53
+ and workflow-state decision is handled by the TypeScript decision engine behind
54
+ `repo-harness-hook prompt-guard-decide`, which returns one action enum from an
55
+ explicit decision table. That split keeps host configuration stable while moving
56
+ the brittle classifier/state-machine layer out of shell conditionals.
57
+
48
58
  The core invariant is that durable truth lives in the repo, not in a chat
49
59
  thread. Hooks are accelerators and guardrails; the authority remains the
50
60
  file-backed plan, contract, review, checks, and handoff artifacts.
@@ -111,9 +121,10 @@ npx -y repo-harness init
111
121
  ```
112
122
 
113
123
  The npm package release line is `0.1.x`; generated workflow compatibility is
114
- tracked separately as the `5.x` model line. The `0.1.2` package publishes the
124
+ tracked separately as the `5.x` model line. The `0.1.3` package publishes the
115
125
  renamed `repo-harness` CLI, user-level Claude/Codex hook adapter bootstrap,
116
- Waza runtime skill sync, `diagram-design` sync, and the release gate used by
126
+ AI-native scaffold overlays, the typed prompt-guard decision engine, Waza
127
+ runtime skill sync, `diagram-design` sync, and the release gate used by
117
128
  maintainers before npm publish. When working from a source checkout instead of
118
129
  npm, run:
119
130
 
@@ -194,6 +205,23 @@ before applying anything.
194
205
  - Codex must mark `~/.codex/hooks.json` as trusted in Codex Settings before those hooks run.
195
206
  - Debug in this order: user-level adapter config -> `repo-harness-hook` (or fallback `repo-harness hook`) -> route registry -> `.ai/hooks/*`.
196
207
 
208
+ Prompt guard has one extra internal step:
209
+
210
+ ```mermaid
211
+ flowchart LR
212
+ Host["Claude/Codex UserPromptSubmit"] --> Adapter["user-level adapter"]
213
+ Adapter --> CLI["repo-harness-hook UserPromptSubmit --route default"]
214
+ CLI --> Route["route registry"]
215
+ Route --> Shell[".ai/hooks/prompt-guard.sh"]
216
+ Shell --> Decision["repo-harness-hook prompt-guard-decide<br/>TypeScript decision table"]
217
+ Decision --> Action["single action enum"]
218
+ Action --> Shell
219
+ Shell --> HostOutput["host-safe allow, advice, block, or done gate output"]
220
+ ```
221
+
222
+ The shell layer still owns filesystem authority and side effects. TypeScript owns
223
+ only the classifier plus `intent x plan state` decision table.
224
+
197
225
  ## Hook Failure Playbook
198
226
 
199
227
  When a hook blocks work, start with the structured output in the terminal. The core
@@ -222,7 +250,7 @@ Most common guards:
222
250
 
223
251
  ## Current Release
224
252
 
225
- - npm package: `repo-harness@0.1.2`
253
+ - npm package: `repo-harness@0.1.3`
226
254
  - Generated workflow compatibility: `5.2.3`
227
255
  - GitHub repository: `Ancienttwo/repo-harness`
228
256
  - Release history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
@@ -270,6 +298,23 @@ Most common guards:
270
298
  - durable capability progress -> `tasks/workstreams/`
271
299
  - release history -> `docs/CHANGELOG.md`
272
300
 
301
+ ## Acknowledgements and Tooling Dependencies
302
+
303
+ `repo-harness` is built around a small set of external skills and repos that
304
+ proved useful while this project was being designed, debugged, and released.
305
+ They are acknowledged here because they shaped the workflow contract, but they
306
+ are not all bundled product dependencies.
307
+
308
+ | Tool or repo | Used for | Dependency shape |
309
+ | --- | --- | --- |
310
+ | gstack skills, including `document-release`, `office-hours`, `plan-eng-review`, and `plan-design-review` | Product discovery, plan review, design review, and post-ship documentation hygiene | External operator workflow; advisory by default |
311
+ | Waza skills, including `think`, `hunt`, `check`, `health`, `design`, `learn`, `read`, and `write` | Daily planning, bug hunts, verification, health checks, and Codex-first skill sync | Installed through the skills CLI into host skill roots |
312
+ | `diagram-design` | Human-readable architecture and system-flow diagrams when Mermaid is not enough | Runtime-referenced skill, not vendored into generated repos |
313
+ | `gbrain` | Knowledge sync, handoff retrieval, and long-form repo memory | Optional external CLI and index |
314
+ | CodeGraph (`@colbymchenry/codegraph`) | Symbol-aware navigation, impact tracing, and readiness checks for this self-host repo | Dev dependency in this repo; generated repos stay global-MCP-first unless policy opts in |
315
+ | Bun | Source checkout execution, tests, template assembly, and release checks | Required local runtime for maintainers |
316
+ | `commander` | `repo-harness` CLI command parsing | Runtime npm dependency |
317
+
273
318
  ## Action Command Skills
274
319
 
275
320
  Source-owned command skill facades live in `assets/skill-commands/`. They keep
@@ -284,6 +329,15 @@ and tests:
284
329
  project or module scaffold. `hooks-init`, `docs-init`, and `create-project-dirs`
285
330
  are internal steps, not public commands.
286
331
 
332
+ `repo-harness-scaffold` keeps the A-K plan catalog as the project-type authority
333
+ and adds AI-native app structure through an optional `ai_native_profile` overlay.
334
+ The default profile is `none`, so existing scaffold output remains unchanged.
335
+ When selected, profiles such as `runtime-console`, `product-copilot`, and
336
+ `sidecar-kernel` document the AG-UI event boundary, assistant-ui or CopilotKit
337
+ UI runtime, Bun/Hono gateway, shared contracts, observability, and MCP/HTTP
338
+ sidecar rules without installing model providers or making Python, Go, Rust, or
339
+ A2UI mandatory defaults.
340
+
287
341
  Use `repo-harness-capability` when the harness already exists and only selected
288
342
  capability boundaries should be added. It updates `.ai/context/capabilities.json`,
289
343
  syncs the requested local `AGENTS.md` / `CLAUDE.md` contract files, and validates
package/README.zh-CN.md CHANGED
@@ -40,6 +40,15 @@ repo-local hooks,然后验证这些 workflow surfaces 仍然一致。
40
40
  repo 是否存在 `.ai/harness/workflow-contract.json`;没有 opt in 就静默退出,有 opt in
41
41
  才进入当前仓库的 `.ai/hooks/*`。
42
42
 
43
+ 对 `UserPromptSubmit` 来说,公开 adapter contract 仍然是
44
+ `repo-harness-hook UserPromptSubmit --route default`。CLI route registry 会把这个
45
+ route dispatch 到 `.ai/hooks/prompt-guard.sh`。Shell hook 继续负责 host JSON 解析、
46
+ workflow 文件读取、plan capture 副作用、quality gate 渲染,以及 host-safe
47
+ stdout/stderr。Prompt intent 和 workflow state 的决策交给
48
+ `repo-harness-hook prompt-guard-decide` 背后的 TypeScript decision engine;它从显式
49
+ decision table 里返回一个 action enum。这样 host 配置不变,但最容易出错的
50
+ classifier/state-machine 层不再散落在 shell 条件分支里。
51
+
43
52
  核心不变量:持久事实在仓库里,不在聊天窗口里。Hooks 只是加速器和 guardrail;
44
53
  真正的 authority 是 plan、contract、review、checks 和 handoff 这些文件。
45
54
 
@@ -103,9 +112,10 @@ npx -y repo-harness init
103
112
  ```
104
113
 
105
114
  npm package release line 是 `0.1.x`;生成的 workflow compatibility model line
106
- 单独以 `5.x` 追踪。`repo-harness@0.1.2` 发布的是改名后的 CLI、Claude/Codex
107
- user-level hook adapter bootstrap、Waza runtime skill sync、`diagram-design` sync,
108
- 以及 maintainer 发布 npm 前使用的 release gate。
115
+ 单独以 `5.x` 追踪。`repo-harness@0.1.3` 发布的是改名后的 CLI、Claude/Codex
116
+ user-level hook adapter bootstrap、AI-native scaffold overlays、typed prompt-guard
117
+ decision engine、Waza runtime skill sync、`diagram-design` sync,以及 maintainer
118
+ 发布 npm 前使用的 release gate。
109
119
 
110
120
  如果从源码 checkout 工作:
111
121
 
@@ -180,6 +190,23 @@ bun test
180
190
  - Codex 必须在 Settings 里信任 `~/.codex/hooks.json`,hooks 才会执行。
181
191
  - 调试顺序:user-level adapter config -> `repo-harness-hook` 或 fallback `repo-harness hook` -> route registry -> `.ai/hooks/*`。
182
192
 
193
+ Prompt guard 多一个内部步骤:
194
+
195
+ ```mermaid
196
+ flowchart LR
197
+ Host["Claude/Codex UserPromptSubmit"] --> Adapter["user-level adapter"]
198
+ Adapter --> CLI["repo-harness-hook UserPromptSubmit --route default"]
199
+ CLI --> Route["route registry"]
200
+ Route --> Shell[".ai/hooks/prompt-guard.sh"]
201
+ Shell --> Decision["repo-harness-hook prompt-guard-decide<br/>TypeScript decision table"]
202
+ Decision --> Action["single action enum"]
203
+ Action --> Shell
204
+ Shell --> HostOutput["host-safe allow, advice, block, or done gate output"]
205
+ ```
206
+
207
+ Shell 层仍然拥有文件系统 authority 和副作用。TypeScript 只拥有 classifier 加
208
+ `intent x plan state` decision table。
209
+
183
210
  ## Hook Failure Playbook
184
211
 
185
212
  hook block 工作时,先看 terminal 里的结构化输出。核心字段是
@@ -208,7 +235,7 @@ hook block 工作时,先看 terminal 里的结构化输出。核心字段是
208
235
 
209
236
  ## 当前 Release
210
237
 
211
- - npm package:`repo-harness@0.1.2`
238
+ - npm package:`repo-harness@0.1.3`
212
239
  - Generated workflow compatibility:`5.2.3`
213
240
  - GitHub repository:`Ancienttwo/repo-harness`
214
241
  - Release history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
package/SKILL.md CHANGED
@@ -138,6 +138,28 @@ Custom Presets (G-K):
138
138
  - Plan J: AI coding agent / TUI
139
139
  - Plan K: Fully custom configuration
140
140
 
141
+ ## AI-native scaffold overlay
142
+
143
+ `repo-harness-scaffold` keeps A-K as the project-type catalog and uses
144
+ `ai_native_profile` as a separate overlay axis. The default profile is `none`,
145
+ so existing generated output stays on the selected A-K plan. Use an overlay only
146
+ when the generated app needs agent runtime, UI protocol, tool, sidecar, state,
147
+ or observability boundaries.
148
+
149
+ Supported profile IDs live in `assets/initializer-question-pack.v4.json`.
150
+ Generated structure overlays currently exist for:
151
+
152
+ - `runtime-console`: Vite 8 + assistant-ui, AG-UI event transport, Bun/Hono
153
+ agent gateway, run store, contracts, approvals, artifacts, and telemetry
154
+ - `product-copilot`: in-product copilot panel, AG-UI app-domain events, product
155
+ context loaders, business action tools, authorization and approval policies
156
+ - `sidecar-kernel`: Bun/Hono app gateway with Python, Go, or Rust kernels behind
157
+ MCP tools or narrow HTTP jobs
158
+
159
+ Do not turn the AI-native overlay into another lettered plan. Do not make A2UI,
160
+ Python, Go, Rust, Redis, ClickHouse, Temporal, object storage, vector DBs, model
161
+ providers, or tracing vendors mandatory defaults.
162
+
141
163
  ## Migration Rules
142
164
 
143
165
  For legacy repos, migrate old document surfaces before refreshing templates.
@@ -10,12 +10,44 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
10
  # shellcheck source=/dev/null
11
11
  . "$SCRIPT_DIR/lib/workflow-state.sh"
12
12
 
13
+ post_bash_set_tool_output_from_stdin() {
14
+ local parsed tmp
15
+
16
+ hook_read_stdin_once
17
+ [[ -n "${HOOK_STDIN_JSON:-}" ]] || return 1
18
+
19
+ if command -v jq >/dev/null 2>&1; then
20
+ if printf '%s' "$HOOK_STDIN_JSON" | jq -e 'has("tool_output") and .tool_output != null' >/dev/null 2>&1; then
21
+ IFS= read -r -d '' parsed < <(printf '%s' "$HOOK_STDIN_JSON" | jq -j '.tool_output' 2>/dev/null; printf '\0')
22
+ TOOL_OUTPUT="$parsed"
23
+ return 0
24
+ fi
25
+ fi
26
+
27
+ command -v bun >/dev/null 2>&1 || return 1
28
+ tmp="$(mktemp "${TMPDIR:-/tmp}/post-bash-tool-output.XXXXXX")" || return 1
29
+ if JSON_INPUT="$HOOK_STDIN_JSON" bun -e '
30
+ const raw = process.env.JSON_INPUT ?? "";
31
+ const value = JSON.parse(raw).tool_output;
32
+ if (value == null) process.exit(1);
33
+ if (typeof value === "object") process.stdout.write(JSON.stringify(value));
34
+ else process.stdout.write(String(value));
35
+ ' > "$tmp" 2>/dev/null; then
36
+ IFS= read -r -d '' parsed < <(cat "$tmp"; printf '\0')
37
+ TOOL_OUTPUT="$parsed"
38
+ rm -f "$tmp"
39
+ return 0
40
+ fi
41
+ rm -f "$tmp"
42
+ return 1
43
+ }
44
+
13
45
  TOOL_OUTPUT="${1:-${TOOL_OUTPUT:-}}"
14
46
  EXIT_CODE="${2:-${EXIT_CODE:-}}"
15
47
  COMMAND_TEXT="$(hook_json_get '.tool_input.command' '')"
16
48
 
17
49
  if [[ -z "$TOOL_OUTPUT" ]]; then
18
- TOOL_OUTPUT="$(hook_json_get '.tool_output' '')"
50
+ post_bash_set_tool_output_from_stdin || TOOL_OUTPUT="$(hook_json_get '.tool_output' '')"
19
51
  fi
20
52
  if [[ -z "$EXIT_CODE" ]]; then
21
53
  EXIT_CODE="$(hook_json_get '.exit_code' '')"
@@ -30,6 +62,35 @@ post_bash_output_line_count() {
30
62
  printf '%s' "$output" | awk 'END { print NR }'
31
63
  }
32
64
 
65
+ post_bash_output_byte_count() {
66
+ local output="$1"
67
+ printf '%s' "$output" | wc -c | tr -d '[:space:]'
68
+ }
69
+
70
+ post_bash_sha256() {
71
+ local output="$1"
72
+ if command -v shasum >/dev/null 2>&1; then
73
+ printf '%s' "$output" | shasum -a 256 | awk '{ print $1 }'
74
+ return
75
+ fi
76
+ if command -v sha256sum >/dev/null 2>&1; then
77
+ printf '%s' "$output" | sha256sum | awk '{ print $1 }'
78
+ return
79
+ fi
80
+ printf ''
81
+ }
82
+
83
+ post_bash_failure_signal() {
84
+ local output="$1"
85
+ [[ -n "$output" ]] || return 1
86
+ printf '%s\n' "$output" | grep -qEi "(^|[[:space:]])(FAIL|FAILED|failed)([[:space:]:,]|$)|Traceback|panic:|fatal:|error.*test"
87
+ }
88
+
89
+ post_bash_exit_failed() {
90
+ local exit_code="$1"
91
+ [[ -n "$exit_code" && "$exit_code" != "0" ]]
92
+ }
93
+
33
94
  post_bash_broad_command() {
34
95
  local command_text="$1"
35
96
  local trimmed
@@ -63,9 +124,45 @@ if post_bash_broad_command "$COMMAND_TEXT"; then
63
124
  recommended_next_tool="codegraph_context"
64
125
  fi
65
126
  output_line_count="$(post_bash_output_line_count "$TOOL_OUTPUT")"
127
+ raw_output_bytes="$(post_bash_output_byte_count "$TOOL_OUTPUT")"
128
+ failure_signal=false
129
+ if post_bash_failure_signal "$TOOL_OUTPUT"; then
130
+ failure_signal=true
131
+ fi
132
+ rtk_available=false
133
+ if command -v rtk >/dev/null 2>&1; then
134
+ rtk_available=true
135
+ fi
136
+
137
+ LONG_OUTPUT_LINES=200
138
+ LONG_OUTPUT_BYTES=32768
139
+ verbosity_class="inline"
140
+ suggested_runner="inline"
141
+ raw_output_path=""
142
+ raw_output_sha256=""
143
+
144
+ if post_bash_exit_failed "$EXIT_CODE"; then
145
+ verbosity_class="failure"
146
+ suggested_runner="raw"
147
+ elif (( output_line_count >= LONG_OUTPUT_LINES || raw_output_bytes >= LONG_OUTPUT_BYTES )); then
148
+ verbosity_class="long"
149
+ if [[ "$broad_command" == "true" && "$rtk_available" == "true" ]]; then
150
+ suggested_runner="rtk"
151
+ else
152
+ suggested_runner="raw"
153
+ fi
154
+ fi
155
+
156
+ if [[ "$verbosity_class" != "inline" ]]; then
157
+ output_dir="$(workflow_runs_dir)/bash-output"
158
+ mkdir -p "$output_dir"
159
+ raw_output_sha256="$(post_bash_sha256 "$TOOL_OUTPUT")"
160
+ raw_output_path="${output_dir}/post-bash-$(date '+%Y%m%dT%H%M%S')-$$-${raw_output_sha256:0:12}.log"
161
+ printf '%s' "$TOOL_OUTPUT" > "$raw_output_path"
162
+ fi
66
163
 
67
164
  if [[ "$EXIT_CODE" != "0" ]]; then
68
- if echo "$TOOL_OUTPUT" | grep -qEi "(FAIL|failed|error.*test)"; then
165
+ if [[ "$failure_signal" == "true" ]]; then
69
166
  echo "[PostBash] Tests failed. Reminder: failure = rewrite module, not patching."
70
167
  fi
71
168
  fi
@@ -78,6 +175,16 @@ if [[ -f "$checks_file" ]] && grep -Eq '"source"[[:space:]]*:[[:space:]]*"verify
78
175
  fi
79
176
 
80
177
  mkdir -p "$(dirname "$target_checks_file")"
178
+ if [[ -n "$raw_output_path" ]]; then
179
+ raw_output_path_json="\"$(hook_json_escape "$raw_output_path")\""
180
+ else
181
+ raw_output_path_json="null"
182
+ fi
183
+ if [[ -n "$raw_output_sha256" ]]; then
184
+ raw_output_sha256_json="\"$(hook_json_escape "$raw_output_sha256")\""
185
+ else
186
+ raw_output_sha256_json="null"
187
+ fi
81
188
  cat > "$target_checks_file" <<EOF_CHECKS
82
189
  {
83
190
  "source": "post-bash",
@@ -86,6 +193,13 @@ cat > "$target_checks_file" <<EOF_CHECKS
86
193
  "status": "$([[ "${EXIT_CODE:-0}" = "0" ]] && echo pass || echo fail)",
87
194
  "broad_command": ${broad_command},
88
195
  "output_line_count": ${output_line_count:-0},
196
+ "verbosity_class": "$(hook_json_escape "$verbosity_class")",
197
+ "suggested_runner": "$(hook_json_escape "$suggested_runner")",
198
+ "raw_output_path": ${raw_output_path_json},
199
+ "raw_output_bytes": ${raw_output_bytes:-0},
200
+ "raw_output_sha256": ${raw_output_sha256_json},
201
+ "failure_signal": ${failure_signal},
202
+ "rtk_available": ${rtk_available},
89
203
  "recommended_next_tool": "$(hook_json_escape "$recommended_next_tool")",
90
204
  "generated_at": "$(date '+%Y-%m-%dT%H:%M:%S%z')"
91
205
  }