gentle-pi 4.2.0 → 4.3.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/README.md +336 -137
- package/assets/agents/gentle-ai-explore.md +1 -0
- package/assets/agents/gentle-ai-verify.md +6 -4
- package/assets/agents/gentle-ai-worker.md +7 -1
- package/assets/orchestrator-delegation-reference.md +163 -0
- package/assets/orchestrator-delegation.md +25 -176
- package/assets/orchestrator-tracking.md +1 -1
- package/assets/orchestrator-verification.md +14 -8
- package/assets/orchestrator-writer.md +5 -1
- package/assets/orchestrator.md +9 -9
- package/bin/gentle-shell.mjs +170 -22
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +8 -7
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/README.md +7 -0
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/manifest.json +11 -2
- package/contracts/review-provider-contract-mirror/v1.4.0/bundle/routing/pi.md +92 -0
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-capabilities.baseline.json +8 -1
- package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/generated/provider-roles.baseline.json +1 -1
- package/docs/assets/diagrams/agent-orchestration.svg +54 -15
- package/docs/assets/diagrams/gentleman-workflow.svg +69 -11
- package/docs/assets/diagrams/measured-routing.svg +49 -0
- package/docs/assets/diagrams/native-review.svg +52 -12
- package/docs/assets/diagrams/odd-workflow.svg +128 -66
- package/docs/assets/diagrams/permission-modes.svg +51 -0
- package/docs/assets/features/audio-notifications.png +0 -0
- package/docs/assets/features/command-palette.png +0 -0
- package/docs/bundled-install.md +33 -3
- package/docs/delegated-verification.md +10 -8
- package/docs/gentle-agents-activity.md +11 -5
- package/docs/gentle-shell-uninstall.md +8 -1
- package/docs/gentle-shell.md +5 -4
- package/docs/install-wizard.md +8 -1
- package/docs/permission-modes.md +1 -1
- package/docs/readme-reference.md +107 -19
- package/docs/yolo-mode.md +21 -8
- package/extensions/codegraph-tools.ts +68 -6
- package/extensions/gentle-agents.ts +99 -12
- package/extensions/gentle-ai.ts +284 -52
- package/extensions/gentle-herdr-activity.ts +2 -3
- package/extensions/gentle-shell.ts +27 -12
- package/extensions/gentle-todo.ts +43 -9
- package/extensions/quiet-tools.ts +1 -1
- package/extensions/session-scratch.ts +365 -0
- package/extensions/startup-banner.ts +2 -3
- package/lib/agent-home.ts +8 -3
- package/lib/agents-protocol.ts +3 -0
- package/lib/agents-runner.ts +55 -6
- package/lib/agents-view.ts +3 -1
- package/lib/bounded-writer-admission.ts +51 -0
- package/lib/command-palette-catalog.ts +0 -4
- package/lib/commit-slice-signal.ts +100 -0
- package/lib/context-backstop.ts +84 -0
- package/lib/delivered-test-lint.ts +80 -0
- package/lib/destructive-command-guard.ts +120 -9
- package/lib/gauge-theme.ts +146 -0
- package/lib/gentle-ai-binary.ts +28 -7
- package/lib/gentle-shell-bundled.ts +39 -3
- package/lib/gentle-shell-import-pi.ts +233 -0
- package/lib/gentle-shell-launcher.ts +145 -11
- package/lib/gentle-shell-uninstall.ts +18 -1
- package/lib/herdr-activity.ts +24 -0
- package/lib/native-review-cli.ts +9 -1
- package/lib/orchestrator-discovery.ts +5 -1
- package/lib/orchestrator-presence.ts +9 -0
- package/lib/orchestrator-scope.ts +21 -3
- package/lib/provider-contract-bundle.ts +99 -53
- package/lib/review-candidate-view-owner.ts +29 -19
- package/lib/review-candidate-view.ts +36 -2
- package/lib/review-risk-assessment.ts +43 -38
- package/lib/review-session-standing-permission.ts +3 -1
- package/lib/session-profile-freeze.ts +30 -1
- package/lib/session-scratch.ts +474 -0
- package/lib/shell-bar.ts +25 -25
- package/lib/shell-changes-view.ts +80 -13
- package/lib/shell-gauge.ts +49 -6
- package/lib/shell-todo.ts +23 -4
- package/lib/shell-usage-view.ts +5 -1
- package/lib/shell-usage.ts +7 -7
- package/lib/verifier-admission.ts +29 -0
- package/lib/yolo-temp-scratch.ts +69 -0
- package/package.json +1 -2
- package/runtime/gentle-ai-binary.mjs +28 -7
- package/runtime/gentle-shell-bundled.mjs +38 -2
- package/runtime/gentle-shell-import-pi.mjs +234 -0
- package/runtime/gentle-shell-launcher.mjs +143 -9
- package/runtime/gentle-shell-uninstall.mjs +18 -1
- package/runtime/native-review-cli.mjs +8 -0
- package/runtime/review-risk-assessment.mjs +43 -38
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/bundled-engram-migration.mjs +125 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-server.mjs +14 -4
- package/scripts/main-channel.mjs +3 -2
- package/scripts/run-test-suite.mjs +5 -0
- package/scripts/verify-package-files.mjs +19 -13
- package/skills/gentle-ai/SKILL.md +3 -3
- package/skills/work-unit-commits/SKILL.md +5 -3
- package/tests/agent-risk-escalation.test.ts +37 -10
- package/tests/agents-runner.test.ts +260 -3
- package/tests/autonomous-guard.test.ts +122 -0
- package/tests/bounded-writer-admission.test.ts +11 -3
- package/tests/card-content-policy.test.ts +19 -9
- package/tests/child-safety.test.ts +39 -0
- package/tests/codegraph-tools.test.ts +123 -2
- package/tests/command-palette.test.ts +14 -4
- package/tests/commit-slice-signal.test.ts +162 -0
- package/tests/context-backstop.test.ts +159 -0
- package/tests/delegate-for-reason-contract.test.ts +91 -24
- package/tests/delivered-test-lint.test.ts +105 -0
- package/tests/destructive-command-guard.test.ts +85 -1
- package/tests/engram-safety.test.ts +1 -1
- package/tests/fixtures/primary-session-prompt/gentleman.golden.md +143 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/README.md +29 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/manifest.json +83 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/orchestration/pi.md +70 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/routing/pi.md +92 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/lens.schema.json +16 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/refuter.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/schemas/targeted-validator.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/lens.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/refuter.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.4.0/vectors/targeted-validator.json +1 -0
- package/tests/gauge-theme.test.ts +120 -0
- package/tests/gentle-agents.test.ts +282 -3
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-child-guards.test.ts +61 -0
- package/tests/gentle-ai-doctor-herdr.test.ts +94 -0
- package/tests/gentle-ai-installer.test.ts +51 -51
- package/tests/gentle-shell-bin.test.ts +163 -0
- package/tests/gentle-shell-bundled.test.ts +169 -6
- package/tests/gentle-shell-import-pi.test.ts +262 -0
- package/tests/gentle-shell-launcher.test.ts +79 -0
- package/tests/gentle-shell-uninstall.test.ts +30 -0
- package/tests/gentle-shell.test.ts +42 -9
- package/tests/gentle-todo.test.ts +179 -0
- package/tests/headless-delivery-question.test.ts +58 -0
- package/tests/herdr-activity.test.ts +34 -1
- package/tests/installer-server.test.ts +10 -2
- package/tests/installer-windows-bootstrap.test.ts +33 -4
- package/tests/native-review-capability-contract.test.ts +7 -1
- package/tests/native-review-parity.test.ts +22 -1
- package/tests/no-self-pause-contract.test.ts +5 -2
- package/tests/odd-integration.test.ts +5 -1
- package/tests/odd-routing-canonical-ratchet.test.ts +127 -162
- package/tests/odd-routing-contract.test.ts +115 -30
- package/tests/orchestrator-budget.test.ts +19 -8
- package/tests/orchestrator-discovery.test.ts +29 -0
- package/tests/orchestrator-rdd-ownership.test.ts +3 -1
- package/tests/orchestrator-scope.test.ts +66 -0
- package/tests/orchestrator-status-publication-contract.test.ts +12 -8
- package/tests/package-manifest.test.ts +24 -20
- package/tests/pi-update-launcher.test.ts +21 -2
- package/tests/primary-session-prompt.test.ts +101 -0
- package/tests/provider-contract-bundle.test.ts +118 -0
- package/tests/provider-contract-mirror.test.ts +24 -0
- package/tests/quiet-tool-rendering.test.ts +23 -0
- package/tests/rdd-aware-verification-contract.test.ts +29 -11
- package/tests/rdd-status-line.test.ts +79 -0
- package/tests/review-agent-end-preflight.test.ts +6 -0
- package/tests/review-candidate-view.test.ts +49 -0
- package/tests/review-contract-prompt.test.ts +5 -2
- package/tests/review-controller-native-routing.test.ts +14 -1
- package/tests/review-controller.test.ts +1 -1
- package/tests/review-host-relay-routing.test.ts +59 -2
- package/tests/review-loadout-rdd-off-sdk.test.ts +237 -0
- package/tests/review-owner-identity.test.ts +132 -0
- package/tests/review-risk-assessment.test.ts +163 -76
- package/tests/review-session-standing-permission-controller.test.ts +14 -1
- package/tests/review-session-standing-permission.test.ts +27 -1
- package/tests/run-test-suite.test.ts +15 -0
- package/tests/runtime-harness.mjs +16 -6
- package/tests/session-changes-shell.test.ts +1 -1
- package/tests/session-profile-freeze.test.ts +23 -0
- package/tests/session-scratch.test.ts +945 -0
- package/tests/session-subject-routing-contract.test.ts +2 -1
- package/tests/shell-bar.test.ts +7 -0
- package/tests/shell-changes-view.test.ts +137 -1
- package/tests/shell-gauge.test.ts +42 -0
- package/tests/small-task-inline-contract.test.ts +37 -0
- package/tests/standalone-config-home.test.ts +324 -0
- package/tests/startup-banner.test.ts +5 -4
- package/tests/startup-home-repo.test.ts +34 -0
- package/tests/support/orchestrator-modules.ts +1 -0
- package/tests/task-size-routing-contract.test.ts +69 -9
- package/tests/test-scratch-contract.test.ts +102 -0
- package/tests/test-strength-contract.test.ts +36 -1
- package/tests/tool-batching-contract.test.ts +64 -0
- package/tests/verification-proportionality.test.ts +46 -0
- package/tests/verifier-admission.test.ts +137 -0
- package/tests/verify-agent-contract.test.ts +8 -8
- package/tests/windows-hidden-processes.test.ts +5 -0
- package/tests/writer-edit-surface-scope.test.ts +3 -0
- package/tests/writer-feature-document-admission.test.ts +156 -0
- package/tests/yolo-mode.test.ts +18 -0
- package/tests/yolo-temp-scratch.test.ts +71 -0
- package/scripts/mirror-odd-routing.mjs +0 -242
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/orchestration/pi.md +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/lens.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/refuter.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/schemas/targeted-validator.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/lens.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/refuter.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.3.0 → v1.4.0}/bundle/vectors/targeted-validator.json +0 -0
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Parent Pi session only. Load it when the Writer rule fires or an explicitly activated Judgment Day fix batch is dispatched; small tasks never need it. The Writer rule fires on a named reason (parallel units, the context backstop), never on size alone or a price ratio: a large task without a reason stays inline, following its logbook. Configured per-agent models (`subagents.json` `model_profiles`) still apply to every writer it launches. Each writer prompt requires the self-review of the Parallel review protocol in `orchestrator-verification.md`. A reason holds only when the launch delivers it:
|
|
4
4
|
|
|
5
|
-
- **
|
|
5
|
+
- **Invariants**: each writer prompt names the existing helpers its unit must reuse for shared state (for example the function that adds an entry other commands also add) and the invariants they keep; units built in parallel cannot see each other, so this is the only place they learn them.
|
|
6
|
+
- **Size threshold**: a subagent costs one to two minutes of reading and setup before it writes anything; delegate a unit only when it needs several minutes of work (several files or roughly 100+ changed lines). Several small independent changes are faster inline, one after another.
|
|
7
|
+
- **Parallelism**: a unit is one independent piece of behavior with its own code, tests, and docs; never split one behavior into a test writer, a docs writer, and inline code, and never delegate a unit that depends on another unit still in progress. With the Background subagent policy on, launch every independent unit in the same turn via `subagent_run` with `mode: "background"`, then wait for all completions before the Seam check; serial launches void the reason: if units cannot launch together, work inline.
|
|
6
8
|
|
|
7
9
|
#### Allowed edit surfaces (MANDATORY)
|
|
8
10
|
|
|
@@ -15,6 +17,8 @@ Before launching a bounded writer (`gentle-ai-worker`, a user-configured `worker
|
|
|
15
17
|
- pre-existing untracked targets the writer may write, listed explicitly;
|
|
16
18
|
- nothing beyond the delegated task — a surface wider than the task is the same defect as no surface at all.
|
|
17
19
|
|
|
20
|
+
Test scratch stays outside the worktree (`mktemp -d`), never in the repository (nor caches or `TMPDIR`); state needed inside uses an excluded path the test removes. The runtime owns session scratch; `/gentle:scratch` lists or cleans recorded clones and worktrees.
|
|
21
|
+
|
|
18
22
|
If the surface genuinely cannot be derived, do not launch the writer or ask the human to author paths. Derive a candidate set first — the exact paths this task would touch — and present that enumerated list as an approve/decline choice under the Lossless Blocking Prompts rules in `orchestrator-prompts.md`. A free-text question asking which paths or globs to authorize is never a valid escalation: computing it is the parent's job.
|
|
19
23
|
|
|
20
24
|
Relay a writer's `interaction_required` payload about edit surfaces the same way: present its derived candidate paths as the choice, and add or drop paths only on the human's explicit instruction.
|
package/assets/orchestrator.md
CHANGED
|
@@ -14,6 +14,8 @@ You are a COORDINATOR, not the default executor for substantial work. Maintain o
|
|
|
14
14
|
|
|
15
15
|
Keep synthesis short by default: decision, outcome, next action. Expand only when the user asks or the situation requires detail.
|
|
16
16
|
|
|
17
|
+
Batch independent tool calls in one turn (parallel calls or one multi-file command). Never spend a turn only on a `todo` or status update.
|
|
18
|
+
|
|
17
19
|
## Language Boundary
|
|
18
20
|
|
|
19
21
|
Reply-language style and the active persona's Spanish variant are defined once in the identity/harness section above (its `Current persona mode:` line). The rules below are delegation/artifact-scoped and not restated there:
|
|
@@ -32,7 +34,7 @@ A task is **small** when all three hold:
|
|
|
32
34
|
2. **Contained risk** — no high-risk item below.
|
|
33
35
|
3. **Resumable from the diff** — resume test: if the session stopped now, someone could finish from the original request and `git diff` alone.
|
|
34
36
|
|
|
35
|
-
The number of files, commands or tests, fixes, or a requested `todo` list never decides size. A task is **large** only when the resume test fails (several sessions, external waits,
|
|
37
|
+
The number of files, commands or tests, fixes, or a requested `todo` list never decides size. A task is **large** only when the resume test fails (several sessions, external waits, deliverables the user wants apart (never several features asked at once), requirements compaction could lose); large tasks get ODD tracking and workers only by the Writer rule, else inline.
|
|
36
38
|
|
|
37
39
|
Small path: inline (parent; `bash_background` policy); observe RED inline before the fix; run the focused test and the suite inline, once each. No explore, worker, or verifier; no feature document, mirror, or commits unless the user asks; `todo` optional. It needs no lazy asset.
|
|
38
40
|
|
|
@@ -40,8 +42,6 @@ Small path: inline (parent; `bash_background` policy); observe RED inline before
|
|
|
40
42
|
|
|
41
43
|
**Risk line**: close every code change, small path or delegated, with `Risk: item N (reason)` or `Risk: none` per the list; any item → Verification rule.
|
|
42
44
|
|
|
43
|
-
ODD (Default Workflow, harness section above) is mandatory on every request, with the harness's applicable test-first policy (RED, GREEN, refactor); detail: `orchestrator-delegation.md`, `orchestrator-memory.md`.
|
|
44
|
-
|
|
45
45
|
## Delegation Rules
|
|
46
46
|
|
|
47
47
|
Core question: does this inflate parent context without need?
|
|
@@ -50,19 +50,19 @@ Before launching bounded writer (`gentle-ai-worker` or `worker`), derive nonempt
|
|
|
50
50
|
|
|
51
51
|
## Mechanisms
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Delegation Triggers — each mechanism turns on only when its own trigger condition truly holds, and only then is it mandatory; no trigger holds by default, and when in doubt work inline (prefer `subagent_run`; role missing/unusable: native `Agent`, same read-only constraints; report fallback). When it resolves, re-evaluate task size.
|
|
54
54
|
|
|
55
55
|
1. **Ask** — open product or design decision → one focused question; stop and wait.
|
|
56
56
|
2. **Evidence-budget rule** — understanding needs more than one read batch or >~5 sequential lookups → one `gentle-ai-explore`, handoff at most ~2k tokens with `path:line` evidence; one spot check only; never for reading before an inline write.
|
|
57
|
-
3. **Verification rule** — high
|
|
57
|
+
3. **Verification rule** — only a named high-risk item (assess `escalate`) → independent `gentle-ai-verify`; else inline; runtime admission, gates/overengineering: `orchestrator-verification.md`.
|
|
58
58
|
4. **Track** — large task → feature document, Engram mirror, `todo`, work-unit commits (`orchestrator-tracking.md`, `orchestrator-memory.md`).
|
|
59
|
-
5. **Writer rule** — never by file count or a large task alone; only for a reason (`orchestrator-writer.md`): 2+ independent units
|
|
59
|
+
5. **Writer rule** — never by file count or a large task alone; only for a reason (`orchestrator-writer.md`): 2+ independent units of behavior (separate features or fixes that do not depend on each other), each heavier than a subagent start (a subagent spends one to two minutes reading before it writes, so a unit qualifies only when it needs several minutes of work: several files or roughly 100+ changed lines; a small change to one module or one command is done inline even when several such changes are independent), launched together in background, else inline; Context backstop. Tests, docs, and code of the same behavior are one unit, never separate writers; a delivery that depends on an earlier one is not independent.
|
|
60
60
|
6. **Incident rule** — diagnose wrong cwd/worktree/git/tooling incidents separately before resuming.
|
|
61
|
-
7. **Context backstop** —
|
|
61
|
+
7. **Context backstop** — when the runtime signals it → delegate the next unit needing several steps. Bound command output (counts, `--stat`, `tail`).
|
|
62
62
|
|
|
63
63
|
{{GENTLE_PI_BACKGROUND_POLICY}}; rules: delegation background-subagents block.
|
|
64
64
|
|
|
65
|
-
Per-action table, Work Routing Ladder, Canonical Workflows: `orchestrator-delegation.md`; blocking-prompt relays and provider defects: `orchestrator-prompts.md`.
|
|
65
|
+
Per-action table, Work Routing Ladder, Canonical Workflows: `orchestrator-delegation-reference.md`; blocking-prompt relays and provider defects: `orchestrator-prompts.md`.
|
|
66
66
|
|
|
67
67
|
## Memory Contract
|
|
68
68
|
|
|
@@ -83,7 +83,7 @@ This package injects the mirrored provider-bundle review execution contract into
|
|
|
83
83
|
## Safety
|
|
84
84
|
|
|
85
85
|
- An eligible interactive Pi host may resolve `gentle-ai.review-integration.consent/v3` before the envelope reaches the model. Permission: host-owned. If `gentle_review` returns the envelope unresolved, it is still the original provider-owned two-choice contract. Use `ask_user_choice` exactly or relay losslessly and stop. Never add the host action to a decoded or relayed provider envelope.
|
|
86
|
-
- Never commit unless the user explicitly asks.
|
|
86
|
+
- Never commit unless the user explicitly asks, except the work-unit commits authorized large ODD implementation makes on its feature branch (ODD step 6).
|
|
87
87
|
- Ask before destructive git operations, publishing, or irreversible file changes.
|
|
88
88
|
- Parallel writers only with disjoint Allowed edit surfaces (runtime-enforced) or isolated worktrees.
|
|
89
89
|
- Keep session work inside the project root and registered same-clone worktrees; ask before any read or write outside it, naming the absolute path. Grants are per-target, per-session, never blanket: in-project scripts naming outside paths are not standing consent.
|
package/bin/gentle-shell.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
chmodSync,
|
|
10
10
|
closeSync,
|
|
11
11
|
constants as fsConstants,
|
|
12
|
+
copyFileSync,
|
|
12
13
|
existsSync,
|
|
13
14
|
fstatSync,
|
|
14
15
|
lstatSync,
|
|
@@ -50,22 +51,31 @@ import {
|
|
|
50
51
|
parseRawLauncherConfig,
|
|
51
52
|
planSpawn,
|
|
52
53
|
POST_INSTALL_REMOVAL_SOURCES,
|
|
54
|
+
withLauncherPackagesExcluded,
|
|
53
55
|
postInstallRemovals,
|
|
54
56
|
provisionedEntry,
|
|
57
|
+
migrateStandaloneConfig,
|
|
55
58
|
recordProvisioned,
|
|
56
59
|
resolveHome,
|
|
57
60
|
resolvePiRuntime,
|
|
58
61
|
restoreJsonField,
|
|
62
|
+
separateHomeHint,
|
|
59
63
|
shellQuote,
|
|
64
|
+
standaloneConfigHome,
|
|
65
|
+
userPiHome,
|
|
60
66
|
} from "../runtime/gentle-shell-launcher.mjs";
|
|
67
|
+
import { formatImportPiReport, importPi } from "../runtime/gentle-shell-import-pi.mjs";
|
|
61
68
|
import {
|
|
62
69
|
BUNDLED_VERIFY_ENV,
|
|
63
70
|
bundledEngramSchema,
|
|
64
71
|
classifyEngramStartup,
|
|
65
72
|
ENGRAM_COMPANION_SOURCE,
|
|
73
|
+
ENGRAM_CORE_CHANGED_NOTICE,
|
|
74
|
+
ENGRAM_PRIVATE_REQUIRED_NOTICE,
|
|
66
75
|
ENGRAM_PROVISION_FAILED_NOTICE,
|
|
67
76
|
ENGRAM_RECOVERY_NOTICE,
|
|
68
77
|
engramHeaderAllows,
|
|
78
|
+
GENTLE_SHELL_CONFIG_HOME_ENV,
|
|
69
79
|
engramProbeAllowed,
|
|
70
80
|
engramProvenanceMatches,
|
|
71
81
|
engramProvenancePath,
|
|
@@ -74,6 +84,7 @@ import {
|
|
|
74
84
|
probeEngramEndpoint,
|
|
75
85
|
sqliteHeaderUserVersion,
|
|
76
86
|
supportsEngramStartupPolicy,
|
|
87
|
+
supportsEngramSessionOwned,
|
|
77
88
|
bundledChildEnv,
|
|
78
89
|
bundledPi,
|
|
79
90
|
bundledSetupEnv,
|
|
@@ -95,6 +106,7 @@ import {
|
|
|
95
106
|
import { bundledGentleAiPaths, GENTLE_AI_VERSION, gentleAiBinaryPath, gentleAiIsolationEnv, PackageLocalGentleAiBinaryMissingError } from "../runtime/gentle-ai-binary.mjs";
|
|
96
107
|
import { DEFAULT_THEME_NAME, installIsolatedTuiModeSetting } from "../scripts/install-tui-mode-setting.mjs";
|
|
97
108
|
import { artifactFor, engramPinVersion } from "../scripts/installer-downloads.mjs";
|
|
109
|
+
import { migrateBundledEngram, migrationPending, supportsBundledSessionOwned, MIGRATION_PENDING_NOTICE, MIGRATION_USAGE } from "../scripts/bundled-engram-migration.mjs";
|
|
98
110
|
import { shouldCheckStartupUpdate, findStartupUpdate } from "../runtime/gentle-shell-startup-update.mjs";
|
|
99
111
|
import { promptStartupUpdate } from "../runtime/gentle-shell-update-panel.mjs";
|
|
100
112
|
import { applyStartupChoice, omitStartupVersion, resolveStartupRelaunch } from "../runtime/gentle-shell-startup-flow.mjs";
|
|
@@ -268,12 +280,24 @@ function ownEngramStore(observed, core) {
|
|
|
268
280
|
// of the default endpoint. No Engram executable, SQLite, identity repair, or
|
|
269
281
|
// contact with an explicitly selected endpoint.
|
|
270
282
|
async function classifyBundledMemory() {
|
|
283
|
+
if (migrationPending(bundledInstall.root)) return { policy: "disabled", notice: MIGRATION_PENDING_NOTICE };
|
|
271
284
|
const core = verifiedBundledCore();
|
|
272
285
|
const decision = { env: process.env, core: core !== undefined, coreVersion: engramPinVersion };
|
|
273
286
|
if (!engramProbeAllowed(process.env)) return classifyEngramStartup({ ...decision, store: "unknown", endpoint: { kind: "unknown" } });
|
|
274
287
|
const observed = observeEngramStore();
|
|
275
288
|
const endpoint = await probeEngramEndpoint();
|
|
276
|
-
|
|
289
|
+
const result = classifyEngramStartup({ ...decision, store: observed.store, endpoint, provenance: ownEngramStore(observed, core) });
|
|
290
|
+
if (result.policy === "disabled" && endpoint.kind === "refused" && observed.store === "present" && core) {
|
|
291
|
+
// Wording only: an unreadable record or core keeps the generic notice and
|
|
292
|
+
// must never abort startup.
|
|
293
|
+
try {
|
|
294
|
+
const record = parseEngramProvenance(readSmallRegularFile(engramProvenancePath(bundledInstall.root, process.platform), 4096));
|
|
295
|
+
if (record?.dataDir === observed.dataDir && record.instanceId === observed.instanceId && record.coreSha256 !== sha256File(core)) {
|
|
296
|
+
return { ...result, notice: ENGRAM_CORE_CHANGED_NOTICE };
|
|
297
|
+
}
|
|
298
|
+
} catch { /* Keep the generic disabled notice. */ }
|
|
299
|
+
}
|
|
300
|
+
return result;
|
|
277
301
|
}
|
|
278
302
|
|
|
279
303
|
// Verified with the published Engram v3.4.0 darwin-arm64 binary in an isolated
|
|
@@ -333,6 +357,7 @@ async function ensureEngramCompanion(home, runtime, stdio, timeoutMs) {
|
|
|
333
357
|
if (!Array.isArray(packages)) return { ok: false, exitCode: 1, message: "gentle-shell: cannot verify Engram startupPolicy from non-array packages" };
|
|
334
358
|
let pinned = false;
|
|
335
359
|
let local = false;
|
|
360
|
+
let localOwned = true;
|
|
336
361
|
let npmSelected = false;
|
|
337
362
|
for (const entry of packages) {
|
|
338
363
|
const source = typeof entry === "string" ? entry : entry?.source;
|
|
@@ -346,9 +371,10 @@ async function ensureEngramCompanion(home, runtime, stdio, timeoutMs) {
|
|
|
346
371
|
return { ok: false, exitCode: 1, message: `gentle-shell: selected companion ${source} lacks engram.startupPolicy=1; update it and recheck (selection preserved)` };
|
|
347
372
|
}
|
|
348
373
|
local = true;
|
|
374
|
+
localOwned &&= supportsEngramSessionOwned(readJsonIfExists(join(selected, "package.json")));
|
|
349
375
|
}
|
|
350
|
-
if (local && !npmSelected) return { ok: true };
|
|
351
|
-
if (pinned && supportsEngramStartupPolicy(readJsonIfExists(metadata))) return { ok: true };
|
|
376
|
+
if (local && !npmSelected) return { ok: true, sessionOwned: localOwned };
|
|
377
|
+
if (pinned && supportsEngramStartupPolicy(readJsonIfExists(metadata))) return { ok: true, sessionOwned: localOwned && supportsEngramSessionOwned(readJsonIfExists(metadata)) };
|
|
352
378
|
process.stderr.write(`gentle-shell: installing policy-capable companion ${ENGRAM_COMPANION_SOURCE} through Pi\n`);
|
|
353
379
|
const result = await spawnAndWait(runtime.command, [...runtime.args, "install", ENGRAM_COMPANION_SOURCE], buildSetupEnv(home, runtime), stdio, timeoutMs);
|
|
354
380
|
let declared = false;
|
|
@@ -359,7 +385,7 @@ async function ensureEngramCompanion(home, runtime, stdio, timeoutMs) {
|
|
|
359
385
|
if (!result.ok || result.timedOut || !declared || !supportsEngramStartupPolicy(readJsonIfExists(metadata))) {
|
|
360
386
|
return { ok: false, exitCode: 1, message: "gentle-shell: companion installation did not establish engram.startupPolicy=1; the Engram guard still keeps unverified stores closed. Repair gentle-engram, then restart Shell." };
|
|
361
387
|
}
|
|
362
|
-
return { ok: true };
|
|
388
|
+
return { ok: true, sessionOwned: localOwned && supportsEngramSessionOwned(readJsonIfExists(metadata)) };
|
|
363
389
|
}
|
|
364
390
|
|
|
365
391
|
// The bundled children's environment (bundledChildEnv), with the pinned Engram
|
|
@@ -627,6 +653,42 @@ function handleHomeCommand(commandArgs) {
|
|
|
627
653
|
process.exit(0);
|
|
628
654
|
}
|
|
629
655
|
|
|
656
|
+
// `gentle-shell [home selectors] home import-pi [--dry-run]`: copies the
|
|
657
|
+
// user's pi sign-ins, MCP servers and default model into the resolved
|
|
658
|
+
// separate home (lib/gentle-shell-import-pi.ts). A home that is new or empty
|
|
659
|
+
// is first bootstrapped exactly as a first launch would, so the files this
|
|
660
|
+
// adds never make it look foreign to auto-provisioning (homeIsForeign).
|
|
661
|
+
async function handleImportPiCommand(args) {
|
|
662
|
+
const options = args.commandArgs.slice(1);
|
|
663
|
+
if (options.some((option) => option !== "--dry-run")) fail("gentle-shell home import-pi accepts only --dry-run. Run 'gentle-shell --help'.", 2);
|
|
664
|
+
const dryRun = options.includes("--dry-run");
|
|
665
|
+
let home = resolveHome({ args, env: process.env, homedir: homedir(), config: loadConfig() });
|
|
666
|
+
if (home.mode === "path") home = { ...home, dir: resolvePath(home.dir) };
|
|
667
|
+
const source = resolvePath(userPiHome(process.env, homedir()));
|
|
668
|
+
const refusal = "Choose a separate home with --isolated or --home <path>.";
|
|
669
|
+
if (home.mode === "link") {
|
|
670
|
+
fail(`gentle-shell home import-pi: the selected home is your pi home itself (--link), so there is nothing to import. ${refusal}`, 1);
|
|
671
|
+
}
|
|
672
|
+
if ([source, join(homedir(), ".pi", "agent")].some((piHome) => safeRealpath(piHome) === safeRealpath(home.dir))) {
|
|
673
|
+
fail(`gentle-shell home import-pi: ${home.dir} is your pi home itself, so there is nothing to import. ${refusal}`, 1);
|
|
674
|
+
}
|
|
675
|
+
if (homeNeedsBootstrap(home.dir)) {
|
|
676
|
+
if (dryRun) {
|
|
677
|
+
process.stdout.write(`Would prepare ${home.dir} as a new Gentle Shell home\n`);
|
|
678
|
+
} else {
|
|
679
|
+
try {
|
|
680
|
+
await bootstrapOwnedHome(home);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
fail(`gentle-shell home import-pi: could not prepare ${home.dir} (${error.message}); nothing was imported`, 1);
|
|
683
|
+
}
|
|
684
|
+
process.stdout.write(`Prepared ${home.dir} as a new Gentle Shell home\n`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
const result = importPi({ source, target: home.dir, dryRun });
|
|
688
|
+
for (const line of formatImportPiReport(result, { source, target: home.dir, dryRun })) process.stdout.write(`${line}\n`);
|
|
689
|
+
process.exitCode = result.failed ? 1 : 0;
|
|
690
|
+
}
|
|
691
|
+
|
|
630
692
|
// Test/development-only override for the setup subcommand's gentle-ai
|
|
631
693
|
// executable path. Lets a test point at a stub script (or a deliberately
|
|
632
694
|
// missing path) without touching the real pinned .gentle-ai/v<version>/gentle-ai
|
|
@@ -799,12 +861,18 @@ function buildSetupEnv(home, runtime, piLauncherDir) {
|
|
|
799
861
|
const env = bundledSetupEnv({ ...bundledEnv, PI_CODING_AGENT_DIR: home.dir, GENTLE_PI_AGENT_HOME: home.dir }, { dirs: bundledSetupDirs, platform: process.platform });
|
|
800
862
|
return gentleAiIsolationEnv(env, { packageRoot });
|
|
801
863
|
}
|
|
802
|
-
|
|
864
|
+
const env = {
|
|
803
865
|
...process.env,
|
|
804
866
|
PI_CODING_AGENT_DIR: home.dir,
|
|
805
867
|
GENTLE_PI_AGENT_HOME: home.dir,
|
|
806
868
|
PATH: [...(piLauncherDir ? [piLauncherDir] : []), dirname(runtime.command), process.env.PATH ?? ""].join(delimiter),
|
|
807
869
|
};
|
|
870
|
+
// #2201: the isolated home's own config folder, given to Gentle AI the
|
|
871
|
+
// bundled way (gentleAiIsolationEnv); never an outer session's marker.
|
|
872
|
+
const configHome = standaloneConfigHome(home);
|
|
873
|
+
if (configHome === undefined) delete env[GENTLE_SHELL_CONFIG_HOME_ENV];
|
|
874
|
+
else env[GENTLE_SHELL_CONFIG_HOME_ENV] = configHome;
|
|
875
|
+
return gentleAiIsolationEnv(env, { packageRoot });
|
|
808
876
|
}
|
|
809
877
|
|
|
810
878
|
// Gentle AI requires a `pi` on its PATH and runs `pi install npm:gentle-pi`
|
|
@@ -847,15 +915,34 @@ function sharedPersonaPath() {
|
|
|
847
915
|
return join(homedir(), ".pi", "gentle-ai", "persona.json");
|
|
848
916
|
}
|
|
849
917
|
|
|
850
|
-
// The persona files a setup run may rewrite. Bundled (S9)
|
|
851
|
-
// which a Gentle AI with
|
|
852
|
-
// still the user's,
|
|
853
|
-
// unchanged file
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
return [join(bundledGentleAiPaths(bundledInstall.root, process.platform).piConfig, "persona.json"), sharedPersonaPath()];
|
|
918
|
+
// The persona files a setup run may rewrite. Bundled (S9) and the standalone
|
|
919
|
+
// isolated home (#2201): its own config folder's, which a Gentle AI with
|
|
920
|
+
// GENTLE_AI_PI_CONFIG_DIR (gentle-ai #5462) writes, and still the user's,
|
|
921
|
+
// which a pinned Gentle AI without it writes; restoring an unchanged file
|
|
922
|
+
// does nothing.
|
|
923
|
+
function setupPersonaPaths(home) {
|
|
924
|
+
if (bundledInstall) return [join(bundledGentleAiPaths(bundledInstall.root, process.platform).piConfig, "persona.json"), sharedPersonaPath()];
|
|
925
|
+
const configHome = standaloneConfigHome(home);
|
|
926
|
+
return configHome === undefined ? [sharedPersonaPath()] : [join(configHome, "persona.json"), sharedPersonaPath()];
|
|
857
927
|
}
|
|
858
928
|
|
|
929
|
+
// The real filesystem behind migrateStandaloneConfig (#2201).
|
|
930
|
+
const configMigrationFs = {
|
|
931
|
+
kind: (path) => {
|
|
932
|
+
try {
|
|
933
|
+
const stat = lstatSync(path);
|
|
934
|
+
return stat.isDirectory() ? "dir" : stat.isFile() ? "file" : "other";
|
|
935
|
+
} catch {
|
|
936
|
+
return "missing";
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
list: (path) => readdirSync(path),
|
|
940
|
+
mkdirPrivate: (path) => {
|
|
941
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
942
|
+
},
|
|
943
|
+
copyNew: (from, to) => copyFileSync(from, to, fsConstants.COPYFILE_EXCL),
|
|
944
|
+
};
|
|
945
|
+
|
|
859
946
|
// Bundled setup (S9): the pinned Engram GENTLE_AI_ENGRAM_BIN names, published
|
|
860
947
|
// once in runtime/ (verified, never brew or the user's PATH). A failure stops
|
|
861
948
|
// setup rather than let Gentle AI acquire another Engram.
|
|
@@ -1134,8 +1221,10 @@ async function runSetupFlow(home, runtime, { dryRun, stdio, timeoutMs }) {
|
|
|
1134
1221
|
|
|
1135
1222
|
const setupArgs = ["install", "--agent", "pi", "--scope", "global", ...(dryRun ? ["--dry-run"] : [])];
|
|
1136
1223
|
const piLauncherDir = writeSetupPiLauncher(runtime);
|
|
1137
|
-
|
|
1138
|
-
|
|
1224
|
+
// #2143: a Gentle AI with package exclusion never installs the launcher-owned
|
|
1225
|
+
// gentle-pi; an older one ignores this and runPostInstallCleanup removes it.
|
|
1226
|
+
const env = withLauncherPackagesExcluded(buildSetupEnv(home, runtime, piLauncherDir));
|
|
1227
|
+
const personaSnapshots = setupPersonaPaths(home).map((path) => [path, safely("snapshot your Pi persona file", path, undefined, () => snapshotFile(path))]);
|
|
1139
1228
|
const statePath = sharedGentleAiStatePath();
|
|
1140
1229
|
const originalStateText = safely("read your Gentle AI state file", statePath, undefined, () => readParsableJsonText(statePath));
|
|
1141
1230
|
// Theme restore (never for --link — that home is the user's own
|
|
@@ -1387,6 +1476,25 @@ function writeHomeOwnershipMarker(home) {
|
|
|
1387
1476
|
writeFileSync(homeOwnershipMarkerPath(home), `${content}\n`, "utf8");
|
|
1388
1477
|
}
|
|
1389
1478
|
|
|
1479
|
+
// The isolated/--home bootstrap: the first launch's own (main, below) and
|
|
1480
|
+
// `home import-pi`'s before it adds files to a new or empty home.
|
|
1481
|
+
async function bootstrapOwnedHome(home) {
|
|
1482
|
+
// 0700: under umask 002 a default mode would leave ~/.gentle-shell group-writable,
|
|
1483
|
+
// which the bundled install's prefix claim must tighten or refuse.
|
|
1484
|
+
mkdirSync(home.dir, { recursive: true, mode: 0o700 });
|
|
1485
|
+
await installIsolatedTuiModeSetting(home.dir);
|
|
1486
|
+
writeHomeOwnershipMarker(home); // R3-001: lets a failed first auto-provision attempt still be retried later
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function homeNeedsBootstrap(dir) {
|
|
1490
|
+
if (!existsSync(dir)) return true;
|
|
1491
|
+
try {
|
|
1492
|
+
return isDirectory(dir) && readdirSync(dir).length === 0;
|
|
1493
|
+
} catch {
|
|
1494
|
+
return false;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1390
1498
|
// `homeHadContentBeforeBootstrap` must be read by the caller (main, below)
|
|
1391
1499
|
// before the isolated/--home bootstrap runs: that bootstrap itself creates
|
|
1392
1500
|
// and seeds a brand-new directory (settings.json with tuiMode, and now the
|
|
@@ -1782,12 +1890,27 @@ async function main() {
|
|
|
1782
1890
|
process.exit(0);
|
|
1783
1891
|
}
|
|
1784
1892
|
if (args.command === "home") {
|
|
1785
|
-
|
|
1893
|
+
if (args.commandArgs[0] === "import-pi") await handleImportPiCommand(args);
|
|
1894
|
+
else handleHomeCommand(args.commandArgs);
|
|
1786
1895
|
return;
|
|
1787
1896
|
}
|
|
1788
1897
|
// The verification input applies to `--version` only (scripts/bundled-install.mjs upgradeBundled).
|
|
1789
1898
|
const verifying = args.version && args.command === undefined ? process.env[BUNDLED_VERIFY_ENV] : undefined;
|
|
1790
1899
|
const bundled = resolveBundledInstall({ packageRoot, platform: process.platform, fs: bundledFs, verifying });
|
|
1900
|
+
if (args.command === "memory") {
|
|
1901
|
+
if (args.commandArgs.length !== 2 || args.commandArgs[0] !== "migrate" || args.commandArgs[1] !== "--confirm-quiescent") {
|
|
1902
|
+
process.stderr.write(MIGRATION_USAGE);
|
|
1903
|
+
process.exitCode = 2;
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
if (!bundled) fail("gentle-shell: memory migrate requires a prefix-bundled installation", 1);
|
|
1907
|
+
bundledInstall = bundled;
|
|
1908
|
+
const result = migrateBundledEngram({ prefix: bundled.root, core: verifiedBundledCore(), home: homedir(), env: process.env });
|
|
1909
|
+
process.stdout.write(result.stdout);
|
|
1910
|
+
process.stderr.write(result.stderr);
|
|
1911
|
+
process.exitCode = result.code;
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1791
1914
|
if (args.command === "upgrade") {
|
|
1792
1915
|
if (bundled) process.exitCode = await handleBundledUpgrade(bundled, args.commandArgs);
|
|
1793
1916
|
else await handleUpgradeCommand(args.commandArgs);
|
|
@@ -1843,7 +1966,11 @@ async function main() {
|
|
|
1843
1966
|
});
|
|
1844
1967
|
if (versionProbe.error) fail(`Could not run the pi runtime at "${runtime.command}": ${versionProbe.error.message}`, 1);
|
|
1845
1968
|
const versionCheck = checkPiVersion(versionProbe.stdout ?? "");
|
|
1846
|
-
|
|
1969
|
+
// A managed self update is how an old Pi gets replaced, so the minimum-version
|
|
1970
|
+
// gate must not block it; everything else still requires the minimum.
|
|
1971
|
+
const managedSelfUpdate = !bundled && args.piSubcommand === "update" && versionCheck.version !== undefined
|
|
1972
|
+
&& (await import("../scripts/pi-update.mjs")).managedUpdatePlan(args.passthrough).self;
|
|
1973
|
+
if (!versionCheck.ok && !managedSelfUpdate) fail(versionCheck.message, 1);
|
|
1847
1974
|
|
|
1848
1975
|
if (args.version) {
|
|
1849
1976
|
process.stdout.write(`${describeVersion({ gentlePiVersion: ownPackageVersion(), piVersion: versionCheck.version, home })}\n`);
|
|
@@ -1893,12 +2020,22 @@ async function main() {
|
|
|
1893
2020
|
// Isolated-home bootstrap: only on a home gentle-shell has not seen before
|
|
1894
2021
|
// (link never bootstraps — it reuses the user's own pi agent home as-is).
|
|
1895
2022
|
if ((home.mode === "isolated" || home.mode === "path") && !existsSync(home.dir)) {
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2023
|
+
await bootstrapOwnedHome(home);
|
|
2024
|
+
const piSignIns = existsSync(join(userPiHome(process.env, homedir()), "auth.json"));
|
|
2025
|
+
process.stderr.write(`${separateHomeHint(home, { piSignIns })}\n`);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// #2201: the standalone isolated home's own config folder, seeded once from
|
|
2029
|
+
// the shared ~/.pi/gentle-ai. Not when an explicit GENTLE_PI_CONFIG_HOME
|
|
2030
|
+
// decides the config home; never blocks the launch.
|
|
2031
|
+
const configHome = bundled || process.env.GENTLE_PI_CONFIG_HOME ? undefined : standaloneConfigHome(home);
|
|
2032
|
+
if (configHome !== undefined) {
|
|
2033
|
+
try {
|
|
2034
|
+
const migration = migrateStandaloneConfig({ source: join(homedir(), ".pi", "gentle-ai"), target: configHome, fs: configMigrationFs });
|
|
2035
|
+
for (const line of migration.lines) process.stderr.write(`${line}\n`);
|
|
2036
|
+
} catch (error) {
|
|
2037
|
+
process.stderr.write(`gentle-shell: could not prepare ${configHome} (${error.message}); continuing\n`);
|
|
2038
|
+
}
|
|
1902
2039
|
}
|
|
1903
2040
|
|
|
1904
2041
|
if (bundled) {
|
|
@@ -2048,6 +2185,16 @@ async function main() {
|
|
|
2048
2185
|
// could not be verified is reported, never a reason to stop Shell.
|
|
2049
2186
|
const companion = await ensureEngramCompanion(home, runtime, ["ignore", 2, 2], 10000);
|
|
2050
2187
|
if (!companion.ok) process.stderr.write(`${companion.message}\n`);
|
|
2188
|
+
if (bundledMemory.policy === "allow" && !bundledMemory.url) {
|
|
2189
|
+
const mode = process.env.ENGRAM_SERVER_MODE;
|
|
2190
|
+
if (mode !== undefined && mode !== "session-owned") {
|
|
2191
|
+
bundledMemory = { policy: "disabled", notice: "Engram memory disabled: explicit ENGRAM_SERVER_MODE is invalid for a local bundled server; unset it or select exactly session-owned. Your selection has not been overridden." };
|
|
2192
|
+
} else {
|
|
2193
|
+
bundledMemory = companion.ok && companion.sessionOwned && supportsBundledSessionOwned(verifiedBundledCore(), process.env)
|
|
2194
|
+
? { ...bundledMemory, owned: true }
|
|
2195
|
+
: { policy: "disabled", notice: ENGRAM_PRIVATE_REQUIRED_NOTICE };
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2051
2198
|
// A fresh store's identity and provenance exist before Pi starts, or
|
|
2052
2199
|
// memory stays off: Pi never runs with allow without a written record.
|
|
2053
2200
|
if (bundledMemory.fresh && !provisionEngramStore()) bundledMemory = { policy: "disabled", notice: ENGRAM_PROVISION_FAILED_NOTICE };
|
|
@@ -2066,6 +2213,7 @@ async function main() {
|
|
|
2066
2213
|
passthrough: [...managedHerdrExtensionArgs(home, args), ...passthrough],
|
|
2067
2214
|
piSubcommand: args.piSubcommand,
|
|
2068
2215
|
baseEnv: bundledEnv ?? process.env,
|
|
2216
|
+
bundled: Boolean(bundled),
|
|
2069
2217
|
homedir: homedir(),
|
|
2070
2218
|
// The spawn below sets no cwd, so pi runs in the launcher's own.
|
|
2071
2219
|
cwd: process.cwd(),
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "gentle-pi.review-provider-contract-mirror-lock/v1",
|
|
3
3
|
"acquisition": "field-test-local",
|
|
4
|
-
"contract_semver": "1.
|
|
4
|
+
"contract_semver": "1.4.0",
|
|
5
5
|
"source": {
|
|
6
6
|
"kind": "archive",
|
|
7
|
-
"archive_sha256": "
|
|
7
|
+
"archive_sha256": "9d2927a84ba9a596f69029e3f854b16f86ca4c8b32cc5d63683764ccf2fb394b"
|
|
8
8
|
},
|
|
9
|
-
"tree_sha256": "
|
|
9
|
+
"tree_sha256": "aab5ab7fe7ee6bb180d8bbce21c034cebb0c0d284afcc8664a9b3bb57323c35d",
|
|
10
10
|
"entries": {
|
|
11
|
-
"README.md": "
|
|
12
|
-
"manifest.json": "
|
|
11
|
+
"README.md": "3a655c2f19aee02636da062f0cae7a189b7e5f691c8ba8010f2ed50e5d8e8d70",
|
|
12
|
+
"manifest.json": "d2b5765e28df5b2459848379e91a27beb806916fabc96207060ad1cc5e911972",
|
|
13
13
|
"orchestration/pi.md": "2d7ddd99f1c739a97f4a6b3929e5e2bdddcbf69aed69356395038d90bca25b2f",
|
|
14
|
+
"routing/pi.md": "1c7466e2333c08e386b4b5afb081531146d181030692463431e7695df7f90690",
|
|
14
15
|
"schemas/lens.schema.json": "9b8a2354a570888486015434501b66b51441a3baf5bf858635e4fff56b2e8298",
|
|
15
16
|
"schemas/refuter.schema.json": "36f8267c6c3f04600b8f1cb77df70d90858611af822cc81922efd6b3502fb646",
|
|
16
17
|
"schemas/targeted-validator.schema.json": "40e397195bdfbc6782fc3090f20c5be082e4d14d2855314f99ecb8506133eddc",
|
|
@@ -19,8 +20,8 @@
|
|
|
19
20
|
"vectors/targeted-validator.json": "7b5a5165e3a913863fb98d2ba5387811860c21333b5c37e6ed3b4e0d121cf2fa"
|
|
20
21
|
},
|
|
21
22
|
"generated": {
|
|
22
|
-
"generated/provider-capabilities.baseline.json": "
|
|
23
|
-
"generated/provider-roles.baseline.json": "
|
|
23
|
+
"generated/provider-capabilities.baseline.json": "bca708f5f67f506b4acb2cfdcb775b02a51468579fc7d6b4d169785ff411a215",
|
|
24
|
+
"generated/provider-roles.baseline.json": "aa36ec6f7469ac6faab756eec681f68f234cbadc1e12b345a93c6c34aa01f7aa"
|
|
24
25
|
},
|
|
25
26
|
"runtimes": [
|
|
26
27
|
"claude-code",
|
|
@@ -19,4 +19,11 @@ It carries no executable content, same as every other file in this bundle: a
|
|
|
19
19
|
runtime mirrors and delivers the text as-is and still relies on Go for every
|
|
20
20
|
review decision, prompt, receipt, and delivery gate.
|
|
21
21
|
|
|
22
|
+
## Routing
|
|
23
|
+
|
|
24
|
+
manifest.json's routing array lists, for closed runtimes only, one
|
|
25
|
+
routing/<runtime>.md file: the exact ODD implementation-routing block Gentle
|
|
26
|
+
AI renders for that runtime, whose prompt Gentle AI does not install. It is
|
|
27
|
+
data only as well: a runtime mirrors and delivers the text as-is.
|
|
28
|
+
|
|
22
29
|
Go remains the admission authority for prompts, results, receipts, and delivery gates.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "gentle-ai.review-provider-contract-bundle/v1",
|
|
3
|
-
"contract_semver": "1.
|
|
3
|
+
"contract_semver": "1.4.0",
|
|
4
4
|
"transport_capability": "gentle-ai.provider-transport/v1",
|
|
5
5
|
"runtimes": [
|
|
6
6
|
"claude-code",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"readme": {
|
|
12
12
|
"path": "README.md",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "3a655c2f19aee02636da062f0cae7a189b7e5f691c8ba8010f2ed50e5d8e8d70"
|
|
14
14
|
},
|
|
15
15
|
"roles": [
|
|
16
16
|
{
|
|
@@ -70,5 +70,14 @@
|
|
|
70
70
|
"sha256": "2d7ddd99f1c739a97f4a6b3929e5e2bdddcbf69aed69356395038d90bca25b2f"
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
],
|
|
74
|
+
"routing": [
|
|
75
|
+
{
|
|
76
|
+
"runtime": "pi",
|
|
77
|
+
"file": {
|
|
78
|
+
"path": "routing/pi.md",
|
|
79
|
+
"sha256": "1c7466e2333c08e386b4b5afb081531146d181030692463431e7695df7f90690"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
73
82
|
]
|
|
74
83
|
}
|