ultimate-pi 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/harness-decisions/SKILL.md +68 -2
- package/.agents/skills/harness-git-commit/SKILL.md +72 -0
- package/.agents/skills/harness-governor/SKILL.md +2 -2
- package/.agents/skills/harness-ls-lint-setup/SKILL.md +59 -0
- package/.agents/skills/harness-plan/SKILL.md +13 -11
- package/.agents/skills/harness-review/SKILL.md +1 -1
- package/.agents/skills/harness-sentrux-repair/SKILL.md +48 -0
- package/.agents/skills/sentrux/SKILL.md +4 -2
- package/.agents/skills/wiki-save/SKILL.md +1 -1
- package/.pi/PACKAGING.md +6 -0
- package/.pi/SYSTEM.md +21 -3
- package/.pi/agents/harness/ls-lint-steward.md +49 -0
- package/.pi/agents/harness/planning/decompose.md +4 -4
- package/.pi/agents/harness/reviewing/evaluator.md +1 -1
- package/.pi/agents/harness/running/executor.md +1 -1
- package/.pi/agents/harness/sentrux-repair-advisor.md +50 -0
- package/.pi/agents/pi-pi/prompt-expert.md +17 -2
- package/.pi/auto-commit.json +9 -2
- package/.pi/extensions/debate-orchestrator.ts +3 -0
- package/.pi/extensions/harness-anchored-edit.ts +7 -9
- package/.pi/extensions/harness-ask-user.ts +13 -34
- package/.pi/extensions/harness-debate-tools.ts +43 -4
- package/.pi/extensions/harness-live-widget.ts +28 -19
- package/.pi/extensions/harness-run-context.ts +278 -115
- package/.pi/extensions/harness-web-tools.ts +598 -471
- package/.pi/extensions/ls-lint-rules-sync.ts +103 -0
- package/.pi/extensions/observation-bus.ts +4 -0
- package/.pi/extensions/policy-gate.ts +270 -229
- package/.pi/extensions/sentrux-rules-sync.ts +2 -0
- package/.pi/extensions/soundboard.ts +48 -48
- package/.pi/harness/README.md +4 -0
- package/.pi/harness/agents.manifest.json +15 -7
- package/.pi/harness/agents.policy.yaml +49 -82
- package/.pi/harness/docs/adrs/0052-ls-lint-naming-lifecycle.md +45 -0
- package/.pi/harness/docs/adrs/0052-sentrux-structured-repair.md +38 -0
- package/.pi/harness/docs/adrs/0053-plan-task-clarification-gate.md +39 -0
- package/.pi/harness/docs/adrs/0054-harness-native-ask-user.md +40 -0
- package/.pi/harness/docs/adrs/0055-auto-commit-coauthor-lifecycle.md +40 -0
- package/.pi/harness/docs/adrs/README.md +5 -0
- package/.pi/harness/docs/practice-map.md +10 -5
- package/.pi/harness/evals/smoke/ls-lint-stub.json +10 -0
- package/.pi/harness/evolution/self-healing-rules.json +16 -0
- package/.pi/harness/ls-lint/naming.manifest.json +128 -0
- package/.pi/harness/sentrux/architecture.manifest.json +1 -1
- package/.pi/harness/specs/auto-commit.schema.json +63 -0
- package/.pi/harness/specs/ls-lint-manifest-proposal.schema.json +80 -0
- package/.pi/harness/specs/ls-lint-signal.schema.json +47 -0
- package/.pi/harness/specs/naming-manifest.schema.json +54 -0
- package/.pi/harness/specs/plan-task-clarification.schema.json +88 -0
- package/.pi/harness/specs/sentrux-diagnostics.schema.json +173 -0
- package/.pi/harness/specs/sentrux-repair-plan.schema.json +133 -0
- package/.pi/harness/specs/sentrux-report.schema.json +119 -0
- package/.pi/harness/specs/sentrux-signal.schema.json +34 -1
- package/.pi/lib/agents-policy.d.mts +26 -51
- package/.pi/lib/agents-policy.mjs +41 -28
- package/.pi/lib/agt/build-evaluation-context.ts +136 -64
- package/.pi/lib/ask-user/constants.mjs +3 -0
- package/.pi/lib/ask-user/constants.ts +4 -0
- package/.pi/lib/ask-user/contracts/glimpse-parse.ts +56 -0
- package/.pi/lib/ask-user/contracts/glimpse-payload-build.ts +58 -0
- package/.pi/lib/ask-user/contracts/glimpse-payload.ts +38 -0
- package/.pi/lib/ask-user/core/questionnaire.ts +74 -0
- package/.pi/lib/ask-user/dialog.ts +2 -314
- package/.pi/lib/ask-user/fallback.ts +2 -78
- package/.pi/lib/ask-user/format.ts +85 -0
- package/.pi/lib/ask-user/glimpseui.d.ts +10 -0
- package/.pi/lib/ask-user/index.ts +114 -0
- package/.pi/lib/ask-user/merge-task-clarification.ts +98 -0
- package/.pi/lib/ask-user/policy.mjs +43 -0
- package/.pi/lib/ask-user/policy.ts +104 -0
- package/.pi/lib/ask-user/presenters/glimpse.ts +130 -0
- package/.pi/lib/ask-user/presenters/headless.ts +131 -0
- package/.pi/lib/ask-user/presenters/select.ts +60 -0
- package/.pi/lib/ask-user/presenters/tui.ts +373 -0
- package/.pi/lib/ask-user/presenters/types.ts +13 -0
- package/.pi/lib/ask-user/render.ts +40 -9
- package/.pi/lib/ask-user/schema.ts +66 -13
- package/.pi/lib/ask-user/types.ts +60 -3
- package/.pi/lib/ask-user/validate-core.mjs +193 -7
- package/.pi/lib/ask-user/validate.ts +53 -34
- package/.pi/lib/harness-anchored-edit/package.json +3 -0
- package/.pi/lib/harness-artifact-gate.ts +75 -21
- package/.pi/lib/harness-auto-commit-config.mjs +321 -0
- package/.pi/lib/harness-lens/clients/lsp/client.ts +62 -39
- package/.pi/lib/harness-lens/clients/tool-policy.ts +73 -181
- package/.pi/lib/harness-lens/index.ts +241 -108
- package/.pi/lib/harness-lens/tools/lsp-navigation.ts +10 -8
- package/.pi/lib/harness-repair-brief.ts +84 -25
- package/.pi/lib/harness-run-context.ts +42 -52
- package/.pi/lib/harness-sentrux-parse.mjs +272 -0
- package/.pi/lib/harness-sentrux-root.mjs +78 -0
- package/.pi/lib/harness-slash-completions.ts +116 -0
- package/.pi/lib/harness-spawn-topology.ts +121 -87
- package/.pi/lib/harness-subagent-submit-registry.ts +10 -0
- package/.pi/lib/harness-subagents-bridge.ts +4 -1
- package/.pi/lib/harness-ui-state.ts +95 -48
- package/.pi/lib/plan-approval/dialog.ts +5 -0
- package/.pi/lib/plan-approval/validate.ts +1 -1
- package/.pi/lib/plan-approval-readiness.ts +32 -0
- package/.pi/lib/plan-debate-gate.ts +154 -114
- package/.pi/lib/plan-task-clarification.ts +158 -0
- package/.pi/prompts/harness-auto.md +2 -2
- package/.pi/prompts/harness-ls-lint-steward.md +43 -0
- package/.pi/prompts/harness-plan.md +58 -8
- package/.pi/prompts/harness-review.md +40 -6
- package/.pi/prompts/harness-run.md +33 -11
- package/.pi/prompts/harness-setup.md +72 -3
- package/.pi/prompts/harness-steer.md +2 -1
- package/.pi/prompts/wiki-save.md +5 -4
- package/.pi/scripts/README.md +8 -0
- package/.pi/scripts/generate-agents-policy-yaml.mjs +14 -2
- package/.pi/scripts/harness-auto-commit-bootstrap.mjs +96 -0
- package/.pi/scripts/harness-cli-verify.sh +47 -0
- package/.pi/scripts/harness-git-churn.mjs +77 -0
- package/.pi/scripts/harness-git-commit.mjs +173 -0
- package/.pi/scripts/harness-ls-lint-bootstrap.mjs +142 -0
- package/.pi/scripts/harness-ls-lint-cli.mjs +184 -0
- package/.pi/scripts/harness-seed-project-contracts.mjs +47 -0
- package/.pi/scripts/harness-sentrux-diagnostics.mjs +230 -0
- package/.pi/scripts/harness-sentrux-report.mjs +256 -0
- package/.pi/scripts/harness-verify.mjs +288 -125
- package/.pi/scripts/ls-lint-rules-sync.mjs +265 -0
- package/.pi/scripts/run-tests.mjs +1 -0
- package/.pi/settings.example.json +1 -0
- package/.sentrux/rules.toml +1 -1
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +25 -0
- package/README.md +13 -4
- package/package.json +5 -1
- package/vendor/pi-vcc/src/hooks/before-compact.ts +86 -60
|
@@ -13,6 +13,7 @@ Read **harness-orchestration** and **harness-review** skills before spawning.
|
|
|
13
13
|
|
|
14
14
|
## Allowed subagents
|
|
15
15
|
|
|
16
|
+
- `harness/sentrux-repair-advisor` (Phase 1b — structural repair plan from OSS diagnostics; before benchmark evaluator)
|
|
16
17
|
- `harness/reviewing/evaluator` (`mode: benchmark` then `mode: verdict`)
|
|
17
18
|
- `harness/reviewing/adversary` (independent red team)
|
|
18
19
|
- `harness/reviewing/tie-breaker` (escalation only when adversary blocks and eval was `conditional_pass`; skip when `--quick`)
|
|
@@ -53,15 +54,24 @@ Ownership: this command **auto-claims** the run for the current Pi session unles
|
|
|
53
54
|
node "$UP_PKG/.pi/scripts/harness-verify.mjs"
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
**Sentrux single-scan rule:** run capture **once** per review unless `artifacts/sentrux-report.json` is missing or `HARNESS_SENTRUX_RESCAN=1`.
|
|
58
|
+
|
|
59
|
+
When `HARNESS_SENTRUX_REQUIRED=true` (or report missing), after verify succeeds:
|
|
57
60
|
|
|
58
61
|
```bash
|
|
59
|
-
node "$UP_PKG/.pi/scripts/harness-sentrux-
|
|
62
|
+
node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out "<run_dir>" --run-id "<run_id>" --signal
|
|
63
|
+
node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report "<run_dir>/artifacts/sentrux-report.json" --out "<run_dir>" --churn
|
|
60
64
|
```
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
Otherwise read existing `artifacts/sentrux-report.json`, `artifacts/sentrux-diagnostics.json`, and `artifacts/sentrux-signal.yaml` from `/harness-run`. If CLI missing (127), record `gate_status: not_installed`. Append or refresh session entry `harness-sentrux-signal`.
|
|
67
|
+
|
|
68
|
+
When `HARNESS_LS_LINT_REQUIRED=true`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
|
|
72
|
+
```
|
|
63
73
|
|
|
64
|
-
Ensure `artifacts/
|
|
74
|
+
Ensure `artifacts/ls-lint-signal.yaml` exists (from `/harness-run` or write from CLI output). Append or refresh `harness-ls-lint-signal`.
|
|
65
75
|
|
|
66
76
|
Run project tests if the approved `PlanPacket` or spawn context lists a test command. Capture stdout paths only — do not paste full logs into the next spawn.
|
|
67
77
|
|
|
@@ -72,10 +82,34 @@ schema_version: "1.0.0"
|
|
|
72
82
|
harness_verify: pass|fail
|
|
73
83
|
sentrux_check: pass|fail|skipped|not_installed
|
|
74
84
|
sentrux_gate: pass|degraded|skipped|not_installed
|
|
85
|
+
ls_lint: pass|fail|skipped|not_installed
|
|
86
|
+
ls_lint_violations: 0
|
|
75
87
|
notes: "…"
|
|
76
88
|
```
|
|
77
89
|
|
|
78
|
-
`harness_artifact_ready({ paths: ["artifacts/benchmark-log.yaml", "artifacts/sentrux-signal.yaml"] })` when written.
|
|
90
|
+
`harness_artifact_ready({ paths: ["artifacts/benchmark-log.yaml", "artifacts/sentrux-report.json", "artifacts/sentrux-diagnostics.json", "artifacts/sentrux-signal.yaml", "artifacts/ls-lint-signal.yaml"] })` when written.
|
|
91
|
+
|
|
92
|
+
## Phase 1b — Sentrux repair advisor (subagent)
|
|
93
|
+
|
|
94
|
+
**Practice:** Close the loop from fitness-function observation → bounded repair directives (ADR 0052). Skip when `artifacts/sentrux-repair-plan.yaml` already exists and `HARNESS_SENTRUX_RESCAN` is unset.
|
|
95
|
+
|
|
96
|
+
Spawn when **any**:
|
|
97
|
+
|
|
98
|
+
- `artifacts/sentrux-report.json` → `check.check_pass` is false, or
|
|
99
|
+
- `gate.status` is `degraded`, or
|
|
100
|
+
- `artifacts/sentrux-diagnostics.json` lists non-empty `diagnostics.complex_functions` or boundary/layer violations
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
subagent({
|
|
104
|
+
agentScope: "both",
|
|
105
|
+
agent: "harness/sentrux-repair-advisor",
|
|
106
|
+
task: "<HarnessSpawnContext run_dir + plan_packet_path + paths: sentrux-report.json, sentrux-diagnostics.json, sentrux-signal.yaml — read only; emit repair plan>"
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Subagent calls **`submit_sentrux_repair_plan`** → `artifacts/sentrux-repair-plan.yaml`.
|
|
111
|
+
|
|
112
|
+
`harness_artifact_ready({ paths: ["artifacts/sentrux-repair-plan.yaml"] })` when written.
|
|
79
113
|
|
|
80
114
|
## Phase 2 — Measure actuals vs plan (benchmark evaluator)
|
|
81
115
|
|
|
@@ -85,7 +119,7 @@ notes: "…"
|
|
|
85
119
|
subagent({
|
|
86
120
|
agentScope: "both",
|
|
87
121
|
agent: "harness/reviewing/evaluator",
|
|
88
|
-
task: "<HarnessSpawnContext mode benchmark + plan_packet_path + run_dir + acceptance_checks + paths: benchmark-log.yaml, sentrux-signal.yaml — treat Sentrux fields as measured structural actuals, not executor goals>"
|
|
122
|
+
task: "<HarnessSpawnContext mode benchmark + plan_packet_path + run_dir + acceptance_checks + paths: benchmark-log.yaml, sentrux-signal.yaml, ls-lint-signal.yaml — treat Sentrux/ls-lint fields as measured structural actuals, not executor goals>"
|
|
89
123
|
})
|
|
90
124
|
```
|
|
91
125
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Execute only against an approved PlanPacket with strict phase gates.
|
|
3
|
-
argument-hint: ""
|
|
4
3
|
---
|
|
5
4
|
|
|
6
5
|
# harness-run
|
|
@@ -38,6 +37,14 @@ The wrapper passes the resolved project root explicitly so Sentrux can find `.se
|
|
|
38
37
|
|
|
39
38
|
Do **not** ask the executor to optimize Sentrux metrics — observation is for `/harness-review` only.
|
|
40
39
|
|
|
40
|
+
When `HARNESS_LS_LINT_REQUIRED=true`, record a pre-execute filename baseline:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Note `violation_count` in run notes (do not block execute on pre-existing violations unless chair policy says otherwise).
|
|
47
|
+
|
|
41
48
|
## Orchestration — Single jelled implementer
|
|
42
49
|
|
|
43
50
|
**Practice:** Peopleware — one accountable team owns delivery; generator–evaluator separation (executor does not self-certify).
|
|
@@ -58,29 +65,44 @@ subagent({ agentScope: "both", agent: "harness/running/executor", task: "<Harnes
|
|
|
58
65
|
|
|
59
66
|
**Practice:** Monitoring actuals vs baseline — in-process fitness functions after generator work.
|
|
60
67
|
|
|
61
|
-
After executor subprocess completes:
|
|
68
|
+
After executor subprocess completes, run **one** Sentrux capture (OSS CLI parse — no MCP/Pro):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out "<run_dir>" --run-id "<run_id>" --signal
|
|
72
|
+
node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report "<run_dir>/artifacts/sentrux-report.json" --out "<run_dir>" --churn
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- If `sentrux-report.json` → `check.check_pass` is false or `gate.status` is `degraded` → set `execution_status: scope_drift` (or `blocked` if unrecoverable); parent runs **`/harness-review`** next (not immediate replan).
|
|
76
|
+
- `harness-sentrux-report.mjs --signal` writes `artifacts/sentrux-signal.yaml` (schema `1.1.0`) with `report_path`, `diagnostics_path`, `quality_signal`, `violation_count`, `degraded_reasons` when present.
|
|
77
|
+
- If `sentrux` is not installed (exit 127), record `gate_status: not_installed` via minimal `write_harness_yaml` and continue.
|
|
78
|
+
|
|
79
|
+
Append session custom entry `harness-sentrux-signal` mirroring the signal file (observation bus / telemetry).
|
|
80
|
+
|
|
81
|
+
`harness_artifact_ready({ paths: ["artifacts/sentrux-report.json", "artifacts/sentrux-diagnostics.json", "artifacts/sentrux-signal.yaml"] })` when written.
|
|
82
|
+
|
|
83
|
+
When `HARNESS_LS_LINT_REQUIRED=true`, after executor completes:
|
|
62
84
|
|
|
63
85
|
```bash
|
|
64
|
-
node "$UP_PKG/.pi/scripts/harness-
|
|
65
|
-
node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate
|
|
86
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
|
|
66
87
|
```
|
|
67
88
|
|
|
68
|
-
- If `
|
|
69
|
-
- Write `artifacts/
|
|
89
|
+
- If `lint_pass` is false → include in `validation_summary`; prefer `scope_drift` when new violations vs pre-run baseline.
|
|
90
|
+
- Write `artifacts/ls-lint-signal.yaml` via `write_harness_yaml`:
|
|
70
91
|
|
|
71
92
|
```yaml
|
|
72
93
|
schema_version: "1.0.0"
|
|
73
94
|
run_id: "<run_id>"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
lint_pass: true|false
|
|
96
|
+
violation_count: 0
|
|
97
|
+
status: pass|fail|skipped|not_installed
|
|
98
|
+
quality_signal_summary: "<one line>"
|
|
77
99
|
recorded_at: "<ISO8601>"
|
|
78
100
|
phase: execute
|
|
79
101
|
```
|
|
80
102
|
|
|
81
|
-
- Append session custom entry `harness-
|
|
103
|
+
- Append session custom entry `harness-ls-lint-signal` with the same fields.
|
|
82
104
|
|
|
83
|
-
`harness_artifact_ready({ paths: ["artifacts/
|
|
105
|
+
`harness_artifact_ready({ paths: ["artifacts/ls-lint-signal.yaml"] })` when written.
|
|
84
106
|
|
|
85
107
|
## Parent rules
|
|
86
108
|
|
|
@@ -15,11 +15,12 @@ Bootstraps the complete ultimate-pi agentic harness: Graphify knowledge graph, C
|
|
|
15
15
|
|---------|------------------|
|
|
16
16
|
| `UP_PKG="$(pwd)"` in an **external** repo | Wrong — scripts live in the npm package. Resolve via `harness-resolve-up-pkg.mjs` (see Step 0). |
|
|
17
17
|
| Re-running 2.1–2.8 manually after CLI verify | Wasteful — trust `harness-cli-verify.sh` output; only fix reported ✗ lines. |
|
|
18
|
-
| Overwriting `AGENTS.md` after graphify | Graphify appends a section — **merge**, do not replace (Step 4.
|
|
18
|
+
| Overwriting `AGENTS.md` after graphify | Graphify appends a section — **merge**, do not replace (Step 4.5). |
|
|
19
19
|
| `sentrux-rules-sync` without project manifest | Use **`harness-sentrux-bootstrap.mjs`** (Step 4.2) — seeds manifest + idempotent rules sync. |
|
|
20
20
|
| Re-running bootstrap with `--force` on unchanged manifest | Wasteful but safe — default bootstrap skips when hash unchanged; `--force` only after manifest edits. |
|
|
21
21
|
| `graph.json` uses `links`, not `edges` | Step 6 stats: `g.get('edges', g.get('links', []))`. |
|
|
22
22
|
| Guessing harness-web / `.env` defaults when `ask_user` is available | **Mandatory `ask_user`** at Step 4.0 unless `--non-interactive`. |
|
|
23
|
+
| WSL2 / SSH without WebView | Set `HARNESS_ASK_USER_UI=tui` in project `.env` (or rely on `auto` TUI fallback). Glimpse needs a display (WSLg or X11). |
|
|
23
24
|
| `sudo apt-get` without passwordless sudo | Skip — report manual fix; do not block the rest of setup. |
|
|
24
25
|
| `graphify codex install` | **Never run** — it writes `.codex/hooks.json`. Harness targets pi only (`graphify install --platform pi`). |
|
|
25
26
|
| Overwriting `.env` | Use `harness-sync-env.mjs` — never rewrite; append missing keys only. |
|
|
@@ -155,7 +156,7 @@ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
|
|
|
155
156
|
# Reinstall everything: bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh" --force
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
**Required (script must exit 0):** scrapling + harness-web smoke, ctx7, ast-grep (`sg`), sentrux (when harness manifest present).
|
|
159
|
+
**Required (script must exit 0):** scrapling + harness-web smoke, ctx7, ast-grep (`sg`), sentrux (when harness manifest present), ls-lint (when naming manifest present).
|
|
159
160
|
|
|
160
161
|
**Warnings allowed:** biome (optional; skipped for non-JS/TS repos or if install fails), gh (if not authenticated), agent-browser (if OS libs need manual `sudo apt-get install`), cocoindex-code (empty corpus on tiny repos; first `[full]` install downloads local embedding model).
|
|
161
162
|
|
|
@@ -326,6 +327,12 @@ sentrux plugin add-standard 2>/dev/null || echo "Plugins already installed or fa
|
|
|
326
327
|
|
|
327
328
|
**Rules.toml bootstrap runs in Step 4.2** (idempotent, merge-safe). Sentrux CLI workflows use the package **`sentrux`** skill (`.agents/skills/sentrux`); no symlink into `.pi/skills/` required.
|
|
328
329
|
|
|
330
|
+
### 2.9 — ls-lint (Filename / Directory Naming)
|
|
331
|
+
|
|
332
|
+
Installed and smoke-tested by `harness-cli-verify.sh` (`npm install -g @ls-lint/ls-lint@2.3.1`).
|
|
333
|
+
|
|
334
|
+
**`.ls-lint.yml` bootstrap runs in Step 4.3** (idempotent, merge-safe). Use skill **`harness-ls-lint-setup`**; sync via `/harness-ls-lint-sync` in pi.
|
|
335
|
+
|
|
329
336
|
## Step 3 — Pi Extension Packages
|
|
330
337
|
|
|
331
338
|
Bundled extensions load from the installed `ultimate-pi` package. The harness lens wrapper at `.pi/extensions/harness-lens.ts` loads `.pi/extensions/lib/harness-lens/` for edit autopatch, secrets blocking, deferred format, and LSP tools. Structural search uses shell `sg` (installed globally by setup); architecture gates use Sentrux. See [ADR 0045](.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md).
|
|
@@ -454,6 +461,18 @@ Rules:
|
|
|
454
461
|
- Re-runs only add keys from `$UP_PKG/.pi/harness/env.harness.template` that are absent (managed block at EOF).
|
|
455
462
|
- Ensure `.env` is gitignored (Step 4.1).
|
|
456
463
|
|
|
464
|
+
### 4.0c — ask_user UI (optional)
|
|
465
|
+
|
|
466
|
+
Harness `ask_user` supports terminal (TUI), headless (CI), and Glimpse WebView (`HARNESS_ASK_USER_UI=auto|tui|glimpse|headless`). Dependencies install with `.pi/npm` during pi package install.
|
|
467
|
+
|
|
468
|
+
| Environment | Recommendation |
|
|
469
|
+
|-------------|----------------|
|
|
470
|
+
| **WSL2 without WSLg / no DISPLAY** | `HARNESS_ASK_USER_UI=tui` in `.env` (default `auto` already falls back) |
|
|
471
|
+
| **Desktop Linux / macOS / WSLg** | `auto` or `glimpse` for richer questionnaires |
|
|
472
|
+
| **CI / `--non-interactive`** | Prompts skipped; do not expect WebView |
|
|
473
|
+
|
|
474
|
+
Append `HARNESS_ASK_USER_UI=tui` to `.env` when WebView is unavailable. The first real `ask_user` reports `ui_backend` and `ui_degraded` in tool details. See ADR 0054.
|
|
475
|
+
|
|
457
476
|
Template keys (placeholders — user fills secrets): `HARNESS_TELEMETRY_ENABLED`, `HARNESS_WEB_*`, `HARNESS_VCC_COMPACTION`, `HARNESS_VCC_DEBUG`, plus commented optional PostHog / Graphify vars.
|
|
458
477
|
|
|
459
478
|
### 4.1 — .gitignore Entries
|
|
@@ -484,6 +503,10 @@ Ensure `.gitignore` contains harness runtime entries (see repo root `.gitignore`
|
|
|
484
503
|
.sentrux/*
|
|
485
504
|
!.sentrux/
|
|
486
505
|
!.sentrux/rules.toml
|
|
506
|
+
|
|
507
|
+
# ls-lint sync meta (.ls-lint.yml is committed)
|
|
508
|
+
.ls-lint/*
|
|
509
|
+
!.ls-lint/
|
|
487
510
|
```
|
|
488
511
|
|
|
489
512
|
### 4.2 — Sentrux rules bootstrap (required)
|
|
@@ -521,7 +544,52 @@ Set up structural regression baseline (optional):
|
|
|
521
544
|
node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate --save 2>/dev/null || echo "Baseline will be saved on first gate run"
|
|
522
545
|
```
|
|
523
546
|
|
|
524
|
-
### 4.3 —
|
|
547
|
+
### 4.3 — ls-lint naming bootstrap (required)
|
|
548
|
+
|
|
549
|
+
**Skill:** invoke **harness-ls-lint-setup** before hand-editing `.ls-lint.yml` or `naming.manifest.json`.
|
|
550
|
+
|
|
551
|
+
From **project root**, run the bundled bootstrap (seeds manifest when missing, syncs `.ls-lint.yml` without clobbering custom YAML):
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs"
|
|
555
|
+
# After editing naming.manifest.json:
|
|
556
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs" --force
|
|
557
|
+
# In pi: /harness-ls-lint-sync (always --force sync)
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
| Command | When |
|
|
561
|
+
|---------|------|
|
|
562
|
+
| `harness-ls-lint-bootstrap.mjs` (no flags) | `/harness-setup`, first install, re-run safe |
|
|
563
|
+
| `harness-ls-lint-bootstrap.mjs --force` | Manifest rules/ignores changed |
|
|
564
|
+
| `ls-lint-rules-sync.mjs --check` | CI / harness-verify drift only |
|
|
565
|
+
| `harness-ls-lint-cli.mjs` | Root-resolving filename checks from harness run dirs |
|
|
566
|
+
| `/harness-ls-lint-sync` | Interactive re-sync from pi |
|
|
567
|
+
|
|
568
|
+
Verify naming:
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" && echo "✓ ls-lint pass" || echo "✗ ls-lint failed"
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### 4.4 — Auto-commit co-author bootstrap (required)
|
|
575
|
+
|
|
576
|
+
**Skill:** invoke **harness-git-commit** before any agent commit.
|
|
577
|
+
|
|
578
|
+
From **project root**:
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs"
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
| Command | When |
|
|
585
|
+
|---------|------|
|
|
586
|
+
| `harness-auto-commit-bootstrap.mjs` | `/harness-setup`, first install, re-run safe |
|
|
587
|
+
| `harness-git-commit.mjs --dry-run --subject "…"` | Preview message + trailer |
|
|
588
|
+
| `harness-git-commit.mjs --type … --scope … --subject "…"` | Commit after `git add` |
|
|
589
|
+
|
|
590
|
+
Edit `.pi/auto-commit.json` to customize `message.template` or `coAuthor` (project overrides package defaults).
|
|
591
|
+
|
|
592
|
+
### 4.5 — Project AGENTS.md
|
|
525
593
|
|
|
526
594
|
**Do not overwrite** an existing `AGENTS.md` — graphify bootstrap may have appended a `## Graphify` section. If missing, create minimal onboarding content; if present, only add harness subsections that are absent.
|
|
527
595
|
|
|
@@ -652,6 +720,7 @@ Output summary table:
|
|
|
652
720
|
| ast-grep | ✓/✗ | AST-aware code search (`sg`)
|
|
653
721
|
| gh CLI | ✓/✗ | Auth: yes/no |
|
|
654
722
|
| sentrux | ✓/✗ | CLI + plugins; rules via Step 4.2 bootstrap |
|
|
723
|
+
| ls-lint | ✓/✗ | CLI; `.ls-lint.yml` via Step 4.3 bootstrap |
|
|
655
724
|
| Sentrux rules.toml | ✓/✗ | `.sentrux/rules.toml` synced from manifest |
|
|
656
725
|
| pi extensions | ✓/✗ | bundled extensions + harness lens wrapper |
|
|
657
726
|
| harness lens | ✓/✗ | `.pi/extensions/harness-lens.ts`; PostHog owns lens telemetry; complements Sentrux architecture signal |
|
|
@@ -15,12 +15,13 @@ Thin orchestrator for the **steer loop** (ADR 0044). Run only after `/harness-re
|
|
|
15
15
|
|
|
16
16
|
## Steps
|
|
17
17
|
|
|
18
|
-
1. Read `artifacts/review-outcome.yaml`, `artifacts/repair-brief.yaml`, `plan_packet_path` (paths only — do not paste bodies into tool args).
|
|
18
|
+
1. Read `artifacts/review-outcome.yaml`, `artifacts/repair-brief.yaml`, `plan_packet_path` (paths only — do not paste bodies into tool args). When present, `repair-brief.yaml` already merges `artifacts/sentrux-repair-plan.yaml` (`[sentrux:…]` directives).
|
|
19
19
|
2. Update `artifacts/steer-state.yaml` (`attempt`, `max_attempts`, `active: true`).
|
|
20
20
|
3. Set policy phase to **execute** before spawning executor (required for mutating tools).
|
|
21
21
|
4. One `ask_user` steer gate unless `run-context.steer_approved` is already true.
|
|
22
22
|
5. Spawn **`harness/running/executor`** with `HarnessSpawnContext.mode: repair` and `repair_brief_path: artifacts/repair-brief.yaml`. Repair uses the same hash-anchored `read`/`edit`, batching, and pre-handoff verification rules as `/harness-run` (ADR 0051).
|
|
23
23
|
6. Optional: `node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate --save` after repair to refresh baseline (ADR 0044).
|
|
24
|
+
7. Optional: `node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs"` after repair to confirm filename conventions (ADR 0052).
|
|
24
25
|
7. `next_command`: **`/harness-review`** (always re-verify; tiered adversary on attempts 2+ per practice-map).
|
|
25
26
|
|
|
26
27
|
## Forbidden
|
package/.pi/prompts/wiki-save.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Save the current conversation or a specific insight as a structured note in the knowledge graph.
|
|
3
|
+
argument-hint: "[name|session|decision <name>]"
|
|
3
4
|
---
|
|
4
5
|
|
|
5
6
|
Read the `graphify` skill for context on graphify-out/ structure.
|
|
@@ -9,10 +10,10 @@ so it can be graphified and queried. Then run `graphify ./raw --update` to
|
|
|
9
10
|
incorporate it into the knowledge graph.
|
|
10
11
|
|
|
11
12
|
Usage:
|
|
12
|
-
- `/save` — analyze the full conversation and save the most valuable content
|
|
13
|
-
- `/save [name]` — save with a specific note title
|
|
14
|
-
- `/save session` — save a complete session summary
|
|
15
|
-
- `/save decision [name]` — save as a design/governance decision (also mirror into `.pi/harness/incidents/` when incident tracking is required)
|
|
13
|
+
- `/wiki-save` — analyze the full conversation and save the most valuable content
|
|
14
|
+
- `/wiki-save [name]` — save with a specific note title
|
|
15
|
+
- `/wiki-save session` — save a complete session summary
|
|
16
|
+
- `/wiki-save decision [name]` — save as a design/governance decision (also mirror into `.pi/harness/incidents/` when incident tracking is required)
|
|
16
17
|
|
|
17
18
|
Save to: `./raw/[sanitized-name].md`
|
|
18
19
|
Then: `graphify ./raw --update`
|
package/.pi/scripts/README.md
CHANGED
|
@@ -28,7 +28,15 @@ From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackag
|
|
|
28
28
|
| Sentrux rules re-sync after manifest edit | `node "$UP_PKG/.pi/scripts/harness-sentrux-bootstrap.mjs" --force` or `/harness-sentrux-sync` |
|
|
29
29
|
| Sentrux rules drift check (CI) | `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --check` |
|
|
30
30
|
| Sentrux run/review check or gate (root-resolving) | `node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" check` / `gate [--save]` |
|
|
31
|
+
| Sentrux single-scan report + signal (ADR 0052) | `node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out <run_dir> --run-id <id> --signal` |
|
|
32
|
+
| Sentrux diagnostics synthesis | `node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report <run_dir>/artifacts/sentrux-report.json --out <run_dir> [--churn]` |
|
|
33
|
+
| ls-lint naming bootstrap (harness-setup) | `node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs"` |
|
|
34
|
+
| ls-lint naming re-sync after manifest edit | `node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs" --force` or `/harness-ls-lint-sync` |
|
|
35
|
+
| ls-lint config drift check (CI) | `node "$UP_PKG/.pi/scripts/ls-lint-rules-sync.mjs" --check` |
|
|
36
|
+
| ls-lint filename check (root-resolving) | `node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs` [`--json`] |
|
|
31
37
|
| Resolve package root (`UP_PKG`) | `node "$UP_PKG/.pi/scripts/harness-resolve-up-pkg.mjs"` |
|
|
38
|
+
| Auto-commit config bootstrap | `node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs"` |
|
|
39
|
+
| Git commit + co-author trailer | `node "$UP_PKG/.pi/scripts/harness-git-commit.mjs" --subject "…"` [`--dry-run`] |
|
|
32
40
|
| Project `.env` (append-only) | `node "$UP_PKG/.pi/scripts/harness-sync-env.mjs"` (`--create-missing` after user confirms) |
|
|
33
41
|
| Harness lens extension | `.pi/extensions/harness-lens.ts` → `.pi/lib/harness-lens/index.ts` (loaded by `.pi/extensions`; PostHog owns lens telemetry) |
|
|
34
42
|
|
|
@@ -32,6 +32,8 @@ const SUBMIT_BY_AGENT = {
|
|
|
32
32
|
"harness/trace-librarian": ["submit_human_required"],
|
|
33
33
|
"harness/incident-recorder": ["submit_human_required"],
|
|
34
34
|
"harness/sentrux-steward": ["submit_sentrux_manifest_proposal"],
|
|
35
|
+
"harness/sentrux-repair-advisor": ["submit_sentrux_repair_plan"],
|
|
36
|
+
"harness/ls-lint-steward": ["submit_ls_lint_manifest_proposal"],
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
function parseFrontmatter(content) {
|
|
@@ -48,7 +50,12 @@ function kindFor(id) {
|
|
|
48
50
|
if (id === "harness/reviewing/tie-breaker") return "tie_breaker";
|
|
49
51
|
if (id === "harness/trace-librarian") return "trace";
|
|
50
52
|
if (id === "harness/incident-recorder") return "incident";
|
|
51
|
-
if (id === "harness/sentrux-
|
|
53
|
+
if (id === "harness/sentrux-repair-advisor") return "evaluator";
|
|
54
|
+
if (
|
|
55
|
+
id === "harness/sentrux-steward" ||
|
|
56
|
+
id === "harness/sentrux-bootstrap" ||
|
|
57
|
+
id === "harness/ls-lint-steward"
|
|
58
|
+
)
|
|
52
59
|
return "planner";
|
|
53
60
|
return "other";
|
|
54
61
|
}
|
|
@@ -79,7 +86,12 @@ async function main() {
|
|
|
79
86
|
|
|
80
87
|
const kinds = {
|
|
81
88
|
planner: { tools: KIND_BASE.planner, extensions: false, read_only: true },
|
|
82
|
-
executor: {
|
|
89
|
+
executor: {
|
|
90
|
+
tools: KIND_BASE.executor,
|
|
91
|
+
extensions: true,
|
|
92
|
+
extension_bundle: "executor",
|
|
93
|
+
read_only: false,
|
|
94
|
+
},
|
|
83
95
|
evaluator: { tools: KIND_BASE.evaluator, extensions: false, read_only: true },
|
|
84
96
|
adversary: { tools: KIND_BASE.adversary, extensions: false, read_only: true },
|
|
85
97
|
tie_breaker: {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Idempotent auto-commit config bootstrap for harness projects.
|
|
4
|
+
*
|
|
5
|
+
* Seeds PROJECT/.pi/auto-commit.json from the ultimate-pi package template when missing.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs" [PROJECT_ROOT] [--check]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFile, writeFile, mkdir, access, copyFile } from "node:fs/promises";
|
|
12
|
+
import { constants } from "node:fs";
|
|
13
|
+
import { join, dirname, basename } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { validateAutoCommitConfig } from "../lib/harness-auto-commit-config.mjs";
|
|
16
|
+
|
|
17
|
+
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const UP_PKG = join(SCRIPT_DIR, "..", "..");
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2).filter((a) => !a.startsWith("-"));
|
|
21
|
+
const checkOnly = process.argv.includes("--check");
|
|
22
|
+
const PROJECT_ROOT = args[0] || process.cwd();
|
|
23
|
+
const CONFIG_PATH = join(PROJECT_ROOT, ".pi", "auto-commit.json");
|
|
24
|
+
const TEMPLATE_PATH = join(UP_PKG, ".pi", "auto-commit.json");
|
|
25
|
+
|
|
26
|
+
async function fileExists(path) {
|
|
27
|
+
try {
|
|
28
|
+
await access(path, constants.R_OK);
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function resolveScopeDefault(root) {
|
|
36
|
+
const pkgPath = join(root, "package.json");
|
|
37
|
+
if (await fileExists(pkgPath)) {
|
|
38
|
+
try {
|
|
39
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
|
|
40
|
+
if (typeof pkg.name === "string" && pkg.name.trim()) {
|
|
41
|
+
return pkg.name.trim().replace(/^@/, "").split("/").pop() ?? pkg.name;
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
/* ignore */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return basename(root) || "project";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function main() {
|
|
51
|
+
if (!(await fileExists(TEMPLATE_PATH))) {
|
|
52
|
+
console.error(
|
|
53
|
+
"harness-auto-commit-bootstrap: missing package template",
|
|
54
|
+
TEMPLATE_PATH,
|
|
55
|
+
);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (await fileExists(CONFIG_PATH)) {
|
|
60
|
+
if (checkOnly) {
|
|
61
|
+
const config = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
|
|
62
|
+
validateAutoCommitConfig(config);
|
|
63
|
+
console.log(`harness-auto-commit-bootstrap: ok ${CONFIG_PATH}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log(
|
|
67
|
+
"harness-auto-commit-bootstrap: config present (edit .pi/auto-commit.json to customize)",
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (checkOnly) {
|
|
73
|
+
console.error(
|
|
74
|
+
`harness-auto-commit-bootstrap: missing ${CONFIG_PATH} (run without --check to seed)`,
|
|
75
|
+
);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await mkdir(dirname(CONFIG_PATH), { recursive: true });
|
|
80
|
+
await copyFile(TEMPLATE_PATH, CONFIG_PATH);
|
|
81
|
+
const config = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
|
|
82
|
+
const scope = await resolveScopeDefault(PROJECT_ROOT);
|
|
83
|
+
if (config.message && typeof config.message === "object") {
|
|
84
|
+
config.message.scopeDefault = scope;
|
|
85
|
+
}
|
|
86
|
+
validateAutoCommitConfig(config);
|
|
87
|
+
await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, "\t")}\n`, "utf-8");
|
|
88
|
+
console.log(
|
|
89
|
+
`harness-auto-commit-bootstrap: seeded -> ${CONFIG_PATH} (message.scopeDefault: ${scope})`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
main().catch((err) => {
|
|
94
|
+
console.error(err);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
});
|
|
@@ -324,6 +324,37 @@ verify_gh() {
|
|
|
324
324
|
fi
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
verify_ls_lint() {
|
|
328
|
+
log "[ls-lint]"
|
|
329
|
+
npm_global_install "@ls-lint/ls-lint@2.3.1" "ls-lint" || {
|
|
330
|
+
fail "ls-lint npm install"
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
if ! ls-lint --version &>/dev/null; then
|
|
334
|
+
fail "ls-lint --version failed"
|
|
335
|
+
return
|
|
336
|
+
fi
|
|
337
|
+
_bootstrap="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-ls-lint-bootstrap.mjs"
|
|
338
|
+
if [ -f "$_bootstrap" ]; then
|
|
339
|
+
node "$_bootstrap" --force 2>/dev/null ||
|
|
340
|
+
warn "ls-lint bootstrap failed (see harness-ls-lint-setup skill)"
|
|
341
|
+
fi
|
|
342
|
+
_cli="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-ls-lint-cli.mjs"
|
|
343
|
+
if [ -f "$_cli" ]; then
|
|
344
|
+
if node "$_cli" 2>/dev/null; then
|
|
345
|
+
pass "ls-lint $(ls-lint --version 2>/dev/null | head -1)"
|
|
346
|
+
else
|
|
347
|
+
fail "ls-lint filename check failed (fix violations or tune naming.manifest.json)"
|
|
348
|
+
fi
|
|
349
|
+
else
|
|
350
|
+
if ls-lint 2>/dev/null; then
|
|
351
|
+
pass "ls-lint $(ls-lint --version 2>/dev/null | head -1)"
|
|
352
|
+
else
|
|
353
|
+
fail "ls-lint check failed"
|
|
354
|
+
fi
|
|
355
|
+
fi
|
|
356
|
+
}
|
|
357
|
+
|
|
327
358
|
verify_sentrux() {
|
|
328
359
|
log "[sentrux]"
|
|
329
360
|
if ! have_cmd sentrux || [ "$FORCE" = true ]; then
|
|
@@ -361,7 +392,23 @@ verify_cocoindex
|
|
|
361
392
|
verify_biome
|
|
362
393
|
verify_sg
|
|
363
394
|
verify_gh
|
|
395
|
+
verify_auto_commit() {
|
|
396
|
+
log "[auto-commit]"
|
|
397
|
+
_git_commit="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-git-commit.mjs"
|
|
398
|
+
if [ ! -f "$_git_commit" ]; then
|
|
399
|
+
warn "harness-git-commit.mjs missing (package incomplete)"
|
|
400
|
+
return
|
|
401
|
+
fi
|
|
402
|
+
if node "$_git_commit" --print-message --subject "harness-cli-verify" 2>/dev/null | grep -qi 'Co-authored-by:'; then
|
|
403
|
+
pass "harness-git-commit (co-author trailer)"
|
|
404
|
+
else
|
|
405
|
+
fail "harness-git-commit --print-message missing Co-authored-by trailer"
|
|
406
|
+
fi
|
|
407
|
+
}
|
|
408
|
+
|
|
364
409
|
verify_sentrux
|
|
410
|
+
verify_ls_lint
|
|
411
|
+
verify_auto_commit
|
|
365
412
|
|
|
366
413
|
log ""
|
|
367
414
|
if [ "$FAILURES" -gt 0 ]; then
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Optional git churn map (path → commit count) for Sentrux hotspot scoring.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node harness-git-churn.mjs [--root <PROJECT_ROOT>] [--days 14]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
import { resolveSentruxProjectRoot, takeRootArg } from "../lib/harness-sentrux-root.mjs";
|
|
11
|
+
|
|
12
|
+
function runGit(args, cwd) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const child = spawn("git", args, { cwd, env: process.env });
|
|
15
|
+
let stdout = "";
|
|
16
|
+
let stderr = "";
|
|
17
|
+
child.stdout?.on("data", (c) => {
|
|
18
|
+
stdout += c.toString();
|
|
19
|
+
});
|
|
20
|
+
child.stderr?.on("data", (c) => {
|
|
21
|
+
stderr += c.toString();
|
|
22
|
+
});
|
|
23
|
+
child.on("error", reject);
|
|
24
|
+
child.on("close", (code) => {
|
|
25
|
+
if (code !== 0) {
|
|
26
|
+
reject(new Error(stderr.trim() || `git exit ${code}`));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
resolve(stdout);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} projectRoot
|
|
36
|
+
* @param {{ days?: number }} opts
|
|
37
|
+
* @returns {Promise<Record<string, number>>}
|
|
38
|
+
*/
|
|
39
|
+
export async function loadGitChurn(projectRoot, opts = {}) {
|
|
40
|
+
const days = opts.days ?? 14;
|
|
41
|
+
const since = `${days} days ago`;
|
|
42
|
+
const stdout = await runGit(
|
|
43
|
+
[
|
|
44
|
+
"log",
|
|
45
|
+
`--since=${since}`,
|
|
46
|
+
"--name-only",
|
|
47
|
+
"--pretty=format:",
|
|
48
|
+
],
|
|
49
|
+
projectRoot,
|
|
50
|
+
);
|
|
51
|
+
const counts = {};
|
|
52
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
53
|
+
const path = line.trim();
|
|
54
|
+
if (!path || path.startsWith(".")) continue;
|
|
55
|
+
counts[path] = (counts[path] || 0) + 1;
|
|
56
|
+
}
|
|
57
|
+
return counts;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function main() {
|
|
61
|
+
const { args, explicitRoot } = takeRootArg(process.argv.slice(2));
|
|
62
|
+
let days = 14;
|
|
63
|
+
for (let i = 0; i < args.length; i++) {
|
|
64
|
+
if (args[i] === "--days") days = Number.parseInt(args[++i] || "14", 10);
|
|
65
|
+
}
|
|
66
|
+
const root = await resolveSentruxProjectRoot(explicitRoot);
|
|
67
|
+
const map = await loadGitChurn(root, { days });
|
|
68
|
+
process.stdout.write(`${JSON.stringify(map, null, 2)}\n`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const isMain = process.argv[1]?.endsWith("harness-git-churn.mjs");
|
|
72
|
+
if (isMain) {
|
|
73
|
+
main().catch((err) => {
|
|
74
|
+
console.error(err.message || err);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
});
|
|
77
|
+
}
|