@skillcap/gdh 0.5.0 → 0.7.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/INSTALL-BUNDLE.json +1 -1
- package/README.md +66 -85
- package/node_modules/@gdh/adapters/dist/claude-settings-patch.d.ts +74 -0
- package/node_modules/@gdh/adapters/dist/claude-settings-patch.d.ts.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-settings-patch.js +158 -0
- package/node_modules/@gdh/adapters/dist/claude-settings-patch.js.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-statusline-render.d.ts +51 -0
- package/node_modules/@gdh/adapters/dist/claude-statusline-render.d.ts.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-statusline-render.js +80 -0
- package/node_modules/@gdh/adapters/dist/claude-statusline-render.js.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-update-hook-render.d.ts +35 -0
- package/node_modules/@gdh/adapters/dist/claude-update-hook-render.d.ts.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-update-hook-render.js +76 -0
- package/node_modules/@gdh/adapters/dist/claude-update-hook-render.js.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-update-worker-render.d.ts +28 -0
- package/node_modules/@gdh/adapters/dist/claude-update-worker-render.d.ts.map +1 -0
- package/node_modules/@gdh/adapters/dist/claude-update-worker-render.js +99 -0
- package/node_modules/@gdh/adapters/dist/claude-update-worker-render.js.map +1 -0
- package/node_modules/@gdh/adapters/dist/index.d.ts +12 -2
- package/node_modules/@gdh/adapters/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/adapters/dist/index.js +382 -244
- package/node_modules/@gdh/adapters/dist/index.js.map +1 -1
- package/node_modules/@gdh/adapters/dist/self-update-mechanics.d.ts +51 -0
- package/node_modules/@gdh/adapters/dist/self-update-mechanics.d.ts.map +1 -0
- package/node_modules/@gdh/adapters/dist/self-update-mechanics.js +155 -0
- package/node_modules/@gdh/adapters/dist/self-update-mechanics.js.map +1 -0
- package/node_modules/@gdh/adapters/package.json +8 -8
- package/node_modules/@gdh/authoring/dist/index.d.ts +1 -0
- package/node_modules/@gdh/authoring/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/authoring/dist/index.js +1 -0
- package/node_modules/@gdh/authoring/dist/index.js.map +1 -1
- package/node_modules/@gdh/authoring/dist/writePinnedVersion.d.ts +17 -0
- package/node_modules/@gdh/authoring/dist/writePinnedVersion.d.ts.map +1 -0
- package/node_modules/@gdh/authoring/dist/writePinnedVersion.js +50 -0
- package/node_modules/@gdh/authoring/dist/writePinnedVersion.js.map +1 -0
- package/node_modules/@gdh/authoring/package.json +5 -2
- package/node_modules/@gdh/cli/dist/index.d.ts +15 -0
- package/node_modules/@gdh/cli/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/cli/dist/index.js +119 -20
- package/node_modules/@gdh/cli/dist/index.js.map +1 -1
- package/node_modules/@gdh/cli/dist/migrate.d.ts +1 -1
- package/node_modules/@gdh/cli/dist/migrate.d.ts.map +1 -1
- package/node_modules/@gdh/cli/dist/migrate.js +44 -3
- package/node_modules/@gdh/cli/dist/migrate.js.map +1 -1
- package/node_modules/@gdh/cli/dist/self-update.d.ts +3 -0
- package/node_modules/@gdh/cli/dist/self-update.d.ts.map +1 -0
- package/node_modules/@gdh/cli/dist/self-update.js +235 -0
- package/node_modules/@gdh/cli/dist/self-update.js.map +1 -0
- package/node_modules/@gdh/cli/dist/update-banner.d.ts +42 -0
- package/node_modules/@gdh/cli/dist/update-banner.d.ts.map +1 -0
- package/node_modules/@gdh/cli/dist/update-banner.js +49 -0
- package/node_modules/@gdh/cli/dist/update-banner.js.map +1 -0
- package/node_modules/@gdh/cli/package.json +10 -10
- package/node_modules/@gdh/core/dist/dev-mode.d.ts +13 -0
- package/node_modules/@gdh/core/dist/dev-mode.d.ts.map +1 -0
- package/node_modules/@gdh/core/dist/dev-mode.js +21 -0
- package/node_modules/@gdh/core/dist/dev-mode.js.map +1 -0
- package/node_modules/@gdh/core/dist/index.d.ts +9 -4
- package/node_modules/@gdh/core/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/core/dist/index.js +8 -5
- package/node_modules/@gdh/core/dist/index.js.map +1 -1
- package/node_modules/@gdh/core/dist/update-cache.d.ts +46 -0
- package/node_modules/@gdh/core/dist/update-cache.d.ts.map +1 -0
- package/node_modules/@gdh/core/dist/update-cache.js +90 -0
- package/node_modules/@gdh/core/dist/update-cache.js.map +1 -0
- package/node_modules/@gdh/core/dist/update-probe.d.ts +102 -0
- package/node_modules/@gdh/core/dist/update-probe.d.ts.map +1 -0
- package/node_modules/@gdh/core/dist/update-probe.js +195 -0
- package/node_modules/@gdh/core/dist/update-probe.js.map +1 -0
- package/node_modules/@gdh/core/package.json +1 -1
- package/node_modules/@gdh/docs/package.json +2 -2
- package/node_modules/@gdh/mcp/dist/index.d.ts +20 -0
- package/node_modules/@gdh/mcp/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/mcp/dist/index.js +39 -2
- package/node_modules/@gdh/mcp/dist/index.js.map +1 -1
- package/node_modules/@gdh/mcp/package.json +8 -8
- package/node_modules/@gdh/observability/dist/guidance-audit.js +2 -1
- package/node_modules/@gdh/observability/dist/guidance-audit.js.map +1 -1
- package/node_modules/@gdh/observability/package.json +2 -2
- package/node_modules/@gdh/runtime/package.json +2 -2
- package/node_modules/@gdh/scan/package.json +3 -3
- package/node_modules/@gdh/verify/package.json +7 -7
- package/package.json +11 -11
package/INSTALL-BUNDLE.json
CHANGED
package/README.md
CHANGED
|
@@ -1,128 +1,111 @@
|
|
|
1
1
|
# GDH
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Godot authoring and validation harness for AI agents
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@skillcap/gdh)
|
|
6
|
+
[](LICENSE)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- scaffold the minimal durable GDH project surface under `.gdh/`
|
|
9
|
-
- configure supported agents against one canonical guidance chain
|
|
10
|
-
- search and fetch official version-aware Godot docs through stable CLI and MCP surfaces with explicit provenance plus bounded machine-local cache fallback
|
|
11
|
-
- run authoring and runtime validation through explicit, inspectable surfaces
|
|
12
|
-
- make evidence-backed "done" decisions instead of trusting confidence alone
|
|
8
|
+
GDH detects your Godot project, configures your AI agents, and gives them the context they need to author, validate, and verify Godot work with real evidence instead of guesswork.
|
|
13
9
|
|
|
14
|
-
GDH
|
|
10
|
+

|
|
15
11
|
|
|
16
|
-
##
|
|
12
|
+
## Install
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
```sh
|
|
15
|
+
npx -y @skillcap/gdh@0.7.0 setup
|
|
16
|
+
```
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
Replace `0.7.0` with the GDH version you want to pin this project to. `gdh setup` records the pinned version in `.gdh/project.yaml`; every managed surface generated from that config invokes GDH at that exact pinned version, so future sessions stay reproducible.
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
The full install and update contract lives in [install-and-update.md](docs/development/install-and-update.md).
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
## Requirements
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
- **Node.js** ≥ 20 (per `package.json` engines)
|
|
25
|
+
- **Godot** 4.4 through 4.6 stable — see [runtime-support-matrix.md](docs/development/runtime-support-matrix.md) for the full bounded support contract
|
|
26
|
+
- **Host OS** macOS for the currently supported development environment
|
|
27
|
+
- **Yarn 4** via `corepack` (required only for contributors working on the GDH implementation repo itself; end users invoking `npx @skillcap/gdh` do not need Yarn)
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
- curated operator-facing release notes live under [docs/releases/](docs/releases/README.md)
|
|
30
|
-
- retained internal pre-public release history lives under [docs/releases/internal/](docs/releases/internal/README.md) and `internal/v...` tags
|
|
31
|
-
- milestone archive history is tracked separately in `.planning/` and under `milestone/vX.Y` tags, not product release tags
|
|
29
|
+
## Quick Start
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
```sh
|
|
32
|
+
# 1. Run setup in your Godot project
|
|
33
|
+
npx -y @skillcap/gdh@0.7.0 setup
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
- [ROADMAP.md](.planning/ROADMAP.md)
|
|
37
|
-
- [docs/development/runtime-release-readiness.md](docs/development/runtime-release-readiness.md)
|
|
38
|
-
- [docs/development/runtime-support-matrix.md](docs/development/runtime-support-matrix.md)
|
|
35
|
+
# 2. Open your AI agent (Claude, Cursor, Codex) in the repo
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
# 3. Run the onboarding handoff
|
|
38
|
+
/gdh-onboard
|
|
39
|
+
```
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
That's it. GDH handles detection, scaffolding, and agent configuration. The agent takes over from `/gdh-onboard`.
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
## What GDH Does
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
### Detects your Godot target
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
npx -y @skillcap/gdh@0.4.1 setup
|
|
50
|
-
```
|
|
47
|
+
Finds the Godot project inside your repo or monorepo automatically. Handles nested targets, worktrees, and non-obvious layouts.
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
### Configures your AI agents
|
|
53
50
|
|
|
54
|
-
|
|
51
|
+
Scaffolds a minimal `.gdh/` surface and wires up agent-specific guidance so Claude, Cursor, and Codex know how to work with your project from the first session — all pinned to one canonical guidance chain.
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
The canonical public git-versus-npm boundary for maintainers lives in [docs/development/open-source-maintainer-contract.md](docs/development/open-source-maintainer-contract.md).
|
|
53
|
+
### Searches Godot docs with version awareness
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
Fetches and searches official Godot documentation through CLI and MCP surfaces, pinned to your project's engine version. Bounded machine-local cache, explicit provenance.
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
gdh setup
|
|
63
|
-
```
|
|
57
|
+
### Validates with evidence
|
|
64
58
|
|
|
65
|
-
|
|
59
|
+
Runs authoring and runtime checks through inspectable surfaces. Agents get structured results they can reason about, not just pass/fail.
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
### Signals completion with evidence
|
|
68
62
|
|
|
69
|
-
|
|
63
|
+
Evidence-backed "done" decisions replace confidence-based guessing. Run records capture what happened; verification scenarios define what must be true.
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
- finds the Godot target, including nested targets inside monorepos
|
|
73
|
-
- asks which supported agents to configure
|
|
74
|
-
- applies the minimal GDH repo surface and agent reinforcement
|
|
75
|
-
- installs the agent-specific `/gdh-onboard` handoff entrypoint for the selected agents
|
|
76
|
-
- always ends with the exact next step to continue in an agent
|
|
65
|
+
### What GDH does not do
|
|
77
66
|
|
|
78
|
-
|
|
67
|
+
GDH is not a general project planner, PR/release orchestrator, or generic codebase knowledge system. It does not manage non-Godot runtimes. Use it for Godot-specific authoring, validation, worktree/import handling, and evidence-backed done decisions — and hand the rest to tools built for those jobs.
|
|
79
68
|
|
|
80
|
-
|
|
81
|
-
2. Run `gdh setup`.
|
|
82
|
-
3. Open one of the configured agents in the repo.
|
|
83
|
-
4. Run `/gdh-onboard`.
|
|
69
|
+
## Core Concepts
|
|
84
70
|
|
|
85
|
-
|
|
71
|
+
| Concept | What it is |
|
|
72
|
+
|---------|-----------|
|
|
73
|
+
| **Target** | The Godot project root or subproject GDH operates on |
|
|
74
|
+
| **Run configuration** | How GDH launches a target |
|
|
75
|
+
| **Verification scenario** | What GDH verifies once a target is running |
|
|
76
|
+
| **Run record** | Structured evidence from one execution or verification run |
|
|
86
77
|
|
|
87
|
-
|
|
78
|
+
## Daily Usage
|
|
88
79
|
|
|
89
|
-
|
|
80
|
+
Normal usage happens through your AI agent, not by memorizing CLI commands.
|
|
90
81
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- ask the human only for unresolved facts GDH could not infer safely
|
|
95
|
-
- run the first safe readiness and validation checks
|
|
96
|
-
- report what is ready, what is blocked, and what the next development step is
|
|
82
|
+
1. Open your agent in the repo
|
|
83
|
+
2. The agent uses GDH surfaces to check readiness, pick validation, run checks
|
|
84
|
+
3. You intervene only for narrow decisions or missing environment input
|
|
97
85
|
|
|
98
|
-
|
|
86
|
+
The CLI exists for advanced operators, debugging, and automation. See [Advanced CLI Usage](docs/development/advanced-cli-usage.md).
|
|
99
87
|
|
|
100
|
-
|
|
88
|
+
## Documentation
|
|
101
89
|
|
|
102
|
-
|
|
90
|
+
- [Install and Update](docs/development/install-and-update.md) — alternative install modes, updating
|
|
91
|
+
- [Advanced CLI Usage](docs/development/advanced-cli-usage.md) — raw CLI reference
|
|
92
|
+
- [Runtime Support Matrix](docs/development/runtime-support-matrix.md) — what's supported today
|
|
93
|
+
- [Runtime Release Readiness](docs/development/runtime-release-readiness.md) — current release stage
|
|
103
94
|
|
|
104
|
-
|
|
105
|
-
2. The agent uses GDH surfaces to inspect readiness, choose validation, and run the right checks.
|
|
106
|
-
3. The human intervenes only when GDH or the project needs a narrow decision or missing environment input.
|
|
95
|
+
## Status
|
|
107
96
|
|
|
108
|
-
|
|
97
|
+
GDH now ships the current `0.7.0` release line and remains ready for broader internal use within the documented support contract. The current release line is `0.7.0` at the `broader_internal_release` stage.
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
The release-stage label applies only to the documented support window in [runtime-support-matrix.md](docs/development/runtime-support-matrix.md) and [runtime-release-readiness.md](docs/development/runtime-release-readiness.md). It is not a blanket claim that every Godot project shape is supported or that this implementation checkout should behave like a GDH-managed target repo.
|
|
111
100
|
|
|
112
|
-
|
|
101
|
+
This repository is the GDH implementation repo. Treat `gdh setup`, `gdh status`, and `/gdh-onboard` here as product smoke-check paths, not as the primary way to learn the state of GDH itself — authoritative product truth lives in the source, tests, release artifacts, and `.planning/` surfaces in this checkout.
|
|
113
102
|
|
|
114
|
-
|
|
115
|
-
- [Advanced CLI Usage](docs/development/advanced-cli-usage.md)
|
|
116
|
-
- [Open-Source Maintainer Contract](docs/development/open-source-maintainer-contract.md)
|
|
117
|
-
- [Runtime Support Matrix](docs/development/runtime-support-matrix.md)
|
|
118
|
-
- [Runtime Release Readiness](docs/development/runtime-release-readiness.md)
|
|
103
|
+
### Support
|
|
119
104
|
|
|
120
|
-
|
|
105
|
+
- **Issues:** [github.com/Skillcap-Studio/gdh/issues](https://github.com/Skillcap-Studio/gdh/issues) — reproducible bugs, concrete feature requests, documentation problems
|
|
106
|
+
- **Contributing:** see [CONTRIBUTING.md](CONTRIBUTING.md) for workflow and commit policy
|
|
121
107
|
|
|
122
|
-
|
|
123
|
-
- `run configuration`: how GDH launches a target
|
|
124
|
-
- `verification scenario`: what GDH verifies once a target is running
|
|
125
|
-
- `run record`: the structured evidence GDH keeps from one runtime execution or verification run
|
|
108
|
+
This repo does not currently promise a dedicated public support channel for project-specific troubleshooting; keep issues focused and reproducible.
|
|
126
109
|
|
|
127
110
|
## Development
|
|
128
111
|
|
|
@@ -134,8 +117,6 @@ If you are working on the GDH implementation repo itself, use these contributor
|
|
|
134
117
|
- [docs/development/open-source-maintainer-contract.md](docs/development/open-source-maintainer-contract.md)
|
|
135
118
|
- [fixtures/README.md](fixtures/README.md)
|
|
136
119
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
When you are cutting a GDH release inside this repo with Claude, Codex, or Cursor, use `/gdh-release` so the agent loads the canonical release guidance and runs `corepack yarn check:public-release` before `release:apply`. Use `/gdh-migration-verify` for the dedicated migration-proof step before the final release gate and apply step. Use `/gdh-publish` only when you explicitly want the already-cut release published to npm; `/gdh-release` stops before npm publish.
|
|
120
|
+
When cutting a GDH release in this repo with Claude, Codex, or Cursor, use `/gdh-release` so the agent loads the canonical release guidance and runs `corepack yarn check:public-release` before `release:apply`. Use `/gdh-migration-verify` for the dedicated migration-proof step before the final release gate. Use `/gdh-publish` only when you explicitly want an already-cut release published to npm.
|
|
140
121
|
|
|
141
|
-
|
|
122
|
+
Release history lives in the generated root [CHANGELOG.md](CHANGELOG.md); curated release notes live under [docs/releases/](docs/releases/README.md).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative path of the Claude Code per-project settings file in a managed
|
|
3
|
+
* target. This is the file GDH patches to register its SessionStart hook.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
6
|
+
/**
|
|
7
|
+
* Exact command literal GDH uses to invoke the SessionStart parent hook.
|
|
8
|
+
*
|
|
9
|
+
* Idempotency in `patchClaudeSettingsForGdhSessionStart` is gated on an exact
|
|
10
|
+
* match against this literal. Keep it in one place so the renderer, the
|
|
11
|
+
* settings patcher, and `gdh verify drift` all agree on the canonical
|
|
12
|
+
* command string.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GDH_SESSION_START_HOOK_COMMAND = "node .claude/hooks/gdh-check-update.js";
|
|
15
|
+
/**
|
|
16
|
+
* Patch-merge .claude/settings.json so the GDH SessionStart hook is
|
|
17
|
+
* registered idempotently without clobbering sibling content.
|
|
18
|
+
*
|
|
19
|
+
* Strategy A (locked by Plan 02): exact command-literal match.
|
|
20
|
+
* - Parses `existingContent` as JSON. If empty / invalid / non-object,
|
|
21
|
+
* starts from a fresh `{}` — treating corruption as "last writer wins"
|
|
22
|
+
* for this narrow hook entry.
|
|
23
|
+
* - Ensures `hooks.SessionStart` exists as an array.
|
|
24
|
+
* - Appends the GDH entry ONLY if no group already contains a command
|
|
25
|
+
* whose `command` string equals `GDH_SESSION_START_HOOK_COMMAND`.
|
|
26
|
+
* - Preserves every other top-level key (e.g. env, and the sibling
|
|
27
|
+
* status-line key which Plan 03 will handle separately),
|
|
28
|
+
* preserves every non-SessionStart hook family (PreToolUse, PostToolUse),
|
|
29
|
+
* and preserves every sibling SessionStart entry (e.g. GSD's hook).
|
|
30
|
+
*
|
|
31
|
+
* Output: 2-space-indented JSON ending in a trailing newline. Passes
|
|
32
|
+
* `JSON.parse` cleanly. Re-applying the function to its own output is
|
|
33
|
+
* byte-identical to the first application (idempotency proof).
|
|
34
|
+
*
|
|
35
|
+
* This function DOES NOT read or write any status-line key — planner-lock #2
|
|
36
|
+
* is resolved separately in Plan 03. Keeping the Plan 02 blast radius tight
|
|
37
|
+
* to UPD-01 (SessionStart hook only).
|
|
38
|
+
*/
|
|
39
|
+
export declare function patchClaudeSettingsForGdhSessionStart(existingContent: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Patch-merge .claude/settings.json so the GDH statusline is registered ONLY
|
|
42
|
+
* when no existing `statusLine` entry is configured (write-if-absent).
|
|
43
|
+
*
|
|
44
|
+
* Planner-lock #2 resolution (Plan 03) — per D-18:
|
|
45
|
+
* - If `settings.statusLine` is present as ANY truthy value, leave it
|
|
46
|
+
* untouched. GDH does not clobber a user-configured statusline; other
|
|
47
|
+
* tools (e.g. GSD) can own the slot, and UPD-02 silently no-ops for
|
|
48
|
+
* that target. The universal cross-adapter detection surface is MCP
|
|
49
|
+
* `_meta` (UPD-03), so a no-op here is acceptable degradation.
|
|
50
|
+
* - If `settings.statusLine` is `undefined` or `null`, register GDH's
|
|
51
|
+
* `{ type: "command", command: "node .claude/hooks/gdh-statusline.js" }`.
|
|
52
|
+
* - Preserves every sibling top-level key verbatim (hooks, env,
|
|
53
|
+
* permissions, etc.). Composes cleanly with
|
|
54
|
+
* `patchClaudeSettingsForGdhSessionStart` (idempotent + commutative,
|
|
55
|
+
* proven by the Task 1 Test J suite).
|
|
56
|
+
*
|
|
57
|
+
* Input handling:
|
|
58
|
+
* - Empty string / whitespace-only → fresh `{}` base (GDH-only output).
|
|
59
|
+
* - Invalid JSON → fresh `{}` base (silent-failure, matches
|
|
60
|
+
* `patchClaudeSettingsForGdhSessionStart` posture).
|
|
61
|
+
* - Non-object JSON (e.g. `"hello"`, `[1, 2]`) → fresh `{}` base.
|
|
62
|
+
*
|
|
63
|
+
* Output: 2-space-indented JSON ending in a trailing newline. Passes
|
|
64
|
+
* `JSON.parse` cleanly. Re-applying this function to its own output is
|
|
65
|
+
* byte-identical (idempotency — Tests C, D, F).
|
|
66
|
+
*
|
|
67
|
+
* Circular-import note: `claude-statusline-render.ts` (source of
|
|
68
|
+
* `GDH_STATUSLINE_COMMAND`) imports ONLY `@gdh/core` — it MUST NOT import
|
|
69
|
+
* from this file. If a future change introduces a circular edge, extract
|
|
70
|
+
* `GDH_STATUSLINE_COMMAND` into a third module (e.g. claude-surface-constants.ts)
|
|
71
|
+
* that both sides import from.
|
|
72
|
+
*/
|
|
73
|
+
export declare function patchClaudeSettingsForGdhStatusline(existingContent: string): string;
|
|
74
|
+
//# sourceMappingURL=claude-settings-patch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings-patch.d.ts","sourceRoot":"","sources":["../src/claude-settings-patch.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,6BAA6B,0BAA0B,CAAC;AAErE;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,2CACD,CAAC;AA6C3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qCAAqC,CACnD,eAAe,EAAE,MAAM,GACtB,MAAM,CA4CR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,mCAAmC,CACjD,eAAe,EAAE,MAAM,GACtB,MAAM,CA6BR"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { GDH_STATUSLINE_COMMAND } from "./claude-statusline-render.js";
|
|
2
|
+
/**
|
|
3
|
+
* Relative path of the Claude Code per-project settings file in a managed
|
|
4
|
+
* target. This is the file GDH patches to register its SessionStart hook.
|
|
5
|
+
*/
|
|
6
|
+
export const CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
7
|
+
/**
|
|
8
|
+
* Exact command literal GDH uses to invoke the SessionStart parent hook.
|
|
9
|
+
*
|
|
10
|
+
* Idempotency in `patchClaudeSettingsForGdhSessionStart` is gated on an exact
|
|
11
|
+
* match against this literal. Keep it in one place so the renderer, the
|
|
12
|
+
* settings patcher, and `gdh verify drift` all agree on the canonical
|
|
13
|
+
* command string.
|
|
14
|
+
*/
|
|
15
|
+
export const GDH_SESSION_START_HOOK_COMMAND = "node .claude/hooks/gdh-check-update.js";
|
|
16
|
+
function hasGdhSessionStartHook(sessionStart) {
|
|
17
|
+
for (const group of sessionStart) {
|
|
18
|
+
if (!group || !Array.isArray(group.hooks))
|
|
19
|
+
continue;
|
|
20
|
+
for (const h of group.hooks) {
|
|
21
|
+
if (h !== null &&
|
|
22
|
+
typeof h === "object" &&
|
|
23
|
+
h.type === "command" &&
|
|
24
|
+
h.command === GDH_SESSION_START_HOOK_COMMAND) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Patch-merge .claude/settings.json so the GDH SessionStart hook is
|
|
33
|
+
* registered idempotently without clobbering sibling content.
|
|
34
|
+
*
|
|
35
|
+
* Strategy A (locked by Plan 02): exact command-literal match.
|
|
36
|
+
* - Parses `existingContent` as JSON. If empty / invalid / non-object,
|
|
37
|
+
* starts from a fresh `{}` — treating corruption as "last writer wins"
|
|
38
|
+
* for this narrow hook entry.
|
|
39
|
+
* - Ensures `hooks.SessionStart` exists as an array.
|
|
40
|
+
* - Appends the GDH entry ONLY if no group already contains a command
|
|
41
|
+
* whose `command` string equals `GDH_SESSION_START_HOOK_COMMAND`.
|
|
42
|
+
* - Preserves every other top-level key (e.g. env, and the sibling
|
|
43
|
+
* status-line key which Plan 03 will handle separately),
|
|
44
|
+
* preserves every non-SessionStart hook family (PreToolUse, PostToolUse),
|
|
45
|
+
* and preserves every sibling SessionStart entry (e.g. GSD's hook).
|
|
46
|
+
*
|
|
47
|
+
* Output: 2-space-indented JSON ending in a trailing newline. Passes
|
|
48
|
+
* `JSON.parse` cleanly. Re-applying the function to its own output is
|
|
49
|
+
* byte-identical to the first application (idempotency proof).
|
|
50
|
+
*
|
|
51
|
+
* This function DOES NOT read or write any status-line key — planner-lock #2
|
|
52
|
+
* is resolved separately in Plan 03. Keeping the Plan 02 blast radius tight
|
|
53
|
+
* to UPD-01 (SessionStart hook only).
|
|
54
|
+
*/
|
|
55
|
+
export function patchClaudeSettingsForGdhSessionStart(existingContent) {
|
|
56
|
+
let settings;
|
|
57
|
+
try {
|
|
58
|
+
const trimmed = existingContent.trim();
|
|
59
|
+
if (trimmed.length === 0) {
|
|
60
|
+
settings = {};
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const parsed = JSON.parse(trimmed);
|
|
64
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
65
|
+
settings = parsed;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
settings = {};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
settings = {};
|
|
74
|
+
}
|
|
75
|
+
const existingHooks = settings.hooks;
|
|
76
|
+
const hooks = existingHooks !== null && typeof existingHooks === "object"
|
|
77
|
+
? { ...existingHooks }
|
|
78
|
+
: {};
|
|
79
|
+
const existingSessionStart = hooks.SessionStart;
|
|
80
|
+
const sessionStart = Array.isArray(existingSessionStart)
|
|
81
|
+
? [...existingSessionStart]
|
|
82
|
+
: [];
|
|
83
|
+
if (!hasGdhSessionStartHook(sessionStart)) {
|
|
84
|
+
sessionStart.push({
|
|
85
|
+
hooks: [
|
|
86
|
+
{ type: "command", command: GDH_SESSION_START_HOOK_COMMAND },
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
hooks.SessionStart = sessionStart;
|
|
91
|
+
settings.hooks = hooks;
|
|
92
|
+
return `${JSON.stringify(settings, null, 2)}\n`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Patch-merge .claude/settings.json so the GDH statusline is registered ONLY
|
|
96
|
+
* when no existing `statusLine` entry is configured (write-if-absent).
|
|
97
|
+
*
|
|
98
|
+
* Planner-lock #2 resolution (Plan 03) — per D-18:
|
|
99
|
+
* - If `settings.statusLine` is present as ANY truthy value, leave it
|
|
100
|
+
* untouched. GDH does not clobber a user-configured statusline; other
|
|
101
|
+
* tools (e.g. GSD) can own the slot, and UPD-02 silently no-ops for
|
|
102
|
+
* that target. The universal cross-adapter detection surface is MCP
|
|
103
|
+
* `_meta` (UPD-03), so a no-op here is acceptable degradation.
|
|
104
|
+
* - If `settings.statusLine` is `undefined` or `null`, register GDH's
|
|
105
|
+
* `{ type: "command", command: "node .claude/hooks/gdh-statusline.js" }`.
|
|
106
|
+
* - Preserves every sibling top-level key verbatim (hooks, env,
|
|
107
|
+
* permissions, etc.). Composes cleanly with
|
|
108
|
+
* `patchClaudeSettingsForGdhSessionStart` (idempotent + commutative,
|
|
109
|
+
* proven by the Task 1 Test J suite).
|
|
110
|
+
*
|
|
111
|
+
* Input handling:
|
|
112
|
+
* - Empty string / whitespace-only → fresh `{}` base (GDH-only output).
|
|
113
|
+
* - Invalid JSON → fresh `{}` base (silent-failure, matches
|
|
114
|
+
* `patchClaudeSettingsForGdhSessionStart` posture).
|
|
115
|
+
* - Non-object JSON (e.g. `"hello"`, `[1, 2]`) → fresh `{}` base.
|
|
116
|
+
*
|
|
117
|
+
* Output: 2-space-indented JSON ending in a trailing newline. Passes
|
|
118
|
+
* `JSON.parse` cleanly. Re-applying this function to its own output is
|
|
119
|
+
* byte-identical (idempotency — Tests C, D, F).
|
|
120
|
+
*
|
|
121
|
+
* Circular-import note: `claude-statusline-render.ts` (source of
|
|
122
|
+
* `GDH_STATUSLINE_COMMAND`) imports ONLY `@gdh/core` — it MUST NOT import
|
|
123
|
+
* from this file. If a future change introduces a circular edge, extract
|
|
124
|
+
* `GDH_STATUSLINE_COMMAND` into a third module (e.g. claude-surface-constants.ts)
|
|
125
|
+
* that both sides import from.
|
|
126
|
+
*/
|
|
127
|
+
export function patchClaudeSettingsForGdhStatusline(existingContent) {
|
|
128
|
+
let settings;
|
|
129
|
+
try {
|
|
130
|
+
const trimmed = existingContent.trim();
|
|
131
|
+
if (trimmed.length === 0) {
|
|
132
|
+
settings = {};
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const parsed = JSON.parse(trimmed);
|
|
136
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
137
|
+
settings = parsed;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
settings = {};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
settings = {};
|
|
146
|
+
}
|
|
147
|
+
// Write-if-absent semantics: any existing truthy statusLine value is
|
|
148
|
+
// preserved verbatim (D-18 — another tool already owns the slot, we
|
|
149
|
+
// silently no-op for UPD-02 on this target).
|
|
150
|
+
if (settings.statusLine === undefined || settings.statusLine === null) {
|
|
151
|
+
settings.statusLine = {
|
|
152
|
+
type: "command",
|
|
153
|
+
command: GDH_STATUSLINE_COMMAND,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return `${JSON.stringify(settings, null, 2)}\n`;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=claude-settings-patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings-patch.js","sourceRoot":"","sources":["../src/claude-settings-patch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative path of the managed Claude statusline renderer script. This is
|
|
3
|
+
* the .js file Claude Code invokes on every prompt render when the managed
|
|
4
|
+
* target has registered `statusLine.command = "node .claude/hooks/gdh-statusline.js"`
|
|
5
|
+
* in its `.claude/settings.json`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CLAUDE_STATUSLINE_RELATIVE_PATH = ".claude/hooks/gdh-statusline.js";
|
|
8
|
+
/**
|
|
9
|
+
* Exact command literal GDH uses to register its statusline in
|
|
10
|
+
* `.claude/settings.json`.
|
|
11
|
+
*
|
|
12
|
+
* `patchClaudeSettingsForGdhStatusline` (in claude-settings-patch.ts) imports
|
|
13
|
+
* this constant and writes it into the `statusLine.command` field ONLY when
|
|
14
|
+
* the target has no pre-existing `statusLine` registration (write-if-absent
|
|
15
|
+
* policy — planner-lock #2 resolution per D-18). If another tool already owns
|
|
16
|
+
* the slot, GDH leaves it untouched and UPD-02 silently no-ops on that repo;
|
|
17
|
+
* the universal cross-adapter detection surface is MCP `_meta` (UPD-03).
|
|
18
|
+
*/
|
|
19
|
+
export declare const GDH_STATUSLINE_COMMAND = "node .claude/hooks/gdh-statusline.js";
|
|
20
|
+
/**
|
|
21
|
+
* Render the Claude statusline source that will be baked into a managed
|
|
22
|
+
* Claude target at the given pinned GDH version.
|
|
23
|
+
*
|
|
24
|
+
* The returned string is written verbatim to `.claude/hooks/gdh-statusline.js`
|
|
25
|
+
* by the adapter install pipeline. At runtime, Claude Code invokes the
|
|
26
|
+
* rendered script (when `statusLine.command` points at it — see D-18 /
|
|
27
|
+
* planner-lock #2) on every prompt render; the script reads the shared
|
|
28
|
+
* cache at `~/.cache/gdh/update-check.json` and prints the yellow
|
|
29
|
+
* `⬆ /gdh-update │ ` indicator when `cache.updateAvailable` is truthy.
|
|
30
|
+
*
|
|
31
|
+
* Invariants enforced by this renderer (see 11-03-PLAN):
|
|
32
|
+
* - shebang on line 1; a hook-version marker on line 2 for drift detection
|
|
33
|
+
* - cache path literal `path.join(homeDir, '.cache', 'gdh', 'update-check.json')`
|
|
34
|
+
* - yellow ANSI arrow + `/gdh-update` hint + trailing ` │ ` separator (Pattern S5)
|
|
35
|
+
* - silent-failure on every I/O + parse op (try/catch) — D-06
|
|
36
|
+
* - output goes to `process.stdout` (Claude Code's statusline convention)
|
|
37
|
+
* - no drift-scanning branch (GSD-only surface; out of UPD-02 scope per D-18)
|
|
38
|
+
* - no legacy-prefix literal anywhere in emitted content
|
|
39
|
+
*
|
|
40
|
+
* The `_pinnedVersion` parameter is accepted for API symmetry with the hook
|
|
41
|
+
* and worker renderers. The statusline body does NOT consume it — the emitted
|
|
42
|
+
* script reads the cache whose `pinned` field was baked at the worker-level
|
|
43
|
+
* pin and doesn't need re-threading. If a future plan decides to bake a
|
|
44
|
+
* version-specific hint format into the statusline, this signature is ready.
|
|
45
|
+
*
|
|
46
|
+
* The baked script is deliberately dependency-free — it imports only Node
|
|
47
|
+
* built-ins and does NOT resolve @gdh/core at runtime. Every string in the
|
|
48
|
+
* output is literal JavaScript.
|
|
49
|
+
*/
|
|
50
|
+
export declare function renderClaudeUpdateStatusline(_pinnedVersion?: string): string;
|
|
51
|
+
//# sourceMappingURL=claude-statusline-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-statusline-render.d.ts","sourceRoot":"","sources":["../src/claude-statusline-render.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,oCACT,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,yCAAyC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,4BAA4B,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CA4B5E"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { GDH_UPDATE_HOOK_VERSION } from "@gdh/core";
|
|
2
|
+
/**
|
|
3
|
+
* Relative path of the managed Claude statusline renderer script. This is
|
|
4
|
+
* the .js file Claude Code invokes on every prompt render when the managed
|
|
5
|
+
* target has registered `statusLine.command = "node .claude/hooks/gdh-statusline.js"`
|
|
6
|
+
* in its `.claude/settings.json`.
|
|
7
|
+
*/
|
|
8
|
+
export const CLAUDE_STATUSLINE_RELATIVE_PATH = ".claude/hooks/gdh-statusline.js";
|
|
9
|
+
/**
|
|
10
|
+
* Exact command literal GDH uses to register its statusline in
|
|
11
|
+
* `.claude/settings.json`.
|
|
12
|
+
*
|
|
13
|
+
* `patchClaudeSettingsForGdhStatusline` (in claude-settings-patch.ts) imports
|
|
14
|
+
* this constant and writes it into the `statusLine.command` field ONLY when
|
|
15
|
+
* the target has no pre-existing `statusLine` registration (write-if-absent
|
|
16
|
+
* policy — planner-lock #2 resolution per D-18). If another tool already owns
|
|
17
|
+
* the slot, GDH leaves it untouched and UPD-02 silently no-ops on that repo;
|
|
18
|
+
* the universal cross-adapter detection surface is MCP `_meta` (UPD-03).
|
|
19
|
+
*/
|
|
20
|
+
export const GDH_STATUSLINE_COMMAND = "node .claude/hooks/gdh-statusline.js";
|
|
21
|
+
/**
|
|
22
|
+
* Render the Claude statusline source that will be baked into a managed
|
|
23
|
+
* Claude target at the given pinned GDH version.
|
|
24
|
+
*
|
|
25
|
+
* The returned string is written verbatim to `.claude/hooks/gdh-statusline.js`
|
|
26
|
+
* by the adapter install pipeline. At runtime, Claude Code invokes the
|
|
27
|
+
* rendered script (when `statusLine.command` points at it — see D-18 /
|
|
28
|
+
* planner-lock #2) on every prompt render; the script reads the shared
|
|
29
|
+
* cache at `~/.cache/gdh/update-check.json` and prints the yellow
|
|
30
|
+
* `⬆ /gdh-update │ ` indicator when `cache.updateAvailable` is truthy.
|
|
31
|
+
*
|
|
32
|
+
* Invariants enforced by this renderer (see 11-03-PLAN):
|
|
33
|
+
* - shebang on line 1; a hook-version marker on line 2 for drift detection
|
|
34
|
+
* - cache path literal `path.join(homeDir, '.cache', 'gdh', 'update-check.json')`
|
|
35
|
+
* - yellow ANSI arrow + `/gdh-update` hint + trailing ` │ ` separator (Pattern S5)
|
|
36
|
+
* - silent-failure on every I/O + parse op (try/catch) — D-06
|
|
37
|
+
* - output goes to `process.stdout` (Claude Code's statusline convention)
|
|
38
|
+
* - no drift-scanning branch (GSD-only surface; out of UPD-02 scope per D-18)
|
|
39
|
+
* - no legacy-prefix literal anywhere in emitted content
|
|
40
|
+
*
|
|
41
|
+
* The `_pinnedVersion` parameter is accepted for API symmetry with the hook
|
|
42
|
+
* and worker renderers. The statusline body does NOT consume it — the emitted
|
|
43
|
+
* script reads the cache whose `pinned` field was baked at the worker-level
|
|
44
|
+
* pin and doesn't need re-threading. If a future plan decides to bake a
|
|
45
|
+
* version-specific hint format into the statusline, this signature is ready.
|
|
46
|
+
*
|
|
47
|
+
* The baked script is deliberately dependency-free — it imports only Node
|
|
48
|
+
* built-ins and does NOT resolve @gdh/core at runtime. Every string in the
|
|
49
|
+
* output is literal JavaScript.
|
|
50
|
+
*/
|
|
51
|
+
export function renderClaudeUpdateStatusline(_pinnedVersion) {
|
|
52
|
+
return [
|
|
53
|
+
"#!/usr/bin/env node",
|
|
54
|
+
`// gdh-hook-version: ${GDH_UPDATE_HOOK_VERSION}`,
|
|
55
|
+
"// Claude statusline: emits an upgrade hint when ~/.cache/gdh/update-check.json reports stale.",
|
|
56
|
+
"// Cache written by .claude/hooks/gdh-check-update-worker.js on SessionStart (UPD-01).",
|
|
57
|
+
"// Silent offline degrade per D-06 — missing/corrupt cache writes the empty string.",
|
|
58
|
+
"",
|
|
59
|
+
"const fs = require('fs');",
|
|
60
|
+
"const path = require('path');",
|
|
61
|
+
"const os = require('os');",
|
|
62
|
+
"",
|
|
63
|
+
"const homeDir = os.homedir();",
|
|
64
|
+
"const cacheFile = path.join(homeDir, '.cache', 'gdh', 'update-check.json');",
|
|
65
|
+
"",
|
|
66
|
+
"let gdhUpdate = '';",
|
|
67
|
+
"if (fs.existsSync(cacheFile)) {",
|
|
68
|
+
" try {",
|
|
69
|
+
" const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));",
|
|
70
|
+
" if (cache && cache.updateAvailable) {",
|
|
71
|
+
" gdhUpdate = '\\x1b[33m⬆ /gdh-update\\x1b[0m │ ';",
|
|
72
|
+
" }",
|
|
73
|
+
" } catch (e) {}",
|
|
74
|
+
"}",
|
|
75
|
+
"",
|
|
76
|
+
"process.stdout.write(gdhUpdate);",
|
|
77
|
+
"",
|
|
78
|
+
].join("\n");
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=claude-statusline-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-statusline-render.js","sourceRoot":"","sources":["../src/claude-statusline-render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAC1C,iCAAiC,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,sCAAsC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,4BAA4B,CAAC,cAAuB;IAClE,OAAO;QACL,qBAAqB;QACrB,wBAAwB,uBAAuB,EAAE;QACjD,gGAAgG;QAChG,wFAAwF;QACxF,qFAAqF;QACrF,EAAE;QACF,2BAA2B;QAC3B,+BAA+B;QAC/B,2BAA2B;QAC3B,EAAE;QACF,+BAA+B;QAC/B,6EAA6E;QAC7E,EAAE;QACF,qBAAqB;QACrB,iCAAiC;QACjC,SAAS;QACT,mEAAmE;QACnE,2CAA2C;QAC3C,wDAAwD;QACxD,OAAO;QACP,kBAAkB;QAClB,GAAG;QACH,EAAE;QACF,kCAAkC;QAClC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative path of the managed Claude SessionStart parent hook script.
|
|
3
|
+
* This is the .js file Claude Code invokes when a session opens on a
|
|
4
|
+
* GDH-managed target; it spawns the worker that refreshes the update cache.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CLAUDE_CHECK_UPDATE_HOOK_RELATIVE_PATH = ".claude/hooks/gdh-check-update.js";
|
|
7
|
+
/**
|
|
8
|
+
* Relative path of the managed Claude background worker script the parent
|
|
9
|
+
* hook spawns. The worker performs the HTTPS probe and writes the cache.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CLAUDE_CHECK_UPDATE_WORKER_RELATIVE_PATH = ".claude/hooks/gdh-check-update-worker.js";
|
|
12
|
+
/**
|
|
13
|
+
* Render the Claude SessionStart parent hook source that will be baked into
|
|
14
|
+
* a managed Claude target at the given pinned GDH version.
|
|
15
|
+
*
|
|
16
|
+
* The returned string is written verbatim to
|
|
17
|
+
* `.claude/hooks/gdh-check-update.js` by the adapter install pipeline.
|
|
18
|
+
*
|
|
19
|
+
* Invariants enforced by this renderer (see 11-02-PLAN):
|
|
20
|
+
* - shebang on line 1; a hook-version marker on line 2 for drift detection
|
|
21
|
+
* - dev-mode short-circuit on GDH_DEV_REPO runs BEFORE spawn()
|
|
22
|
+
* - spawn uses detached:true + child.unref() + windowsHide:true + stdio:'ignore'
|
|
23
|
+
* - pinned version flows to the worker via GDH_PINNED_VERSION env var
|
|
24
|
+
* - cache file path flows to the worker via GDH_CACHE_FILE env var
|
|
25
|
+
* - cache dir (~/.cache/gdh/) is created with fs.mkdirSync recursive:true
|
|
26
|
+
*
|
|
27
|
+
* The body wraps everything after the requires in an IIFE so `return` exits
|
|
28
|
+
* cleanly (Node's CommonJS module body does not allow top-level return).
|
|
29
|
+
*
|
|
30
|
+
* The baked script is deliberately dependency-free — it imports only Node
|
|
31
|
+
* built-ins and does NOT resolve @gdh/core at runtime. Every string in the
|
|
32
|
+
* output is literal JavaScript.
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderClaudeCheckUpdateHook(pinnedVersion: string): string;
|
|
35
|
+
//# sourceMappingURL=claude-update-hook-render.d.ts.map
|