@selesai/code 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/core/agent-session.js +13 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/provider-composer.js +17 -4
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/system-prompt.js +2 -8
- package/dist/core/system-prompt.test.js +6 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/schema-prune.d.ts +16 -0
- package/dist/core/tools/schema-prune.js +39 -0
- package/dist/core/tools/schema-prune.test.d.ts +1 -0
- package/dist/core/tools/schema-prune.test.js +111 -0
- package/dist/defaults/models.json +5 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/agent-browser.test.ts +178 -2
- package/dist/extensions/agent-browser.ts +2 -0
- package/dist/extensions/copy-turn.test.ts +229 -0
- package/dist/extensions/copy-turn.ts +11 -0
- package/dist/extensions/grep-app/index.test.ts +356 -1
- package/dist/extensions/grep-app/index.ts +6 -1
- package/dist/extensions/handoff-new.test.ts +351 -161
- package/dist/extensions/handoff-new.ts +3 -0
- package/dist/extensions/inline-skills.test.ts +93 -0
- package/dist/extensions/inline-skills.ts +3 -0
- package/dist/extensions/model-prompt-injector/config.json +10 -0
- package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
- package/dist/extensions/model-prompt-injector/index.ts +151 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
- package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
- package/dist/extensions/pi-subagents/agents/builder.md +5 -2
- package/dist/extensions/pi-subagents/agents/commentator.md +1 -1
- package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
- package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/agents/worker.md +1 -1
- package/dist/extensions/pi-subagents/docs/configuration.md +78 -11
- package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
- package/dist/extensions/pi-subagents/docs/missions.md +5 -3
- package/dist/extensions/pi-subagents/docs/models.md +1 -1
- package/dist/extensions/pi-subagents/docs/observability.md +42 -2
- package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
- package/dist/extensions/pi-subagents/docs/workflows.md +4 -4
- package/dist/extensions/pi-subagents/install.mjs +2 -2
- package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +16 -15
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
- package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
- package/dist/extensions/pi-subagents/src/extension/config.ts +59 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +146 -23
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
- package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
- package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
- package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +17 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +11 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +224 -42
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +35 -26
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +108 -9
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +7 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +368 -50
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
- package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
- package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
- package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/session-lineage.ts +71 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +66 -4
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +129 -17
- package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
- package/dist/extensions/pi-subagents/src/workflows/workflow-auto-relaunch.ts +28 -0
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +369 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
- package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
- package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
- package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
- package/dist/extensions/pi-subagents/test/unit/handoff-adoption.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
- package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
- package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
- package/dist/extensions/pi-subagents/test/unit/session-lineage.test.ts +73 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-auto-relaunch.test.ts +45 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
- package/dist/extensions/ponytail/index.js +11 -0
- package/dist/extensions/ponytail/ponytail-config.cjs +2 -0
- package/dist/extensions/ponytail/ponytail-instructions.cjs +6 -0
- package/dist/extensions/ponytail/test/extension.test.js +274 -140
- package/dist/extensions/ponytail/test/helpers.test.js +280 -92
- package/dist/extensions/question/index.ts +33 -0
- package/dist/extensions/question/question-list.ts +28 -0
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/batch.test.ts +103 -65
- package/dist/extensions/question/tests/exp.test.ts +70 -0
- package/dist/extensions/question/tests/exp2.test.ts +59 -0
- package/dist/extensions/question/tests/exp3.test.ts +47 -0
- package/dist/extensions/question/tests/helpers.test.ts +75 -35
- package/dist/extensions/question/tests/question-list.test.ts +640 -198
- package/dist/extensions/question/tests/row-layout.test.ts +193 -114
- package/dist/extensions/question/tests/schemas.test.ts +42 -19
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/shortcuts.test.ts +106 -84
- package/dist/extensions/question/tests/wizard.test.ts +771 -50
- package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
- package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
- package/dist/extensions/rtk.test.ts +180 -1
- package/dist/extensions/tokenin-onboarding.ts +3 -0
- package/dist/extensions/undo.test.ts +720 -0
- package/dist/extensions/undo.ts +6 -0
- package/dist/extensions/web-agent-onboarding.test.ts +415 -0
- package/dist/extensions/workflow/extension.ts +3 -3
- package/dist/extensions/workflow/modes.ts +41 -19
- package/dist/skills/pi-subagents/SKILL.md +1 -1
- package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/skills/pi-subagents/references/execution-controls.md +16 -15
- package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/docs/plans/workflow-autoloop-reference.md +1 -2
- package/docs/plans/workflow-handoff-carryover.md +108 -0
- package/docs/settings.md +6 -0
- package/package.json +4 -1
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { afterEach, test } from "node:test";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import { createOrcaProgressTab, resolveOrcaCommand, resolvePiSessionId } from "../../src/runs/shared/orca-progress-tabs.ts";
|
|
9
|
+
import { TEMP_ROOT_DIR } from "../../src/shared/types.ts";
|
|
10
|
+
import { writeNodeCommand } from "../support/node-command.ts";
|
|
11
|
+
|
|
12
|
+
const tempDirs: string[] = [];
|
|
13
|
+
|
|
14
|
+
function removeProgressFiles(prefix: string): void {
|
|
15
|
+
const root = path.join(TEMP_ROOT_DIR, "orca-progress");
|
|
16
|
+
if (!fs.existsSync(root)) return;
|
|
17
|
+
for (const name of fs.readdirSync(root)) {
|
|
18
|
+
if (name.startsWith(prefix)) fs.rmSync(path.join(root, name), { force: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
const progressRoot = path.join(TEMP_ROOT_DIR, "orca-progress");
|
|
24
|
+
for (const dir of tempDirs.splice(0)) {
|
|
25
|
+
const key = createHash("sha256").update(path.resolve(dir)).digest("hex").slice(0, 20);
|
|
26
|
+
fs.rmSync(path.join(progressRoot, `counter-${key}`), { force: true });
|
|
27
|
+
fs.rmSync(path.join(progressRoot, `counter-${key}.lock`), { recursive: true, force: true });
|
|
28
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
29
|
+
}
|
|
30
|
+
removeProgressFiles("progress-");
|
|
31
|
+
removeProgressFiles("disabled-run-");
|
|
32
|
+
removeProgressFiles("standalone-pi-");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
function tempDir(): string {
|
|
36
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-orca-tabs-test-"));
|
|
37
|
+
tempDirs.push(dir);
|
|
38
|
+
return dir;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function waitForFile(file: string): Promise<void> {
|
|
42
|
+
const deadline = Date.now() + 5_000;
|
|
43
|
+
while (!fs.existsSync(file)) {
|
|
44
|
+
if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${file}`);
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function progressFile(prefix: string, suffix: ".log" | ".done"): string {
|
|
50
|
+
const root = path.join(TEMP_ROOT_DIR, "orca-progress");
|
|
51
|
+
const name = fs.readdirSync(root).find((candidate) => candidate.startsWith(prefix) && candidate.endsWith(suffix));
|
|
52
|
+
assert.ok(name, `Expected ${suffix} file for ${prefix}`);
|
|
53
|
+
return path.join(root, name);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function captureCommand(command: string, cwd: string): Promise<string> {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const child = spawn(command, { cwd, shell: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
59
|
+
let output = "";
|
|
60
|
+
child.stdout.setEncoding("utf-8");
|
|
61
|
+
child.stdout.on("data", (chunk: string) => { output += chunk; });
|
|
62
|
+
child.once("error", reject);
|
|
63
|
+
child.once("close", (code) => code === 0 ? resolve(output) : reject(new Error(`Viewer exited ${code}: ${output}`)));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function writeCaptureOrca(dir: string): string {
|
|
68
|
+
return writeNodeCommand(dir, "orca", "require('fs').writeFileSync(process.env.ORCA_TEST_CAPTURE, JSON.stringify(process.argv.slice(2)))");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
test("Orca progress tabs are disabled on Windows", { skip: process.platform === "win32" ? undefined : "Windows-only platform boundary" }, () => {
|
|
72
|
+
const dir = tempDir();
|
|
73
|
+
assert.equal(createOrcaProgressTab({
|
|
74
|
+
cwd: dir,
|
|
75
|
+
runId: "windows-disabled",
|
|
76
|
+
agent: "worker",
|
|
77
|
+
index: 0,
|
|
78
|
+
config: { enabled: true },
|
|
79
|
+
command: process.execPath,
|
|
80
|
+
}), undefined);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("resolveOrcaCommand only returns executable commands", () => {
|
|
84
|
+
const dir = tempDir();
|
|
85
|
+
const executable = writeNodeCommand(dir, "orca", "process.exit(0)");
|
|
86
|
+
assert.equal(resolveOrcaCommand({ PATH: dir, PATHEXT: ".CMD" }), executable);
|
|
87
|
+
assert.equal(resolveOrcaCommand({ PATH: "", SELESAI_SUBAGENT_ORCA_BINARY: path.join(dir, "missing") }), undefined);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("an unavailable Orca command leaves native execution untouched", () => {
|
|
91
|
+
const dir = tempDir();
|
|
92
|
+
assert.equal(createOrcaProgressTab({
|
|
93
|
+
cwd: dir,
|
|
94
|
+
runId: "missing-orca",
|
|
95
|
+
agent: "worker",
|
|
96
|
+
index: 0,
|
|
97
|
+
config: { enabled: true },
|
|
98
|
+
env: { PATH: "", SELESAI_SUBAGENT_ORCA_BINARY: path.join(dir, "missing") },
|
|
99
|
+
}), undefined);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("standalone Pi executables use PATH Node for the watchdog and viewer", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
103
|
+
const dir = tempDir();
|
|
104
|
+
const capture = path.join(dir, "capture.json");
|
|
105
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
106
|
+
const fakePi = path.join(dir, "pi");
|
|
107
|
+
const originalExecPath = process.execPath;
|
|
108
|
+
try {
|
|
109
|
+
process.execPath = fakePi;
|
|
110
|
+
const tab = createOrcaProgressTab({
|
|
111
|
+
cwd: dir,
|
|
112
|
+
runId: "standalone-pi",
|
|
113
|
+
agent: "worker",
|
|
114
|
+
index: 0,
|
|
115
|
+
config: { enabled: true },
|
|
116
|
+
command: fakeOrca,
|
|
117
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
118
|
+
});
|
|
119
|
+
assert.ok(tab);
|
|
120
|
+
tab.finish("failed");
|
|
121
|
+
await waitForFile(capture);
|
|
122
|
+
const args = JSON.parse(fs.readFileSync(capture, "utf-8")) as string[];
|
|
123
|
+
const viewer = args[args.indexOf("--command") + 1]!;
|
|
124
|
+
assert.match(viewer, /^'node' '-e' /);
|
|
125
|
+
assert.equal(viewer.includes(fakePi), false);
|
|
126
|
+
assert.match(await captureCommand(viewer, dir), /failed/);
|
|
127
|
+
} finally {
|
|
128
|
+
process.execPath = originalExecPath;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("hung Orca terminal creation does not delay the owning process", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
133
|
+
const dir = tempDir();
|
|
134
|
+
const fakeOrca = writeNodeCommand(dir, "orca", "require('fs').writeFileSync(process.env.ORCA_TEST_PID, String(process.pid));setInterval(()=>{},1000)");
|
|
135
|
+
const pidFile = path.join(dir, "orca.pid");
|
|
136
|
+
const moduleUrl = new URL("../../src/runs/shared/orca-progress-tabs.ts", import.meta.url).href;
|
|
137
|
+
const ownerScript = `import {createOrcaProgressTab} from ${JSON.stringify(moduleUrl)};const tab=createOrcaProgressTab({cwd:${JSON.stringify(dir)},runId:'progress-hung-owner',agent:'worker',index:0,config:{enabled:true},command:${JSON.stringify(fakeOrca)},env:{...process.env,ORCA_TEST_PID:${JSON.stringify(pidFile)}}});if(!tab)throw new Error('tab unavailable');`;
|
|
138
|
+
const startedAt = Date.now();
|
|
139
|
+
const owner = spawn(process.execPath, ["--experimental-strip-types", "--input-type=module", "--eval", ownerScript], { cwd: dir, stdio: "ignore" });
|
|
140
|
+
const ownerClosed = new Promise<number | null>((resolve, reject) => {
|
|
141
|
+
owner.once("error", reject);
|
|
142
|
+
owner.once("close", resolve);
|
|
143
|
+
});
|
|
144
|
+
let fakePid: number | undefined;
|
|
145
|
+
try {
|
|
146
|
+
assert.equal(await ownerClosed, 0);
|
|
147
|
+
assert.ok(Date.now() - startedAt < 2_000, "the Orca observer delayed runner completion");
|
|
148
|
+
await waitForFile(pidFile);
|
|
149
|
+
fakePid = Number.parseInt(fs.readFileSync(pidFile, "utf-8"), 10);
|
|
150
|
+
process.kill(fakePid, 0);
|
|
151
|
+
} finally {
|
|
152
|
+
if (fakePid !== undefined) {
|
|
153
|
+
try { process.kill(fakePid, "SIGKILL"); } catch { /* already stopped */ }
|
|
154
|
+
}
|
|
155
|
+
if (owner.exitCode === null) owner.kill("SIGKILL");
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("malformed optional observer metadata cannot break child execution", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
160
|
+
const dir = tempDir();
|
|
161
|
+
const capture = path.join(dir, "capture.json");
|
|
162
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
163
|
+
const tab = createOrcaProgressTab({
|
|
164
|
+
cwd: dir,
|
|
165
|
+
runId: undefined,
|
|
166
|
+
agent: undefined,
|
|
167
|
+
index: undefined,
|
|
168
|
+
config: { enabled: true },
|
|
169
|
+
command: fakeOrca,
|
|
170
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
171
|
+
} as never);
|
|
172
|
+
assert.ok(tab);
|
|
173
|
+
tab.finish("completed");
|
|
174
|
+
await waitForFile(capture);
|
|
175
|
+
const args = JSON.parse(fs.readFileSync(capture, "utf-8")) as string[];
|
|
176
|
+
assert.equal(args[args.indexOf("--title") + 1], "subagent · subagent · 1");
|
|
177
|
+
removeProgressFiles("run-0-");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("disabled Orca progress tabs do not invoke Orca", async () => {
|
|
181
|
+
const dir = tempDir();
|
|
182
|
+
const capture = path.join(dir, "capture.json");
|
|
183
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
184
|
+
const tab = createOrcaProgressTab({
|
|
185
|
+
cwd: dir,
|
|
186
|
+
runId: "disabled-run",
|
|
187
|
+
agent: "worker",
|
|
188
|
+
index: 0,
|
|
189
|
+
config: { enabled: false },
|
|
190
|
+
command: fakeOrca,
|
|
191
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
192
|
+
});
|
|
193
|
+
assert.equal(tab, undefined);
|
|
194
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
195
|
+
assert.equal(fs.existsSync(capture), false);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("enabled tabs use a worktree sequence and successful Pi sessions get cleanup guidance", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
199
|
+
const dir = tempDir();
|
|
200
|
+
const capture = path.join(dir, "capture.json");
|
|
201
|
+
const secondCapture = path.join(dir, "capture-2.json");
|
|
202
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
203
|
+
fs.mkdirSync(path.join(dir, ".git"));
|
|
204
|
+
const runId = `progress-${Date.now()}`;
|
|
205
|
+
const tab = createOrcaProgressTab({
|
|
206
|
+
cwd: dir,
|
|
207
|
+
runId,
|
|
208
|
+
agent: "worker",
|
|
209
|
+
index: 2,
|
|
210
|
+
config: { enabled: true },
|
|
211
|
+
command: fakeOrca,
|
|
212
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
213
|
+
});
|
|
214
|
+
assert.ok(tab);
|
|
215
|
+
tab.append("starting\n");
|
|
216
|
+
tab.event({ type: "tool_execution_start", toolName: "read", args: { path: "README.md" } });
|
|
217
|
+
tab.event({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "done output" }] } as never });
|
|
218
|
+
const sessionId = "019ffd40-4859-7015-94e4-7d15c31885ef";
|
|
219
|
+
const sessionFile = path.join(dir, `session file's ${sessionId}.jsonl`);
|
|
220
|
+
fs.writeFileSync(sessionFile, `${JSON.stringify({ type: "session", version: 3, id: sessionId })}\n`);
|
|
221
|
+
assert.equal(resolvePiSessionId(sessionFile), sessionId);
|
|
222
|
+
assert.equal(resolvePiSessionId(path.join(dir, `missing_${sessionId}.jsonl`)), undefined);
|
|
223
|
+
tab.finish("completed", sessionFile);
|
|
224
|
+
|
|
225
|
+
await waitForFile(capture);
|
|
226
|
+
const args = JSON.parse(fs.readFileSync(capture, "utf-8")) as string[];
|
|
227
|
+
assert.deepEqual(args.slice(0, 2), ["terminal", "create"]);
|
|
228
|
+
assert.equal(args[args.indexOf("--worktree") + 1], `path:${path.resolve(dir)}`);
|
|
229
|
+
assert.equal(args[args.indexOf("--title") + 1], "subagent · worker · 1");
|
|
230
|
+
const viewer = args[args.indexOf("--command") + 1];
|
|
231
|
+
assert.ok(viewer.includes(process.execPath));
|
|
232
|
+
assert.doesNotMatch(viewer, /(?:^|;)\s*exec\s/);
|
|
233
|
+
assert.doesNotMatch(viewer, /(?:&|;)\s*exit(?:\s|$)/);
|
|
234
|
+
|
|
235
|
+
const progressDir = path.join(TEMP_ROOT_DIR, "orca-progress");
|
|
236
|
+
const log = fs.readdirSync(progressDir).find((name) => name.startsWith(`${runId}-2-`) && name.endsWith(".log"));
|
|
237
|
+
assert.ok(log);
|
|
238
|
+
const text = fs.readFileSync(path.join(progressDir, log), "utf-8");
|
|
239
|
+
assert.match(text, /starting/);
|
|
240
|
+
assert.match(text, /› read: README\.md/);
|
|
241
|
+
assert.match(text, /done output/);
|
|
242
|
+
const quotedSessionFile = `'${fs.realpathSync(sessionFile).replace(/'/g, `'"'"'`)}'`;
|
|
243
|
+
assert.ok(text.includes(`completed. To remove the Pi session of this subagent, run rm -- ${quotedSessionFile}`));
|
|
244
|
+
assert.doesNotMatch(text, /find ~\/\.pi\/agent\/sessions/);
|
|
245
|
+
|
|
246
|
+
const nestedCwd = path.join(dir, "packages", "app");
|
|
247
|
+
fs.mkdirSync(nestedCwd, { recursive: true });
|
|
248
|
+
const secondTab = createOrcaProgressTab({
|
|
249
|
+
cwd: nestedCwd,
|
|
250
|
+
runId: `${runId}-second`,
|
|
251
|
+
agent: "worker",
|
|
252
|
+
index: 0,
|
|
253
|
+
config: { enabled: true },
|
|
254
|
+
command: fakeOrca,
|
|
255
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: secondCapture },
|
|
256
|
+
});
|
|
257
|
+
assert.ok(secondTab);
|
|
258
|
+
secondTab.finish("failed", sessionFile);
|
|
259
|
+
await waitForFile(secondCapture);
|
|
260
|
+
const secondArgs = JSON.parse(fs.readFileSync(secondCapture, "utf-8")) as string[];
|
|
261
|
+
assert.equal(secondArgs[secondArgs.indexOf("--title") + 1], "subagent · worker · 2");
|
|
262
|
+
const secondLog = fs.readdirSync(progressDir).find((name) => name.startsWith(`${runId}-second-0-`) && name.endsWith(".log"));
|
|
263
|
+
assert.ok(secondLog);
|
|
264
|
+
const secondText = fs.readFileSync(path.join(progressDir, secondLog), "utf-8");
|
|
265
|
+
assert.match(secondText, /failed/);
|
|
266
|
+
assert.doesNotMatch(secondText, /To remove the Pi session/);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("viewer strips split terminal control sequences across poll ticks", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
270
|
+
const dir = tempDir();
|
|
271
|
+
const capture = path.join(dir, "capture.json");
|
|
272
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
273
|
+
const runId = `progress-sanitize-${Date.now()}`;
|
|
274
|
+
const tab = createOrcaProgressTab({
|
|
275
|
+
cwd: dir,
|
|
276
|
+
runId,
|
|
277
|
+
agent: "worker",
|
|
278
|
+
index: 0,
|
|
279
|
+
config: { enabled: true },
|
|
280
|
+
command: fakeOrca,
|
|
281
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
282
|
+
});
|
|
283
|
+
assert.ok(tab);
|
|
284
|
+
await waitForFile(capture);
|
|
285
|
+
const args = JSON.parse(fs.readFileSync(capture, "utf-8")) as string[];
|
|
286
|
+
const viewer = args[args.indexOf("--command") + 1]!;
|
|
287
|
+
const outputPromise = captureCommand(viewer, dir);
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
289
|
+
tab.append("safe CSI \u001b[");
|
|
290
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
291
|
+
tab.append("31mred OSC \u001b]0;secret");
|
|
292
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
293
|
+
tab.append(" title\u0007visible\u0000\u0001\r\t\u007f\n");
|
|
294
|
+
tab.finish("failed");
|
|
295
|
+
const output = await outputPromise;
|
|
296
|
+
assert.match(output, /safe CSI red OSC visible\n/);
|
|
297
|
+
assert.doesNotMatch(output, /\u001b|31m|secret|title|\u0000|\u0001|\r|\t|\u007f/);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test("mirror output keeps small writes that hit stream backpressure before the byte limit", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
301
|
+
const dir = tempDir();
|
|
302
|
+
const capture = path.join(dir, "capture.json");
|
|
303
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
304
|
+
const runId = `progress-backpressure-${Date.now()}`;
|
|
305
|
+
const tab = createOrcaProgressTab({
|
|
306
|
+
cwd: dir,
|
|
307
|
+
runId,
|
|
308
|
+
agent: "worker",
|
|
309
|
+
index: 0,
|
|
310
|
+
config: { enabled: true },
|
|
311
|
+
command: fakeOrca,
|
|
312
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
313
|
+
});
|
|
314
|
+
assert.ok(tab);
|
|
315
|
+
for (let index = 0; index < 2_000; index++) tab.append(`line-${index.toString().padStart(4, "0")} ${"x".repeat(80)}\n`);
|
|
316
|
+
tab.finish("completed");
|
|
317
|
+
const log = progressFile(`${runId}-0-`, ".log");
|
|
318
|
+
await waitForFile(log.replace(/\.log$/, ".done"));
|
|
319
|
+
const text = fs.readFileSync(log, "utf-8");
|
|
320
|
+
assert.match(text, /line-1999/);
|
|
321
|
+
assert.doesNotMatch(text, /progress mirror truncated/);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test("mirror output truncates at a finite byte bound", { skip: process.platform === "win32" ? "Orca progress tabs are not supported on Windows" : undefined }, async () => {
|
|
325
|
+
const dir = tempDir();
|
|
326
|
+
const capture = path.join(dir, "capture.json");
|
|
327
|
+
const fakeOrca = writeCaptureOrca(dir);
|
|
328
|
+
const runId = `progress-bounded-${Date.now()}`;
|
|
329
|
+
const tab = createOrcaProgressTab({
|
|
330
|
+
cwd: dir,
|
|
331
|
+
runId,
|
|
332
|
+
agent: "worker",
|
|
333
|
+
index: 0,
|
|
334
|
+
config: { enabled: true },
|
|
335
|
+
command: fakeOrca,
|
|
336
|
+
env: { ...process.env, ORCA_TEST_CAPTURE: capture },
|
|
337
|
+
});
|
|
338
|
+
assert.ok(tab);
|
|
339
|
+
tab.append("x".repeat(2 * 1024 * 1024));
|
|
340
|
+
tab.append("must be dropped");
|
|
341
|
+
tab.finish("completed");
|
|
342
|
+
const log = progressFile(`${runId}-0-`, ".log");
|
|
343
|
+
await waitForFile(log.replace(/\.log$/, ".done"));
|
|
344
|
+
assert.ok(fs.statSync(log).size <= 1024 * 1024);
|
|
345
|
+
const text = fs.readFileSync(log, "utf-8");
|
|
346
|
+
assert.match(text, /progress mirror truncated at 1048576 bytes/);
|
|
347
|
+
assert.doesNotMatch(text, /must be dropped/);
|
|
348
|
+
});
|
|
@@ -69,8 +69,11 @@ test("published extension APIs use supported package entrypoints", async () => {
|
|
|
69
69
|
assert.equal(backgroundWork.BACKGROUND_WORK_PROTOCOL_VERSION, 1);
|
|
70
70
|
assert.equal(backgroundWork.BACKGROUND_WORK_REGISTRY_KEY, "pi-subagents.background-work.v1");
|
|
71
71
|
const externalRuns = await import("pi-subagents/external-runs");
|
|
72
|
-
assert.equal(externalRuns.EXTERNAL_RUN_REGISTRY_VERSION,
|
|
73
|
-
assert.equal(typeof externalRuns.
|
|
72
|
+
assert.equal(externalRuns.EXTERNAL_RUN_REGISTRY_VERSION, 2);
|
|
73
|
+
assert.equal(typeof externalRuns.registerExternalRun, "function");
|
|
74
|
+
assert.equal(typeof externalRuns.updateExternalRun, "function");
|
|
75
|
+
assert.equal(typeof externalRuns.snapshotExternalRuns, "function");
|
|
76
|
+
assert.equal(typeof externalRuns.unregisterExternalRun, "function");
|
|
74
77
|
const capability = await import("pi-subagents/capability-ceiling");
|
|
75
78
|
assert.equal(capability.SUBAGENT_CAPABILITY_CEILING_VERSION, 1);
|
|
76
79
|
assert.equal(capability.SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY, "pi-subagents.capability-ceiling.v1");
|
|
@@ -825,7 +825,7 @@ describe("buildPiArgs system prompt mode wiring", () => {
|
|
|
825
825
|
tools: reviewer.tools,
|
|
826
826
|
});
|
|
827
827
|
|
|
828
|
-
assert.equal(args[args.indexOf("--tools") + 1], "read,grep,find,ls
|
|
828
|
+
assert.equal(args[args.indexOf("--tools") + 1], "read,grep,find,ls");
|
|
829
829
|
assert.doesNotMatch(args[args.indexOf("--tools") + 1] ?? "", /\b(?:bash|edit|write)\b/);
|
|
830
830
|
});
|
|
831
831
|
|
|
@@ -214,6 +214,7 @@ Package skill content.
|
|
|
214
214
|
it("resolves configured artifact directory preferences", () => {
|
|
215
215
|
const sessionFile = path.join(agentDir, "sessions", "session-1", "session.jsonl");
|
|
216
216
|
|
|
217
|
+
// Selesai fork default: project-scoped .pi-subagents artifacts.
|
|
217
218
|
assert.equal(getArtifactsDir(sessionFile, cwd), getProjectArtifactsDir(cwd));
|
|
218
219
|
assert.equal(getArtifactsDir(sessionFile, cwd, "project"), getProjectArtifactsDir(cwd));
|
|
219
220
|
assert.equal(getArtifactsDir(sessionFile, cwd, "session"), path.join(path.dirname(sessionFile), "subagent-artifacts"));
|
|
@@ -241,6 +242,39 @@ Package skill content.
|
|
|
241
242
|
assert.throws(() => updateConfig((config) => config), /config\.fleetKeybindings\.pageUp entries must be non-empty strings/);
|
|
242
243
|
});
|
|
243
244
|
|
|
245
|
+
it("loads and validates the foreground detach shortcut", () => {
|
|
246
|
+
const configPath = path.join(agentDir, "extensions", "subagent", "config.json");
|
|
247
|
+
writeFile(configPath, JSON.stringify({ foregroundDetachShortcut: "ctrl+b" }));
|
|
248
|
+
assert.equal(loadConfig().foregroundDetachShortcut, "ctrl+b");
|
|
249
|
+
|
|
250
|
+
writeFile(configPath, JSON.stringify({ foregroundDetachShortcut: "banana" }));
|
|
251
|
+
assert.throws(() => updateConfig((config) => config), /config\.foregroundDetachShortcut must be a valid keybinding string/);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("loads and validates main-window renderer density config", () => {
|
|
255
|
+
const configPath = path.join(agentDir, "extensions", "subagent", "config.json");
|
|
256
|
+
writeFile(configPath, JSON.stringify({ mainWindowRenderer: { horizontalSpacing: 0, compactResultMaxLines: 4 } }));
|
|
257
|
+
assert.deepEqual(loadConfig().mainWindowRenderer, { horizontalSpacing: 0, compactResultMaxLines: 4 });
|
|
258
|
+
|
|
259
|
+
writeFile(configPath, JSON.stringify({ mainWindowRenderer: { horizontalSpacing: -1 } }));
|
|
260
|
+
assert.throws(() => updateConfig((config) => config), /config\.mainWindowRenderer\.horizontalSpacing must be an integer from 0 to 4/);
|
|
261
|
+
|
|
262
|
+
writeFile(configPath, JSON.stringify({ mainWindowRenderer: { compactResultMaxLines: 0 } }));
|
|
263
|
+
assert.throws(() => updateConfig((config) => config), /config\.mainWindowRenderer\.compactResultMaxLines must be a positive integer/);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("loads and validates experimental Orca progress-tab config", () => {
|
|
267
|
+
const configPath = path.join(agentDir, "extensions", "subagent", "config.json");
|
|
268
|
+
writeFile(configPath, JSON.stringify({ orcaProgressTabs: { enabled: true } }));
|
|
269
|
+
assert.deepEqual(loadConfig().orcaProgressTabs, { enabled: true });
|
|
270
|
+
|
|
271
|
+
writeFile(configPath, JSON.stringify({ orcaProgressTabs: { enabled: "yes" } }));
|
|
272
|
+
assert.throws(() => updateConfig((config) => config), /config\.orcaProgressTabs\.enabled must be a boolean/);
|
|
273
|
+
|
|
274
|
+
writeFile(configPath, JSON.stringify({ orcaProgressTabs: { enabled: true, focus: true } }));
|
|
275
|
+
assert.throws(() => updateConfig((config) => config), /config\.orcaProgressTabs\.focus is not supported/);
|
|
276
|
+
});
|
|
277
|
+
|
|
244
278
|
it("hardens and redacts existing run history while recording", () => {
|
|
245
279
|
const historyPath = path.join(agentDir, "run-history.jsonl");
|
|
246
280
|
fs.mkdirSync(agentDir, { recursive: true, mode: 0o755 });
|
|
@@ -5,7 +5,12 @@ import { normalizePublicSubagentExecution } from "../../src/extension/public-exe
|
|
|
5
5
|
describe("public subagent execution normalization", () => {
|
|
6
6
|
it("accepts all four execution modes, management, and direct-field schedules", () => {
|
|
7
7
|
assert.deepEqual(normalizePublicSubagentExecution({ workflowScript: "return 1" }), { ok: true, params: { workflowScript: "return 1" } });
|
|
8
|
-
|
|
8
|
+
const single = normalizePublicSubagentExecution({ agent: "worker", task: "work" });
|
|
9
|
+
assert.equal(single.ok, true);
|
|
10
|
+
if (single.ok) {
|
|
11
|
+
assert.equal(typeof (single.params as { workflowScript?: unknown }).workflowScript, "string");
|
|
12
|
+
assert.match((single.params as { workflowScript: string }).workflowScript, /runs\.run\("main", \{"agent":"worker","task":"work","output":true\}\)/);
|
|
13
|
+
}
|
|
9
14
|
assert.deepEqual(normalizePublicSubagentExecution({ tasks: [{ agent: "worker" }] }), { ok: true, params: { tasks: [{ agent: "worker" }] } });
|
|
10
15
|
assert.deepEqual(normalizePublicSubagentExecution({ chain: [{ agent: "worker" }] }), { ok: true, params: { chain: [{ agent: "worker" }] } });
|
|
11
16
|
assert.deepEqual(normalizePublicSubagentExecution({ action: " list " }), { ok: true, params: { action: "list" } });
|
|
@@ -80,6 +80,50 @@ test("multiline rendering omits two-column graphemes at one-column width", () =>
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
test("running single-subagent cards show the configured detach shortcut", () => {
|
|
84
|
+
const running = {
|
|
85
|
+
...result("reviewer", ""),
|
|
86
|
+
progress: { status: "running", index: 0, agent: "reviewer", toolCount: 0, tokens: 0, durationMs: 0 },
|
|
87
|
+
};
|
|
88
|
+
const toolResult = {
|
|
89
|
+
content: [{ type: "text", text: "running" }],
|
|
90
|
+
details: { mode: "single", results: [running] },
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const configured = componentText(renderSubagentResult(
|
|
94
|
+
toolResult as never,
|
|
95
|
+
{ expanded: false },
|
|
96
|
+
theme as any,
|
|
97
|
+
undefined,
|
|
98
|
+
undefined,
|
|
99
|
+
"ctrl+b",
|
|
100
|
+
));
|
|
101
|
+
assert.match(configured, /Ctrl\+B to run in background/);
|
|
102
|
+
|
|
103
|
+
const unconfigured = componentText(renderSubagentResult(toolResult as never, { expanded: false }, theme as any));
|
|
104
|
+
assert.doesNotMatch(unconfigured, /run in background/);
|
|
105
|
+
|
|
106
|
+
const alreadyBackground = componentText(renderSubagentResult(
|
|
107
|
+
{ ...toolResult, details: { ...toolResult.details, asyncId: "async-123" } } as never,
|
|
108
|
+
{ expanded: false },
|
|
109
|
+
theme as any,
|
|
110
|
+
undefined,
|
|
111
|
+
undefined,
|
|
112
|
+
"ctrl+b",
|
|
113
|
+
));
|
|
114
|
+
assert.doesNotMatch(alreadyBackground, /run in background/);
|
|
115
|
+
|
|
116
|
+
const pendingBackground = componentText(renderSubagentResult(
|
|
117
|
+
{ ...toolResult, details: { ...toolResult.details, background: true } } as never,
|
|
118
|
+
{ expanded: false },
|
|
119
|
+
theme as any,
|
|
120
|
+
undefined,
|
|
121
|
+
undefined,
|
|
122
|
+
"ctrl+b",
|
|
123
|
+
));
|
|
124
|
+
assert.doesNotMatch(pendingBackground, /run in background/);
|
|
125
|
+
});
|
|
126
|
+
|
|
83
127
|
test("compact chain rendering uses workflow graph spans for dynamic fanout results", () => {
|
|
84
128
|
const component = renderSubagentResult({
|
|
85
129
|
content: [{ type: "text", text: "done" }],
|
|
@@ -238,3 +282,51 @@ test("static sequential and static parallel chain rendering keep existing labels
|
|
|
238
282
|
assert.match(parallel, /Agent 2\/2: auditor/);
|
|
239
283
|
assert.match(parallel, /Step 3: writer/);
|
|
240
284
|
});
|
|
285
|
+
|
|
286
|
+
test("main-window renderer config removes compact result indentation without changing status glyphs", () => {
|
|
287
|
+
const component = renderSubagentResult({
|
|
288
|
+
content: [{ type: "text", text: "done" }],
|
|
289
|
+
details: {
|
|
290
|
+
mode: "parallel",
|
|
291
|
+
results: [result("scout", "a"), { ...result("reviewer", ""), exitCode: 1, error: "failed" }],
|
|
292
|
+
},
|
|
293
|
+
}, { expanded: false }, theme as any, undefined, { horizontalSpacing: 0 });
|
|
294
|
+
|
|
295
|
+
const text = componentText(component);
|
|
296
|
+
assert.match(text, /^✗ parallel/m);
|
|
297
|
+
assert.match(text, /^✓ Agent 1\/2: scout/m);
|
|
298
|
+
assert.match(text, /^✗ Agent 2\/2: reviewer/m);
|
|
299
|
+
assert.match(text, /^⎿ Error: failed/m);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test("main-window renderer config caps only collapsed rich result rows", () => {
|
|
303
|
+
const rendered = renderSubagentResult({
|
|
304
|
+
content: [{ type: "text", text: "done" }],
|
|
305
|
+
details: {
|
|
306
|
+
mode: "parallel",
|
|
307
|
+
results: [
|
|
308
|
+
result("scout", "a"),
|
|
309
|
+
result("reviewer", "b"),
|
|
310
|
+
result("writer", "c"),
|
|
311
|
+
],
|
|
312
|
+
},
|
|
313
|
+
}, { expanded: false }, theme as any, undefined, { compactResultMaxLines: 3 }).render(120);
|
|
314
|
+
|
|
315
|
+
assert.equal(rendered.length, 3);
|
|
316
|
+
assert.match(rendered[2]!, /rows hidden/);
|
|
317
|
+
|
|
318
|
+
const expanded = renderSubagentResult({
|
|
319
|
+
content: [{ type: "text", text: "done" }],
|
|
320
|
+
details: {
|
|
321
|
+
mode: "parallel",
|
|
322
|
+
results: [
|
|
323
|
+
result("scout", "a"),
|
|
324
|
+
result("reviewer", "b"),
|
|
325
|
+
result("writer", "c"),
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
}, { expanded: true }, theme as any, undefined, { compactResultMaxLines: 3 }).render(120);
|
|
329
|
+
|
|
330
|
+
assert.ok(expanded.length > 3);
|
|
331
|
+
assert.doesNotMatch(expanded.join("\n"), /rows hidden/);
|
|
332
|
+
});
|