@selesai/code 0.5.19 → 0.5.21
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/dist/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import "../../shared/env.ts";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { encodeNestedPathEnv, parseNestedPathEnv, type NestedPathEntry } from "./nested-path.ts";
|
|
6
|
-
import {
|
|
7
|
+
import { resolveMcpDirectToolSelections, type ResolvedMcpDirectToolSelection } from "./mcp-direct-tool-allowlist.ts";
|
|
8
|
+
import { resolvePiPackageRoot } from "./pi-spawn.ts";
|
|
7
9
|
import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV } from "./structured-output.ts";
|
|
8
10
|
import { TEMP_ROOT_DIR, type JsonSchemaObject, type ResolvedToolBudget } from "../../shared/types.ts";
|
|
9
|
-
import {
|
|
11
|
+
import { THINKING_LEVELS } from "../../shared/model-info.ts";
|
|
12
|
+
import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV, encodeToolBudgetEnv } from "./tool-budget.ts";
|
|
13
|
+
import { CHILD_TOOL_DIAGNOSTIC_PATH_ENV, MCP_DIRECT_CHILD_TOOLS_ENV, REQUIRED_CHILD_TOOLS_ENV } from "./tool-availability.ts";
|
|
14
|
+
import { CHILD_WATCHDOG_CONFIG_ENV, encodeChildWatchdogConfig, type ChildWatchdogConfig } from "../../watchdog/child-status.ts";
|
|
15
|
+
import { WAIT_TOOL_ENABLED_ENV } from "../background/wait-config.ts";
|
|
16
|
+
import { SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV } from "../../shared/utils.ts";
|
|
17
|
+
import { SUBAGENT_CAPABILITY_CEILING_ENV, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, type ResolvedSubagentCapabilityCeiling, type SubagentCapabilityAudit } from "./capability-ceiling.ts";
|
|
10
18
|
|
|
11
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
12
19
|
const TASK_ARG_LIMIT = 8000;
|
|
13
20
|
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
|
|
14
21
|
const FANOUT_CHILD_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "extension", "fanout-child.ts");
|
|
@@ -30,8 +37,10 @@ export const SUBAGENT_PARENT_PATH_ENV = "SELESAI_SUBAGENT_PARENT_PATH";
|
|
|
30
37
|
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = "SELESAI_SUBAGENT_PARENT_CAPABILITY_TOKEN";
|
|
31
38
|
export const SUBAGENT_PARENT_SESSION_ENV = "SELESAI_SUBAGENT_PARENT_SESSION";
|
|
32
39
|
export const SUBAGENT_STEER_INBOX_ENV = "SELESAI_SUBAGENT_STEER_INBOX";
|
|
40
|
+
export const SUBAGENT_STEER_CAPABILITY_ENV = "SELESAI_SUBAGENT_STEER_CAPABILITY";
|
|
41
|
+
export const SUBAGENT_STEER_ACK_DIR_ENV = "SELESAI_SUBAGENT_STEER_ACK_DIR";
|
|
33
42
|
|
|
34
|
-
interface BuildPiArgsInput {
|
|
43
|
+
export interface BuildPiArgsInput {
|
|
35
44
|
parentSessionId?: string;
|
|
36
45
|
baseArgs: string[];
|
|
37
46
|
task: string;
|
|
@@ -39,7 +48,7 @@ interface BuildPiArgsInput {
|
|
|
39
48
|
sessionDir?: string;
|
|
40
49
|
sessionFile?: string;
|
|
41
50
|
model?: string;
|
|
42
|
-
thinking?: string;
|
|
51
|
+
thinking?: string | false;
|
|
43
52
|
systemPromptMode?: "append" | "replace";
|
|
44
53
|
inheritProjectContext: boolean;
|
|
45
54
|
inheritSkills: boolean;
|
|
@@ -65,18 +74,26 @@ interface BuildPiArgsInput {
|
|
|
65
74
|
parentPath?: NestedPathEntry[];
|
|
66
75
|
parentCapabilityToken?: string;
|
|
67
76
|
steerInboxDir?: string;
|
|
77
|
+
steerCapabilityPath?: string;
|
|
78
|
+
steerAckDir?: string;
|
|
68
79
|
structuredOutput?: {
|
|
69
80
|
schema: JsonSchemaObject;
|
|
70
81
|
schemaPath: string;
|
|
71
82
|
outputPath: string;
|
|
72
83
|
};
|
|
73
84
|
toolBudget?: ResolvedToolBudget;
|
|
85
|
+
allowZeroToolBudget?: boolean;
|
|
86
|
+
childWatchdog?: ChildWatchdogConfig;
|
|
87
|
+
waitToolEnabled?: boolean;
|
|
88
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
74
89
|
}
|
|
75
90
|
|
|
76
|
-
interface BuildPiArgsResult {
|
|
91
|
+
export interface BuildPiArgsResult {
|
|
77
92
|
args: string[];
|
|
78
93
|
env: Record<string, string | undefined>;
|
|
79
94
|
tempDir?: string;
|
|
95
|
+
toolDiagnosticPath?: string;
|
|
96
|
+
capabilityAudit?: SubagentCapabilityAudit;
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
function sanitizeSupervisorChannelSegment(value: string): string {
|
|
@@ -87,15 +104,115 @@ function supervisorChannelDir(runId: string, agent: string, childIndex: number):
|
|
|
87
104
|
return path.join(TEMP_ROOT_DIR, "supervisor-channels", `${sanitizeSupervisorChannelSegment(runId)}-${sanitizeSupervisorChannelSegment(agent)}-${childIndex}`);
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
export function applyThinkingSuffix(model: string | undefined, thinking: string | undefined, replaceExisting = false): string | undefined {
|
|
107
|
+
export function applyThinkingSuffix(model: string | undefined, thinking: string | false | undefined, replaceExisting = false): string | undefined {
|
|
91
108
|
if (!model || !thinking) return model;
|
|
92
109
|
const colonIdx = model.lastIndexOf(":");
|
|
93
|
-
if (colonIdx !== -1 && THINKING_LEVELS.
|
|
110
|
+
if (colonIdx !== -1 && THINKING_LEVELS.some((level) => level === model.substring(colonIdx + 1))) {
|
|
94
111
|
return replaceExisting ? `${model.slice(0, colonIdx)}:${thinking}` : model;
|
|
95
112
|
}
|
|
96
113
|
return `${model}:${thinking}`;
|
|
97
114
|
}
|
|
98
115
|
|
|
116
|
+
export interface ResolvePiLaunchToolPlanInput {
|
|
117
|
+
tools?: string[];
|
|
118
|
+
extensions?: string[];
|
|
119
|
+
subagentOnlyExtensions?: string[];
|
|
120
|
+
mcpDirectTools?: string[];
|
|
121
|
+
cwd?: string;
|
|
122
|
+
requireReadTool?: boolean;
|
|
123
|
+
structuredOutput?: boolean;
|
|
124
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
125
|
+
inheritedCapabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface PiLaunchToolPlan {
|
|
129
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
130
|
+
requestedBuiltinTools: string[];
|
|
131
|
+
declaredBuiltinTools: string[];
|
|
132
|
+
toolExtensionPaths: string[];
|
|
133
|
+
resolvedMcpSelections: ResolvedMcpDirectToolSelection[];
|
|
134
|
+
effectiveMcpSelections: ResolvedMcpDirectToolSelection[];
|
|
135
|
+
effectiveMcpTools: string[];
|
|
136
|
+
explicitToolAllowlist: boolean;
|
|
137
|
+
internalTools: string[];
|
|
138
|
+
effectiveToolAllowlist: string[];
|
|
139
|
+
requiredChildTools: string[];
|
|
140
|
+
fanoutAuthorized: boolean;
|
|
141
|
+
runtimeExtensions: string[];
|
|
142
|
+
configuredExtensions: string[];
|
|
143
|
+
extensionArgs: string[];
|
|
144
|
+
disableAmbientExtensions: boolean;
|
|
145
|
+
capabilityAudit?: SubagentCapabilityAudit;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function resolvePiLaunchToolPlan(input: ResolvePiLaunchToolPlanInput): PiLaunchToolPlan {
|
|
149
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(input.capabilityCeiling, input.inheritedCapabilityCeiling);
|
|
150
|
+
const allowedToolSet = capabilityCeiling?.allowedTools === undefined ? undefined : new Set(capabilityCeiling.allowedTools);
|
|
151
|
+
const requestedBuiltinTools = input.tools?.filter((tool) => !(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) ?? [];
|
|
152
|
+
if (input.requireReadTool && allowedToolSet && !allowedToolSet.has("read")) {
|
|
153
|
+
throw new Error(`Capability ceiling from ${capabilityCeiling?.sources.join(", ") || "unknown source"} excludes required tool 'read' for lazy skill loading.`);
|
|
154
|
+
}
|
|
155
|
+
const declaredBuiltinTools = input.tools === undefined
|
|
156
|
+
? (allowedToolSet ? [...allowedToolSet] : [])
|
|
157
|
+
: (input.requireReadTool && requestedBuiltinTools.length > 0 && !requestedBuiltinTools.includes("read") && !allowedToolSet
|
|
158
|
+
? ["read", ...requestedBuiltinTools]
|
|
159
|
+
: requestedBuiltinTools).filter((tool) => !allowedToolSet || allowedToolSet.has(tool));
|
|
160
|
+
const fanoutAuthorized = declaredBuiltinTools.includes("subagent");
|
|
161
|
+
const toolExtensionPaths: string[] = capabilityCeiling?.denyExtensions ? [] : (input.tools ?? []).filter((tool) => !requestedBuiltinTools.includes(tool) && (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")));
|
|
162
|
+
const resolvedMcpSelections = capabilityCeiling?.denyExtensions ? [] : resolveMcpDirectToolSelections(input.mcpDirectTools, input.cwd);
|
|
163
|
+
const effectiveMcpSelections = resolvedMcpSelections.filter((selection) => !allowedToolSet || allowedToolSet.has(selection.name));
|
|
164
|
+
const effectiveMcpTools = effectiveMcpSelections.map((selection) => selection.name);
|
|
165
|
+
const explicitToolAllowlist = input.tools !== undefined || (input.mcpDirectTools?.length ?? 0) > 0 || allowedToolSet !== undefined;
|
|
166
|
+
const internalTools = input.structuredOutput ? ["structured_output"] : [];
|
|
167
|
+
const effectiveToolAllowlist = [...new Set([...declaredBuiltinTools, ...effectiveMcpTools, ...internalTools])];
|
|
168
|
+
const requiredChildTools = explicitToolAllowlist ? [...new Set([
|
|
169
|
+
...(input.tools !== undefined ? declaredBuiltinTools : []),
|
|
170
|
+
...(input.mcpDirectTools?.length ? effectiveMcpTools : []),
|
|
171
|
+
...internalTools,
|
|
172
|
+
])] : [];
|
|
173
|
+
const runtimeExtensions = fanoutAuthorized
|
|
174
|
+
? [PROMPT_RUNTIME_EXTENSION_PATH, FANOUT_CHILD_EXTENSION_PATH]
|
|
175
|
+
: [PROMPT_RUNTIME_EXTENSION_PATH];
|
|
176
|
+
const disableAmbientExtensions = capabilityCeiling?.denyExtensions === true || input.extensions !== undefined;
|
|
177
|
+
const configuredExtensions = capabilityCeiling?.denyExtensions ? [] : [...toolExtensionPaths, ...(input.extensions ?? []), ...(input.subagentOnlyExtensions ?? [])];
|
|
178
|
+
const extensionArgs = disableAmbientExtensions
|
|
179
|
+
? [...new Set([...runtimeExtensions, ...configuredExtensions])]
|
|
180
|
+
: [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...(input.subagentOnlyExtensions ?? [])])];
|
|
181
|
+
const requestedToolNames = input.tools !== undefined
|
|
182
|
+
? [...new Set([...requestedBuiltinTools, ...resolvedMcpSelections.map((selection) => selection.name)])]
|
|
183
|
+
: undefined;
|
|
184
|
+
const capabilityAudit = capabilityCeiling ? {
|
|
185
|
+
ceiling: capabilityCeiling,
|
|
186
|
+
...(requestedToolNames ? { requestedTools: requestedToolNames } : {}),
|
|
187
|
+
effectiveTools: effectiveToolAllowlist,
|
|
188
|
+
removedTools: requestedToolNames?.filter((tool) => !effectiveToolAllowlist.includes(tool)) ?? [],
|
|
189
|
+
internalTools,
|
|
190
|
+
extensionsDenied: capabilityCeiling.denyExtensions,
|
|
191
|
+
removedExtensionCount: capabilityCeiling.denyExtensions ? (input.extensions?.length ?? 0) + (input.subagentOnlyExtensions?.length ?? 0) + ((input.tools ?? []).filter((tool) => tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")).length) : 0,
|
|
192
|
+
requestedMcpToolCount: input.mcpDirectTools?.length ?? 0,
|
|
193
|
+
effectiveMcpTools,
|
|
194
|
+
} satisfies SubagentCapabilityAudit : undefined;
|
|
195
|
+
return {
|
|
196
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
197
|
+
requestedBuiltinTools,
|
|
198
|
+
declaredBuiltinTools,
|
|
199
|
+
toolExtensionPaths,
|
|
200
|
+
resolvedMcpSelections,
|
|
201
|
+
effectiveMcpSelections,
|
|
202
|
+
effectiveMcpTools,
|
|
203
|
+
explicitToolAllowlist,
|
|
204
|
+
internalTools,
|
|
205
|
+
effectiveToolAllowlist,
|
|
206
|
+
requiredChildTools,
|
|
207
|
+
fanoutAuthorized,
|
|
208
|
+
runtimeExtensions,
|
|
209
|
+
configuredExtensions,
|
|
210
|
+
extensionArgs,
|
|
211
|
+
disableAmbientExtensions,
|
|
212
|
+
...(capabilityAudit ? { capabilityAudit } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
99
216
|
export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
100
217
|
const args = [...input.baseArgs];
|
|
101
218
|
|
|
@@ -117,40 +234,25 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
117
234
|
args.push("--model", modelArg);
|
|
118
235
|
}
|
|
119
236
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
if (input.mcpDirectTools?.length) {
|
|
135
|
-
builtinTools.push(...resolveMcpDirectToolNames(input.mcpDirectTools, input.cwd));
|
|
136
|
-
}
|
|
137
|
-
args.push("--tools", builtinTools.join(","));
|
|
138
|
-
}
|
|
237
|
+
const toolPlan = resolvePiLaunchToolPlan({
|
|
238
|
+
tools: input.tools,
|
|
239
|
+
extensions: input.extensions,
|
|
240
|
+
subagentOnlyExtensions: input.subagentOnlyExtensions,
|
|
241
|
+
mcpDirectTools: input.mcpDirectTools,
|
|
242
|
+
cwd: input.cwd,
|
|
243
|
+
requireReadTool: input.requireReadTool,
|
|
244
|
+
structuredOutput: input.structuredOutput,
|
|
245
|
+
capabilityCeiling: input.capabilityCeiling,
|
|
246
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
247
|
+
});
|
|
248
|
+
if (toolPlan.explicitToolAllowlist) {
|
|
249
|
+
args.push(toolPlan.effectiveToolAllowlist.length > 0 ? "--tools" : "--no-tools");
|
|
250
|
+
if (toolPlan.effectiveToolAllowlist.length > 0) args.push(toolPlan.effectiveToolAllowlist.join(","));
|
|
139
251
|
}
|
|
140
|
-
|
|
141
|
-
const runtimeExtensions = fanoutAuthorized
|
|
142
|
-
? [PROMPT_RUNTIME_EXTENSION_PATH, FANOUT_CHILD_EXTENSION_PATH]
|
|
143
|
-
: [PROMPT_RUNTIME_EXTENSION_PATH];
|
|
144
|
-
if (input.extensions !== undefined) {
|
|
252
|
+
if (toolPlan.disableAmbientExtensions) {
|
|
145
253
|
args.push("--no-extensions");
|
|
146
|
-
for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...input.extensions, ...(input.subagentOnlyExtensions ?? [])])]) {
|
|
147
|
-
args.push("--extension", extPath);
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...(input.subagentOnlyExtensions ?? [])])]) {
|
|
151
|
-
args.push("--extension", extPath);
|
|
152
|
-
}
|
|
153
254
|
}
|
|
255
|
+
for (const extPath of toolPlan.extensionArgs) args.push("--extension", extPath);
|
|
154
256
|
|
|
155
257
|
if (!input.inheritSkills) {
|
|
156
258
|
args.push("--no-skills");
|
|
@@ -177,8 +279,21 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
177
279
|
}
|
|
178
280
|
|
|
179
281
|
const env: Record<string, string | undefined> = {};
|
|
282
|
+
const piPackageRoot = process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV] ?? resolvePiPackageRoot();
|
|
283
|
+
if (piPackageRoot) env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV] = piPackageRoot;
|
|
284
|
+
let toolDiagnosticPath: string | undefined;
|
|
285
|
+
if (toolPlan.requiredChildTools.length > 0) {
|
|
286
|
+
if (!tempDir) tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
287
|
+
toolDiagnosticPath = path.join(tempDir, "tool-diagnostic.json");
|
|
288
|
+
env[REQUIRED_CHILD_TOOLS_ENV] = JSON.stringify(toolPlan.requiredChildTools);
|
|
289
|
+
env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV] = toolDiagnosticPath;
|
|
290
|
+
}
|
|
291
|
+
env[MCP_DIRECT_CHILD_TOOLS_ENV] = toolPlan.effectiveMcpTools.length > 0 ? JSON.stringify(toolPlan.effectiveMcpTools) : undefined;
|
|
180
292
|
env[SUBAGENT_CHILD_ENV] = "1";
|
|
181
|
-
env[SUBAGENT_FANOUT_CHILD_ENV] = fanoutAuthorized ? "1" : "0";
|
|
293
|
+
env[SUBAGENT_FANOUT_CHILD_ENV] = toolPlan.fanoutAuthorized ? "1" : "0";
|
|
294
|
+
if (input.waitToolEnabled !== undefined) {
|
|
295
|
+
env[WAIT_TOOL_ENABLED_ENV] = input.waitToolEnabled ? "true" : "false";
|
|
296
|
+
}
|
|
182
297
|
const inheritedNestedRoute = Boolean(process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] && process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] && process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV]);
|
|
183
298
|
const parentRunId = input.parentRunId ?? input.runId ?? (inheritedNestedRoute ? process.env[SUBAGENT_RUN_ID_ENV] : undefined) ?? process.env[SUBAGENT_PARENT_RUN_ID_ENV] ?? "";
|
|
184
299
|
const parentChildIndex = input.parentChildIndex !== undefined
|
|
@@ -196,20 +311,20 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
196
311
|
...(input.childAgentName ? { agent: input.childAgentName } : {}),
|
|
197
312
|
}] : []),
|
|
198
313
|
];
|
|
199
|
-
env[SUBAGENT_PARENT_EVENT_SINK_ENV] = fanoutAuthorized
|
|
314
|
+
env[SUBAGENT_PARENT_EVENT_SINK_ENV] = toolPlan.fanoutAuthorized
|
|
200
315
|
? input.parentEventSink ?? process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] ?? ""
|
|
201
316
|
: "";
|
|
202
|
-
env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = fanoutAuthorized
|
|
317
|
+
env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = toolPlan.fanoutAuthorized
|
|
203
318
|
? input.parentControlInbox ?? process.env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] ?? ""
|
|
204
319
|
: "";
|
|
205
|
-
env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = fanoutAuthorized
|
|
320
|
+
env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = toolPlan.fanoutAuthorized
|
|
206
321
|
? input.parentRootRunId ?? process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] ?? input.runId ?? ""
|
|
207
322
|
: "";
|
|
208
|
-
env[SUBAGENT_PARENT_RUN_ID_ENV] = fanoutAuthorized ? parentRunId : "";
|
|
209
|
-
env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = fanoutAuthorized ? parentChildIndex : "";
|
|
210
|
-
env[SUBAGENT_PARENT_DEPTH_ENV] = fanoutAuthorized ? String(parentDepth) : "";
|
|
211
|
-
env[SUBAGENT_PARENT_PATH_ENV] = fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
|
|
212
|
-
env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
|
|
323
|
+
env[SUBAGENT_PARENT_RUN_ID_ENV] = toolPlan.fanoutAuthorized ? parentRunId : "";
|
|
324
|
+
env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = toolPlan.fanoutAuthorized ? parentChildIndex : "";
|
|
325
|
+
env[SUBAGENT_PARENT_DEPTH_ENV] = toolPlan.fanoutAuthorized ? String(parentDepth) : "";
|
|
326
|
+
env[SUBAGENT_PARENT_PATH_ENV] = toolPlan.fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
|
|
327
|
+
env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = toolPlan.fanoutAuthorized
|
|
213
328
|
? input.parentCapabilityToken ?? process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] ?? ""
|
|
214
329
|
: "";
|
|
215
330
|
env.SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext ? "1" : "0";
|
|
@@ -239,11 +354,11 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
239
354
|
if (input.childIndex !== undefined) {
|
|
240
355
|
env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
|
|
241
356
|
}
|
|
242
|
-
if (input.mcpDirectTools?.length)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
357
|
+
if (!toolPlan.capabilityCeiling && input.mcpDirectTools?.length) env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
|
|
358
|
+
else if (toolPlan.capabilityCeiling && toolPlan.effectiveMcpSelections.length && !toolPlan.capabilityCeiling.denyExtensions) env.MCP_DIRECT_TOOLS = toolPlan.effectiveMcpSelections.map((selection) => selection.selector).join(",");
|
|
359
|
+
else env.MCP_DIRECT_TOOLS = "__none__";
|
|
360
|
+
const encodedCapabilityCeiling = encodeSubagentCapabilityCeiling(toolPlan.capabilityCeiling);
|
|
361
|
+
if (encodedCapabilityCeiling) env[SUBAGENT_CAPABILITY_CEILING_ENV] = encodedCapabilityCeiling;
|
|
247
362
|
if (input.structuredOutput) {
|
|
248
363
|
env[STRUCTURED_OUTPUT_CAPTURE_ENV] = input.structuredOutput.outputPath;
|
|
249
364
|
env[STRUCTURED_OUTPUT_SCHEMA_ENV] = input.structuredOutput.schemaPath;
|
|
@@ -251,12 +366,17 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
251
366
|
if (input.steerInboxDir) {
|
|
252
367
|
env[SUBAGENT_STEER_INBOX_ENV] = input.steerInboxDir;
|
|
253
368
|
}
|
|
369
|
+
if (input.steerCapabilityPath) env[SUBAGENT_STEER_CAPABILITY_ENV] = input.steerCapabilityPath;
|
|
370
|
+
if (input.steerAckDir) env[SUBAGENT_STEER_ACK_DIR_ENV] = input.steerAckDir;
|
|
254
371
|
const encodedToolBudget = encodeToolBudgetEnv(input.toolBudget);
|
|
255
372
|
if (encodedToolBudget) env[TOOL_BUDGET_ENV] = encodedToolBudget;
|
|
373
|
+
env[TOOL_BUDGET_ZERO_AUTH_ENV] = input.allowZeroToolBudget ? "1" : undefined;
|
|
374
|
+
const encodedChildWatchdog = encodeChildWatchdogConfig(input.childWatchdog);
|
|
375
|
+
if (encodedChildWatchdog) env[CHILD_WATCHDOG_CONFIG_ENV] = encodedChildWatchdog;
|
|
256
376
|
|
|
257
377
|
env[SUBAGENT_PARENT_SESSION_ENV] = input.parentSessionId ?? process.env[SUBAGENT_PARENT_SESSION_ENV] ?? "";
|
|
258
378
|
|
|
259
|
-
return { args, env, tempDir };
|
|
379
|
+
return { args, env, tempDir, toolDiagnosticPath, capabilityAudit: toolPlan.capabilityAudit };
|
|
260
380
|
}
|
|
261
381
|
|
|
262
382
|
export const parseParentPathEnv = parseNestedPathEnv;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { readSubagentEnv } from "../../shared/env.ts";
|
|
4
5
|
|
|
5
|
-
export const
|
|
6
|
+
export const PI_CODING_AGENT_PACKAGE = "@selesai/code";
|
|
6
7
|
export const SELESAI_SUBAGENT_PI_BINARY_ENV = "SELESAI_SUBAGENT_PI_BINARY";
|
|
7
8
|
|
|
8
|
-
export function
|
|
9
|
+
export function findPiPackageRootFromEntry(
|
|
9
10
|
entryPoint: string,
|
|
10
11
|
): string | undefined {
|
|
11
12
|
let dir = path.dirname(entryPoint);
|
|
@@ -15,24 +16,24 @@ export function findSelesaiPackageRootFromEntry(
|
|
|
15
16
|
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
|
16
17
|
name?: unknown;
|
|
17
18
|
};
|
|
18
|
-
if (pkg.name ===
|
|
19
|
+
if (pkg.name === PI_CODING_AGENT_PACKAGE) return dir;
|
|
19
20
|
}
|
|
20
21
|
dir = path.dirname(dir);
|
|
21
22
|
}
|
|
22
23
|
return undefined;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export function
|
|
26
|
-
return
|
|
27
|
-
fileURLToPath(import.meta.resolve(
|
|
26
|
+
export function resolveInstalledPiPackageRoot(): string | undefined {
|
|
27
|
+
return findPiPackageRootFromEntry(
|
|
28
|
+
fileURLToPath(import.meta.resolve(PI_CODING_AGENT_PACKAGE)),
|
|
28
29
|
);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export function
|
|
32
|
+
export function resolvePiPackageRoot(): string | undefined {
|
|
32
33
|
try {
|
|
33
34
|
const entry = process.argv[1];
|
|
34
35
|
return entry
|
|
35
|
-
?
|
|
36
|
+
? findPiPackageRootFromEntry(fs.realpathSync(entry))
|
|
36
37
|
: undefined;
|
|
37
38
|
} catch {
|
|
38
39
|
// process.argv[1] probing is best-effort; callers can fall back to PATH/package resolution.
|
|
@@ -40,11 +41,12 @@ export function resolveSelesaiPackageRoot(): string | undefined {
|
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
export interface
|
|
44
|
+
export interface PiSpawnDeps {
|
|
44
45
|
platform?: NodeJS.Platform;
|
|
45
46
|
execPath?: string;
|
|
46
47
|
argv1?: string;
|
|
47
48
|
existsSync?: (filePath: string) => boolean;
|
|
49
|
+
realpathSync?: (filePath: string) => string;
|
|
48
50
|
readFileSync?: (filePath: string, encoding: "utf-8") => string;
|
|
49
51
|
resolvePackageJson?: () => string;
|
|
50
52
|
resolvePackageEntry?: () => string;
|
|
@@ -52,7 +54,7 @@ export interface SelesaiSpawnDeps {
|
|
|
52
54
|
env?: NodeJS.ProcessEnv;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
interface
|
|
57
|
+
interface PiSpawnCommand {
|
|
56
58
|
command: string;
|
|
57
59
|
args: string[];
|
|
58
60
|
}
|
|
@@ -69,10 +71,11 @@ function normalizePath(filePath: string): string {
|
|
|
69
71
|
return path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
export function
|
|
73
|
-
deps:
|
|
74
|
+
export function resolvePiCliScript(
|
|
75
|
+
deps: PiSpawnDeps = {},
|
|
74
76
|
): string | undefined {
|
|
75
77
|
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
78
|
+
const realpathSync = deps.realpathSync ?? fs.realpathSync;
|
|
76
79
|
const readFileSync =
|
|
77
80
|
deps.readFileSync ??
|
|
78
81
|
((filePath, encoding) => fs.readFileSync(filePath, encoding));
|
|
@@ -81,7 +84,14 @@ export function resolveWindowsSelesaiCliScript(
|
|
|
81
84
|
if (argv1) {
|
|
82
85
|
const argvPath = normalizePath(argv1);
|
|
83
86
|
if (isRunnableNodeScript(argvPath, existsSync)) {
|
|
84
|
-
|
|
87
|
+
try {
|
|
88
|
+
const canonicalArgvPath = realpathSync(argvPath);
|
|
89
|
+
if (isRunnableNodeScript(canonicalArgvPath, existsSync) && findPiPackageRootFromEntry(canonicalArgvPath)) {
|
|
90
|
+
return canonicalArgvPath;
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
// Host package metadata is untrusted here; keep resolving the installed Pi CLI.
|
|
94
|
+
}
|
|
85
95
|
}
|
|
86
96
|
}
|
|
87
97
|
|
|
@@ -89,14 +99,14 @@ export function resolveWindowsSelesaiCliScript(
|
|
|
89
99
|
const resolvePackageJson =
|
|
90
100
|
deps.resolvePackageJson ??
|
|
91
101
|
(() => {
|
|
92
|
-
const root = deps.piPackageRoot ??
|
|
102
|
+
const root = deps.piPackageRoot ?? resolvePiPackageRoot();
|
|
93
103
|
if (root) return path.join(root, "package.json");
|
|
94
104
|
const packageRoot = deps.resolvePackageEntry
|
|
95
|
-
?
|
|
96
|
-
:
|
|
105
|
+
? findPiPackageRootFromEntry(deps.resolvePackageEntry())
|
|
106
|
+
: resolveInstalledPiPackageRoot();
|
|
97
107
|
if (!packageRoot)
|
|
98
108
|
throw new Error(
|
|
99
|
-
`Could not resolve ${
|
|
109
|
+
`Could not resolve ${PI_CODING_AGENT_PACKAGE} package root`,
|
|
100
110
|
);
|
|
101
111
|
return path.join(packageRoot, "package.json");
|
|
102
112
|
});
|
|
@@ -115,32 +125,29 @@ export function resolveWindowsSelesaiCliScript(
|
|
|
115
125
|
return candidate;
|
|
116
126
|
}
|
|
117
127
|
} catch {
|
|
118
|
-
//
|
|
128
|
+
// Verified CLI resolution is optional; falling back to `selesai` lets PATH handle execution.
|
|
119
129
|
return undefined;
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
return undefined;
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
export function
|
|
135
|
+
export function getPiSpawnCommand(
|
|
126
136
|
args: string[],
|
|
127
|
-
deps:
|
|
128
|
-
):
|
|
137
|
+
deps: PiSpawnDeps = {},
|
|
138
|
+
): PiSpawnCommand {
|
|
129
139
|
const env = deps.env ?? process.env;
|
|
130
|
-
const piBinary = env
|
|
140
|
+
const piBinary = readSubagentEnv(env, SELESAI_SUBAGENT_PI_BINARY_ENV)?.trim();
|
|
131
141
|
if (piBinary) {
|
|
132
142
|
return { command: piBinary, args };
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
args: [piCliPath, ...args],
|
|
142
|
-
};
|
|
143
|
-
}
|
|
145
|
+
const piCliPath = resolvePiCliScript(deps);
|
|
146
|
+
if (piCliPath) {
|
|
147
|
+
return {
|
|
148
|
+
command: deps.execPath ?? process.execPath,
|
|
149
|
+
args: [piCliPath, ...args],
|
|
150
|
+
};
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
return { command: "selesai", args };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { getAgentDir } from "../../shared/utils.ts";
|
|
@@ -5,6 +6,7 @@ import { getAgentDir } from "../../shared/utils.ts";
|
|
|
5
6
|
export interface RunEntry {
|
|
6
7
|
agent: string;
|
|
7
8
|
task: string;
|
|
9
|
+
taskHash?: string;
|
|
8
10
|
ts: number;
|
|
9
11
|
status: "ok" | "error";
|
|
10
12
|
duration: number;
|
|
@@ -13,24 +15,103 @@ export interface RunEntry {
|
|
|
13
15
|
|
|
14
16
|
const ROTATE_READ_THRESHOLD = 1200;
|
|
15
17
|
const ROTATE_KEEP = 1000;
|
|
18
|
+
const PRIVATE_DIR_MODE = 0o700;
|
|
19
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
20
|
+
const REDACTED_TASK = "[redacted]";
|
|
16
21
|
|
|
17
22
|
function getHistoryPath(): string {
|
|
18
23
|
return path.join(getAgentDir(), "run-history.jsonl");
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
function hashTask(task: string): string {
|
|
27
|
+
return createHash("sha256").update(task).digest("hex");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function hardenHistoryStorage(historyPath: string): void {
|
|
31
|
+
const historyDir = path.dirname(historyPath);
|
|
32
|
+
fs.mkdirSync(historyDir, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
33
|
+
try { fs.chmodSync(historyDir, PRIVATE_DIR_MODE); } catch {}
|
|
34
|
+
try { if (fs.existsSync(historyPath)) fs.chmodSync(historyPath, PRIVATE_FILE_MODE); } catch {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function sanitizeHistoryLine(line: string): string | undefined {
|
|
38
|
+
let value: unknown;
|
|
39
|
+
try {
|
|
40
|
+
value = JSON.parse(line);
|
|
41
|
+
} catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
if (!value || typeof value !== "object") return undefined;
|
|
45
|
+
|
|
46
|
+
const record = value as Record<string, unknown>;
|
|
47
|
+
const task = typeof record.task === "string" ? record.task : "";
|
|
48
|
+
const taskHash = typeof record.taskHash === "string" && record.taskHash
|
|
49
|
+
? record.taskHash
|
|
50
|
+
: task && task !== REDACTED_TASK
|
|
51
|
+
? hashTask(task)
|
|
52
|
+
: undefined;
|
|
53
|
+
|
|
54
|
+
return JSON.stringify({
|
|
55
|
+
...record,
|
|
56
|
+
task: REDACTED_TASK,
|
|
57
|
+
...(taskHash ? { taskHash } : {}),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function sanitizeHistoryLines(raw: string): { lines: string[]; changed: boolean } {
|
|
62
|
+
const lines: string[] = [];
|
|
63
|
+
let changed = false;
|
|
64
|
+
for (const line of raw.split("\n")) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (!trimmed) continue;
|
|
67
|
+
const sanitized = sanitizeHistoryLine(trimmed);
|
|
68
|
+
if (!sanitized) {
|
|
69
|
+
changed = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (sanitized !== trimmed) changed = true;
|
|
73
|
+
lines.push(sanitized);
|
|
74
|
+
}
|
|
75
|
+
return { lines, changed };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function writePrivateHistory(historyPath: string, lines: string[]): void {
|
|
79
|
+
fs.writeFileSync(historyPath, lines.length ? `${lines.join("\n")}\n` : "", { encoding: "utf-8", mode: PRIVATE_FILE_MODE });
|
|
80
|
+
try { fs.chmodSync(historyPath, PRIVATE_FILE_MODE); } catch {}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function sanitizeHistoryFile(historyPath: string): void {
|
|
84
|
+
if (!fs.existsSync(historyPath)) return;
|
|
85
|
+
const raw = fs.readFileSync(historyPath, "utf-8");
|
|
86
|
+
const { lines, changed } = sanitizeHistoryLines(raw);
|
|
87
|
+
if (changed) writePrivateHistory(historyPath, lines);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function appendPrivateHistoryLine(historyPath: string, line: string): void {
|
|
91
|
+
const fd = fs.openSync(historyPath, fs.constants.O_APPEND | fs.constants.O_CREAT | fs.constants.O_WRONLY, PRIVATE_FILE_MODE);
|
|
92
|
+
try {
|
|
93
|
+
fs.writeSync(fd, `${line}\n`);
|
|
94
|
+
} finally {
|
|
95
|
+
fs.closeSync(fd);
|
|
96
|
+
}
|
|
97
|
+
try { fs.chmodSync(historyPath, PRIVATE_FILE_MODE); } catch {}
|
|
98
|
+
}
|
|
99
|
+
|
|
21
100
|
export function recordRun(agent: string, task: string, exitCode: number, durationMs: number): void {
|
|
22
101
|
try {
|
|
23
102
|
const entry: RunEntry = {
|
|
24
103
|
agent,
|
|
25
|
-
task:
|
|
104
|
+
task: REDACTED_TASK,
|
|
105
|
+
taskHash: hashTask(task),
|
|
26
106
|
ts: Math.floor(Date.now() / 1000),
|
|
27
107
|
status: exitCode === 0 ? "ok" : "error",
|
|
28
108
|
duration: durationMs,
|
|
29
109
|
...(exitCode !== 0 ? { exit: exitCode } : {}),
|
|
30
110
|
};
|
|
31
111
|
const historyPath = getHistoryPath();
|
|
32
|
-
|
|
33
|
-
|
|
112
|
+
hardenHistoryStorage(historyPath);
|
|
113
|
+
try { sanitizeHistoryFile(historyPath); } catch {}
|
|
114
|
+
appendPrivateHistoryLine(historyPath, JSON.stringify(entry));
|
|
34
115
|
} catch {
|
|
35
116
|
// Best-effort — never crash the execution flow for history recording
|
|
36
117
|
}
|
|
@@ -38,6 +119,7 @@ export function recordRun(agent: string, task: string, exitCode: number, duratio
|
|
|
38
119
|
|
|
39
120
|
export function loadRunsForAgent(agent: string): RunEntry[] {
|
|
40
121
|
const historyPath = getHistoryPath();
|
|
122
|
+
try { hardenHistoryStorage(historyPath); } catch {}
|
|
41
123
|
if (!fs.existsSync(historyPath)) return [];
|
|
42
124
|
let raw: string;
|
|
43
125
|
try {
|
|
@@ -46,11 +128,14 @@ export function loadRunsForAgent(agent: string): RunEntry[] {
|
|
|
46
128
|
return [];
|
|
47
129
|
}
|
|
48
130
|
|
|
49
|
-
let lines
|
|
131
|
+
let { lines, changed } = sanitizeHistoryLines(raw);
|
|
50
132
|
|
|
51
133
|
if (lines.length > ROTATE_READ_THRESHOLD) {
|
|
52
134
|
lines = lines.slice(-ROTATE_KEEP);
|
|
53
|
-
|
|
135
|
+
changed = true;
|
|
136
|
+
}
|
|
137
|
+
if (changed) {
|
|
138
|
+
try { writePrivateHistory(historyPath, lines); } catch {}
|
|
54
139
|
}
|
|
55
140
|
|
|
56
141
|
return lines
|