gentle-pi 4.2.0 → 4.4.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 +340 -138
- 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/design-canvas/canvas.css +648 -0
- package/assets/design-canvas/canvas.js +1497 -0
- package/assets/design-canvas/index.html +88 -0
- package/assets/design-canvas/inspector.js +290 -0
- 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 +11 -11
- package/bin/engram-guard +1 -1
- package/bin/gentle-shell.mjs +237 -139
- 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 +65 -30
- package/docs/delegated-verification.md +16 -8
- package/docs/gentle-agents-activity.md +16 -6
- package/docs/gentle-music.md +61 -0
- package/docs/gentle-shell-uninstall.md +8 -1
- package/docs/gentle-shell.md +80 -9
- package/docs/install-wizard.md +37 -6
- package/docs/permission-modes.md +8 -3
- package/docs/readme-reference.md +120 -28
- package/docs/session-profile-format.md +26 -0
- package/docs/voice.md +259 -0
- package/docs/yolo-mode.md +38 -10
- package/extensions/ask-user-choice.ts +4 -1
- package/extensions/codegraph-tools.ts +68 -6
- package/extensions/gentle-agents.ts +270 -48
- package/extensions/gentle-ai.ts +490 -113
- package/extensions/gentle-design.ts +158 -0
- package/extensions/gentle-herdr-activity.ts +2 -3
- package/extensions/gentle-music.ts +289 -0
- package/extensions/gentle-shell.ts +359 -85
- package/extensions/gentle-todo.ts +43 -9
- package/extensions/gentle-voice.ts +11 -0
- package/extensions/quiet-tools.ts +1 -1
- package/extensions/session-scratch.ts +384 -0
- package/extensions/skill-registry.ts +63 -8
- package/extensions/startup-banner.ts +2 -3
- package/lib/agent-home.ts +8 -3
- package/lib/agent-profiles.ts +26 -0
- package/lib/agents-config.ts +35 -0
- package/lib/agents-protocol.ts +60 -1
- package/lib/agents-runner.ts +107 -9
- package/lib/agents-session-transport.ts +101 -6
- package/lib/agents-view.ts +3 -1
- package/lib/agents-widget.ts +14 -1
- package/lib/auto-permission-memory.ts +48 -18
- package/lib/auto-permission-runtime.ts +21 -6
- package/lib/bounded-writer-admission.ts +51 -0
- package/lib/clipboard-image.ts +147 -0
- package/lib/command-palette-catalog.ts +2 -4
- package/lib/commit-slice-signal.ts +100 -0
- package/lib/context-backstop.ts +120 -0
- package/lib/delivered-test-lint.ts +80 -0
- package/lib/design-canvas-server.ts +947 -0
- package/lib/design-comments.ts +437 -0
- package/lib/design-handoffs.ts +313 -0
- package/lib/design-open-browser.ts +58 -0
- package/lib/design-sources.ts +120 -0
- package/lib/destructive-command-guard.ts +120 -9
- package/lib/external-editor.ts +31 -0
- package/lib/gauge-theme.ts +146 -0
- package/lib/gentle-ai-binary.ts +28 -7
- package/lib/gentle-design.ts +513 -0
- package/lib/gentle-shell-bundled.ts +146 -36
- package/lib/gentle-shell-import-pi.ts +233 -0
- package/lib/gentle-shell-launcher.ts +154 -15
- package/lib/gentle-shell-startup-update.ts +61 -9
- package/lib/gentle-shell-uninstall.ts +51 -2
- package/lib/herdr-activity.ts +24 -0
- package/lib/image-attachments.ts +150 -0
- package/lib/inprocess-reviewer.ts +33 -2
- package/lib/nan-provider.ts +3 -0
- package/lib/native-review-cli.ts +20 -5
- package/lib/notification-audio-native.ts +149 -13
- package/lib/notification-audio.ts +4 -0
- package/lib/notification-pulse-worker.ts +82 -18
- package/lib/notification-service.ts +5 -1
- package/lib/orchestrator-discovery.ts +5 -1
- package/lib/orchestrator-presence.ts +87 -8
- package/lib/orchestrator-scope.ts +31 -3
- package/lib/orchestrator-state.ts +11 -3
- package/lib/permission-mode-policy.ts +2 -2
- 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-host-relay.ts +11 -2
- package/lib/review-reminder-receipt.ts +24 -1
- package/lib/review-risk-assessment.ts +43 -38
- package/lib/review-session-standing-permission.ts +3 -1
- package/lib/session-profile-append-controller.ts +713 -0
- package/lib/session-profile-disk-reader.ts +182 -0
- package/lib/session-profile-freeze.ts +30 -1
- package/lib/session-profile-persistence.ts +15 -7
- package/lib/session-scratch.ts +523 -0
- package/lib/session-worktree-registry.ts +7 -0
- package/lib/shell-bar.ts +29 -28
- package/lib/shell-changes-view.ts +80 -13
- package/lib/shell-changes.ts +81 -5
- package/lib/shell-gauge.ts +49 -6
- package/lib/shell-prompt.ts +4 -4
- package/lib/shell-sidebar-layout.ts +26 -6
- package/lib/shell-todo.ts +24 -5
- package/lib/shell-usage-view.ts +5 -1
- package/lib/shell-usage.ts +7 -7
- package/lib/verifier-admission.ts +30 -0
- package/lib/vim-editor-adapter.ts +11 -8
- package/lib/voice-artifacts.ts +188 -0
- package/lib/voice-command.ts +576 -0
- package/lib/voice-install.ts +455 -0
- package/lib/voice-platform.ts +99 -0
- package/lib/voice-push-to-talk.ts +262 -0
- package/lib/voice-session.ts +460 -0
- package/lib/voice-settings.ts +50 -0
- package/lib/voice-ui.ts +158 -0
- package/lib/yolo-session-policy.ts +58 -22
- 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 +145 -35
- package/runtime/gentle-shell-import-pi.mjs +234 -0
- package/runtime/gentle-shell-launcher.mjs +152 -13
- package/runtime/gentle-shell-startup-update.mjs +61 -9
- package/runtime/gentle-shell-uninstall.mjs +51 -2
- package/runtime/native-review-cli.mjs +19 -4
- package/runtime/review-risk-assessment.mjs +43 -38
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/bundled-engram-migration.mjs +119 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/installer-downloads.mjs +7 -7
- package/scripts/installer-preflight.mjs +5 -3
- package/scripts/installer-server.mjs +14 -4
- package/scripts/installer-windows.mjs +37 -7
- package/scripts/main-channel.mjs +94 -19
- package/scripts/pi-update.mjs +34 -6
- package/scripts/run-test-suite.mjs +5 -0
- package/scripts/verify-package-files.mjs +43 -13
- package/scripts/voice-worker.cjs +476 -0
- package/skills/design/SKILL.md +110 -0
- package/skills/gentle-ai/SKILL.md +3 -3
- package/skills/work-unit-commits/SKILL.md +5 -3
- package/tests/agent-profiles.test.ts +24 -0
- package/tests/agent-risk-escalation.test.ts +37 -10
- package/tests/agents-config.test.ts +61 -0
- package/tests/agents-fake-child.ts +8 -1
- package/tests/agents-protocol.test.ts +32 -0
- package/tests/agents-runner.test.ts +485 -7
- package/tests/agents-session-transport.test.ts +53 -3
- package/tests/ask-user-choice.test.ts +30 -0
- package/tests/auto-mode.test.ts +17 -0
- package/tests/auto-permission-memory-diagnostics.test.ts +56 -0
- package/tests/auto-permission-runtime.test.ts +85 -1
- package/tests/autonomous-guard.test.ts +142 -0
- package/tests/bounded-writer-admission.test.ts +11 -3
- package/tests/bundled-install.test.ts +3 -3
- package/tests/card-content-policy.test.ts +19 -9
- package/tests/child-safety.test.ts +39 -0
- package/tests/clipboard-image.test.ts +114 -0
- package/tests/codegraph-tools.test.ts +123 -2
- package/tests/command-palette.test.ts +15 -5
- package/tests/commit-slice-signal.test.ts +162 -0
- package/tests/context-backstop.test.ts +225 -0
- package/tests/delegate-for-reason-contract.test.ts +92 -24
- package/tests/delivered-test-lint.test.ts +105 -0
- package/tests/design-canvas-assets.test.ts +710 -0
- package/tests/design-canvas-server.test.ts +1096 -0
- package/tests/design-comments.test.ts +201 -0
- package/tests/design-handoffs.test.ts +282 -0
- package/tests/design-open-browser.test.ts +70 -0
- package/tests/design-sources.test.ts +132 -0
- package/tests/destructive-command-guard.test.ts +85 -1
- package/tests/engram-safety.test.ts +132 -57
- package/tests/external-editor.test.ts +84 -0
- 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 +645 -21
- 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-ai.test.ts +292 -13
- package/tests/gentle-design.test.ts +1313 -0
- package/tests/gentle-music.test.ts +335 -0
- package/tests/gentle-shell-bin.test.ts +163 -0
- package/tests/gentle-shell-bundled.test.ts +392 -176
- package/tests/gentle-shell-import-pi.test.ts +262 -0
- package/tests/gentle-shell-launcher.test.ts +107 -2
- package/tests/gentle-shell-startup-update.test.ts +77 -1
- package/tests/gentle-shell-uninstall.test.ts +89 -0
- package/tests/gentle-shell.test.ts +225 -17
- package/tests/gentle-todo.test.ts +190 -0
- package/tests/headless-delivery-question.test.ts +58 -0
- package/tests/herdr-activity.test.ts +34 -1
- package/tests/image-attachments.test.ts +119 -0
- package/tests/image-paste-chips.test.ts +236 -0
- package/tests/inprocess-reviewer.test.ts +55 -2
- package/tests/installer-bundles.test.ts +12 -6
- package/tests/installer-posix-bootstrap.test.ts +8 -8
- package/tests/installer-preflight.test.ts +16 -0
- package/tests/installer-server.test.ts +10 -2
- package/tests/installer-windows-bootstrap.test.ts +94 -7
- package/tests/installer-windows-diagnostics.test.ts +111 -0
- package/tests/main-channel-upgrade.test.ts +232 -2
- package/tests/main-channel.test.ts +140 -21
- package/tests/nan-provider.test.ts +36 -0
- package/tests/native-review-capability-contract.test.ts +17 -4
- package/tests/native-review-parity.test.ts +23 -2
- package/tests/no-self-pause-contract.test.ts +5 -2
- package/tests/notification-audio-native.test.ts +128 -9
- package/tests/notification-customize.test.ts +17 -5
- package/tests/odd-integration.test.ts +5 -1
- package/tests/odd-routing-canonical-ratchet.test.ts +128 -162
- package/tests/odd-routing-contract.test.ts +115 -30
- package/tests/orchestrator-budget.test.ts +22 -8
- package/tests/orchestrator-discovery.test.ts +29 -0
- package/tests/orchestrator-presence.test.ts +100 -2
- package/tests/orchestrator-rdd-ownership.test.ts +3 -1
- package/tests/orchestrator-scope.test.ts +80 -0
- package/tests/orchestrator-state.test.ts +29 -0
- package/tests/orchestrator-status-publication-contract.test.ts +12 -8
- package/tests/package-files.test.ts +34 -0
- package/tests/package-manifest.test.ts +24 -20
- package/tests/permission-mode-policy.test.ts +10 -1
- package/tests/pi-update-launcher.test.ts +21 -2
- package/tests/pi-update.test.ts +99 -4
- 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 +147 -3
- package/tests/review-host-relay.test.ts +9 -2
- package/tests/review-json-arguments.test.ts +20 -3
- package/tests/review-loadout-rdd-off-sdk.test.ts +258 -0
- package/tests/review-owner-identity.test.ts +132 -0
- package/tests/review-relay-transport-agent.test.ts +26 -0
- package/tests/review-reminder-receipt.test.ts +31 -1
- 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-changes.test.ts +2 -1
- package/tests/session-profile-append-controller-fork.test.ts +458 -0
- package/tests/session-profile-append-controller-pi.test.ts +290 -0
- package/tests/session-profile-append-controller.test.ts +731 -0
- package/tests/session-profile-disk-reader-pi.test.ts +183 -0
- package/tests/session-profile-disk-reader.test.ts +311 -0
- package/tests/session-profile-freeze.test.ts +23 -0
- package/tests/session-scratch.test.ts +1011 -0
- package/tests/session-subject-routing-contract.test.ts +2 -1
- package/tests/session-worktree-registry.test.ts +13 -1
- package/tests/shell-bar.test.ts +21 -2
- package/tests/shell-changes-view.test.ts +137 -1
- package/tests/shell-changes.test.ts +148 -1
- package/tests/shell-gauge.test.ts +42 -0
- package/tests/shell-prompt.test.ts +3 -3
- package/tests/shell-render-cache.test.ts +134 -1
- package/tests/shell-sidebar-layout.test.ts +50 -0
- package/tests/short-check-routing-contract.test.ts +1 -1
- package/tests/skill-collision-prefixes.test.ts +3 -1
- package/tests/skill-registry-watcher.test.ts +17 -5
- package/tests/skill-registry.test.ts +47 -3
- 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 +70 -10
- 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 +154 -0
- package/tests/verify-agent-contract.test.ts +8 -8
- package/tests/voice-command.test.ts +773 -0
- package/tests/voice-install.test.ts +323 -0
- package/tests/voice-platform.test.ts +176 -0
- package/tests/voice-push-to-talk.test.ts +444 -0
- package/tests/voice-session.test.ts +434 -0
- package/tests/voice-settings.test.ts +49 -0
- package/tests/voice-ui.test.ts +97 -0
- package/tests/voice-worker.test.ts +445 -0
- package/tests/weak-model-economy-prompt.test.ts +32 -0
- package/tests/windows-hidden-processes.test.ts +30 -2
- package/tests/writer-edit-surface-scope.test.ts +3 -0
- package/tests/writer-feature-document-admission.test.ts +156 -0
- package/tests/yolo-customize.test.ts +5 -1
- package/tests/yolo-mode.test.ts +19 -1
- package/tests/yolo-session-policy-capture.test.ts +104 -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
|
@@ -107,6 +107,36 @@ function exists(path) {
|
|
|
107
107
|
try { lstatSync(path); return true; }
|
|
108
108
|
catch (error) { if (error.code === "ENOENT") return false; throw error; }
|
|
109
109
|
}
|
|
110
|
+
// Failure-only diagnostics, in UTF-16 code units. Suppress entire sensitive
|
|
111
|
+
// streams (including continuation lines), and individual path/SID/opaque lines.
|
|
112
|
+
// This is conservative diagnostic filtering, not a general-purpose secret parser.
|
|
113
|
+
function processDiagnosticText(value, limit) {
|
|
114
|
+
if (typeof value !== "string") return "";
|
|
115
|
+
if (/(?:^|[^a-z0-9])(?:authorization|bearer|token|password|passphrase|secret|credential|api[_-]?key|access[_-]?key|cookie)(?:$|[^a-z0-9])/i.test(value)) return "[redacted]";
|
|
116
|
+
return value.split(/\r\n?|\n/).map(line =>
|
|
117
|
+
/[A-Za-z]:[\\/]|\\|(?:^|[\s"'=])\/\S+|\bS-\d-(?:\d+-)+\d+\b|unsafe:[^|]*\||[A-Za-z0-9+/=_-]{64,}|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/i.test(line) ? "[redacted]" : line
|
|
118
|
+
).join("\n").slice(0, limit);
|
|
119
|
+
}
|
|
120
|
+
function prerequisiteProcessCause(result) {
|
|
121
|
+
const failure = result.error;
|
|
122
|
+
const code = processDiagnosticText(failure?.code, 64);
|
|
123
|
+
const details = {
|
|
124
|
+
status: Number.isSafeInteger(result.status) ? result.status : null,
|
|
125
|
+
signal: processDiagnosticText(result.signal, 32) || null,
|
|
126
|
+
error: failure ? {
|
|
127
|
+
code, name: processDiagnosticText(failure.name, 64),
|
|
128
|
+
// Spawn text may contain a bare private executable name, not just paths.
|
|
129
|
+
message: /^E[A-Z0-9_]+$/.test(code) ? `Windows prerequisite process error: ${code}` : "Windows prerequisite process error",
|
|
130
|
+
errno: Number.isSafeInteger(failure.errno) ? failure.errno : processDiagnosticText(failure.errno, 64),
|
|
131
|
+
} : null,
|
|
132
|
+
stdout: processDiagnosticText(result.stdout, 1024), stderr: processDiagnosticText(result.stderr, 1024),
|
|
133
|
+
};
|
|
134
|
+
const cause = Object.assign(new Error("Windows prerequisite process diagnostics"), details);
|
|
135
|
+
// Existing evidence consumers read cause.stack only; omit local callsites and
|
|
136
|
+
// never attach the raw spawn Error (which carries command/path/argv fields).
|
|
137
|
+
cause.stack = `Error: ${cause.message}\n${JSON.stringify(details)}`.slice(0, 8192);
|
|
138
|
+
return cause;
|
|
139
|
+
}
|
|
110
140
|
export function windowsProcessCheck(command, args, env) {
|
|
111
141
|
// Owned direct children only, not a tree/global kill. Descendant-held stdio
|
|
112
142
|
// is outside this guarantee. Never execute .cmd through a command interpreter.
|
|
@@ -114,7 +144,7 @@ export function windowsProcessCheck(command, args, env) {
|
|
|
114
144
|
// A neutral cwd: inside a project (the bundle itself), pnpm 11 reports, and may
|
|
115
145
|
// fetch, the version that project's packageManager pins instead of its own.
|
|
116
146
|
const result = spawnSync(command, args, { cwd: parse(command).root || undefined, env, shell: false, encoding: "utf8", timeout: 15000, killSignal: "SIGKILL", maxBuffer: 1024 * 1024, windowsHide: true });
|
|
117
|
-
if (result.error || result.status !== 0) throw new Error("Windows prerequisite process failed");
|
|
147
|
+
if (result.error || result.status !== 0) throw new Error("Windows prerequisite process failed", { cause: prerequisiteProcessCause(result) });
|
|
118
148
|
return result.stdout.trim();
|
|
119
149
|
}
|
|
120
150
|
|
|
@@ -151,9 +181,9 @@ try {
|
|
|
151
181
|
$depth = 0;
|
|
152
182
|
while ($path) {
|
|
153
183
|
$role = 'ancestor'; if ($depth -eq 0) { $role = 'target' } elseif ($depth -eq 1) { $role = 'parent' };
|
|
154
|
-
$
|
|
155
|
-
if ($
|
|
156
|
-
if ($
|
|
184
|
+
$attributes = [IO.File]::GetAttributes($path);
|
|
185
|
+
if ($attributes -band [IO.FileAttributes]::ReparsePoint) { $detail = $path + '|||'; throw ($role + '-reparse') };
|
|
186
|
+
if ($attributes -band [IO.FileAttributes]::Directory) { $acl = [IO.Directory]::GetAccessControl($path) } else { $acl = [IO.File]::GetAccessControl($path) };
|
|
157
187
|
$owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]);
|
|
158
188
|
if ($trusted -notcontains $owner.Value) { $detail = $path + '|' + $owner.Value + '|' + (& $account $owner) + '|'; throw ($role + '-owner') };
|
|
159
189
|
$allowedRights = 0x1200a9; if ($depth -ge 2) { $allowedRights = 0x1200ad };
|
|
@@ -186,9 +216,9 @@ foreach ($start in $env:GENTLE_WINDOWS_CHECKS.Split('|')) {
|
|
|
186
216
|
$depth = 0;
|
|
187
217
|
while ($path) {
|
|
188
218
|
$role = 'ancestor'; if ($depth -eq 0) { $role = 'target' } elseif ($depth -eq 1) { $role = 'parent' };
|
|
189
|
-
$
|
|
190
|
-
if ($
|
|
191
|
-
if ($
|
|
219
|
+
$attributes = [IO.File]::GetAttributes($path);
|
|
220
|
+
if ($attributes -band [IO.FileAttributes]::ReparsePoint) { $detail = $path + '|||'; throw ($role + '-reparse') };
|
|
221
|
+
if ($attributes -band [IO.FileAttributes]::Directory) { $acl = [IO.Directory]::GetAccessControl($path) } else { $acl = [IO.File]::GetAccessControl($path) };
|
|
192
222
|
$owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]);
|
|
193
223
|
if ($trusted -notcontains $owner.Value) { $detail = $path + '|' + $owner.Value + '|' + (& $account $owner) + '|'; throw ($role + '-owner') };
|
|
194
224
|
$allowedRights = 0x1200a9; if ($depth -ge 2) { $allowedRights = 0x1200ad };
|
package/scripts/main-channel.mjs
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
// an exact commit SHA resolved at install or upgrade time:
|
|
5
5
|
// - Gentle AI: `go install <module>@<sha>` in a sealed Go environment, so the
|
|
6
6
|
// module source is verified by Go's checksum database (sum.golang.org), as
|
|
7
|
-
// the Windows release build already is.
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// the Windows release build already is. Go must resolve the commit to a
|
|
8
|
+
// module version (a tag or a pseudo-version) whose origin is that commit,
|
|
9
|
+
// and the binary must embed that version and report it, then it is
|
|
10
|
+
// activated through the existing dev-binary override, which never falls
|
|
11
|
+
// back to the pinned binary silently.
|
|
10
12
|
// - Gentle Shell: the exact commit's source tarball, versioned
|
|
11
13
|
// `<version>-main.<sha12>` and packed without `prepack` (which runs the full
|
|
12
14
|
// test suite), then installed globally like any local tarball.
|
|
@@ -18,13 +20,14 @@ import { goAcquisition, pnpmGlobalBin, requirements } from "./installer-prefligh
|
|
|
18
20
|
|
|
19
21
|
export const SHELL_REPOSITORY = "Gentleman-Programming/gentle-shell";
|
|
20
22
|
export const GENTLE_AI_REPOSITORY = "Gentleman-Programming/gentle-ai";
|
|
23
|
+
export const GENTLE_AI_MODULE = "github.com/gentleman-programming/gentle-ai/v4";
|
|
21
24
|
export const GENTLE_AI_MAIN_PACKAGE = "github.com/gentleman-programming/gentle-ai/v4/cmd/gentle-ai";
|
|
22
25
|
export const CHANNEL_SCHEMA = "gentle-shell.channel/v1";
|
|
23
26
|
export const CHANNELS = Object.freeze(["release", "main"]);
|
|
24
27
|
|
|
25
28
|
const SHA = /^[0-9a-f]{40}$/;
|
|
26
29
|
const MINUTE = 60_000;
|
|
27
|
-
const deadlines = Object.freeze({ build: 15 * MINUTE, version: 30_000, extract: 2 * MINUTE, pack: 5 * MINUTE });
|
|
30
|
+
const deadlines = Object.freeze({ build: 15 * MINUTE, resolve: 2 * MINUTE, version: 30_000, extract: 2 * MINUTE, pack: 5 * MINUTE });
|
|
28
31
|
const MAX_SOURCE_BYTES = 100 * 1024 * 1024;
|
|
29
32
|
|
|
30
33
|
export class MainChannelError extends Error {
|
|
@@ -35,9 +38,10 @@ export class MainChannelError extends Error {
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
/** Same config home as the dev-binary override: GENTLE_PI_CONFIG_HOME or ~/.pi/gentle-ai.
|
|
41
|
+
/** Same config home as the dev-binary override: a nonempty GENTLE_PI_CONFIG_HOME or ~/.pi/gentle-ai.
|
|
42
|
+
* Install-level state, so never the standalone launcher's per-home marker (#2201). */
|
|
39
43
|
export function configHome({ env, home }) {
|
|
40
|
-
return env.GENTLE_PI_CONFIG_HOME
|
|
44
|
+
return env.GENTLE_PI_CONFIG_HOME || join(home, ".pi", "gentle-ai");
|
|
41
45
|
}
|
|
42
46
|
export function channelStatePath(ctx) {
|
|
43
47
|
return join(configHome(ctx), "channel.json");
|
|
@@ -135,23 +139,57 @@ export async function buildMainGentleAi({ commit, ctx, platform, goPath, run, fs
|
|
|
135
139
|
const executable = platform === "win32" ? "gentle-ai.exe" : "gentle-ai";
|
|
136
140
|
const directory = join(configHome(ctx), "main", "gentle-ai", commit);
|
|
137
141
|
const buildDirectory = join(configHome(ctx), "main", ".build");
|
|
142
|
+
// Verified in the work folder before it replaces anything, so a failed rebuild of
|
|
143
|
+
// an already registered commit never touches the override; the final move stays
|
|
144
|
+
// on one filesystem, and uninstall already accepts a leftover .build.
|
|
145
|
+
const staging = join(buildDirectory, commit);
|
|
138
146
|
await fs.rm(buildDirectory, { recursive: true, force: true });
|
|
139
147
|
const env = sealedGoEnvironment(goPath, buildDirectory, platform);
|
|
140
148
|
for (const path of [env.GOBIN, env.GOPATH, env.GOMODCACHE, env.GOCACHE, join(buildDirectory, "tmp")]) await fs.mkdir(path, { recursive: true });
|
|
141
149
|
try {
|
|
142
150
|
const install = await run(goPath, ["install", `${GENTLE_AI_MAIN_PACKAGE}@${commit}`], { env, cwd: buildDirectory, deadlineMs: deadlines.build, stderrTail: 4096 });
|
|
143
151
|
if (!succeeded(install)) throw new MainChannelError("main-gentle-ai-build-failed", `go install ${GENTLE_AI_MAIN_PACKAGE}@${commit} failed`, stderrCause(install));
|
|
144
|
-
await fs.mkdir(
|
|
145
|
-
const
|
|
146
|
-
await fs.copyFile(join(env.GOBIN, executable),
|
|
147
|
-
if (platform !== "win32") await fs.chmod(
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
await fs.mkdir(staging, { recursive: true });
|
|
153
|
+
const stagedPath = join(staging, executable);
|
|
154
|
+
await fs.copyFile(join(env.GOBIN, executable), stagedPath);
|
|
155
|
+
if (platform !== "win32") await fs.chmod(stagedPath, 0o755);
|
|
156
|
+
const reject = async (message, cause) => {
|
|
157
|
+
throw new MainChannelError("main-gentle-ai-unverified", message, cause);
|
|
158
|
+
};
|
|
159
|
+
const short = commit.slice(0, 12);
|
|
160
|
+
const goOptions = { env, cwd: buildDirectory, deadlineMs: deadlines.version, stderrTail: 4096 };
|
|
161
|
+
// Go resolves the commit through the proxy and checksum database: a tag commit is
|
|
162
|
+
// stamped with its tag, any other with a pseudo-version, so the version is not guessed.
|
|
163
|
+
// Resolving may reach the proxy, so it gets a network deadline, not the local one.
|
|
164
|
+
const listed = await run(goPath, ["list", "-m", "-json", `${GENTLE_AI_MODULE}@${commit}`], { ...goOptions, deadlineMs: deadlines.resolve });
|
|
165
|
+
if (!succeeded(listed)) return await reject(`Go could not resolve Gentle AI commit ${short}`, stderrCause(listed));
|
|
166
|
+
let resolved = null;
|
|
167
|
+
try {
|
|
168
|
+
resolved = JSON.parse(String(listed.stdout ?? ""));
|
|
169
|
+
} catch {
|
|
170
|
+
return await reject(`Go returned unreadable module information for Gentle AI commit ${short}`);
|
|
171
|
+
}
|
|
172
|
+
const resolvedVersion = typeof resolved?.Version === "string" ? resolved.Version : "";
|
|
173
|
+
const originHash = resolved?.Origin?.Hash;
|
|
174
|
+
if (resolvedVersion === "") return await reject(`Go resolved Gentle AI commit ${short} to no module version`);
|
|
175
|
+
if (originHash !== commit) {
|
|
176
|
+
return await reject(`Go resolved Gentle AI commit ${short} to ${originHash ? `commit ${originHash}` : "no commit"}, not the requested commit`);
|
|
177
|
+
}
|
|
178
|
+
const embedded = await run(goPath, ["version", "-m", stagedPath], goOptions);
|
|
179
|
+
if (!succeeded(embedded)) return await reject("the built Gentle AI's embedded module version could not be read", stderrCause(embedded));
|
|
180
|
+
const modLine = String(embedded.stdout ?? "").split(/\r?\n/).map((line) => line.trim().split(/\s+/)).find((fields) => fields[0] === "mod" && fields[1] === GENTLE_AI_MODULE);
|
|
181
|
+
if (modLine?.[2] !== resolvedVersion) {
|
|
182
|
+
return await reject(`the built Gentle AI embeds module version ${modLine?.[2] ?? "none"}, expected ${resolvedVersion} for commit ${short}`);
|
|
183
|
+
}
|
|
184
|
+
const probe = await run(stagedPath, ["version"], { env: { PATH: env.PATH }, deadlineMs: deadlines.version });
|
|
150
185
|
const match = succeeded(probe) && /^gentle-ai (\S+)$/m.exec(String(probe.stdout ?? ""));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
186
|
+
const expectedVersion = resolvedVersion.replace(/^v/, "");
|
|
187
|
+
if (!match || match[1] !== expectedVersion) {
|
|
188
|
+
return await reject(`the built Gentle AI reports version ${match ? match[1] : "none"}, expected ${expectedVersion} for commit ${short}`);
|
|
154
189
|
}
|
|
190
|
+
await fs.mkdir(directory, { recursive: true });
|
|
191
|
+
const binaryPath = join(directory, executable);
|
|
192
|
+
await fs.rename(stagedPath, binaryPath);
|
|
155
193
|
registerGentleAiDevBinary(binaryPath, ctx, platform);
|
|
156
194
|
return { binaryPath, version: match[1] };
|
|
157
195
|
} finally {
|
|
@@ -386,6 +424,21 @@ async function mainGo({ userGo, pinnedGo, acquire, run }) {
|
|
|
386
424
|
}
|
|
387
425
|
}
|
|
388
426
|
|
|
427
|
+
/** A thrown value's message when it has one (an Error or not), otherwise the value as text. */
|
|
428
|
+
function describe(error) {
|
|
429
|
+
return typeof error?.message === "string" ? error.message : String(error);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** `error` with `detail` appended to its message, keeping its code and cause; any
|
|
433
|
+
* other error becomes `main-upgrade-incomplete` with its message and itself as cause. */
|
|
434
|
+
function withDetail(error, detail) {
|
|
435
|
+
if (!(error instanceof MainChannelError)) {
|
|
436
|
+
return new MainChannelError("main-upgrade-incomplete", `${describe(error)}; ${detail}`, error);
|
|
437
|
+
}
|
|
438
|
+
const message = error.message.slice(`${error.code}: `.length);
|
|
439
|
+
return new MainChannelError(error.code, `${message}; ${detail}`, error.cause);
|
|
440
|
+
}
|
|
441
|
+
|
|
389
442
|
/**
|
|
390
443
|
* Updates Gentle Shell along its recorded channel (or the one `--channel` selects):
|
|
391
444
|
* release goes to the latest npm release, main to the latest `main` commits of
|
|
@@ -440,11 +493,33 @@ export async function runUpgrade({ args, ctx, platform, arch = process.arch, pac
|
|
|
440
493
|
out(`gentle-shell is already at the latest main: ${summary}.`);
|
|
441
494
|
return 0;
|
|
442
495
|
}
|
|
443
|
-
|
|
496
|
+
// Fail forward (#2356): a Gentle AI step that fails still installs a main Shell that
|
|
497
|
+
// moved, so the retry runs the new Shell's code; the channel is recorded only when
|
|
498
|
+
// both steps succeed, so that retry rebuilds Gentle AI. Verification stays fail-closed.
|
|
499
|
+
// A flag, not the caught value: a rejection may be any value, even a falsy one.
|
|
500
|
+
let aiFailed = false;
|
|
501
|
+
let aiError;
|
|
502
|
+
if (!aiCurrent) {
|
|
503
|
+
try {
|
|
504
|
+
await buildMainGentleAi({ commit: gentleAiCommit, ctx, platform, goPath: await mainGo({ userGo, pinnedGo, acquire, run }), run, fs });
|
|
505
|
+
} catch (error) {
|
|
506
|
+
if (shellCurrent) throw error;
|
|
507
|
+
aiFailed = true;
|
|
508
|
+
aiError = error;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
444
511
|
if (!shellCurrent) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
512
|
+
try {
|
|
513
|
+
const manager = await ownerManager({ ctx, platform, packageRoot, adapters });
|
|
514
|
+
const tgz = await packMainShell({ commit: shellCommit, ctx, fetch, run, pnpm, fs, platform });
|
|
515
|
+
await installGlobal(manager, tgz, run);
|
|
516
|
+
} catch (error) {
|
|
517
|
+
throw aiFailed ? withDetail(error, `Gentle AI was not updated either (${describe(aiError)})`) : error;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (aiFailed) {
|
|
521
|
+
out(`Updated Gentle Shell to the latest main (${shellCommit.slice(0, 12)}); Gentle AI was not updated.`);
|
|
522
|
+
throw withDetail(aiError, `Gentle Shell was updated to main ${shellCommit.slice(0, 12)} but Gentle AI was not: run gentle-shell upgrade --channel main to finish`);
|
|
448
523
|
}
|
|
449
524
|
await writeChannel(ctx, { channel: "main", shellCommit, gentleAiCommit }, fs);
|
|
450
525
|
out(`Updated to the latest main: ${summary}.`);
|
package/scripts/pi-update.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Narrow update ownership proof. Deliberately independent of Shell upgrade/uninstall.
|
|
2
2
|
import { posix, win32 } from 'node:path';
|
|
3
3
|
import { bundledUpdatePlan } from '../runtime/gentle-shell-bundled.mjs';
|
|
4
|
+
import { setupErrorDetail } from './installer-runner.mjs';
|
|
4
5
|
|
|
5
6
|
const PI = '@earendil-works/pi-coding-agent';
|
|
6
7
|
const SHELL = 'gentle-pi';
|
|
@@ -8,6 +9,9 @@ const object = value => value !== null && typeof value === 'object' && !Array.is
|
|
|
8
9
|
const succeeded = result => result?.code === 0 && !result.timedOut && result.signal == null;
|
|
9
10
|
const refusal = detail => new Error(`gentle-shell update: ownership ${detail}; update Pi with the package manager or source checkout that supplies the selected runtime. No installation changed.`);
|
|
10
11
|
const LINKED = /^(?:file|link|workspace):/i;
|
|
12
|
+
// A main-channel Shell (`<version>-main.<sha12>`, scripts/main-channel.mjs
|
|
13
|
+
// mainVersion) is never published; it exists only as the packed tarball.
|
|
14
|
+
const MAIN_BUILD = /^[0-9A-Za-z.+-]+-main\.[0-9a-f]{12}$/;
|
|
11
15
|
const CLI_TAIL = /[\\/]dist[\\/]bundle[\\/]cli\.js$/i;
|
|
12
16
|
// A quoted cli.js target inside a package-manager shim: pnpm's POSIX shim
|
|
13
17
|
// (`"$basedir/../global/.../cli.js"`), its `.CMD`/npm's `.cmd` shim
|
|
@@ -136,7 +140,19 @@ async function listedEntries(groups, {adapters, path, key, canonical}) {
|
|
|
136
140
|
* ownership. An adjacent runtime is owned by the Shell group that resolved
|
|
137
141
|
* it: updating a separate global Pi never changes what that Shell runs.
|
|
138
142
|
*/
|
|
139
|
-
|
|
143
|
+
/** Where `gentle-shell upgrade --channel main` packed this Shell version: the
|
|
144
|
+
* same config home as scripts/main-channel.mjs configHome. A relative config
|
|
145
|
+
* home is refused, not resolved: `upgrade` resolved it from its own working
|
|
146
|
+
* directory, so it names no single folder, and the package manager runs from
|
|
147
|
+
* the neutral cwd.
|
|
148
|
+
*/
|
|
149
|
+
function mainBuildTarball(version, {env, home, path}) {
|
|
150
|
+
const config = env?.GENTLE_PI_CONFIG_HOME || (typeof home === 'string' ? path.join(home, '.pi', 'gentle-ai') : null);
|
|
151
|
+
if (!config || !path.isAbsolute(config)) throw refusal('cannot locate the main-channel build without an absolute config home');
|
|
152
|
+
return path.join(config, 'main', 'packages', `${SHELL}-${version}.tgz`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function resolveUpdateOwner({runtime, packageRoot, platform = process.platform, adapters, cwd, env, home}) {
|
|
140
156
|
const {path, key} = pathsFor(platform);
|
|
141
157
|
const canonical = canonicalWith(adapters, path);
|
|
142
158
|
const selected = await selectedCliOf(runtime, {adapters, path, canonical});
|
|
@@ -154,7 +170,7 @@ export async function resolveUpdateOwner({runtime, packageRoot, platform = proce
|
|
|
154
170
|
const root = await canonical(dependency.path);
|
|
155
171
|
const manifest = await manifestOf(adapters, path, root);
|
|
156
172
|
if (manifest.name !== pkg) throw refusal('listed package identity differs');
|
|
157
|
-
let cli, spec;
|
|
173
|
+
let cli, spec, artifact = false;
|
|
158
174
|
if (pkg === PI) {
|
|
159
175
|
if (manifest.bin?.pi !== 'dist/bundle/cli.js') throw refusal('listed Pi bin is unsupported');
|
|
160
176
|
cli = await canonical(path.join(root, manifest.bin.pi));
|
|
@@ -169,11 +185,12 @@ export async function resolveUpdateOwner({runtime, packageRoot, platform = proce
|
|
|
169
185
|
// Reinstalling the same Shell version re-resolves its peer; `update`
|
|
170
186
|
// never upgrades Shell itself (that is `gentle-shell upgrade`).
|
|
171
187
|
if (typeof manifest.version !== 'string') throw refusal('listed Shell version is missing');
|
|
172
|
-
|
|
188
|
+
artifact = MAIN_BUILD.test(manifest.version);
|
|
189
|
+
spec = artifact ? mainBuildTarball(manifest.version, {env, home, path}) : `${SHELL}@${manifest.version}`;
|
|
173
190
|
}
|
|
174
191
|
if (key(cli) !== key(selected)) continue;
|
|
175
192
|
if (name === 'pnpm' && members.get(key(groupRoot)).size !== 1) throw refusal('selected supplier shares its global install group');
|
|
176
|
-
candidates.push({name, ...invocation, package:pkg, spec});
|
|
193
|
+
candidates.push({name, ...invocation, package:pkg, spec, artifact});
|
|
177
194
|
}
|
|
178
195
|
}
|
|
179
196
|
if (candidates.length !== 1) throw refusal(candidates.length > 1 ? 'is ambiguous' : 'could not be verified from global listings');
|
|
@@ -207,11 +224,22 @@ export async function updateSelectedPi(input) {
|
|
|
207
224
|
let owner;
|
|
208
225
|
try { owner = await resolveUpdateOwner(input); }
|
|
209
226
|
catch (error) { throw error.message?.includes('ownership') ? error : refusal('could not be resolved'); }
|
|
227
|
+
if (owner.artifact) {
|
|
228
|
+
try { await input.adapters.fs.realpath(owner.spec); }
|
|
229
|
+
catch { throw new Error(`gentle-shell update: the main-channel build ${owner.spec} is missing, and this unpublished build cannot be reinstalled from the registry; run 'gentle-shell upgrade --channel release' and then 'gentle-shell upgrade --channel main' to rebuild it. No installation changed.`); }
|
|
230
|
+
}
|
|
210
231
|
// Exactly one approved package per command; never create a comma group or
|
|
211
232
|
// reinstall arbitrary dependencies merely because they share a store.
|
|
212
233
|
const args = owner.name === 'pnpm' ? ['add', '-g', owner.spec, ...(owner.package === SHELL ? ['--allow-build=gentle-pi'] : [])] : ['install', '-g', owner.spec, ...(owner.package === PI ? ['--ignore-scripts'] : [])];
|
|
213
|
-
const result = await input.adapters.run(owner.command, [...owner.prefix, ...args], {deadlineMs:20 * 60_000, cwd: input.cwd});
|
|
214
|
-
if (!succeeded(result))
|
|
234
|
+
const result = await input.adapters.run(owner.command, [...owner.prefix, ...args], {deadlineMs:20 * 60_000, cwd: input.cwd, stderrTail:4096});
|
|
235
|
+
if (!succeeded(result)) {
|
|
236
|
+
// One sanitized line of the manager's own error: npm prints it on stderr,
|
|
237
|
+
// pnpm 11 prints ERR_PNPM_* on stdout. Read as one text, stderr last, an
|
|
238
|
+
// error line in either stream wins over a stderr warning, stderr's on a tie.
|
|
239
|
+
const output = [result?.stdout, result?.stderrTail].filter(text => typeof text === 'string').join('\n');
|
|
240
|
+
const detail = setupErrorDetail(output, input.home, input.platform);
|
|
241
|
+
throw new Error(`gentle-shell update: ${owner.name} (${[owner.command, ...owner.prefix].join(' ')}) could not install ${owner.spec}${detail ? `\n${detail}` : ''}`);
|
|
242
|
+
}
|
|
215
243
|
const after = await suppliedPiVersion(owner, input);
|
|
216
244
|
const before = input.currentVersion;
|
|
217
245
|
if (after === null) input.out?.(`${owner.name} installed ${owner.spec}. The Pi version it now supplies could not be read back; run 'gentle-shell --version' to check it.`);
|
|
@@ -30,6 +30,10 @@ export async function runStage(stage) {
|
|
|
30
30
|
return !normalizedKey.startsWith("GIT_") && !normalizedKey.startsWith("GENTLE_PI_AGENTS_") && normalizedKey !== "GENTLE_PI_CONFIG_HOME";
|
|
31
31
|
})) : process.env;
|
|
32
32
|
if (configHome) env.GENTLE_PI_CONFIG_HOME = configHome;
|
|
33
|
+
// Unit fixtures also get a private temp dir, removed with the stage, so a
|
|
34
|
+
// fixture that leaves a subagent unfinished cannot leave its TMPDIR behind.
|
|
35
|
+
const unitTmp = configHome ? mkdtempSync(join(tmpdir(), "gentle-pi-unit-tmp-")) : undefined;
|
|
36
|
+
if (unitTmp) env.TMPDIR = unitTmp;
|
|
33
37
|
try {
|
|
34
38
|
return await new Promise((resolve) => {
|
|
35
39
|
const child = spawn(stage.command, { shell: true, stdio: "inherit", env });
|
|
@@ -41,6 +45,7 @@ export async function runStage(stage) {
|
|
|
41
45
|
});
|
|
42
46
|
} finally {
|
|
43
47
|
if (configHome) rmSync(configHome, { recursive: true, force: true });
|
|
48
|
+
if (unitTmp) rmSync(unitTmp, { recursive: true, force: true });
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -50,9 +50,33 @@ export const requiredPaths = [
|
|
|
50
50
|
"assets/sounds/LICENSE.md",
|
|
51
51
|
"docs/sound-notifications.md",
|
|
52
52
|
"docs/sound-notifications-proposal.md",
|
|
53
|
+
"extensions/gentle-voice.ts",
|
|
54
|
+
"lib/voice-artifacts.ts",
|
|
55
|
+
"lib/voice-command.ts",
|
|
56
|
+
"lib/voice-install.ts",
|
|
57
|
+
"lib/voice-platform.ts",
|
|
58
|
+
"lib/voice-session.ts",
|
|
59
|
+
"lib/voice-ui.ts",
|
|
60
|
+
// The dictation worker is spawned by path, never imported, so nothing else
|
|
61
|
+
// would notice it missing from the packed tarball.
|
|
62
|
+
"scripts/voice-worker.cjs",
|
|
63
|
+
"docs/voice.md",
|
|
64
|
+
"extensions/gentle-design.ts",
|
|
65
|
+
"lib/gentle-design.ts",
|
|
66
|
+
// The design canvas server reads its page and scripts from assets/ by path.
|
|
67
|
+
"lib/design-canvas-server.ts",
|
|
68
|
+
"lib/design-open-browser.ts",
|
|
69
|
+
"lib/design-comments.ts",
|
|
70
|
+
"lib/design-handoffs.ts",
|
|
71
|
+
"lib/design-sources.ts",
|
|
72
|
+
"assets/design-canvas/index.html",
|
|
73
|
+
"assets/design-canvas/canvas.js",
|
|
74
|
+
"assets/design-canvas/canvas.css",
|
|
75
|
+
"assets/design-canvas/inspector.js",
|
|
53
76
|
"scripts/npm-pack-result.mjs",
|
|
54
77
|
"assets/orchestrator.md",
|
|
55
78
|
"assets/orchestrator-delegation.md",
|
|
79
|
+
"assets/orchestrator-delegation-reference.md",
|
|
56
80
|
"assets/orchestrator-tracking.md",
|
|
57
81
|
"assets/orchestrator-verification.md",
|
|
58
82
|
"assets/orchestrator-writer.md",
|
|
@@ -81,6 +105,7 @@ export const requiredPaths = [
|
|
|
81
105
|
"docs/review-integration.md",
|
|
82
106
|
"extensions/gentle-ai.ts",
|
|
83
107
|
"extensions/resume-hint.ts",
|
|
108
|
+
"extensions/session-scratch.ts",
|
|
84
109
|
"extensions/skill-registry.ts",
|
|
85
110
|
"lib/child-package-injection.ts",
|
|
86
111
|
"lib/gentle-ai-binary.ts",
|
|
@@ -90,6 +115,7 @@ export const requiredPaths = [
|
|
|
90
115
|
"lib/gentle-shell-update-panel.ts",
|
|
91
116
|
"lib/gentle-shell-startup-flow.ts",
|
|
92
117
|
"lib/gentle-shell-resume-hint.ts",
|
|
118
|
+
"lib/gentle-shell-import-pi.ts",
|
|
93
119
|
"lib/native-review-cli.ts",
|
|
94
120
|
"lib/status-timing-diagnostics.ts",
|
|
95
121
|
"lib/provider-contract-bundle.ts",
|
|
@@ -98,6 +124,7 @@ export const requiredPaths = [
|
|
|
98
124
|
"lib/review-relay-contract.ts",
|
|
99
125
|
"lib/agent-assets.ts",
|
|
100
126
|
"lib/telemetry-trigger.ts",
|
|
127
|
+
"lib/session-scratch.ts",
|
|
101
128
|
"runtime/child-package-injection.mjs",
|
|
102
129
|
"runtime/gentle-ai-binary.mjs",
|
|
103
130
|
"runtime/gentle-shell-launcher.mjs",
|
|
@@ -107,6 +134,7 @@ export const requiredPaths = [
|
|
|
107
134
|
"runtime/gentle-shell-startup-flow.mjs",
|
|
108
135
|
"runtime/gentle-shell-resume-hint.mjs",
|
|
109
136
|
"runtime/gentle-shell-uninstall.mjs",
|
|
137
|
+
"runtime/gentle-shell-import-pi.mjs",
|
|
110
138
|
"runtime/native-review-cli.mjs",
|
|
111
139
|
"runtime/status-timing-diagnostics.mjs",
|
|
112
140
|
"runtime/review-integration-v2.mjs",
|
|
@@ -131,23 +159,25 @@ export const requiredPaths = [
|
|
|
131
159
|
// exact bytes are pinned by the lock-driven scripts/check-provider-contract.mjs
|
|
132
160
|
// drift check, which runs in the same pnpm test flow.
|
|
133
161
|
"contracts/review-provider-contract-mirror/provider-contract.lock.json",
|
|
134
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
135
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
136
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
137
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
138
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
139
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
140
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
141
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
142
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
143
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
144
|
-
"contracts/review-provider-contract-mirror/v1.
|
|
162
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/README.md",
|
|
163
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/manifest.json",
|
|
164
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/orchestration/pi.md",
|
|
165
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/routing/pi.md",
|
|
166
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/schemas/lens.schema.json",
|
|
167
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/schemas/refuter.schema.json",
|
|
168
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/schemas/targeted-validator.schema.json",
|
|
169
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/vectors/lens.json",
|
|
170
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/vectors/refuter.json",
|
|
171
|
+
"contracts/review-provider-contract-mirror/v1.4.0/bundle/vectors/targeted-validator.json",
|
|
172
|
+
"contracts/review-provider-contract-mirror/v1.4.0/generated/provider-capabilities.baseline.json",
|
|
173
|
+
"contracts/review-provider-contract-mirror/v1.4.0/generated/provider-roles.baseline.json",
|
|
145
174
|
"prompts/skill-creation.md",
|
|
146
175
|
"skills/_shared/review-ledger-contract.md",
|
|
147
176
|
"skills/branch-pr/SKILL.md",
|
|
148
177
|
"skills/chained-pr/SKILL.md",
|
|
149
178
|
"skills/cognitive-doc-design/SKILL.md",
|
|
150
179
|
"skills/comment-writer/SKILL.md",
|
|
180
|
+
"skills/design/SKILL.md",
|
|
151
181
|
"skills/gentle-ai/SKILL.md",
|
|
152
182
|
"skills/issue-creation/SKILL.md",
|
|
153
183
|
"skills/judgment-day/SKILL.md",
|
|
@@ -395,7 +425,7 @@ async function main() {
|
|
|
395
425
|
});
|
|
396
426
|
|
|
397
427
|
if (driftedContracts.length > 0) {
|
|
398
|
-
console.error("gentle-pi packaged review-integration/v1 and review-integration/v2 contract bytes drifted from the pinned v4.
|
|
428
|
+
console.error("gentle-pi packaged review-integration/v1 and review-integration/v2 contract bytes drifted from the pinned v4.3.1 runtime's vendored Gentle AI contract artifacts:");
|
|
399
429
|
for (const drift of driftedContracts) console.error(`- ${drift.relativePath}: expected ${drift.expected}, got ${drift.actual}`);
|
|
400
430
|
process.exit(1);
|
|
401
431
|
}
|
|
@@ -440,7 +470,7 @@ async function main() {
|
|
|
440
470
|
process.exit(1);
|
|
441
471
|
}
|
|
442
472
|
|
|
443
|
-
console.log(`gentle-pi package resource check passed (${requiredPaths.length} files; ${Object.keys(contractHashes).length} exact byte-pinned contract artifacts for the v4.
|
|
473
|
+
console.log(`gentle-pi package resource check passed (${requiredPaths.length} files; ${Object.keys(contractHashes).length} exact byte-pinned contract artifacts for the v4.3.1 runtime).`);
|
|
444
474
|
}
|
|
445
475
|
|
|
446
476
|
const isMainModule = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;
|