@jinn-network/client 0.1.6 → 0.1.7
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/CHANGELOG.md +33 -0
- package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
- package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
- package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
- package/dist/adapters/mech/adapter.d.ts +38 -1
- package/dist/adapters/mech/adapter.js +241 -54
- package/dist/adapters/mech/adapter.js.map +1 -1
- package/dist/adapters/mech/contracts.d.ts +17 -4
- package/dist/adapters/mech/contracts.js +8 -2
- package/dist/adapters/mech/contracts.js.map +1 -1
- package/dist/adapters/mech/safe-revert.d.ts +20 -0
- package/dist/adapters/mech/safe-revert.js +12 -4
- package/dist/adapters/mech/safe-revert.js.map +1 -1
- package/dist/adapters/mech/safe.d.ts +5 -1
- package/dist/adapters/mech/safe.js +27 -8
- package/dist/adapters/mech/safe.js.map +1 -1
- package/dist/adapters/mech/verdict-code.d.ts +1 -0
- package/dist/adapters/mech/verdict-code.js +18 -0
- package/dist/adapters/mech/verdict-code.js.map +1 -1
- package/dist/api/admin-endpoint.d.ts +15 -3
- package/dist/api/admin-endpoint.js +24 -2
- package/dist/api/admin-endpoint.js.map +1 -1
- package/dist/api/bootstrap-endpoint.js +49 -0
- package/dist/api/bootstrap-endpoint.js.map +1 -1
- package/dist/api/codex-doctor-endpoint.d.ts +73 -0
- package/dist/api/codex-doctor-endpoint.js +177 -0
- package/dist/api/codex-doctor-endpoint.js.map +1 -0
- package/dist/api/discovery-endpoint.d.ts +1 -0
- package/dist/api/discovery-endpoint.js +26 -0
- package/dist/api/discovery-endpoint.js.map +1 -1
- package/dist/api/fleet-build.d.ts +1 -0
- package/dist/api/fleet-build.js +2 -1
- package/dist/api/fleet-build.js.map +1 -1
- package/dist/api/gather-status.d.ts +11 -0
- package/dist/api/gather-status.js +400 -4
- package/dist/api/gather-status.js.map +1 -1
- package/dist/api/hermes-doctor-endpoint.d.ts +117 -0
- package/dist/api/hermes-doctor-endpoint.js +229 -23
- package/dist/api/hermes-doctor-endpoint.js.map +1 -1
- package/dist/api/launcher-status.d.ts +21 -16
- package/dist/api/launcher-status.js +2 -1
- package/dist/api/launcher-status.js.map +1 -1
- package/dist/api/portfolio-v0-build.d.ts +10 -0
- package/dist/api/portfolio-v0-build.js +24 -5
- package/dist/api/portfolio-v0-build.js.map +1 -1
- package/dist/api/prediction-v1-build.d.ts +10 -0
- package/dist/api/prediction-v1-build.js +7 -1
- package/dist/api/prediction-v1-build.js.map +1 -1
- package/dist/api/server.d.ts +31 -1
- package/dist/api/server.js +68 -1
- package/dist/api/server.js.map +1 -1
- package/dist/api/setup-endpoints.d.ts +16 -0
- package/dist/api/setup-endpoints.js +78 -4
- package/dist/api/setup-endpoints.js.map +1 -1
- package/dist/api/setup-retry-endpoint.d.ts +19 -0
- package/dist/api/setup-retry-endpoint.js +32 -0
- package/dist/api/setup-retry-endpoint.js.map +1 -0
- package/dist/api/solvernets-endpoints.d.ts +8 -0
- package/dist/api/solvernets-endpoints.js +71 -43
- package/dist/api/solvernets-endpoints.js.map +1 -1
- package/dist/api/status-build.d.ts +72 -0
- package/dist/api/status-build.js +73 -18
- package/dist/api/status-build.js.map +1 -1
- package/dist/api/task-run-routing.d.ts +7 -0
- package/dist/api/task-run-routing.js +12 -0
- package/dist/api/task-run-routing.js.map +1 -0
- package/dist/api/task-runs-build.d.ts +21 -0
- package/dist/api/task-runs-build.js +14 -1
- package/dist/api/task-runs-build.js.map +1 -1
- package/dist/build-info.json +4 -4
- package/dist/build-meta.json +1 -1
- package/dist/chain-read-errors.d.ts +10 -0
- package/dist/chain-read-errors.js +15 -0
- package/dist/chain-read-errors.js.map +1 -1
- package/dist/cli/commands/auth.js +1 -1
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/create.js +3 -2
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.js +2 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/rewards.js +11 -7
- package/dist/cli/commands/rewards.js.map +1 -1
- package/dist/cli/commands/solver-nets.js +24 -9
- package/dist/cli/commands/solver-nets.js.map +1 -1
- package/dist/cli/commands/status.js +1 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/tasks.js +86 -9
- package/dist/cli/commands/tasks.js.map +1 -1
- package/dist/cli/commands/update.d.ts +10 -0
- package/dist/cli/commands/update.js +36 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/introspection-context.js +5 -0
- package/dist/cli/introspection-context.js.map +1 -1
- package/dist/cli/task-native-readiness.d.ts +3 -1
- package/dist/cli/task-native-readiness.js +28 -6
- package/dist/cli/task-native-readiness.js.map +1 -1
- package/dist/config.d.ts +106 -5
- package/dist/config.js +97 -18
- package/dist/config.js.map +1 -1
- package/dist/daemon/checkpoint-loop.d.ts +48 -0
- package/dist/daemon/checkpoint-loop.js +76 -0
- package/dist/daemon/checkpoint-loop.js.map +1 -0
- package/dist/daemon/creator.d.ts +1 -1
- package/dist/daemon/creator.js +7 -3
- package/dist/daemon/creator.js.map +1 -1
- package/dist/daemon/daemon.d.ts +19 -0
- package/dist/daemon/daemon.js +68 -1
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/eviction-loop.d.ts +40 -0
- package/dist/daemon/eviction-loop.js +67 -0
- package/dist/daemon/eviction-loop.js.map +1 -0
- package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
- package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
- package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
- package/dist/daemon/jinn-claim-loop.d.ts +24 -17
- package/dist/daemon/jinn-claim-loop.js +77 -23
- package/dist/daemon/jinn-claim-loop.js.map +1 -1
- package/dist/daemon/skip-log-dedup.d.ts +69 -0
- package/dist/daemon/skip-log-dedup.js +106 -0
- package/dist/daemon/skip-log-dedup.js.map +1 -0
- package/dist/dashboard/assets/index-BUlE8F3Y.js +330 -0
- package/dist/dashboard/assets/index-blqc7eqq.css +32 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/discovery/factory.d.ts +17 -5
- package/dist/discovery/factory.js +46 -18
- package/dist/discovery/factory.js.map +1 -1
- package/dist/discovery/http.js +142 -3
- package/dist/discovery/http.js.map +1 -1
- package/dist/discovery/onchain.d.ts +5 -0
- package/dist/discovery/onchain.js +407 -15
- package/dist/discovery/onchain.js.map +1 -1
- package/dist/discovery/types.d.ts +45 -1
- package/dist/discovery/types.js +8 -10
- package/dist/discovery/types.js.map +1 -1
- package/dist/discovery/with-fallback.d.ts +7 -0
- package/dist/discovery/with-fallback.js +10 -0
- package/dist/discovery/with-fallback.js.map +1 -1
- package/dist/earning/bootstrap.d.ts +92 -1
- package/dist/earning/bootstrap.js +203 -63
- package/dist/earning/bootstrap.js.map +1 -1
- package/dist/earning/contracts.d.ts +14 -0
- package/dist/earning/contracts.js +17 -5
- package/dist/earning/contracts.js.map +1 -1
- package/dist/earning/funding-plan.js +27 -18
- package/dist/earning/funding-plan.js.map +1 -1
- package/dist/earning/jinn-rewards.d.ts +46 -0
- package/dist/earning/jinn-rewards.js +32 -0
- package/dist/earning/jinn-rewards.js.map +1 -1
- package/dist/earning/safe-adapter.d.ts +2 -0
- package/dist/earning/safe-adapter.js +26 -12
- package/dist/earning/safe-adapter.js.map +1 -1
- package/dist/earning/store.d.ts +8 -0
- package/dist/earning/store.js.map +1 -1
- package/dist/earning/testnet-setup-migration.d.ts +12 -0
- package/dist/earning/testnet-setup-migration.js +27 -1
- package/dist/earning/testnet-setup-migration.js.map +1 -1
- package/dist/earning/types.d.ts +15 -0
- package/dist/erc8004/reputation.d.ts +8 -0
- package/dist/erc8004/reputation.js +22 -3
- package/dist/erc8004/reputation.js.map +1 -1
- package/dist/harnesses/cost-estimates.d.ts +145 -0
- package/dist/harnesses/cost-estimates.js +297 -0
- package/dist/harnesses/cost-estimates.js.map +1 -0
- package/dist/harnesses/engine/engine.d.ts +72 -0
- package/dist/harnesses/engine/engine.js +105 -8
- package/dist/harnesses/engine/engine.js.map +1 -1
- package/dist/harnesses/engine/persistence.d.ts +51 -1
- package/dist/harnesses/engine/persistence.js +118 -5
- package/dist/harnesses/engine/persistence.js.map +1 -1
- package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
- package/dist/harnesses/engine/work-dir-reaper.js +100 -0
- package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
- package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
- package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
- package/dist/harnesses/impls/hermes-agent/bootstrap.js +40 -6
- package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
- package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
- package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
- package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
- package/dist/harnesses/impls/index.d.ts +7 -0
- package/dist/harnesses/impls/index.js +16 -1
- package/dist/harnesses/impls/index.js.map +1 -1
- package/dist/harnesses/impls/learner/harness.d.ts +38 -4
- package/dist/harnesses/impls/learner/harness.js +96 -2
- package/dist/harnesses/impls/learner/harness.js.map +1 -1
- package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
- package/dist/harnesses/impls/learner/plugin-path.js +35 -15
- package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
- package/dist/harnesses/impls/learner/types.d.ts +11 -0
- package/dist/harnesses/impls/stub.d.ts +58 -0
- package/dist/harnesses/impls/stub.js +89 -0
- package/dist/harnesses/impls/stub.js.map +1 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +178 -93
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +15 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +54 -4
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
- package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
- package/dist/harnesses/readiness-registry.js +9 -1
- package/dist/harnesses/readiness-registry.js.map +1 -1
- package/dist/main.js +371 -82
- package/dist/main.js.map +1 -1
- package/dist/observability/emit-event.d.ts +1 -1
- package/dist/observability/emit-event.js.map +1 -1
- package/dist/operator-errors.d.ts +7 -0
- package/dist/operator-errors.js +13 -1
- package/dist/operator-errors.js.map +1 -1
- package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
- package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
- package/dist/plugins/learner/AGENTS.md +40 -0
- package/dist/plugins/learner/CLAUDE.md +33 -0
- package/dist/plugins/learner/README.md +59 -0
- package/dist/plugins/learner/hooks/hooks.json +16 -0
- package/dist/plugins/learner/hooks/session-start +38 -0
- package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
- package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
- package/dist/plugins/learner/skills/learn/consolidator-prompt.md +94 -0
- package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
- package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
- package/dist/plugins/learner/skills/learn/promoter-prompt.md +113 -0
- package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
- package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
- package/dist/restart-daemon.d.ts +90 -0
- package/dist/restart-daemon.js +95 -0
- package/dist/restart-daemon.js.map +1 -0
- package/dist/setup/halt-mode.d.ts +14 -0
- package/dist/setup/halt-mode.js +17 -0
- package/dist/setup/halt-mode.js.map +1 -0
- package/dist/solver-nets/prediction-operator-ux.js +43 -3
- package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
- package/dist/solver-nets/registry.d.ts +1 -0
- package/dist/solver-nets/registry.js +1 -1
- package/dist/solver-nets/registry.js.map +1 -1
- package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
- package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
- package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
- package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
- package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
- package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
- package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +65 -0
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js +243 -26
- package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
- package/dist/solver-types/swe-rebench-v2-auto.d.ts +22 -7
- package/dist/solver-types/swe-rebench-v2-auto.js +45 -20
- package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
- package/dist/solver-types/swe-rebench-v2.d.ts +13 -2
- package/dist/solver-types/swe-rebench-v2.js +233 -94
- package/dist/solver-types/swe-rebench-v2.js.map +1 -1
- package/dist/solvernets/daemon-init.d.ts +10 -2
- package/dist/solvernets/daemon-init.js +22 -2
- package/dist/solvernets/daemon-init.js.map +1 -1
- package/dist/solvernets/launched-record-dispatcher.js +35 -7
- package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
- package/dist/solvernets/store.d.ts +5 -0
- package/dist/solvernets/store.js +1 -0
- package/dist/solvernets/store.js.map +1 -1
- package/dist/store/store.d.ts +15 -0
- package/dist/store/store.js +118 -3
- package/dist/store/store.js.map +1 -1
- package/dist/tasks/sources.d.ts +18 -1
- package/dist/tasks/sources.js +33 -5
- package/dist/tasks/sources.js.map +1 -1
- package/dist/tx-retry.d.ts +151 -19
- package/dist/tx-retry.js +286 -32
- package/dist/tx-retry.js.map +1 -1
- package/dist/types/payloads/prediction-apy-v0.d.ts +5 -5
- package/dist/types/payloads/prediction-v0.d.ts +5 -5
- package/dist/types/task-document.d.ts +392 -0
- package/dist/types/task-document.js +10 -0
- package/dist/types/task-document.js.map +1 -1
- package/dist/types/task.d.ts +28 -0
- package/dist/util/extract-tx-hash.d.ts +14 -0
- package/dist/util/extract-tx-hash.js +19 -0
- package/dist/util/extract-tx-hash.js.map +1 -0
- package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
- package/package.json +29 -12
- package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
- package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generic info-gathering subagent. Spawned by orient or debrief skills with a topic + scope. Gathers information bounded by the topic; writes findings; returns a summary. Does not spawn further agents.
|
|
3
|
+
tools: Bash, Read, Write, Glob, Grep
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Explorer (subagent role)
|
|
7
|
+
|
|
8
|
+
You are a fresh-context info-gatherer. The dispatching section of `skills/learn/SKILL.md` has handed you a topic and a scope. Your job is to gather information about that topic and report findings.
|
|
9
|
+
|
|
10
|
+
## Inputs (from your spawn prompt)
|
|
11
|
+
|
|
12
|
+
- `topic` — string label (e.g., "goal-parse", "world-state", "own-history", "others-history", or a debrief-specific topic)
|
|
13
|
+
- `goal` — the goal (read-only)
|
|
14
|
+
- `scope` — topic-specific scope description: what to look at, what to ignore, what depth
|
|
15
|
+
- `workingDir` — path; you write to `outputPath` only, which lives under `workingDir/.<phase>/`
|
|
16
|
+
- `implStateDir` — path; read-only
|
|
17
|
+
- `outputPath` — exact path to write your findings JSON to
|
|
18
|
+
- `msUntilDeadline` — your time budget
|
|
19
|
+
|
|
20
|
+
## Topic conventions
|
|
21
|
+
|
|
22
|
+
- **goal-parse** — extract id, kind, window timestamps, spec details, eligibility constraints. Output is purely structural — the parsed goal plus any normalized flags.
|
|
23
|
+
- **world-state** — call (whatever tools the harness exposes for this goal) to fetch current state. Include a snapshot timestamp. Be conservative on volume.
|
|
24
|
+
- **own-history** — read `implStateDir/runs/index.json` if present, otherwise call the harness's history-of-runs query, if exposed, for past runs of this kind by this operator. Note success/failure trends.
|
|
25
|
+
- **others-history** — call the harness's history-of-runs query, if exposed, for runs of this kind by other operators. Annotate evidence tier per envelope.
|
|
26
|
+
- (debrief-specific topics) — outcome-probe, cross-operator-comparison, divergence-attribution; the dispatching section of `skills/learn/SKILL.md` describes the scope.
|
|
27
|
+
|
|
28
|
+
## What you do
|
|
29
|
+
|
|
30
|
+
1. Parse the inputs.
|
|
31
|
+
2. Gather only the data the topic + scope describe.
|
|
32
|
+
3. Write a JSON file at `outputPath` with at minimum:
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"topic": "<topic>",
|
|
36
|
+
"gatheredAt": <unix-ms>,
|
|
37
|
+
"data": { /* topic-specific structured payload */ },
|
|
38
|
+
"flags": ["string — e.g., 'stale', 'partial', 'access-denied'"]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
4. Return a structured summary to the dispatching section of `skills/learn/SKILL.md`: `{ summary: '<one sentence>', artifactPath: '<outputPath>', flags: ['...'] }`.
|
|
42
|
+
|
|
43
|
+
## Boundaries
|
|
44
|
+
|
|
45
|
+
- Do not spawn other subagents — you are one level below the main session; further nesting is not supported.
|
|
46
|
+
- Do not modify `implStateDir`.
|
|
47
|
+
- Do not write outside `outputPath`.
|
|
48
|
+
- Do not exceed the topic's scope.
|
|
49
|
+
- Stay within your time budget; if you can't finish, return with a `flags: ['partial']` entry rather than blocking past the budget.
|
|
50
|
+
|
|
51
|
+
## Cross-reference
|
|
52
|
+
|
|
53
|
+
Spec: §4.1 (orient), §4.5 (debrief).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Specialized fresh-context subagent for Plan. Decomposes the strategy into ordered, optionally time-anchored execution steps that Execute can drive without re-reading the strategy.
|
|
3
|
+
tools: Bash, Read, Write
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Planner (subagent role)
|
|
7
|
+
|
|
8
|
+
Turn the strategy into concrete steps Execute can follow.
|
|
9
|
+
|
|
10
|
+
## Inputs (from your spawn prompt)
|
|
11
|
+
|
|
12
|
+
- `goal`
|
|
13
|
+
- `strategyPath` — read for chosen approach + success criteria + timing posture + constraints
|
|
14
|
+
- `orientSummaryPath` — read for grounding
|
|
15
|
+
- `priorPlanTemplatesPath` — read if non-null
|
|
16
|
+
- `replanContextPath` — read if non-null; contains `{ failedStepId, blockers, partialOutputs[] }` from the prior Execute attempt
|
|
17
|
+
- `priorPlanArchives` — array of paths to prior plan versions (`plan-v<N>.json`); read them to understand what was already tried before producing the new plan
|
|
18
|
+
- `workingDir`, `implStateDir` (read-only)
|
|
19
|
+
- `outputPath` — write plan.json here
|
|
20
|
+
- `msUntilDeadline`
|
|
21
|
+
|
|
22
|
+
## Decompose
|
|
23
|
+
|
|
24
|
+
Each step must be specific enough that a `step-worker` subagent can carry it out with no other context. For each step include:
|
|
25
|
+
|
|
26
|
+
- Unique step id (`step-1`, `step-2`, ...)
|
|
27
|
+
- `kind`: `work` or `wait`
|
|
28
|
+
- `concurrency`: `sequential` or `parallel-batch-A` (parallel steps with the same batch label run concurrently)
|
|
29
|
+
- Brief description (one sentence)
|
|
30
|
+
- Inputs the worker reads (paths or structured payloads)
|
|
31
|
+
- Tools / MCPs the worker needs
|
|
32
|
+
- Expected outputs (paths under `workingDir/`)
|
|
33
|
+
- Success signal — how the orchestrator knows this step succeeded
|
|
34
|
+
- Abort/recovery condition
|
|
35
|
+
|
|
36
|
+
For `hold-and-revise` or `continuous-observation` postures, include `wait`-kind steps where appropriate:
|
|
37
|
+
|
|
38
|
+
**On replan:** if `replanContextPath` was provided, the new plan must explicitly avoid the failure mode named in `failedStepId` + `blockers` — either skip that step's approach, route around it, or change the inputs that triggered it. Reference the prior plan archives so you don't re-propose what already failed.
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{ "id": "step-3", "kind": "wait", "durationMs": 7200000, "untilTs": null, "condition": null }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Output
|
|
45
|
+
|
|
46
|
+
Write `<outputPath>`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"successCriteria": "<copied from strategy.json>",
|
|
51
|
+
"timingPosture": "<copied>",
|
|
52
|
+
"steps": [
|
|
53
|
+
{
|
|
54
|
+
"id": "step-1",
|
|
55
|
+
"kind": "work",
|
|
56
|
+
"concurrency": "sequential",
|
|
57
|
+
"description": "string",
|
|
58
|
+
"inputs": { "...": "..." },
|
|
59
|
+
"toolsNeeded": ["string", "..."],
|
|
60
|
+
"expectedOutputs": ["workingDir/<path>", "..."],
|
|
61
|
+
"successSignal": "string — what proves this step succeeded",
|
|
62
|
+
"abortCondition": "string — when to give up"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "step-2",
|
|
66
|
+
"kind": "wait",
|
|
67
|
+
"concurrency": "sequential",
|
|
68
|
+
"durationMs": 7200000
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For wait-kind steps, only the wait fields are required.
|
|
75
|
+
|
|
76
|
+
Return to the dispatching section of `skills/learn/SKILL.md`: a one-line summary plus the path to plan.json.
|
|
77
|
+
|
|
78
|
+
## Boundaries
|
|
79
|
+
|
|
80
|
+
- Do not change success criteria or timing posture
|
|
81
|
+
- Do not execute steps
|
|
82
|
+
- Do not modify `implStateDir`
|
|
83
|
+
- Do not spawn further subagents
|
|
84
|
+
|
|
85
|
+
## Cross-reference
|
|
86
|
+
|
|
87
|
+
Spec: §4.3, §5.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Specialized fresh-context subagent for Improve. Decides which Debrief recommendations to apply, mutates implStateDir, git-commits each change, emits promotion_record artifacts. Changes take effect next run.
|
|
3
|
+
tools: Bash, Read, Write, Edit, Glob, Grep
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Promoter (subagent role)
|
|
7
|
+
|
|
8
|
+
Act on Debrief by mutating `implStateDir`. Each accepted change is one git commit.
|
|
9
|
+
|
|
10
|
+
**Critical:** changes take effect on the **next run**. Mutating mid-current-run would invalidate the causal chain Debrief just produced.
|
|
11
|
+
|
|
12
|
+
## Inputs (from your spawn prompt)
|
|
13
|
+
|
|
14
|
+
- `analysisPath` — read for recommendations + trend
|
|
15
|
+
- `policyPath` — read if non-null for operator policy
|
|
16
|
+
- `implStateDir` — your write target; git repo with `claude-code-learner` author identity already configured
|
|
17
|
+
- `outputDir` — write summary + promotion records here
|
|
18
|
+
- `msUntilDeadline`
|
|
19
|
+
|
|
20
|
+
## Action surface (in increasing risk order)
|
|
21
|
+
|
|
22
|
+
1. **Skill edits** — modify `implStateDir/skills/<name>/SKILL.md`
|
|
23
|
+
2. **Hook edits** — modify `implStateDir/hooks/*.sh`
|
|
24
|
+
3. **Tool config edits** — modify `implStateDir/configs/<name>.json`
|
|
25
|
+
4. **New skills / hooks / configs** — add files
|
|
26
|
+
5. **New tool source** — write a new tool implementation under `implStateDir/tools/<name>/`
|
|
27
|
+
6. **Operator-access requests** — emit deferred artifacts under `workingDir/.operator-requests/<name>.json` describing things you'd like the operator to provide. Never blocks.
|
|
28
|
+
7. **Harness install patches** — only if `policy.json` allows AND the harness adapter permits. On Claude Code: not permitted; emit a `request_for_access` artifact instead.
|
|
29
|
+
|
|
30
|
+
Allowed write paths: `implStateDir/**`, `workingDir/.improve/**`, `workingDir/.operator-requests/**`. Anywhere else is forbidden.
|
|
31
|
+
|
|
32
|
+
## What you do
|
|
33
|
+
|
|
34
|
+
For each Debrief recommendation:
|
|
35
|
+
|
|
36
|
+
1. Decide: accept or reject. Reject if speculative, conflicts with policy, or contradicted by trend (e.g., a recently reverted promotion).
|
|
37
|
+
2. For accepted changes, make the change (edit / write the file).
|
|
38
|
+
3. Stage and commit:
|
|
39
|
+
```bash
|
|
40
|
+
IMPL_STATE_DIR="<implStateDir from spawn input>"
|
|
41
|
+
cd "$IMPL_STATE_DIR"
|
|
42
|
+
git add -A
|
|
43
|
+
if ! git diff --cached --quiet; then
|
|
44
|
+
msg_file="$(mktemp)"
|
|
45
|
+
cat > "$msg_file" <<'MSG'
|
|
46
|
+
improve: <one-line description>
|
|
47
|
+
|
|
48
|
+
Run: <goal.id>
|
|
49
|
+
Cause: <attributed cause from analysis>
|
|
50
|
+
Recommendation: <short pointer into analysis>
|
|
51
|
+
MSG
|
|
52
|
+
git commit --quiet -F "$msg_file"
|
|
53
|
+
rm -f "$msg_file"
|
|
54
|
+
fi
|
|
55
|
+
```
|
|
56
|
+
4. Record `<outputDir>/promotions/<n>.json`:
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"ts": <unix-ms>,
|
|
60
|
+
"implStateDirShaBefore": "<git rev-parse HEAD^ after the commit; null for the first commit on a fresh repo>",
|
|
61
|
+
"implStateDirShaAfter": "<git rev-parse HEAD post-commit>",
|
|
62
|
+
"changeKind": "skill-edit | hook-edit | config-edit | new-skill | new-hook | new-config | new-tool | operator-request | harness-patch",
|
|
63
|
+
"target": "implStateDir/<path> | workingDir/.operator-requests/<name>.json",
|
|
64
|
+
"summary": "string",
|
|
65
|
+
"analysisSource": "string — pointer into analysis.json"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Consolidator reverts via `implStateDirShaAfter` (the commit that introduced the change); `implStateDirShaBefore` is informational only.
|
|
70
|
+
|
|
71
|
+
One commit per logical change so `git log` and `git revert` operate cleanly.
|
|
72
|
+
|
|
73
|
+
## Operator-access requests
|
|
74
|
+
|
|
75
|
+
Format under `workingDir/.operator-requests/<short-name>.json`:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"ts": <unix-ms>,
|
|
80
|
+
"what": "string — what's needed",
|
|
81
|
+
"why": "string — analysis grounding",
|
|
82
|
+
"howToGrant": "string — concrete steps for the operator",
|
|
83
|
+
"blocksKinds": ["<goal-kind>"]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Final summary
|
|
88
|
+
|
|
89
|
+
After all decisions, write `<outputDir>/summary.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"implStateDirShaBefore": "<at start>",
|
|
94
|
+
"implStateDirShaAfter": "<at end>",
|
|
95
|
+
"changesAccepted": <count>,
|
|
96
|
+
"changesRejected": <count>,
|
|
97
|
+
"operatorRequests": <count>,
|
|
98
|
+
"rejectionsRationale": [{ "recommendation": "string", "reason": "string" }]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Return to the dispatching section of `skills/learn/SKILL.md`: one paragraph of what changed (or didn't) and why.
|
|
103
|
+
|
|
104
|
+
## Boundaries
|
|
105
|
+
|
|
106
|
+
- Never write outside `implStateDir/**` (except `<outputDir>` and `workingDir/.operator-requests/`)
|
|
107
|
+
- Never accept a change the trend signal contradicts
|
|
108
|
+
- Never spawn further subagents
|
|
109
|
+
- Never modify the analysis itself
|
|
110
|
+
|
|
111
|
+
## Cross-reference
|
|
112
|
+
|
|
113
|
+
Spec: §4.6, §6.2, §6.4, §7.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Specialized fresh-context subagent for one Execute plan step. Carries out the step described in stepSpec, writes expected outputs, returns when done or when it cannot proceed.
|
|
3
|
+
tools: Bash, Read, Write, Edit, Glob, Grep
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Step-worker (subagent role)
|
|
7
|
+
|
|
8
|
+
You execute one plan step. Fresh context. Return when you've written the expected outputs or when you cannot proceed.
|
|
9
|
+
|
|
10
|
+
## Inputs (from your spawn prompt)
|
|
11
|
+
|
|
12
|
+
- `stepSpec` — the entire step object from plan.json
|
|
13
|
+
- `goal` — for context
|
|
14
|
+
- `workingDir`, `implStateDir` (read-only)
|
|
15
|
+
- `msUntilDeadline`
|
|
16
|
+
|
|
17
|
+
## What you do
|
|
18
|
+
|
|
19
|
+
1. Read `stepSpec.description` and `stepSpec.inputs`. Do not re-read `plan.json` — the orchestrator gave you everything you need.
|
|
20
|
+
2. Use the tools listed in `stepSpec.toolsNeeded`. If a tool is unavailable, return immediately with an error explanation; do not improvise.
|
|
21
|
+
3. Write the outputs listed in `stepSpec.expectedOutputs`. Each is a path under `workingDir/`.
|
|
22
|
+
4. Check yourself against `stepSpec.successSignal`. Did your work satisfy it? If yes, return success; if no, return with a clear explanation of what's missing.
|
|
23
|
+
|
|
24
|
+
## Return shape
|
|
25
|
+
|
|
26
|
+
Return a structured summary to the orchestrator:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"stepId": "<from stepSpec.id>",
|
|
31
|
+
"status": "success | partial | failed",
|
|
32
|
+
"outputsWritten": ["workingDir/<path>", "..."],
|
|
33
|
+
"summary": "string — one sentence",
|
|
34
|
+
"blockers": ["string — if status != success, what's missing"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Boundaries
|
|
39
|
+
|
|
40
|
+
- Do not modify `implStateDir`
|
|
41
|
+
- Do not spawn further subagents
|
|
42
|
+
- Do not do work outside `stepSpec` — if you think additional work is needed, return with a `partial` status and explain
|
|
43
|
+
- Stay within your time budget; if you can't finish, return `partial` rather than blocking past the budget
|
|
44
|
+
|
|
45
|
+
## Cross-reference
|
|
46
|
+
|
|
47
|
+
Spec: §4.4.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Specialized fresh-context subagent for Strategize. Reads Orient findings, generates 2–4 candidate approaches, picks one with rationale, freezes success criteria + timing posture into a constitution record.
|
|
3
|
+
tools: Bash, Read, Write
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Strategist (subagent role)
|
|
7
|
+
|
|
8
|
+
You commit to one approach for this run. Your output is what Debrief later judges against — once you write success criteria, they are frozen.
|
|
9
|
+
|
|
10
|
+
## Inputs (from your spawn prompt)
|
|
11
|
+
|
|
12
|
+
- `goal`
|
|
13
|
+
- `orientSummaryPath` — read this for context
|
|
14
|
+
- `priorStrategiesPath` — read if non-null for prior promoted strategies for this kind
|
|
15
|
+
- `workingDir`, `implStateDir` (read-only)
|
|
16
|
+
- `outputDir` — write strategy.json + constitution.json here
|
|
17
|
+
- `skillBundleCid`, `implStateDirShaAtStart` — for the constitution
|
|
18
|
+
- `msUntilDeadline`
|
|
19
|
+
|
|
20
|
+
## Diverge
|
|
21
|
+
|
|
22
|
+
Generate 2–4 candidate approaches given the Orient findings. For each, name:
|
|
23
|
+
|
|
24
|
+
- The angle (one sentence)
|
|
25
|
+
- What success looks like
|
|
26
|
+
- What could go wrong
|
|
27
|
+
- The timing posture this approach implies
|
|
28
|
+
|
|
29
|
+
## Converge
|
|
30
|
+
|
|
31
|
+
Pick one. Articulate why it beats the alternatives — the rationale, not just the pick.
|
|
32
|
+
|
|
33
|
+
## Freeze invariants
|
|
34
|
+
|
|
35
|
+
Write `<outputDir>/strategy.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"approach": "string — chosen approach, descriptive",
|
|
40
|
+
"rationale": "string — why this beats alternatives",
|
|
41
|
+
"successCriteria": "string — concrete 'success if X' statement",
|
|
42
|
+
"timingPosture": "early-return | hold-and-revise | continuous-observation",
|
|
43
|
+
"constraints": ["string", "..."],
|
|
44
|
+
"rejectedAlternatives": [
|
|
45
|
+
{ "approach": "string", "reason": "string" }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Compute the success-criteria CID:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
SUCCESS_CID="sha256:$(printf '%s' '<successCriteria>' | sha256sum | cut -d' ' -f1)"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Write `<outputDir>/constitution.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"successCriteriaCid": "<SUCCESS_CID>",
|
|
61
|
+
"timingPosture": "<from strategy.json>",
|
|
62
|
+
"skillBundleCid": "<from input>",
|
|
63
|
+
"implStateDirSha": "<implStateDirShaAtStart from input>",
|
|
64
|
+
"editableScope": ["<implStateDir>/**", "<workingDir>/**"]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Return to the dispatching section of `skills/learn/SKILL.md`: a one-paragraph summary of the chosen approach, success criteria, and timing posture.
|
|
69
|
+
|
|
70
|
+
## Timing postures
|
|
71
|
+
|
|
72
|
+
- `early-return` — finish work and exit before window end. Default for kinds where late information doesn't help.
|
|
73
|
+
- `hold-and-revise` — work, wait until late, optionally revise based on world-state evolution, exit.
|
|
74
|
+
- `continuous-observation` — submit early, monitor across window, occasionally adjust, exit at end.
|
|
75
|
+
|
|
76
|
+
## Boundaries
|
|
77
|
+
|
|
78
|
+
- Do not gather more info — Orient already did
|
|
79
|
+
- Do not detail per-step actions — Plan does that
|
|
80
|
+
- Do not modify `implStateDir`
|
|
81
|
+
- Do not spawn further subagents
|
|
82
|
+
|
|
83
|
+
## Cross-reference
|
|
84
|
+
|
|
85
|
+
Spec: §4.2, §10.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process respawn helper for operator-triggered daemon restarts.
|
|
3
|
+
*
|
|
4
|
+
* Issue #289 added respawn-instead-of-exit so the operator panel survives a
|
|
5
|
+
* restart click. Issue #561 fixed the follow-on bug: the original respawn
|
|
6
|
+
* spawned the child *before* the parent had released its server sockets, so
|
|
7
|
+
* the child raced into `.listen(7332)` while the parent still held the port
|
|
8
|
+
* and died with EADDRINUSE / exitCode 11. The fix is `preSpawnCleanup` — an
|
|
9
|
+
* async hook the caller uses to close API + OTLP receivers before the child
|
|
10
|
+
* is spawned. With cleanup in place the port is free synchronously and the
|
|
11
|
+
* child binds on first try; without it (older callers, tests) the helper
|
|
12
|
+
* behaves as before.
|
|
13
|
+
*
|
|
14
|
+
* Every restart-required config change funnels through the same handler:
|
|
15
|
+
*
|
|
16
|
+
* - POST /v1/setup/network — RPC URL change
|
|
17
|
+
* - POST /v1/setup/change-password — keystore password rotation
|
|
18
|
+
* - POST /v1/setup/solvernets/:name — SolverNet enable/disable
|
|
19
|
+
* - POST /v1/operator/join/:cid — SolverNet join
|
|
20
|
+
*
|
|
21
|
+
* Headless gate: `JINN_NO_UI=1` (already the established headless flag in
|
|
22
|
+
* main.ts) skips the respawn — operators running `jinn run --no-ui` from a
|
|
23
|
+
* supervisor / systemd unit / docker entrypoint want the supervisor to
|
|
24
|
+
* decide whether to restart, not the daemon.
|
|
25
|
+
*
|
|
26
|
+
* The helper is split out from main.ts so it's unit-testable without
|
|
27
|
+
* touching the entry-point bootstrap path.
|
|
28
|
+
*/
|
|
29
|
+
import { spawn } from 'node:child_process';
|
|
30
|
+
/**
|
|
31
|
+
* Options for `requestDaemonRestart`. All optional in production; the helper
|
|
32
|
+
* defaults to `process` / `node:child_process`. Tests inject doubles.
|
|
33
|
+
*/
|
|
34
|
+
export interface RequestDaemonRestartOptions {
|
|
35
|
+
/** Defaults to `process.env`. */
|
|
36
|
+
env?: NodeJS.ProcessEnv;
|
|
37
|
+
/** Defaults to `process.argv` (`[node, scriptPath, ...args]`). */
|
|
38
|
+
argv?: readonly string[];
|
|
39
|
+
/** Defaults to `process.execPath` (the node binary). */
|
|
40
|
+
execPath?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Defaults to `node:child_process.spawn`. Injected for tests so we can
|
|
43
|
+
* assert what was spawned without actually forking node.
|
|
44
|
+
*/
|
|
45
|
+
spawnFn?: typeof spawn;
|
|
46
|
+
/** Defaults to `(code) => process.exit(code)`. Injected for tests. */
|
|
47
|
+
exitFn?: (code: number) => void;
|
|
48
|
+
/** Defaults to `console.log`. Injected for tests to capture output. */
|
|
49
|
+
log?: (message: string) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Delay (ms) between spawning the child and exiting the parent. Gives the
|
|
52
|
+
* child a moment to bind the API port before the parent vacates it.
|
|
53
|
+
* Defaults to 250ms per the issue body. Tests can pass 0 for synchrony.
|
|
54
|
+
*/
|
|
55
|
+
exitDelayMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Bypass the headless gate. The operator-dashboard Restart button passes
|
|
58
|
+
* this — when the operator clicks Restart, they explicitly want the
|
|
59
|
+
* daemon to come back, even under a supervisor. Supervisor-driven
|
|
60
|
+
* restart flows (MCP tools, signals) leave this `false` so the
|
|
61
|
+
* supervisor stays in charge.
|
|
62
|
+
*/
|
|
63
|
+
forceRespawn?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Optional async hook run *before* the replacement child is spawned. The
|
|
66
|
+
* caller uses this to close listening sockets the child will need to
|
|
67
|
+
* bind — API server (7332) and OTLP receiver (4317/4318) — so the child
|
|
68
|
+
* doesn't lose an EADDRINUSE race with the parent. Errors are caught and
|
|
69
|
+
* logged; the respawn still proceeds because leaving the operator
|
|
70
|
+
* stranded is worse than a noisy close. Skipped in headless mode.
|
|
71
|
+
*/
|
|
72
|
+
preSpawnCleanup?: () => Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Pure predicate: true when the current env is headless and respawn should
|
|
76
|
+
* be skipped. Exposed so callers and tests can share the same check.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isHeadless(env?: NodeJS.ProcessEnv): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Handle an operator-triggered restart request.
|
|
81
|
+
*
|
|
82
|
+
* - In **interactive** mode (default), spawn a detached child that re-runs
|
|
83
|
+
* the current node invocation, then exit after a short delay so the child
|
|
84
|
+
* can bind the API port.
|
|
85
|
+
* - In **headless** mode (`JINN_NO_UI=1`), exit without respawning. The
|
|
86
|
+
* supervisor is responsible for relaunching the daemon if it wants to.
|
|
87
|
+
*
|
|
88
|
+
* Returns the action taken (for tests). Production callers ignore the return.
|
|
89
|
+
*/
|
|
90
|
+
export declare function requestDaemonRestart(opts?: RequestDaemonRestartOptions): Promise<'respawned' | 'headless-exit'>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process respawn helper for operator-triggered daemon restarts.
|
|
3
|
+
*
|
|
4
|
+
* Issue #289 added respawn-instead-of-exit so the operator panel survives a
|
|
5
|
+
* restart click. Issue #561 fixed the follow-on bug: the original respawn
|
|
6
|
+
* spawned the child *before* the parent had released its server sockets, so
|
|
7
|
+
* the child raced into `.listen(7332)` while the parent still held the port
|
|
8
|
+
* and died with EADDRINUSE / exitCode 11. The fix is `preSpawnCleanup` — an
|
|
9
|
+
* async hook the caller uses to close API + OTLP receivers before the child
|
|
10
|
+
* is spawned. With cleanup in place the port is free synchronously and the
|
|
11
|
+
* child binds on first try; without it (older callers, tests) the helper
|
|
12
|
+
* behaves as before.
|
|
13
|
+
*
|
|
14
|
+
* Every restart-required config change funnels through the same handler:
|
|
15
|
+
*
|
|
16
|
+
* - POST /v1/setup/network — RPC URL change
|
|
17
|
+
* - POST /v1/setup/change-password — keystore password rotation
|
|
18
|
+
* - POST /v1/setup/solvernets/:name — SolverNet enable/disable
|
|
19
|
+
* - POST /v1/operator/join/:cid — SolverNet join
|
|
20
|
+
*
|
|
21
|
+
* Headless gate: `JINN_NO_UI=1` (already the established headless flag in
|
|
22
|
+
* main.ts) skips the respawn — operators running `jinn run --no-ui` from a
|
|
23
|
+
* supervisor / systemd unit / docker entrypoint want the supervisor to
|
|
24
|
+
* decide whether to restart, not the daemon.
|
|
25
|
+
*
|
|
26
|
+
* The helper is split out from main.ts so it's unit-testable without
|
|
27
|
+
* touching the entry-point bootstrap path.
|
|
28
|
+
*/
|
|
29
|
+
import { spawn } from 'node:child_process';
|
|
30
|
+
/**
|
|
31
|
+
* Pure predicate: true when the current env is headless and respawn should
|
|
32
|
+
* be skipped. Exposed so callers and tests can share the same check.
|
|
33
|
+
*/
|
|
34
|
+
export function isHeadless(env = process.env) {
|
|
35
|
+
return env['JINN_NO_UI'] === '1';
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle an operator-triggered restart request.
|
|
39
|
+
*
|
|
40
|
+
* - In **interactive** mode (default), spawn a detached child that re-runs
|
|
41
|
+
* the current node invocation, then exit after a short delay so the child
|
|
42
|
+
* can bind the API port.
|
|
43
|
+
* - In **headless** mode (`JINN_NO_UI=1`), exit without respawning. The
|
|
44
|
+
* supervisor is responsible for relaunching the daemon if it wants to.
|
|
45
|
+
*
|
|
46
|
+
* Returns the action taken (for tests). Production callers ignore the return.
|
|
47
|
+
*/
|
|
48
|
+
export async function requestDaemonRestart(opts = {}) {
|
|
49
|
+
const env = opts.env ?? process.env;
|
|
50
|
+
const argv = opts.argv ?? process.argv;
|
|
51
|
+
const execPath = opts.execPath ?? process.execPath;
|
|
52
|
+
const spawnFn = opts.spawnFn ?? spawn;
|
|
53
|
+
const exitFn = opts.exitFn ?? ((code) => process.exit(code));
|
|
54
|
+
const log = opts.log ?? ((message) => console.log(message));
|
|
55
|
+
const exitDelayMs = opts.exitDelayMs ?? 250;
|
|
56
|
+
if (isHeadless(env) && !opts.forceRespawn) {
|
|
57
|
+
log('[main] Restart requested via operator MCP, but JINN_NO_UI=1 — exiting without respawn (let the supervisor decide).');
|
|
58
|
+
exitFn(0);
|
|
59
|
+
return 'headless-exit';
|
|
60
|
+
}
|
|
61
|
+
log('[main] Restart requested via operator MCP. Spawning replacement and exiting...');
|
|
62
|
+
// jinn-mono #561: release server sockets BEFORE the child spawns. Without
|
|
63
|
+
// this, the child loses an EADDRINUSE race on 7332 (and OTLP 4317/4318)
|
|
64
|
+
// and dies with exitCode 11 before it can take over.
|
|
65
|
+
if (opts.preSpawnCleanup) {
|
|
66
|
+
try {
|
|
67
|
+
await opts.preSpawnCleanup();
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
log(`[main] preSpawnCleanup error (proceeding with respawn anyway): ${err instanceof Error ? err.message : String(err)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// argv[0] is the node binary; argv[1..] are the script + flags. The child
|
|
74
|
+
// re-runs the same script with the same flags, under the same node binary.
|
|
75
|
+
const childArgs = argv.slice(1);
|
|
76
|
+
const spawnOptions = {
|
|
77
|
+
detached: true,
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
env,
|
|
80
|
+
};
|
|
81
|
+
const child = spawnFn(execPath, childArgs, spawnOptions);
|
|
82
|
+
// Detach so the parent can exit without taking the child with it.
|
|
83
|
+
child.unref();
|
|
84
|
+
// With preSpawnCleanup the port is already free; the small delay is kept
|
|
85
|
+
// as a paranoid belt-and-suspenders against any kernel-level lingering on
|
|
86
|
+
// SO_LINGER-disabled sockets. Tests pass 0.
|
|
87
|
+
if (exitDelayMs <= 0) {
|
|
88
|
+
exitFn(0);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
setTimeout(() => exitFn(0), exitDelayMs);
|
|
92
|
+
}
|
|
93
|
+
return 'respawned';
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=restart-daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart-daemon.js","sourceRoot":"","sources":["../src/restart-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AA+C9D;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;AACnC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAoC,EAAE;IAEtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC;IAE5C,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1C,GAAG,CACD,oHAAoH,CACrH,CAAC;QACF,MAAM,CAAC,CAAC,CAAC,CAAC;QACV,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,GAAG,CAAC,gFAAgF,CAAC,CAAC;IAEtF,0EAA0E;IAC1E,wEAAwE;IACxE,qDAAqD;IACrD,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CACD,kEACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,YAAY,GAAiB;QACjC,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,SAAS;QAChB,GAAG;KACJ,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACzD,kEAAkE;IAClE,KAAK,CAAC,KAAK,EAAE,CAAC;IAEd,yEAAyE;IACzE,0EAA0E;IAC1E,4CAA4C;IAC5C,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,CAAC,CAAC,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Halt-and-resume gate (jinn-mono-hjex.6).
|
|
3
|
+
*
|
|
4
|
+
* When bootstrap fails after the setup API has come up, we want the dashboard
|
|
5
|
+
* to stay alive so the operator can click Retry from `BootstrapErrorCard`
|
|
6
|
+
* (see `main.ts` halt-and-resume loop). That mode is only safe when there is
|
|
7
|
+
* actually a human (or watcher) on the other side; in CI / agent-driven flows
|
|
8
|
+
* driven with `JINN_NO_UI=1` or `JINN_NO_DAEMON=1` no Retry click is coming,
|
|
9
|
+
* so a halt must surface as a fatal exit immediately rather than suspending
|
|
10
|
+
* in the retry loop forever.
|
|
11
|
+
*
|
|
12
|
+
* This predicate is the single source of truth for that gate.
|
|
13
|
+
*/
|
|
14
|
+
export declare function keepSetupUiOnBootstrapError(env?: NodeJS.ProcessEnv): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Halt-and-resume gate (jinn-mono-hjex.6).
|
|
3
|
+
*
|
|
4
|
+
* When bootstrap fails after the setup API has come up, we want the dashboard
|
|
5
|
+
* to stay alive so the operator can click Retry from `BootstrapErrorCard`
|
|
6
|
+
* (see `main.ts` halt-and-resume loop). That mode is only safe when there is
|
|
7
|
+
* actually a human (or watcher) on the other side; in CI / agent-driven flows
|
|
8
|
+
* driven with `JINN_NO_UI=1` or `JINN_NO_DAEMON=1` no Retry click is coming,
|
|
9
|
+
* so a halt must surface as a fatal exit immediately rather than suspending
|
|
10
|
+
* in the retry loop forever.
|
|
11
|
+
*
|
|
12
|
+
* This predicate is the single source of truth for that gate.
|
|
13
|
+
*/
|
|
14
|
+
export function keepSetupUiOnBootstrapError(env = process.env) {
|
|
15
|
+
return env['JINN_NO_UI'] !== '1' && env['JINN_NO_DAEMON'] !== '1';
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=halt-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"halt-mode.js","sourceRoot":"","sources":["../../src/setup/halt-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC9E,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,KAAK,GAAG,CAAC;AACpE,CAAC"}
|