gentle-pi 3.7.0 → 4.1.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 +155 -10
- package/assets/agents/gentle-ai-explore.md +13 -6
- package/assets/agents/gentle-ai-verify.md +27 -6
- package/assets/agents/gentle-ai-worker.md +13 -15
- package/assets/install-wizard/index.html +47 -0
- package/assets/install-wizard/wizard.css +1279 -0
- package/assets/install-wizard/wizard.js +951 -0
- package/assets/orchestrator-delegation.md +75 -169
- package/assets/orchestrator-memory.md +12 -26
- package/assets/orchestrator-prompts.md +48 -0
- package/assets/orchestrator-skills.md +1 -1
- package/assets/orchestrator-tracking.md +53 -0
- package/assets/orchestrator-verification.md +28 -0
- package/assets/orchestrator-writer.md +38 -0
- package/assets/orchestrator.md +30 -38
- package/assets/sounds/LICENSE.md +52 -0
- package/assets/sounds/attention.wav +0 -0
- package/assets/sounds/error.wav +0 -0
- package/assets/sounds/success.wav +0 -0
- package/assets/support/strict-tdd-verify.md +4 -266
- package/assets/support/strict-tdd.md +8 -360
- package/bin/engram-guard +9 -0
- package/bin/gentle-shell-install.mjs +302 -0
- package/bin/gentle-shell.mjs +956 -50
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
- package/docs/bundled-install.md +397 -0
- package/docs/delegated-verification.md +27 -4
- package/docs/gentle-agents-activity.md +537 -0
- package/docs/gentle-shell-uninstall.md +136 -0
- package/docs/gentle-shell.md +165 -51
- package/docs/install-wizard.md +2040 -0
- package/docs/native-authority-architecture.md +3 -3
- package/docs/permission-modes.md +82 -0
- package/docs/prompt-history.md +280 -0
- package/docs/readme-reference.md +364 -231
- package/docs/render-cache-performance.md +28 -0
- package/docs/sound-notifications-proposal.md +191 -0
- package/docs/sound-notifications.md +114 -0
- package/docs/telemetry.md +1 -1
- package/docs/yolo-mode.md +86 -0
- package/extensions/child-context.ts +35 -0
- package/extensions/child-safety.ts +25 -0
- package/extensions/codegraph-tools.ts +18 -5
- package/extensions/gentle-agents.ts +1093 -326
- package/extensions/gentle-ai.ts +1636 -890
- package/extensions/gentle-herdr-activity.ts +81 -0
- package/extensions/gentle-notifications.ts +104 -0
- package/extensions/gentle-shell.ts +1619 -136
- package/extensions/gentle-stats.ts +101 -0
- package/extensions/gentle-todo.ts +126 -20
- package/extensions/history/atomic-write.ts +38 -0
- package/extensions/history/hide-prompts.ts +183 -0
- package/extensions/history/index.ts +1424 -0
- package/extensions/history/load-shared-history.ts +39 -0
- package/extensions/history/selector-helpers.ts +538 -0
- package/extensions/history/session-scan.ts +233 -0
- package/extensions/history/store.ts +1119 -0
- package/extensions/nan-provider.ts +6 -0
- package/extensions/pi-pretty.ts +39 -3
- package/extensions/quiet-tools.ts +254 -92
- package/extensions/resume-hint.ts +60 -0
- package/extensions/skill-registry.ts +191 -58
- package/extensions/startup-banner.ts +71 -33
- package/lib/agent-assets.ts +604 -0
- package/lib/agent-home.ts +10 -1
- package/lib/agent-model-resolution.ts +80 -0
- package/lib/agent-profile-pin.ts +12 -0
- package/lib/agent-profiles.ts +13 -3
- package/lib/agents-completion-delivery.ts +11 -3
- package/lib/agents-message-delivery.ts +181 -0
- package/lib/agents-messaging.ts +1 -1
- package/lib/agents-protocol.ts +99 -0
- package/lib/agents-runner.ts +180 -107
- package/lib/agents-view.ts +26 -3
- package/lib/agents-widget.ts +16 -9
- package/lib/append-system-prompt.ts +21 -0
- package/lib/auto-permission-classifier.ts +280 -0
- package/lib/auto-permission-runtime.ts +268 -0
- package/lib/background-jobs-tools.ts +202 -0
- package/lib/background-jobs.ts +253 -0
- package/lib/background-monitor.ts +154 -0
- package/lib/bounded-writer-admission.ts +220 -0
- package/lib/builtin-codemode-optout.ts +166 -0
- package/lib/card-content-policy.ts +85 -0
- package/lib/card-style-policy.ts +60 -0
- package/lib/child-context-files.ts +166 -0
- package/lib/child-package-injection.ts +62 -0
- package/lib/codemode-renderer.ts +195 -0
- package/lib/command-palette-catalog.ts +5 -10
- package/lib/command-palette.ts +25 -14
- package/lib/context-threshold.ts +26 -0
- package/lib/destructive-command-guard.ts +144 -0
- package/lib/gentle-ai-binary.ts +109 -4
- package/lib/gentle-ai-elapsed-store.ts +87 -0
- package/lib/gentle-ai-renderer.ts +196 -39
- package/lib/gentle-shell-bundled.ts +517 -0
- package/lib/gentle-shell-launcher.ts +89 -27
- package/lib/gentle-shell-resume-hint.ts +176 -0
- package/lib/gentle-shell-startup-flow.ts +54 -0
- package/lib/gentle-shell-startup-update.ts +92 -0
- package/lib/gentle-shell-uninstall.ts +840 -0
- package/lib/gentle-shell-update-panel.ts +231 -0
- package/lib/herdr-activity.ts +183 -0
- package/lib/history-capture-policy.ts +95 -0
- package/lib/inprocess-reviewer.ts +3 -0
- package/lib/jobs-sidebar-state.ts +20 -0
- package/lib/jobs-view.ts +161 -0
- package/lib/model-price-ratio.ts +83 -0
- package/lib/model-routing-authority.ts +5 -1
- package/lib/nan-provider.ts +249 -0
- package/lib/native-review-cli.ts +242 -180
- package/lib/notification-audio-native.ts +162 -0
- package/lib/notification-audio-windows.ts +399 -0
- package/lib/notification-audio.ts +332 -0
- package/lib/notification-customize.ts +241 -0
- package/lib/notification-events.ts +113 -0
- package/lib/notification-policy.ts +148 -0
- package/lib/notification-pulse-client.ts +367 -0
- package/lib/notification-pulse-protocol.ts +305 -0
- package/lib/notification-pulse-stream.ts +213 -0
- package/lib/notification-pulse-worker.ts +66 -0
- package/lib/notification-scheduler.ts +173 -0
- package/lib/notification-service.ts +202 -0
- package/lib/notification-ui.ts +87 -0
- package/lib/odd-phase-inference.ts +231 -0
- package/lib/odd-phase.ts +141 -0
- package/lib/orchestrator-alias.ts +20 -0
- package/lib/orchestrator-catalog.ts +79 -0
- package/lib/orchestrator-consultation.ts +61 -0
- package/lib/orchestrator-discovery.ts +49 -0
- package/lib/orchestrator-helper-consent.ts +122 -0
- package/lib/orchestrator-helper.ts +167 -0
- package/lib/orchestrator-message-card.ts +105 -0
- package/lib/orchestrator-presence.ts +115 -14
- package/lib/orchestrator-scope.ts +80 -0
- package/lib/orchestrator-state.ts +107 -0
- package/lib/orchestrator-tool-card.ts +280 -0
- package/lib/orchestrator-work-search.ts +218 -0
- package/lib/orchestrator-work.ts +79 -0
- package/lib/overlay-repaint.ts +26 -0
- package/lib/permission-mode-policy.ts +59 -0
- package/lib/pi-tui-keys.ts +53 -0
- package/lib/review-candidate-view-owner.ts +73 -21
- package/lib/review-candidate-view.ts +115 -27
- package/lib/review-compact-contract.ts +2 -2
- package/lib/review-host-relay.ts +7 -2
- package/lib/review-integration-v2.ts +100 -22
- package/lib/review-publication-gate.ts +1 -1
- package/lib/review-reminder-receipt.ts +48 -8
- package/lib/review-risk-assessment.ts +227 -56
- package/lib/review-sidebar-state.ts +224 -0
- package/lib/review-transaction.ts +72 -3
- package/lib/runtime-metrics-children.ts +1 -1
- package/lib/runtime-metrics-native.ts +3 -2
- package/lib/selection-engine.ts +527 -0
- package/lib/session-change-capture.ts +5 -4
- package/lib/session-changes.ts +27 -22
- package/lib/session-messaging-grants.ts +135 -0
- package/lib/session-profile-binding.ts +83 -0
- package/lib/session-profile-freeze.ts +266 -0
- package/lib/session-worktree-registry.ts +87 -9
- package/lib/shell-bar.ts +215 -30
- package/lib/shell-card.ts +287 -18
- package/lib/shell-changes-view.ts +42 -14
- package/lib/shell-changes.ts +86 -71
- package/lib/shell-prompt.ts +102 -6
- package/lib/shell-sidebar-layout.ts +83 -15
- package/lib/shell-sidebar.ts +15 -1
- package/lib/shell-todo.ts +84 -31
- package/lib/shell-usage-view.ts +9 -4
- package/lib/shell-usage.ts +70 -13
- package/lib/stats-collector.ts +381 -0
- package/lib/stats-view.ts +431 -0
- package/lib/status-timing-diagnostics.ts +201 -0
- package/lib/telemetry-trigger.ts +3 -1
- package/lib/theme-customization.ts +52 -0
- package/lib/vim-editor-adapter.ts +383 -0
- package/lib/vim-normal-engine.ts +154 -0
- package/lib/vim-operator-engine.ts +416 -0
- package/lib/vim-policy.ts +49 -0
- package/lib/vim-visual-engine.ts +107 -0
- package/lib/visual-customization-policy.ts +119 -0
- package/lib/visual-customize-view.ts +481 -0
- package/lib/visual-profiles.ts +228 -0
- package/lib/writer-surfaces.ts +162 -0
- package/lib/yolo-session-policy.ts +317 -0
- package/package.json +20 -8
- package/runtime/child-package-injection.mjs +63 -0
- package/runtime/gentle-ai-binary.mjs +109 -4
- package/runtime/gentle-shell-bundled.mjs +518 -0
- package/runtime/gentle-shell-launcher.mjs +87 -25
- package/runtime/gentle-shell-resume-hint.mjs +177 -0
- package/runtime/gentle-shell-startup-flow.mjs +55 -0
- package/runtime/gentle-shell-startup-update.mjs +93 -0
- package/runtime/gentle-shell-uninstall.mjs +841 -0
- package/runtime/gentle-shell-update-panel.mjs +232 -0
- package/runtime/native-review-cli.mjs +239 -177
- package/runtime/review-integration-v2.mjs +100 -22
- package/runtime/review-risk-assessment.mjs +225 -54
- package/runtime/status-timing-diagnostics.mjs +202 -0
- package/runtime/telemetry-trigger.mjs +3 -1
- package/scripts/bootstrap.cmd +255 -0
- package/scripts/bootstrap.sh +168 -0
- package/scripts/build-distribution.mjs +157 -0
- package/scripts/build-installer-bundles.mjs +136 -0
- package/scripts/build-runtime-modules.mjs +8 -0
- package/scripts/bundled-install.mjs +1308 -0
- package/scripts/bundled-wizard.mjs +399 -0
- package/scripts/check-types.mjs +4 -6
- package/scripts/gentle-ai-installer.mjs +83 -35
- package/scripts/install-gentle-ai.mjs +48 -1
- package/scripts/install-tui-mode-setting.mjs +10 -1
- package/scripts/install-wizard-preview.mjs +154 -0
- package/scripts/installer-downloads.mjs +648 -0
- package/scripts/installer-preflight.mjs +387 -0
- package/scripts/installer-probes.mjs +564 -0
- package/scripts/installer-runner.mjs +1102 -0
- package/scripts/installer-server.mjs +881 -0
- package/scripts/installer-windows-artifacts.json +15 -0
- package/scripts/installer-windows.mjs +752 -0
- package/scripts/main-channel.mjs +452 -0
- package/scripts/mirror-odd-routing.mjs +2 -2
- package/scripts/npm-pack-result.mjs +31 -0
- package/scripts/render-cache-performance-worker.mjs +205 -0
- package/scripts/render-cache-performance.mjs +115 -0
- package/scripts/run-test-suite.mjs +90 -0
- package/scripts/test-installer-acceptance.sh +161 -0
- package/scripts/test-packed-runner.mjs +54 -19
- package/scripts/types-baseline.json +2 -92
- package/scripts/verify-package-files.mjs +91 -38
- package/skills/branch-pr/SKILL.md +24 -52
- package/skills/chained-pr/SKILL.md +31 -15
- package/skills/chained-pr/references/chaining-details.md +31 -20
- package/skills/gentle-ai/SKILL.md +16 -21
- package/skills/issue-creation/SKILL.md +8 -2
- package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
- package/skills/work-unit-commits/SKILL.md +4 -3
- package/tests/agent-home.test.ts +56 -3
- package/tests/agent-model-resolution.test.ts +113 -0
- package/tests/agent-profiles.test.ts +30 -0
- package/tests/agent-risk-escalation.test.ts +123 -0
- package/tests/agents-completion-delivery.test.ts +17 -0
- package/tests/agents-fake-child.ts +2 -2
- package/tests/agents-message-delivery.test.ts +106 -0
- package/tests/agents-protocol.test.ts +97 -0
- package/tests/agents-queries.test.ts +9 -9
- package/tests/agents-runner-process.test.ts +31 -0
- package/tests/agents-runner.test.ts +467 -93
- package/tests/agents-view-thread-identity.test.ts +169 -0
- package/tests/agents-view.test.ts +8 -2
- package/tests/agents-widget.test.ts +154 -15
- package/tests/append-system-prompt-route.test.ts +160 -0
- package/tests/append-system-prompt.test.ts +46 -0
- package/tests/artifact-language.test.ts +19 -213
- package/tests/ask-user-question.test.ts +44 -1
- package/tests/asset-installation-runtime.test.ts +5 -16
- package/tests/auto-mode-invariants.test.ts +258 -0
- package/tests/auto-mode-sdk.test.ts +57 -0
- package/tests/auto-mode.test.ts +49 -0
- package/tests/auto-permission-classifier.test.ts +283 -0
- package/tests/auto-permission-runtime.test.ts +196 -0
- package/tests/autonomous-guard.test.ts +69 -1
- package/tests/background-cache-warming.test.ts +2 -1
- package/tests/background-jobs.test.ts +227 -0
- package/tests/background-monitor.test.ts +195 -0
- package/tests/background-subagents-default-mode.test.ts +28 -5
- package/tests/bounded-stop-contract.test.ts +85 -0
- package/tests/bounded-writer-admission.test.ts +146 -0
- package/tests/branch-pr-skill.test.ts +43 -0
- package/tests/bridge-wake-lifecycle.test.ts +129 -0
- package/tests/bridge-wake-rendering.test.ts +56 -0
- package/tests/build-distribution.test.ts +269 -0
- package/tests/builtin-codemode-optout.test.ts +242 -0
- package/tests/bundled-install.test.ts +1319 -0
- package/tests/bundled-wizard.test.ts +505 -0
- package/tests/card-content-policy.test.ts +68 -0
- package/tests/card-style-policy.test.ts +87 -0
- package/tests/chained-pr-skill.test.ts +124 -0
- package/tests/child-codegraph-bootstrap.test.ts +74 -0
- package/tests/child-context-files.test.ts +255 -0
- package/tests/child-package-entrypoints.test.ts +65 -0
- package/tests/child-package-injection.test.ts +74 -0
- package/tests/child-safety.test.ts +94 -0
- package/tests/child-web-package.test.ts +224 -0
- package/tests/codegraph-tools.test.ts +35 -0
- package/tests/codemode-rendering.test.ts +596 -0
- package/tests/command-palette.test.ts +43 -7
- package/tests/context-threshold.test.ts +31 -0
- package/tests/delegate-for-reason-contract.test.ts +327 -0
- package/tests/delegated-key-learnings-contract.test.ts +3 -78
- package/tests/destructive-command-guard.test.ts +84 -0
- package/tests/devbinary/native-review-parity.devtest.ts +171 -3
- package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
- package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
- package/tests/engram-safety.test.ts +288 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
- package/tests/generic-agent-tools.test.ts +69 -0
- package/tests/gentle-agents.test.ts +2804 -346
- package/tests/gentle-ai-binary-isolation.test.ts +135 -0
- package/tests/gentle-ai-binary.test.ts +21 -4
- package/tests/gentle-ai-child-guards.test.ts +202 -0
- package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
- package/tests/gentle-ai-elapsed-store.test.ts +68 -0
- package/tests/gentle-ai-installer.test.ts +566 -62
- package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
- package/tests/gentle-ai-renderer.test.ts +493 -14
- package/tests/gentle-ai.test.ts +1427 -236
- package/tests/gentle-card-text.ts +2 -1
- package/tests/gentle-herdr-activity.test.ts +100 -0
- package/tests/gentle-notifications.test.ts +427 -0
- package/tests/gentle-shell-bin.test.ts +896 -115
- package/tests/gentle-shell-bundled.test.ts +1002 -0
- package/tests/gentle-shell-launcher.test.ts +333 -65
- package/tests/gentle-shell-resume-hint.test.ts +270 -0
- package/tests/gentle-shell-startup-flow.test.ts +75 -0
- package/tests/gentle-shell-startup-update.test.ts +85 -0
- package/tests/gentle-shell-uninstall.test.ts +978 -0
- package/tests/gentle-shell-update-panel.test.ts +158 -0
- package/tests/gentle-shell.test.ts +4216 -119
- package/tests/gentle-stats.test.ts +152 -0
- package/tests/gentle-theme.test.ts +4 -1
- package/tests/gentle-todo.test.ts +333 -10
- package/tests/herdr-activity.test.ts +243 -0
- package/tests/history-agent-home.test.ts +81 -0
- package/tests/history-atomic-write.test.ts +57 -0
- package/tests/history-capture-policy.test.ts +102 -0
- package/tests/history-child-guard.test.ts +70 -0
- package/tests/history-command-registration.test.ts +164 -0
- package/tests/history-dedupe-entries.test.ts +123 -0
- package/tests/history-delete-backfill.test.ts +190 -0
- package/tests/history-delete-confirm.test.ts +460 -0
- package/tests/history-dispatch.test.ts +180 -0
- package/tests/history-drain-hidden.test.ts +110 -0
- package/tests/history-drain-order.test.ts +98 -0
- package/tests/history-expanded-globals.test.ts +62 -0
- package/tests/history-gc.test.ts +832 -0
- package/tests/history-header-layout.test.ts +265 -0
- package/tests/history-hide-prompts.test.ts +275 -0
- package/tests/history-lazy-windowing.test.ts +508 -0
- package/tests/history-legacy-migrate-v2.test.ts +297 -0
- package/tests/history-load-shared-history.test.ts +53 -0
- package/tests/history-max-results-cap.test.ts +76 -0
- package/tests/history-multi-reader.test.ts +203 -0
- package/tests/history-off-path.test.ts +170 -0
- package/tests/history-openflow-integration.test.ts +173 -0
- package/tests/history-overlay-margin.test.ts +326 -0
- package/tests/history-preview-layout.test.ts +93 -0
- package/tests/history-registry.test.ts +143 -0
- package/tests/history-scope-delete.test.ts +411 -0
- package/tests/history-search-caret-keys.test.ts +142 -0
- package/tests/history-seed-bootstrap.test.ts +170 -0
- package/tests/history-seed-regen.test.ts +129 -0
- package/tests/history-selector-windowing.test.ts +94 -0
- package/tests/history-session-scan-directory.test.ts +87 -0
- package/tests/history-session-scan-extract.test.ts +583 -0
- package/tests/history-session-writer.test.ts +351 -0
- package/tests/history-store-paths.test.ts +79 -0
- package/tests/history-tombstone-exact.test.ts +139 -0
- package/tests/history-wheel-mouse.test.ts +242 -0
- package/tests/inprocess-reviewer.test.ts +49 -19
- package/tests/install-gentle-ai-failure.test.ts +69 -0
- package/tests/install-tui-mode-setting.test.ts +15 -0
- package/tests/install-wizard.test.ts +1223 -0
- package/tests/installer-bundles.test.ts +122 -0
- package/tests/installer-posix-bootstrap.test.ts +1201 -0
- package/tests/installer-preflight.test.ts +750 -0
- package/tests/installer-probes.test.ts +1106 -0
- package/tests/installer-runner.test.ts +2158 -0
- package/tests/installer-server.test.ts +1567 -0
- package/tests/installer-windows-bootstrap.test.ts +2410 -0
- package/tests/issue-creation-skill.test.ts +61 -0
- package/tests/jobs-view.test.ts +160 -0
- package/tests/main-channel-upgrade.test.ts +389 -0
- package/tests/main-channel.test.ts +344 -0
- package/tests/maintainer/provider-relay.maintest.ts +13 -12
- package/tests/model-price-ratio.test.ts +116 -0
- package/tests/model-profiles-preservation.test.ts +153 -0
- package/tests/model-routing-authority.test.ts +16 -0
- package/tests/model-routing-package.test.ts +10 -0
- package/tests/nan-provider-runtime.test.ts +156 -0
- package/tests/nan-provider.test.ts +481 -0
- package/tests/native-binary-gate.test.ts +2 -0
- package/tests/native-review-capability-contract.test.ts +13 -1
- package/tests/native-review-cli.test.ts +239 -118
- package/tests/native-review-consent.test.ts +2 -2
- package/tests/native-review-parity-runtime.test.ts +101 -4
- package/tests/native-review-parity.test.ts +12 -48
- package/tests/native-risk-evidence-parity.test.ts +21 -0
- package/tests/no-self-pause-contract.test.ts +87 -0
- package/tests/notification-audio-native.test.ts +281 -0
- package/tests/notification-audio-windows.test.ts +581 -0
- package/tests/notification-audio.test.ts +548 -0
- package/tests/notification-customize.test.ts +655 -0
- package/tests/notification-events.test.ts +115 -0
- package/tests/notification-policy.test.ts +201 -0
- package/tests/notification-pulse-client.test.ts +356 -0
- package/tests/notification-pulse-protocol.test.ts +213 -0
- package/tests/notification-pulse-stream.test.ts +320 -0
- package/tests/notification-scheduler.test.ts +258 -0
- package/tests/notification-ui.test.ts +157 -0
- package/tests/npm-pack-result.test.ts +41 -0
- package/tests/odd-integration.test.ts +76 -0
- package/tests/odd-phase-inference.test.ts +213 -0
- package/tests/odd-phase-loader.test.ts +253 -0
- package/tests/odd-phase.test.ts +307 -0
- package/tests/odd-routing-canonical-ratchet.test.ts +60 -14
- package/tests/odd-routing-contract.test.ts +158 -50
- package/tests/orchestrator-budget.test.ts +43 -45
- package/tests/orchestrator-catalog.test.ts +146 -0
- package/tests/orchestrator-consultation-sdk.test.ts +614 -0
- package/tests/orchestrator-consultation.test.ts +111 -0
- package/tests/orchestrator-discovery.test.ts +241 -0
- package/tests/orchestrator-helper-consent.test.ts +171 -0
- package/tests/orchestrator-helper.test.ts +297 -0
- package/tests/orchestrator-message-card.test.ts +190 -0
- package/tests/orchestrator-presence.test.ts +23 -0
- package/tests/orchestrator-rdd-ownership.test.ts +8 -7
- package/tests/orchestrator-scope.test.ts +107 -0
- package/tests/orchestrator-state.test.ts +114 -0
- package/tests/orchestrator-status-publication-contract.test.ts +34 -0
- package/tests/orchestrator-tool-card.test.ts +398 -0
- package/tests/orchestrator-work-search.test.ts +318 -0
- package/tests/orchestrator-work.test.ts +147 -0
- package/tests/overlay-repaint.test.ts +74 -0
- package/tests/package-manifest.test.ts +344 -123
- package/tests/packed-runner-owned-path.test.ts +80 -0
- package/tests/parallel-reason-contract.test.ts +21 -0
- package/tests/parallel-writer-admission.test.ts +210 -0
- package/tests/permission-mode-policy.test.ts +194 -0
- package/tests/persona-single-channel.test.ts +10 -18
- package/tests/pi-pretty.test.ts +56 -0
- package/tests/provider-defect-handoff.test.ts +7 -14
- package/tests/quiet-bash-runtime.test.ts +76 -0
- package/tests/quiet-tool-rendering.test.ts +569 -187
- package/tests/rdd-aware-verification-contract.test.ts +103 -40
- package/tests/rdd-status-line.test.ts +9 -4
- package/tests/render-cache-performance.test.ts +48 -0
- package/tests/resume-hint-extension.test.ts +122 -0
- package/tests/review-agent-end-preflight.test.ts +237 -21
- package/tests/review-candidate-owner-retry.test.ts +22 -1
- package/tests/review-candidate-view.test.ts +399 -12
- package/tests/review-contract-prompt.test.ts +138 -44
- package/tests/review-controller-lock-status.test.ts +0 -1
- package/tests/review-controller-native-recovery.test.ts +327 -17
- package/tests/review-controller-native-routing.test.ts +866 -6
- package/tests/review-controller-workspace-root.test.ts +206 -6
- package/tests/review-controller.test.ts +2 -2
- package/tests/review-correction-lifecycle.test.ts +2 -1
- package/tests/review-gate.test.ts +7 -4
- package/tests/review-graph-schema.test.ts +2 -2
- package/tests/review-host-relay-routing.test.ts +342 -4
- package/tests/review-host-relay.test.ts +49 -2
- package/tests/review-integration-v2-forward.test.ts +221 -1
- package/tests/review-json-arguments.test.ts +167 -0
- package/tests/review-last-event-closure.test.ts +157 -8
- package/tests/review-ledger-contract.test.ts +14 -37
- package/tests/review-policy-judgment-day.test.ts +1 -1
- package/tests/review-policy-ordinary.test.ts +2 -2
- package/tests/review-relay-transport-agent.test.ts +66 -1
- package/tests/review-reminder-receipt.test.ts +47 -1
- package/tests/review-risk-assessment.test.ts +594 -26
- package/tests/review-session-standing-permission-controller.test.ts +16 -17
- package/tests/review-session-standing-permission-ipc.test.ts +6 -5
- package/tests/review-sidebar-state.test.ts +402 -0
- package/tests/review-test-fixtures.ts +7 -1
- package/tests/review-transaction.test.ts +18 -1
- package/tests/run-test-suite.test.ts +202 -0
- package/tests/runtime-harness.mjs +186 -800
- package/tests/runtime-metrics-children.test.ts +16 -23
- package/tests/runtime-metrics-extension.test.ts +1 -1
- package/tests/runtime-metrics-native.test.ts +31 -1
- package/tests/selection-engine.test.ts +451 -0
- package/tests/session-change-capture.test.ts +10 -10
- package/tests/session-changes-shell.test.ts +242 -48
- package/tests/session-changes.test.ts +17 -24
- package/tests/session-messaging-grants.test.ts +255 -0
- package/tests/session-profile-binding.test.ts +163 -0
- package/tests/session-profile-freeze.test.ts +381 -0
- package/tests/session-subject-routing-contract.test.ts +34 -0
- package/tests/session-worktree-registry.test.ts +134 -2
- package/tests/shell-bar.test.ts +422 -1
- package/tests/shell-card.test.ts +353 -1
- package/tests/shell-changes-view.test.ts +135 -32
- package/tests/shell-changes.test.ts +61 -62
- package/tests/shell-prompt.test.ts +94 -2
- package/tests/shell-render-cache-runtime.test.ts +69 -0
- package/tests/shell-render-cache.test.ts +129 -0
- package/tests/shell-sidebar-layout.test.ts +351 -22
- package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
- package/tests/shell-todo.test.ts +207 -3
- package/tests/shell-usage-view.test.ts +28 -1
- package/tests/shell-usage.test.ts +108 -0
- package/tests/short-check-routing-contract.test.ts +49 -0
- package/tests/skill-registry-watcher.test.ts +119 -0
- package/tests/skill-registry.test.ts +357 -2
- package/tests/startup-banner.test.ts +246 -4
- package/tests/startup-home-repo.test.ts +170 -0
- package/tests/stats-collector.test.ts +195 -0
- package/tests/stats-view.test.ts +202 -0
- package/tests/status-timing-diagnostics.test.ts +283 -0
- package/tests/support/orchestrator-modules.ts +19 -0
- package/tests/task-size-routing-contract.test.ts +241 -0
- package/tests/telemetry-trigger.test.ts +107 -20
- package/tests/test-strength-contract.test.ts +124 -0
- package/tests/theme-customization.test.ts +72 -0
- package/tests/verify-agent-contract.test.ts +90 -0
- package/tests/verify-first-launch-contract.test.ts +139 -0
- package/tests/verify-package-files.test.ts +56 -0
- package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
- package/tests/vim-editor-adapter.test.ts +804 -0
- package/tests/vim-normal-engine.test.ts +101 -0
- package/tests/vim-operator-engine.test.ts +215 -0
- package/tests/vim-policy.test.ts +19 -0
- package/tests/vim-visual-engine.test.ts +52 -0
- package/tests/visual-customization-policy.test.ts +139 -0
- package/tests/visual-customize-view.test.ts +696 -0
- package/tests/visual-profiles.test.ts +87 -0
- package/tests/writer-edit-surface-scope.test.ts +59 -2
- package/tests/writer-surfaces.test.ts +199 -0
- package/tests/yolo-customize.test.ts +271 -0
- package/tests/yolo-mode-runtime.test.ts +188 -0
- package/tests/yolo-mode.test.ts +289 -0
- package/tests/yolo-session-policy.test.ts +59 -0
- package/themes/Gentle.json +2 -1
- package/themes/Gentleman-Cute.json +2 -1
- package/themes/Gentleman-Sexy.json +2 -1
- package/assets/agents/sdd-apply.md +0 -159
- package/assets/agents/sdd-archive.md +0 -228
- package/assets/agents/sdd-design.md +0 -49
- package/assets/agents/sdd-explore.md +0 -48
- package/assets/agents/sdd-init.md +0 -56
- package/assets/agents/sdd-onboard.md +0 -52
- package/assets/agents/sdd-proposal.md +0 -64
- package/assets/agents/sdd-remediate.md +0 -37
- package/assets/agents/sdd-research.md +0 -49
- package/assets/agents/sdd-spec.md +0 -192
- package/assets/agents/sdd-status.md +0 -54
- package/assets/agents/sdd-tasks.md +0 -108
- package/assets/agents/sdd-verify.md +0 -124
- package/assets/chains/sdd-full.chain.md +0 -83
- package/assets/chains/sdd-plan.chain.md +0 -56
- package/assets/chains/sdd-verify.chain.md +0 -43
- package/assets/sdd-orchestrator-workflow.md +0 -319
- package/assets/support/sdd-status-contract.md +0 -77
- package/docs/assets/diagrams/sdd-cycle.svg +0 -14
- package/extensions/sdd-init.ts +0 -816
- package/lib/openspec-deltas.ts +0 -156
- package/lib/sdd-preflight.ts +0 -1066
- package/lib/sdd-research-capabilities.ts +0 -94
- package/lib/sdd-status.ts +0 -26
- package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
- package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
- package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
- package/tests/openspec-deltas.test.ts +0 -209
- package/tests/sdd-agent-tools.test.ts +0 -156
- package/tests/sdd-archive-replay.test.ts +0 -82
- package/tests/sdd-classical-continuation.test.ts +0 -74
- package/tests/sdd-execution-routing-contract.test.ts +0 -44
- package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
- package/tests/sdd-native-managed-uptake.test.ts +0 -243
- package/tests/sdd-no-attempts-contract.test.ts +0 -15
- package/tests/sdd-odd-integration.test.ts +0 -33
- package/tests/sdd-optional-research.test.ts +0 -124
- package/tests/sdd-planning-routing-contract.test.ts +0 -45
- package/tests/sdd-preflight-rpc-input.test.ts +0 -125
- package/tests/sdd-preflight.test.ts +0 -541
- package/tests/sdd-research-capabilities.test.ts +0 -114
- package/tests/sdd-research-live.test.ts +0 -241
- package/tests/sdd-selection-transport.test.ts +0 -653
- package/tests/sdd-status.test.ts +0 -9
- package/tests/sdd-task-truth.test.ts +0 -43
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
package/lib/agent-profile-pin.ts
CHANGED
|
@@ -293,6 +293,18 @@ export function evaluateProfilePin(
|
|
|
293
293
|
return evaluation;
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
// Admission-only lookup at an explicitly bound non-Git project. Do not create
|
|
297
|
+
// a fake commonDir or change public pin/status semantics outside repositories.
|
|
298
|
+
export function resolveUnversionedProjectProfile(cwd: string, configHome: string): (ProfilePinSelection & { modelProfiles: AgentModelConfig }) | undefined {
|
|
299
|
+
const path = repoProfileDeclarationPath(cwd);
|
|
300
|
+
const pin = readProfilePinResult(path);
|
|
301
|
+
if (pin.status !== "valid") return undefined;
|
|
302
|
+
const store = readProfilesFileResult(profilesFilePath(configHome));
|
|
303
|
+
if (store.status !== "valid" || !hasProfile(store.file.profiles, pin.profile)) return undefined;
|
|
304
|
+
const config = store.file.profiles[pin.profile];
|
|
305
|
+
return { source: "repo", profile: pin.profile, path, modelProfiles: Object.fromEntries(profileRoleEntries(config).map(([agent, entry]) => [agent, { ...entry }])) };
|
|
306
|
+
}
|
|
307
|
+
|
|
296
308
|
export interface ProfilePinResolveOptions {
|
|
297
309
|
cwd: string;
|
|
298
310
|
configHome: string;
|
package/lib/agent-profiles.ts
CHANGED
|
@@ -406,18 +406,28 @@ export interface ProfileListItem {
|
|
|
406
406
|
description: string;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
/** One list item per saved profile, named with the markers that explain what a launch would use: the global `(active)` claim, plus `(pinned)` for the pin winner or `(session)` for this session's binding when either applies. */
|
|
409
410
|
export function buildProfileListItems(
|
|
410
411
|
file: AgentProfilesFile,
|
|
411
412
|
pinned?: string,
|
|
413
|
+
sessionBound?: string,
|
|
412
414
|
): ProfileListItem[] {
|
|
413
415
|
return Object.entries(file.profiles).map(([name, config]) => {
|
|
414
416
|
const roles = profileRoleEntries(config).length;
|
|
415
417
|
const active = name === file.active ? `${name} (active)` : name;
|
|
418
|
+
// A pinned profile is the one this repository launches with, which is not the
|
|
419
|
+
// same thing as the globally active profile, so both are named. A session
|
|
420
|
+
// binding outranks the pin in this list (slice 1 stores it; slice 2,
|
|
421
|
+
// gentle-shell#1558, makes launches resolve it), so its marker wins on the
|
|
422
|
+
// same profile.
|
|
423
|
+
const label = name === sessionBound
|
|
424
|
+
? `${active} (session)`
|
|
425
|
+
: name === pinned
|
|
426
|
+
? `${active} (pinned)`
|
|
427
|
+
: active;
|
|
416
428
|
return {
|
|
417
429
|
id: name,
|
|
418
|
-
|
|
419
|
-
// same thing as the globally active profile, so both are named.
|
|
420
|
-
label: name === pinned ? `${active} (pinned)` : active,
|
|
430
|
+
label,
|
|
421
431
|
description: `${roles} ${roles === 1 ? "role" : "roles"}`,
|
|
422
432
|
};
|
|
423
433
|
});
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
// behavior is unit-testable against a fake clock.
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* A completion older than this at flush time is stale:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* A completion older than this at flush time is stale: replaying its full
|
|
15
|
+
* report into the model context could re-enter state the conversation may
|
|
16
|
+
* already have used, so the parent gets a compact notice instead. The parent
|
|
17
|
+
* is told never to poll, so a stale completion must still announce itself.
|
|
17
18
|
* Ninety seconds comfortably covers one slow orchestrator turn (model latency
|
|
18
19
|
* plus a few tool calls) while staying orders of magnitude below the 50-58
|
|
19
20
|
* minute followUp delays measured in issue #867.
|
|
@@ -36,6 +37,8 @@ export interface CompletionQueue<T extends { id: string }> {
|
|
|
36
37
|
consume(taskId: string): void;
|
|
37
38
|
/** Remove and return the still-pending completions in settle order, each with its staleness decision at `now`. Consumed entries are dropped and never returned. */
|
|
38
39
|
takeDeliverable(now: number): Array<DeliverableCompletion<T>>;
|
|
40
|
+
/** Return a taken completion whose forwarding failed to the pending queue, so a later flush retries it. A consumed id stays dropped. */
|
|
41
|
+
requeue(entry: DeliverableCompletion<T>): void;
|
|
39
42
|
/** Discard everything: pending completions and consumed/delivered bookkeeping. Used on session start and shutdown so nothing replays after a resume. */
|
|
40
43
|
dropAll(): void;
|
|
41
44
|
}
|
|
@@ -63,6 +66,11 @@ export function createCompletionQueue<T extends { id: string }>(): CompletionQue
|
|
|
63
66
|
}
|
|
64
67
|
return deliverable;
|
|
65
68
|
},
|
|
69
|
+
requeue(entry) {
|
|
70
|
+
delivered.delete(entry.task.id);
|
|
71
|
+
if (consumed.has(entry.task.id) || pending.some((pendingEntry) => pendingEntry.task.id === entry.task.id)) return;
|
|
72
|
+
pending.push({ task: entry.task, settledAt: entry.settledAt });
|
|
73
|
+
},
|
|
66
74
|
dropAll() {
|
|
67
75
|
pending = [];
|
|
68
76
|
consumed.clear();
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Gentle Agents subagent message delivery queue (issue #1162).
|
|
2
|
+
//
|
|
3
|
+
// Background and foreground child notifications and queries used to be handed
|
|
4
|
+
// straight to the host as `deliverAs: "followUp"` messages. Because the host
|
|
5
|
+
// only drains the follow-up queue when the parent agent stops calling tools
|
|
6
|
+
// entirely, stale notifications and already-answered or expired queries could
|
|
7
|
+
// re-enter the conversation long after the child task completed, re-triggering
|
|
8
|
+
// the parent LLM unnecessarily (#1162).
|
|
9
|
+
//
|
|
10
|
+
// This module owns the pending messages instead: the extension enqueues them,
|
|
11
|
+
// tracks query answer/timeout/cancellation lifecycle, invalidates messages on
|
|
12
|
+
// task completion, and flushes only live, fresh messages at turn boundaries or
|
|
13
|
+
// idle using `deliverAs: "steer"`.
|
|
14
|
+
|
|
15
|
+
export const STALE_NOTIFICATION_MS = 90_000;
|
|
16
|
+
|
|
17
|
+
export type AgentMessageKind = "notification" | "query";
|
|
18
|
+
|
|
19
|
+
export interface PendingAgentMessage {
|
|
20
|
+
taskId: string;
|
|
21
|
+
agent: string;
|
|
22
|
+
kind: AgentMessageKind;
|
|
23
|
+
content: string;
|
|
24
|
+
parentSessionId: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
display: boolean;
|
|
27
|
+
details: Record<string, unknown>;
|
|
28
|
+
enqueuedAt: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AgentMessageQueue {
|
|
32
|
+
/** Enqueue an ordinary notification from a subagent. */
|
|
33
|
+
enqueueNotification(
|
|
34
|
+
task: { id: string; agent: string; parentSessionId: string },
|
|
35
|
+
content: string,
|
|
36
|
+
enqueuedAt: number,
|
|
37
|
+
): void;
|
|
38
|
+
|
|
39
|
+
/** Enqueue an interactive query from a subagent. */
|
|
40
|
+
enqueueQuery(
|
|
41
|
+
task: { id: string; agent: string; parentSessionId: string },
|
|
42
|
+
requestId: string,
|
|
43
|
+
question: string,
|
|
44
|
+
enqueuedAt: number,
|
|
45
|
+
): void;
|
|
46
|
+
|
|
47
|
+
/** Mark a query as consumed (e.g. answered or directly handed off). Prevents subsequent delivery. */
|
|
48
|
+
consumeQuery(taskId: string, requestId: string): void;
|
|
49
|
+
|
|
50
|
+
/** Mark a query as expired (timed out or errored). Prevents delivery. */
|
|
51
|
+
expireQuery(taskId: string, requestId: string): void;
|
|
52
|
+
|
|
53
|
+
/** Invalidate all pending messages (notifications and queries) for a settled or cancelled task. */
|
|
54
|
+
invalidateTask(taskId: string): void;
|
|
55
|
+
|
|
56
|
+
/** Return deliverable messages in enqueue order for the active session, dropping stale/consumed ones. */
|
|
57
|
+
takeDeliverable(
|
|
58
|
+
now: number,
|
|
59
|
+
activeSessionId: string,
|
|
60
|
+
isTaskLive: (taskId: string) => boolean,
|
|
61
|
+
): Array<PendingAgentMessage>;
|
|
62
|
+
|
|
63
|
+
/** Return number of pending messages waiting to be delivered. */
|
|
64
|
+
pendingCount(): number;
|
|
65
|
+
|
|
66
|
+
/** Discard all pending messages and tracking sets (on session change or shutdown). */
|
|
67
|
+
dropAll(): void;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates an agent message queue that manages pending notifications and queries
|
|
72
|
+
* from subagents, bounding their lifetime and invalidating stale messages upon
|
|
73
|
+
* task settlement or query resolution.
|
|
74
|
+
*/
|
|
75
|
+
export function createAgentMessageQueue(): AgentMessageQueue {
|
|
76
|
+
let pending: Array<PendingAgentMessage> = [];
|
|
77
|
+
const consumedQueries = new Set<string>();
|
|
78
|
+
const expiredQueries = new Set<string>();
|
|
79
|
+
const invalidatedTasks = new Set<string>();
|
|
80
|
+
|
|
81
|
+
const queryKey = (taskId: string, requestId: string) => `${taskId}:${requestId}`;
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
enqueueNotification(task, content, enqueuedAt) {
|
|
85
|
+
if (invalidatedTasks.has(task.id)) return;
|
|
86
|
+
pending.push({
|
|
87
|
+
taskId: task.id,
|
|
88
|
+
agent: task.agent,
|
|
89
|
+
kind: "notification",
|
|
90
|
+
content,
|
|
91
|
+
parentSessionId: task.parentSessionId,
|
|
92
|
+
display: false,
|
|
93
|
+
details: {
|
|
94
|
+
gentleAgents: {
|
|
95
|
+
taskId: task.id,
|
|
96
|
+
agent: task.agent,
|
|
97
|
+
parentSessionId: task.parentSessionId,
|
|
98
|
+
kind: "notification",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
enqueuedAt,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
enqueueQuery(task, requestId, question, enqueuedAt) {
|
|
106
|
+
const key = queryKey(task.id, requestId);
|
|
107
|
+
if (invalidatedTasks.has(task.id) || consumedQueries.has(key) || expiredQueries.has(key)) return;
|
|
108
|
+
if (pending.some((msg) => msg.kind === "query" && msg.taskId === task.id && msg.requestId === requestId)) return;
|
|
109
|
+
pending.push({
|
|
110
|
+
taskId: task.id,
|
|
111
|
+
agent: task.agent,
|
|
112
|
+
kind: "query",
|
|
113
|
+
content: `Subagent ${task.agent} asks:\nTask ID: ${task.id}\nRequest ID: ${requestId}\nQuestion: ${question}`,
|
|
114
|
+
parentSessionId: task.parentSessionId,
|
|
115
|
+
requestId,
|
|
116
|
+
display: true,
|
|
117
|
+
details: {
|
|
118
|
+
gentleAgents: {
|
|
119
|
+
taskId: task.id,
|
|
120
|
+
agent: task.agent,
|
|
121
|
+
parentSessionId: task.parentSessionId,
|
|
122
|
+
requestId,
|
|
123
|
+
kind: "query",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
enqueuedAt,
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
consumeQuery(taskId, requestId) {
|
|
131
|
+
const key = queryKey(taskId, requestId);
|
|
132
|
+
consumedQueries.add(key);
|
|
133
|
+
pending = pending.filter((msg) => !(msg.kind === "query" && msg.taskId === taskId && msg.requestId === requestId));
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
expireQuery(taskId, requestId) {
|
|
137
|
+
const key = queryKey(taskId, requestId);
|
|
138
|
+
expiredQueries.add(key);
|
|
139
|
+
pending = pending.filter((msg) => !(msg.kind === "query" && msg.taskId === taskId && msg.requestId === requestId));
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
invalidateTask(taskId) {
|
|
143
|
+
invalidatedTasks.add(taskId);
|
|
144
|
+
pending = pending.filter((msg) => msg.taskId !== taskId);
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
takeDeliverable(now, activeSessionId, isTaskLive) {
|
|
148
|
+
const taken = pending;
|
|
149
|
+
pending = [];
|
|
150
|
+
const deliverable: Array<PendingAgentMessage> = [];
|
|
151
|
+
|
|
152
|
+
for (const msg of taken) {
|
|
153
|
+
if (msg.parentSessionId !== activeSessionId) continue;
|
|
154
|
+
if (invalidatedTasks.has(msg.taskId)) continue;
|
|
155
|
+
if (!isTaskLive(msg.taskId)) continue;
|
|
156
|
+
|
|
157
|
+
if (msg.kind === "query") {
|
|
158
|
+
const key = queryKey(msg.taskId, msg.requestId!);
|
|
159
|
+
if (consumedQueries.has(key) || expiredQueries.has(key)) continue;
|
|
160
|
+
} else if (msg.kind === "notification") {
|
|
161
|
+
if (now - msg.enqueuedAt >= STALE_NOTIFICATION_MS) continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
deliverable.push(msg);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return deliverable;
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
pendingCount() {
|
|
171
|
+
return pending.length;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
dropAll() {
|
|
175
|
+
pending = [];
|
|
176
|
+
consumedQueries.clear();
|
|
177
|
+
expiredQueries.clear();
|
|
178
|
+
invalidatedTasks.clear();
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
package/lib/agents-messaging.ts
CHANGED
|
@@ -95,7 +95,7 @@ function parseAck(value: unknown): AckFrame | undefined {
|
|
|
95
95
|
if (!record(value) || !exact(value, ["id", "kind", "accepted", "error"]) || !validChildId(value.id) || value.kind !== "ack" || typeof value.accepted !== "boolean") return undefined;
|
|
96
96
|
if (value.accepted && value.error !== undefined) return undefined;
|
|
97
97
|
if (value.error !== undefined && !boundedText(value.error, CHILD_ACK_ERROR_MAX_BYTES)) return undefined;
|
|
98
|
-
return { id: value.id, accepted: value.accepted, ...(value.error ===
|
|
98
|
+
return { id: value.id, accepted: value.accepted, ...(typeof value.error === "string" ? { error: value.error } : {}) };
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
function parseReply(value: unknown): ReplyFrame | undefined {
|
package/lib/agents-protocol.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
1
2
|
import { sanitizeTerminalText } from "./terminal-theme.ts";
|
|
2
3
|
|
|
3
4
|
// Gentle Agents protocol. A child pi process streams RPC events; the host
|
|
@@ -147,10 +148,23 @@ export interface TaskSummary {
|
|
|
147
148
|
|
|
148
149
|
export type TaskListener = (task: TaskRecord, thread: TaskThread) => void;
|
|
149
150
|
export type SummaryListener = (summary: TaskSummary) => void;
|
|
151
|
+
export interface TaskStatusChange {
|
|
152
|
+
readonly producerId: string;
|
|
153
|
+
readonly sessionId: string;
|
|
154
|
+
readonly parentSessionId: string;
|
|
155
|
+
readonly taskId: string;
|
|
156
|
+
readonly runId: string;
|
|
157
|
+
readonly status: TaskStatus;
|
|
158
|
+
readonly previousStatus?: TaskStatus;
|
|
159
|
+
readonly sequence: number;
|
|
160
|
+
}
|
|
161
|
+
export type StatusChangeListener = (change: TaskStatusChange) => void | Promise<void>;
|
|
150
162
|
|
|
151
163
|
const DEFAULT_LIMITS: ThreadLimits = { maxItems: 400, maxOutputChars: 16_000 };
|
|
152
164
|
/** Child UI requests that block on an answer; everything else (notify, setStatus, setWidget) is noise here. */
|
|
153
165
|
export const DIALOG_METHODS: ReadonlySet<string> = new Set(["select", "confirm", "input", "editor"]);
|
|
166
|
+
/** The one child notify that reaches the task thread: requested --tools the child does not have (#1690). */
|
|
167
|
+
export const MISSING_TOOLS_NOTE_PREFIX = "gentle-agents: requested tools missing in child:";
|
|
154
168
|
const LABEL_MAX = 72;
|
|
155
169
|
const TEXT_CAP = 20_000;
|
|
156
170
|
const ELLIPSIS = "…";
|
|
@@ -226,6 +240,65 @@ function childResponse(message: Raw): ChildResponseObservation | undefined {
|
|
|
226
240
|
});
|
|
227
241
|
}
|
|
228
242
|
|
|
243
|
+
const ARGUMENT_PROGRESS_MAX = 4096;
|
|
244
|
+
|
|
245
|
+
/** Per-child liveness evidence, separate from display events and usage.
|
|
246
|
+
* RPC deltas have no sequence number. Reject duplicate fingerprints rather
|
|
247
|
+
* than claiming indistinguishable repeated bytes are fresh progress. Retain
|
|
248
|
+
* only hashes, never arguments; exhaustion fails closed until a new message.
|
|
249
|
+
*/
|
|
250
|
+
export class ToolArgumentProgress {
|
|
251
|
+
private timestamp = -1;
|
|
252
|
+
private active = false;
|
|
253
|
+
private readonly blocks = new Map<number, boolean>();
|
|
254
|
+
private readonly fingerprints = new Set<string>();
|
|
255
|
+
|
|
256
|
+
observe(raw: Record<string, unknown>): boolean {
|
|
257
|
+
if (raw.type === "message_start") {
|
|
258
|
+
const message = raw.message as Raw | undefined;
|
|
259
|
+
if (message?.role === "assistant" && typeof message.timestamp === "number" && Number.isSafeInteger(message.timestamp)
|
|
260
|
+
&& message.timestamp >= 0 && message.timestamp > this.timestamp && !this.active) {
|
|
261
|
+
this.timestamp = message.timestamp;
|
|
262
|
+
this.active = true;
|
|
263
|
+
this.blocks.clear();
|
|
264
|
+
this.fingerprints.clear();
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
if (raw.type === "message_end" || raw.type === "agent_end" || raw.type === "agent_settled" || raw.type === "turn_end") {
|
|
269
|
+
this.active = false;
|
|
270
|
+
this.blocks.clear();
|
|
271
|
+
this.fingerprints.clear();
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
if (!this.active || raw.type !== "message_update") return false;
|
|
275
|
+
const inner = raw.assistantMessageEvent as Raw | undefined;
|
|
276
|
+
if (!inner || typeof inner !== "object") return false;
|
|
277
|
+
const index = inner.contentIndex;
|
|
278
|
+
if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0 || index >= ARGUMENT_PROGRESS_MAX) return false;
|
|
279
|
+
if (inner.type === "toolcall_start") {
|
|
280
|
+
// Older Pi RPC forwards SDK partial snapshots; current RPC puts the
|
|
281
|
+
// identity directly on toolcall_start. Neither shape is persisted.
|
|
282
|
+
const partial = inner.partial as Raw | undefined;
|
|
283
|
+
const block = Array.isArray(partial?.content) ? partial.content[index] as Raw | undefined : undefined;
|
|
284
|
+
const id = inner.id ?? (block?.type === "toolCall" ? block.id : undefined);
|
|
285
|
+
const name = inner.toolName ?? (block?.type === "toolCall" ? block.name : undefined);
|
|
286
|
+
if (typeof id === "string" && id.length > 0 && typeof name === "string" && name.length > 0 && !this.blocks.has(index)) this.blocks.set(index, true);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
if (inner.type === "toolcall_end") {
|
|
290
|
+
if (this.blocks.has(index)) this.blocks.set(index, false);
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
if (inner.type !== "toolcall_delta" || this.blocks.get(index) !== true || typeof inner.delta !== "string" || inner.delta.length === 0) return false;
|
|
294
|
+
if (this.fingerprints.size >= ARGUMENT_PROGRESS_MAX) return false;
|
|
295
|
+
const fingerprint = createHash("sha256").update(`${index}:`).update(inner.delta).digest("hex");
|
|
296
|
+
if (this.fingerprints.has(fingerprint)) return false;
|
|
297
|
+
this.fingerprints.add(fingerprint);
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
229
302
|
// One RPC line in, zero or more deltas out. Streaming deltas carry only the
|
|
230
303
|
// chunk; whole-message payloads that pi repeats on every update are ignored.
|
|
231
304
|
export function normalizeRpcEvent(raw: unknown, options: { observeResponses?: boolean } = {}): TaskEvent[] {
|
|
@@ -270,6 +343,7 @@ export function normalizeRpcEvent(raw: unknown, options: { observeResponses?: bo
|
|
|
270
343
|
case "agent_settled":
|
|
271
344
|
return [{ type: TASK_EVENT.AGENT_SETTLED }];
|
|
272
345
|
case "extension_ui_request":
|
|
346
|
+
if (event.method === "notify" && typeof event.message === "string" && event.message.startsWith(MISSING_TOOLS_NOTE_PREFIX)) return [{ type: TASK_EVENT.NOTE, text: clean(event.message) }];
|
|
273
347
|
return DIALOG_METHODS.has(String(event.method)) ? [{ type: TASK_EVENT.ASK, request: askRequest(event) }] : [];
|
|
274
348
|
case "auto_retry_start":
|
|
275
349
|
return [{ type: TASK_EVENT.NOTE, text: `retrying (${String(event.attempt ?? "?")}/${String(event.maxAttempts ?? "?")})` }];
|
|
@@ -400,14 +474,21 @@ export class TaskStore {
|
|
|
400
474
|
private readonly listeners = new Map<string, Set<TaskListener>>();
|
|
401
475
|
private readonly summaryListeners = new Set<SummaryListener>();
|
|
402
476
|
private readonly limits: Partial<ThreadLimits>;
|
|
477
|
+
private readonly producerId = randomUUID();
|
|
478
|
+
private sequence = 0;
|
|
479
|
+
private readonly runIds = new Map<string, string>();
|
|
480
|
+
private readonly statusListeners = new Set<StatusChangeListener>();
|
|
403
481
|
|
|
404
482
|
constructor(limits: Partial<ThreadLimits> = {}) {
|
|
405
483
|
this.limits = limits;
|
|
406
484
|
}
|
|
407
485
|
|
|
408
486
|
add(task: TaskRecord): void {
|
|
487
|
+
const previous = this.tasks.get(task.id)?.status;
|
|
488
|
+
if (!this.tasks.has(task.id)) this.runIds.set(task.id, randomUUID());
|
|
409
489
|
this.tasks.set(task.id, task);
|
|
410
490
|
this.threads.set(task.id, emptyThread(this.limits));
|
|
491
|
+
this.notifyStatus(task, previous);
|
|
411
492
|
this.notifySummary();
|
|
412
493
|
}
|
|
413
494
|
|
|
@@ -416,6 +497,7 @@ export class TaskStore {
|
|
|
416
497
|
restore(task: TaskRecord, thread: TaskThread): boolean {
|
|
417
498
|
if (this.tasks.has(task.id)) return false;
|
|
418
499
|
this.tasks.set(task.id, task);
|
|
500
|
+
this.runIds.set(task.id, randomUUID());
|
|
419
501
|
this.threads.set(task.id, { ...thread, limits: { ...DEFAULT_LIMITS, ...this.limits } });
|
|
420
502
|
this.notifySummary();
|
|
421
503
|
return true;
|
|
@@ -446,6 +528,7 @@ export class TaskStore {
|
|
|
446
528
|
if (!current) return undefined;
|
|
447
529
|
const next = { ...current, ...patch };
|
|
448
530
|
this.tasks.set(id, next);
|
|
531
|
+
this.notifyStatus(next, current.status);
|
|
449
532
|
this.notifyTask(next);
|
|
450
533
|
if (next.status !== current.status) this.notifySummary();
|
|
451
534
|
return next;
|
|
@@ -473,6 +556,22 @@ export class TaskStore {
|
|
|
473
556
|
return () => this.summaryListeners.delete(listener);
|
|
474
557
|
}
|
|
475
558
|
|
|
559
|
+
/** Optional, content-free observer. Restores and unchanged snapshots are silent. */
|
|
560
|
+
subscribeStatusChanges(listener: StatusChangeListener): () => void {
|
|
561
|
+
this.statusListeners.add(listener);
|
|
562
|
+
return () => { this.statusListeners.delete(listener); };
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
private notifyStatus(task: TaskRecord, previousStatus?: TaskStatus): void {
|
|
566
|
+
if (task.status === previousStatus) return;
|
|
567
|
+
const change: TaskStatusChange = Object.freeze({ producerId: this.producerId,
|
|
568
|
+
sessionId: task.parentSessionId, parentSessionId: task.parentSessionId, taskId: task.id,
|
|
569
|
+
runId: this.runIds.get(task.id)!, status: task.status, previousStatus, sequence: ++this.sequence });
|
|
570
|
+
for (const listener of [...this.statusListeners]) {
|
|
571
|
+
try { void Promise.resolve(listener(change)).catch(() => {}); } catch { /* Observability cannot fail a mutation. */ }
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
476
575
|
private notifyTask(task: TaskRecord): void {
|
|
477
576
|
const set = this.listeners.get(task.id);
|
|
478
577
|
if (!set) return;
|