@oharness/engine 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/acp/claude.d.ts +34 -0
  2. package/dist/acp/claude.js +122 -0
  3. package/dist/acp/claude.js.map +1 -0
  4. package/dist/acp/client.d.ts +193 -0
  5. package/dist/acp/client.js +279 -0
  6. package/dist/acp/client.js.map +1 -0
  7. package/dist/acp/runner.d.ts +80 -0
  8. package/dist/acp/runner.js +159 -0
  9. package/dist/acp/runner.js.map +1 -0
  10. package/dist/agent/agent.d.ts +51 -1
  11. package/dist/agent/agent.js +322 -1
  12. package/dist/agent/agent.js.map +1 -1
  13. package/dist/agent/hooks.js +6 -6
  14. package/dist/agent/hooks.js.map +1 -1
  15. package/dist/agent/session.d.ts +2 -0
  16. package/dist/agent/session.js +19 -2
  17. package/dist/agent/session.js.map +1 -1
  18. package/dist/agent/subagent.d.ts +9 -0
  19. package/dist/agent/subagent.js +6 -0
  20. package/dist/agent/subagent.js.map +1 -1
  21. package/dist/auth/index.d.ts +3 -1
  22. package/dist/auth/index.js +3 -1
  23. package/dist/auth/index.js.map +1 -1
  24. package/dist/auth/manager.js +4 -0
  25. package/dist/auth/manager.js.map +1 -1
  26. package/dist/auth/oauth.d.ts +33 -0
  27. package/dist/auth/oauth.js +59 -8
  28. package/dist/auth/oauth.js.map +1 -1
  29. package/dist/auth/providers/anthropic.d.ts +25 -5
  30. package/dist/auth/providers/anthropic.js +47 -6
  31. package/dist/auth/providers/anthropic.js.map +1 -1
  32. package/dist/auth/providers/chatgpt.d.ts +8 -0
  33. package/dist/auth/providers/chatgpt.js +180 -0
  34. package/dist/auth/providers/chatgpt.js.map +1 -0
  35. package/dist/auth/providers/openrouter.d.ts +2 -0
  36. package/dist/auth/providers/openrouter.js +101 -0
  37. package/dist/auth/providers/openrouter.js.map +1 -0
  38. package/dist/auth/types.d.ts +15 -0
  39. package/dist/auth/types.js.map +1 -1
  40. package/dist/browser/index.d.ts +1 -1
  41. package/dist/browser/plugin.d.ts +6 -1
  42. package/dist/browser/plugin.js.map +1 -1
  43. package/dist/browser/session.d.ts +47 -0
  44. package/dist/browser/session.js +177 -2
  45. package/dist/browser/session.js.map +1 -1
  46. package/dist/browser/tools.js +139 -18
  47. package/dist/browser/tools.js.map +1 -1
  48. package/dist/computer/cua-driver.d.ts +60 -1
  49. package/dist/computer/cua-driver.js +149 -5
  50. package/dist/computer/cua-driver.js.map +1 -1
  51. package/dist/computer/helper-client.d.ts +3 -1
  52. package/dist/computer/helper-client.js +3 -0
  53. package/dist/computer/helper-client.js.map +1 -1
  54. package/dist/computer/index.d.ts +3 -2
  55. package/dist/computer/index.js +1 -1
  56. package/dist/computer/index.js.map +1 -1
  57. package/dist/computer/mode.d.ts +15 -0
  58. package/dist/computer/mode.js +11 -1
  59. package/dist/computer/mode.js.map +1 -1
  60. package/dist/computer/session.d.ts +36 -7
  61. package/dist/computer/session.js +118 -17
  62. package/dist/computer/session.js.map +1 -1
  63. package/dist/computer/target.d.ts +19 -0
  64. package/dist/computer/target.js.map +1 -1
  65. package/dist/computer/tools.js +135 -8
  66. package/dist/computer/tools.js.map +1 -1
  67. package/dist/config.d.ts +7 -0
  68. package/dist/config.js.map +1 -1
  69. package/dist/harness.d.ts +52 -0
  70. package/dist/harness.js +113 -12
  71. package/dist/harness.js.map +1 -1
  72. package/dist/mcp/manager.d.ts +15 -0
  73. package/dist/mcp/manager.js +28 -1
  74. package/dist/mcp/manager.js.map +1 -1
  75. package/dist/providers/catalog.json +14 -3
  76. package/dist/providers/models-dev.d.ts +15 -0
  77. package/dist/providers/models-dev.js +14 -0
  78. package/dist/providers/models-dev.js.map +1 -1
  79. package/dist/providers/piai.d.ts +38 -1
  80. package/dist/providers/piai.js +70 -2
  81. package/dist/providers/piai.js.map +1 -1
  82. package/dist/providers/registry.d.ts +16 -1
  83. package/dist/providers/registry.js +42 -11
  84. package/dist/providers/registry.js.map +1 -1
  85. package/dist/runtime-plugins/builtin/studio.d.ts +7 -0
  86. package/dist/runtime-plugins/builtin/studio.js +69 -4
  87. package/dist/runtime-plugins/builtin/studio.js.map +1 -1
  88. package/dist/tools/builtin/bash.js +6 -10
  89. package/dist/tools/builtin/bash.js.map +1 -1
  90. package/dist/util/shell.d.ts +30 -0
  91. package/dist/util/shell.js +70 -0
  92. package/dist/util/shell.js.map +1 -1
  93. package/package.json +3 -3
  94. package/skills/media-generation/SKILL.md +22 -1
@@ -0,0 +1,80 @@
1
+ import type { PermissionAnswer } from "../agent/permissions.ts";
2
+ import type { AcpFileSystem, AcpMcpServer, AcpStopReason, AcpUpdate } from "./client.ts";
3
+ /**
4
+ * A subagent whose loop is someone else's: an external agent reached over ACP.
5
+ *
6
+ * Declared on a subagent definition. The harness keeps everything around the
7
+ * run — the `task` tool, background tasks, worktrees, permission cards — and
8
+ * hands the turn itself to the agent named here.
9
+ */
10
+ export interface AcpRuntime {
11
+ kind: "acp";
12
+ command: string;
13
+ args?: string[];
14
+ env?: Record<string, string>;
15
+ /**
16
+ * What to tell the person when the agent says it needs signing in. The
17
+ * agent's own login is the only one offered: this is the sentence that
18
+ * sends them to it.
19
+ */
20
+ signInHint?: string;
21
+ /**
22
+ * Why this agent cannot run here — Node too old, say. Set at detection, so
23
+ * a task gets this sentence as its answer instead of a process that dies.
24
+ */
25
+ unavailable?: string;
26
+ }
27
+ /** The agent cannot run on this machine; the message says why. */
28
+ export declare class AcpUnavailable extends Error {
29
+ constructor(message: string);
30
+ }
31
+ export declare function looksLikeSignIn(text: string): boolean;
32
+ /** The agent refused to start a session until it is signed in. */
33
+ export declare class AcpSignInRequired extends Error {
34
+ constructor(message: string);
35
+ }
36
+ export interface AcpRunOptions {
37
+ runtime: AcpRuntime;
38
+ cwd: string;
39
+ /** The prompt for a fresh session — a follow-up's carries what came before. */
40
+ prompt: string;
41
+ /**
42
+ * An earlier session of this task to pick up, and the prompt to send when
43
+ * it is picked up (the new message alone: the agent has the rest). Falls
44
+ * back to a fresh session and `prompt` when the agent cannot load it.
45
+ */
46
+ resume?: {
47
+ sessionId: string;
48
+ prompt: string;
49
+ };
50
+ /** MCP servers to give the agent, so it has this conversation's tools. */
51
+ mcpServers?: AcpMcpServer[];
52
+ /** Route the agent's file reads and writes through the workspace policy. */
53
+ fs?: AcpFileSystem;
54
+ signal?: AbortSignal;
55
+ /** Put one of the agent's tool calls to the person. */
56
+ askPermission(title: string, input: unknown, toolCallId: string): Promise<boolean | PermissionAnswer>;
57
+ /** What the agent is doing now, for a background task's status line. */
58
+ onActivity?(title: string): void;
59
+ /** Every update as it arrives, for a caller that shows the turn live. */
60
+ onUpdate?(update: AcpUpdate): void;
61
+ }
62
+ export interface AcpRunResult {
63
+ /** The agent's last say: what it wrote after its final tool call. */
64
+ text: string;
65
+ stopReason: AcpStopReason;
66
+ toolCalls: number;
67
+ /** The session this turn ran in, for the next follow-up to resume. */
68
+ sessionId: string;
69
+ /** Whether it continued an earlier session rather than starting one. */
70
+ resumed: boolean;
71
+ }
72
+ /**
73
+ * One turn of an external agent, start to finish: a process, a session, the
74
+ * prompt, and the process gone again.
75
+ *
76
+ * A process per turn rather than one kept warm: a task's follow-up may come
77
+ * after a restart, and the same path serving both is what keeps them alike.
78
+ * The conversation so far rides in the prompt instead.
79
+ */
80
+ export declare function runAcpTurn(opts: AcpRunOptions): Promise<AcpRunResult>;
@@ -0,0 +1,159 @@
1
+ import { AcpClient, AcpError, ACP_AUTH_REQUIRED, allowOnce, refuse } from "./client.js";
2
+ /** The agent cannot run on this machine; the message says why. */
3
+ export class AcpUnavailable extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "AcpUnavailable";
7
+ }
8
+ }
9
+ /**
10
+ * Replies that mean "not signed in" whatever form they arrive in.
11
+ *
12
+ * ACP has an error code for it, and an agent may use it — or may start the
13
+ * session anyway and answer the first prompt with its own login complaint,
14
+ * as text or as an error. All of them become the same sentence pointing at
15
+ * the agent's own login, so what the person reads does not depend on which
16
+ * an adapter version happened to do.
17
+ */
18
+ const SIGN_IN_TEXT = /please run \/login|run `?claude`? (?:to )?(?:log|sign) ?in|invalid api key|not (?:logged|signed) in|authentication[_ ](?:error|required|failed)|oauth token (?:has )?expired/i;
19
+ export function looksLikeSignIn(text) {
20
+ return SIGN_IN_TEXT.test(text);
21
+ }
22
+ /** The agent refused to start a session until it is signed in. */
23
+ export class AcpSignInRequired extends Error {
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = "AcpSignInRequired";
27
+ }
28
+ }
29
+ /**
30
+ * One turn of an external agent, start to finish: a process, a session, the
31
+ * prompt, and the process gone again.
32
+ *
33
+ * A process per turn rather than one kept warm: a task's follow-up may come
34
+ * after a restart, and the same path serving both is what keeps them alike.
35
+ * The conversation so far rides in the prompt instead.
36
+ */
37
+ export async function runAcpTurn(opts) {
38
+ if (opts.runtime.unavailable)
39
+ throw new AcpUnavailable(opts.runtime.unavailable);
40
+ const signIn = () => new AcpSignInRequired(opts.runtime.signInHint ?? "The agent needs signing in. Run it in a terminal, sign in there, then try again.");
41
+ // Said before anything else: the first run fetches the adapter, which can
42
+ // take half a minute with nothing else to show for it.
43
+ opts.onActivity?.("Starting the agent…");
44
+ const client = new AcpClient({
45
+ command: opts.runtime.command,
46
+ ...(opts.runtime.args ? { args: opts.runtime.args } : {}),
47
+ ...(opts.runtime.env ? { env: opts.runtime.env } : {}),
48
+ cwd: opts.cwd,
49
+ ...(opts.fs ? { fs: opts.fs } : {}),
50
+ });
51
+ // A stop is first a `session/cancel`, which lets the agent end its turn
52
+ // tidily; an agent that has not ended it a few seconds later is closed.
53
+ const kill = () => setTimeout(() => client.close(), 3_000).unref?.();
54
+ opts.signal?.addEventListener("abort", kill, { once: true });
55
+ try {
56
+ await client.initialize();
57
+ const servers = opts.mcpServers ?? [];
58
+ let sessionId;
59
+ let prompt = opts.prompt;
60
+ let resumed = false;
61
+ try {
62
+ if (opts.resume && client.capabilities.loadSession) {
63
+ try {
64
+ await client.loadSession(opts.resume.sessionId, opts.cwd, servers);
65
+ sessionId = opts.resume.sessionId;
66
+ prompt = opts.resume.prompt;
67
+ resumed = true;
68
+ }
69
+ catch (err) {
70
+ // Gone from the agent's side — cleared, or another machine's. A
71
+ // fresh session with the history in its prompt is the fallback.
72
+ if (err instanceof AcpError && err.code === ACP_AUTH_REQUIRED)
73
+ throw err;
74
+ }
75
+ }
76
+ sessionId ??= await client.newSession(opts.cwd, servers);
77
+ }
78
+ catch (err) {
79
+ if (err instanceof AcpError && (err.code === ACP_AUTH_REQUIRED || looksLikeSignIn(err.message)))
80
+ throw signIn();
81
+ throw err;
82
+ }
83
+ // Text arrives in chunks between tool calls. What the parent wants is the
84
+ // agent's conclusion, so each tool call starts a fresh segment and the
85
+ // last one with anything in it is the answer.
86
+ const segments = [""];
87
+ const titles = new Map();
88
+ let toolCalls = 0;
89
+ let stopReason;
90
+ try {
91
+ stopReason = await client.prompt(sessionId, prompt, {
92
+ onUpdate(update) {
93
+ opts.onUpdate?.(update);
94
+ switch (update.sessionUpdate) {
95
+ case "agent_message_chunk": {
96
+ const content = update.content;
97
+ if (content?.type === "text" && content.text)
98
+ segments[segments.length - 1] += content.text;
99
+ break;
100
+ }
101
+ case "tool_call": {
102
+ const call = update;
103
+ toolCalls++;
104
+ const title = call.title || call.kind || "tool";
105
+ titles.set(call.toolCallId, title);
106
+ opts.onActivity?.(title);
107
+ if (segments[segments.length - 1].trim())
108
+ segments.push("");
109
+ break;
110
+ }
111
+ case "tool_call_update": {
112
+ const call = update;
113
+ if (call.title)
114
+ titles.set(call.toolCallId, call.title);
115
+ break;
116
+ }
117
+ case "plan": {
118
+ const entries = update.entries ?? [];
119
+ const current = entries.find((entry) => entry.status === "in_progress") ?? entries[0];
120
+ if (current)
121
+ opts.onActivity?.(current.content);
122
+ break;
123
+ }
124
+ }
125
+ },
126
+ async onPermission(request) {
127
+ const title = request.toolCall.title || titles.get(request.toolCall.toolCallId) || "a tool call";
128
+ const answer = await opts.askPermission(title, request.toolCall.rawInput, request.toolCall.toolCallId);
129
+ const allowed = typeof answer === "boolean" ? answer : answer.allow;
130
+ if (!allowed)
131
+ return refuse(request.options);
132
+ // "Always" is the person's to give, and only when they gave it: it
133
+ // is remembered on the agent's side, beyond this card.
134
+ const always = typeof answer === "object" && answer.remember
135
+ ? request.options.find((option) => option.kind === "allow_always")
136
+ : undefined;
137
+ return always ? { outcome: "selected", optionId: always.optionId } : allowOnce(request.options);
138
+ },
139
+ }, opts.signal);
140
+ }
141
+ catch (err) {
142
+ // A login complaint can also come back as the prompt's error.
143
+ if (err instanceof AcpError && (err.code === ACP_AUTH_REQUIRED || looksLikeSignIn(err.message)))
144
+ throw signIn();
145
+ throw err;
146
+ }
147
+ const text = [...segments].reverse().find((segment) => segment.trim())?.trim() ?? "";
148
+ // Or as the whole of its answer, before it ever got to a tool: a short
149
+ // reply that is only a login complaint is the sign-in, not a result.
150
+ if (toolCalls === 0 && text.length < 400 && looksLikeSignIn(text))
151
+ throw signIn();
152
+ return { text, stopReason, toolCalls, sessionId, resumed };
153
+ }
154
+ finally {
155
+ opts.signal?.removeEventListener("abort", kill);
156
+ client.close();
157
+ }
158
+ }
159
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/acp/runner.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,8 @@ import { MemoryStore } from "./memory.ts";
13
13
  import type { ExtractedSummary, MemoryProvider, MemoryRecallItem } from "./memory-provider.ts";
14
14
  import type { CompactionOptions } from "./compaction.ts";
15
15
  import { HookRegistry } from "./hooks.ts";
16
- import type { PermissionPrompt, PermissionRequest } from "./permissions.ts";
16
+ import type { AcpFileSystem } from "../acp/client.ts";
17
+ import type { PermissionAnswer, PermissionPrompt, PermissionRequest } from "./permissions.ts";
17
18
  import type { QuestionPrompt, QuestionRequest, QuestionResult } from "../tools/questions.ts";
18
19
  import type { Session } from "./session.ts";
19
20
  import { SubagentRegistry } from "./subagent.ts";
@@ -456,6 +457,55 @@ export declare class Agent implements ToolHost {
456
457
  * the task say what the subagent is doing now.
457
458
  */
458
459
  private runChild;
460
+ /**
461
+ * One run of a subagent whose loop is an external agent's (ACP).
462
+ *
463
+ * The child session is still kept, as the record of the task: the prompt
464
+ * and the agent's answer go into it, so a background task's transcript and
465
+ * a follow-up after a restart read the same as any other subagent's. The
466
+ * agent itself starts fresh each run, so what came before rides in the
467
+ * prompt.
468
+ */
469
+ private runExternalChild;
470
+ /**
471
+ * File access for an external agent, through this agent's workspace policy:
472
+ * reads where ours may read, writes where ours may write, nowhere else.
473
+ */
474
+ externalFs(): AcpFileSystem;
475
+ /**
476
+ * `@claude …`: a message addressed to an external agent by name.
477
+ *
478
+ * Only an agent with an ACP runtime answers to this, and only at the start
479
+ * of what was typed — or of the paragraph after a reference note, which the
480
+ * page puts above the prompt. The note stays with the message; the name
481
+ * does not.
482
+ */
483
+ private directTarget;
484
+ /**
485
+ * A turn answered by an external agent instead of the model.
486
+ *
487
+ * What makes `@claude` worth having: the message goes straight to the
488
+ * user's own Claude Code, so it is paid for by their Claude account and
489
+ * nothing is spent on this harness's model in between. The agent's reply
490
+ * streams into the conversation as text, its tool calls as tool cards, its
491
+ * questions as the usual permission card; the exchange is kept as an
492
+ * ordinary user/assistant pair, and the agent's session id rides on the
493
+ * reply so the next `@claude` picks up where this one left off.
494
+ */
495
+ private runDirect;
496
+ /**
497
+ * This conversation's MCP servers, in the shape ACP's `session/new` takes,
498
+ * so an external agent works with the same tools. HTTP ones are filtered
499
+ * out later for an agent that does not take them.
500
+ */
501
+ private forwardedMcpServers;
502
+ /**
503
+ * An external agent's own tool call, put to the person the way this
504
+ * harness's calls are — the same card, placed in the conversation that
505
+ * started the task and labelled with who is asking. Plan mode and a
506
+ * read-only workspace refuse; bypass allows, as it would for our own tools.
507
+ */
508
+ askForExternal(title: string, input: unknown, toolCallId: string, signal: AbortSignal | undefined, from?: string): Promise<boolean | PermissionAnswer>;
459
509
  /** What a subagent left in its worktree, when it left anything. */
460
510
  private worktreeNote;
461
511
  /**