@astrosheep/keiyaku 4.6.6 → 4.6.8

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 (217) hide show
  1. package/README.md +11 -0
  2. package/build/{integrations/marketplace → plugins}/.agents/plugins/marketplace.json +1 -1
  3. package/build/plugins/.claude-plugin/marketplace.json +5 -0
  4. package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/.claude-plugin/plugin.json +1 -1
  5. package/build/{integrations/marketplace/plugins/keiyaku → plugins/codex}/.codex-plugin/plugin.json +1 -1
  6. package/build/plugins/codex/skills/keiyaku/SKILL.md +44 -0
  7. package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +130 -0
  8. package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +269 -0
  9. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +65 -0
  10. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +216 -0
  11. package/build/plugins/codex/skills/keiyaku-bind/agents/openai.yaml +4 -0
  12. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +104 -0
  13. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +129 -0
  14. package/build/plugins/opencode/package.json +6 -0
  15. package/build/plugins/opencode/skills/keiyaku/SKILL.md +44 -0
  16. package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +130 -0
  17. package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +269 -0
  18. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +65 -0
  19. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +216 -0
  20. package/build/plugins/opencode/skills/keiyaku-bind/agents/openai.yaml +4 -0
  21. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +104 -0
  22. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +129 -0
  23. package/build/{integrations → plugins}/pi/keiyaku.ts +0 -5
  24. package/build/skills/keiyaku/SKILL.md +44 -0
  25. package/build/skills/keiyaku-akuma/SKILL.md +130 -0
  26. package/build/skills/keiyaku-akuma/references/automation.md +269 -0
  27. package/build/skills/keiyaku-babysit/SKILL.md +65 -0
  28. package/build/skills/keiyaku-bind/SKILL.md +216 -0
  29. package/build/skills/keiyaku-bind/agents/openai.yaml +4 -0
  30. package/build/skills/keiyaku-task/SKILL.md +104 -0
  31. package/build/skills/keiyaku-workflow/SKILL.md +129 -0
  32. package/build/src/akuma/akuma-call.d.ts +2 -0
  33. package/build/src/akuma/akuma-call.js +8 -2
  34. package/build/src/akuma/akuma-instance.d.ts +12 -1
  35. package/build/src/akuma/akuma-instance.js +31 -9
  36. package/build/src/akuma/akuma-observe.d.ts +4 -0
  37. package/build/src/akuma/akuma-observe.js +14 -0
  38. package/build/src/akuma/akuma-owner.d.ts +6 -2
  39. package/build/src/akuma/akuma-owner.js +32 -10
  40. package/build/src/akuma/akuma-selection-execution.d.ts +3 -1
  41. package/build/src/akuma/akuma-selection-execution.js +2 -1
  42. package/build/src/akuma/akuma-wait.d.ts +2 -1
  43. package/build/src/akuma/akuma-wait.js +4 -1
  44. package/build/src/akuma/akuma.d.ts +35 -5
  45. package/build/src/akuma/akuma.js +8 -10
  46. package/build/src/akuma/archetype.d.ts +7 -15
  47. package/build/src/akuma/archetype.js +36 -35
  48. package/build/src/akuma/body.d.ts +6 -3
  49. package/build/src/akuma/body.js +41 -30
  50. package/build/src/akuma/call-request.d.ts +18 -10
  51. package/build/src/akuma/call-request.js +10 -3
  52. package/build/src/akuma/caller.d.ts +39 -0
  53. package/build/src/akuma/caller.js +36 -0
  54. package/build/src/akuma/dispatch-association.d.ts +0 -1
  55. package/build/src/akuma/dispatch-association.js +0 -3
  56. package/build/src/akuma/heart/facts.d.ts +16 -12
  57. package/build/src/akuma/heart/facts.js +8 -0
  58. package/build/src/akuma/heart/index.d.ts +2 -7
  59. package/build/src/akuma/heart/index.js +3 -17
  60. package/build/src/akuma/heart/rows.d.ts +3 -3
  61. package/build/src/akuma/heart/soul.d.ts +1 -1
  62. package/build/src/akuma/heart/soul.js +5 -24
  63. package/build/src/akuma/heart/storage.d.ts +5 -0
  64. package/build/src/akuma/heart/storage.js +7 -3
  65. package/build/src/akuma/identity.d.ts +0 -1
  66. package/build/src/akuma/identity.js +2 -5
  67. package/build/src/akuma/index.d.ts +5 -2
  68. package/build/src/akuma/index.js +1 -0
  69. package/build/src/akuma/nuke.js +6 -28
  70. package/build/src/akuma/projection.d.ts +0 -11
  71. package/build/src/akuma/provider-recipe.d.ts +7 -6
  72. package/build/src/akuma/provider-recipe.js +1 -1
  73. package/build/src/akuma/provider.d.ts +6 -10
  74. package/build/src/akuma/provider.js +6 -7
  75. package/build/src/akuma/providers/acp/events.js +5 -18
  76. package/build/src/akuma/providers/acp/index.js +2 -3
  77. package/build/src/akuma/providers/claude/events.js +35 -60
  78. package/build/src/akuma/providers/claude/index.d.ts +2 -2
  79. package/build/src/akuma/providers/claude/index.js +2 -3
  80. package/build/src/akuma/providers/codex-app-server/index.js +2 -2
  81. package/build/src/akuma/providers/decode.d.ts +25 -0
  82. package/build/src/akuma/providers/decode.js +44 -0
  83. package/build/src/akuma/providers/execution-environment.d.ts +2 -1
  84. package/build/src/akuma/providers/execution-environment.js +3 -0
  85. package/build/src/akuma/providers/grok-build/index.js +6 -22
  86. package/build/src/akuma/providers/index.js +2 -0
  87. package/build/src/akuma/providers/lifecycle.d.ts +9 -0
  88. package/build/src/akuma/providers/lifecycle.js +10 -0
  89. package/build/src/akuma/providers/opencode-sdk/events.js +1 -14
  90. package/build/src/akuma/providers/opencode-sdk/index.js +10 -17
  91. package/build/src/akuma/providers/opencode-sdk/session.js +1 -3
  92. package/build/src/akuma/providers/paseo/events.d.ts +25 -0
  93. package/build/src/akuma/providers/paseo/events.js +157 -0
  94. package/build/src/akuma/providers/paseo/index.d.ts +9 -0
  95. package/build/src/akuma/providers/paseo/index.js +353 -0
  96. package/build/src/akuma/providers/pi/events.js +5 -15
  97. package/build/src/akuma/publication.d.ts +2 -0
  98. package/build/src/akuma/publication.js +5 -0
  99. package/build/src/akuma/request-lifecycle.d.ts +3 -0
  100. package/build/src/akuma/request-lifecycle.js +25 -4
  101. package/build/src/akuma/requests.d.ts +3 -1
  102. package/build/src/akuma/requests.js +32 -0
  103. package/build/src/akuma/selection-observation.d.ts +72 -2
  104. package/build/src/akuma/selection-observation.js +0 -6
  105. package/build/src/akuma/selection-owner-port.d.ts +1 -1
  106. package/build/src/akuma/selection-owner-port.js +16 -5
  107. package/build/src/akuma/selection-request.d.ts +2 -0
  108. package/build/src/akuma/selection-request.js +2 -1
  109. package/build/src/akuma/turn-drive.js +2 -5
  110. package/build/src/akuma-body.js +4 -2
  111. package/build/src/cli/akuma-caller.d.ts +3 -0
  112. package/build/src/cli/akuma-caller.js +21 -0
  113. package/build/src/cli/commands/akuma-grammar.js +7 -12
  114. package/build/src/cli/commands/akuma.js +18 -16
  115. package/build/src/cli/commands/contract-grammar.d.ts +2 -1
  116. package/build/src/cli/commands/contract-grammar.js +13 -15
  117. package/build/src/cli/commands/contract-help.d.ts +2 -1
  118. package/build/src/cli/commands/contract-help.js +31 -1
  119. package/build/src/cli/commands/contract.js +24 -53
  120. package/build/src/cli/commands/install.js +3 -3
  121. package/build/src/cli/commands/task.js +18 -35
  122. package/build/src/cli/parse.d.ts +2 -2
  123. package/build/src/cli/render/catalog.d.ts +2 -5
  124. package/build/src/cli/render/contract-history.js +3 -6
  125. package/build/src/cli/render/contract.js +15 -50
  126. package/build/src/cli/render/receipt.js +3 -10
  127. package/build/src/cli/render/task.d.ts +4 -6
  128. package/build/src/cli/render/task.js +9 -26
  129. package/build/src/cli/runtime.d.ts +1 -1
  130. package/build/src/cli/runtime.js +11 -17
  131. package/build/src/cli/selectors.d.ts +3 -6
  132. package/build/src/cli/selectors.js +22 -53
  133. package/build/src/dispatch/index.d.ts +3 -3
  134. package/build/src/dispatch/index.js +1 -2
  135. package/build/src/git/observe.d.ts +6 -2
  136. package/build/src/git/observe.js +6 -2
  137. package/build/src/index.d.ts +6 -6
  138. package/build/src/index.js +2 -2
  139. package/build/src/kanshi/index.d.ts +1 -1
  140. package/build/src/kanshi/read.js +21 -6
  141. package/build/src/library/address.js +2 -4
  142. package/build/src/library/akuma-creation.d.ts +5 -1
  143. package/build/src/library/akuma-creation.js +33 -51
  144. package/build/src/library/akumas.d.ts +5 -4
  145. package/build/src/library/akumas.js +13 -9
  146. package/build/src/library/bind.d.ts +14 -14
  147. package/build/src/library/bind.js +11 -7
  148. package/build/src/library/contract-address.d.ts +9 -0
  149. package/build/src/library/contract-address.js +71 -0
  150. package/build/src/library/contract-composition.d.ts +4 -7
  151. package/build/src/library/contract-composition.js +6 -18
  152. package/build/src/library/contract-creation.d.ts +3 -5
  153. package/build/src/library/contract-creation.js +19 -17
  154. package/build/src/library/contract-execution.js +18 -23
  155. package/build/src/library/contract-outcomes.d.ts +2 -14
  156. package/build/src/library/contract-outcomes.js +2 -13
  157. package/build/src/library/contract-types.d.ts +36 -2
  158. package/build/src/library/delivery.d.ts +0 -2
  159. package/build/src/library/delivery.js +2 -5
  160. package/build/src/library/keiyaku.d.ts +0 -5
  161. package/build/src/library/keiyaku.js +6 -12
  162. package/build/src/library/outcome.d.ts +500 -499
  163. package/build/src/library/outcome.js +10 -0
  164. package/build/src/library/reconcile.js +8 -16
  165. package/build/src/library/refusal.d.ts +2 -2
  166. package/build/src/library/repo.d.ts +3 -2
  167. package/build/src/library/repo.js +10 -5
  168. package/build/src/library/selection.d.ts +4 -4
  169. package/build/src/library/selection.js +12 -9
  170. package/build/src/plugin/akuma-signals.d.ts +12 -11
  171. package/build/src/plugin/akuma-signals.js +40 -20
  172. package/build/src/plugin/public.d.ts +32 -2
  173. package/build/src/plugin/runtime.d.ts +1 -0
  174. package/build/src/plugin/runtime.js +35 -24
  175. package/build/src/protocol/amend.js +3 -2
  176. package/build/src/protocol/attempt.js +3 -8
  177. package/build/src/protocol/bind.d.ts +2 -2
  178. package/build/src/protocol/bind.js +1 -1
  179. package/build/src/protocol/deliver.js +3 -3
  180. package/build/src/protocol/operations.d.ts +1 -3
  181. package/build/src/protocol/operations.js +0 -8
  182. package/build/src/protocol/outcome.d.ts +1 -2
  183. package/build/src/protocol/outcome.js +1 -13
  184. package/build/src/protocol/placement.js +3 -10
  185. package/build/src/protocol/read/status.js +31 -70
  186. package/build/src/protocol/reintegrate.js +3 -10
  187. package/build/src/protocol/review.js +3 -3
  188. package/build/src/protocol/run.d.ts +5 -1
  189. package/build/src/protocol/run.js +3 -3
  190. package/build/src/runtime/proc/windows-launch.exe +0 -0
  191. package/package.json +12 -8
  192. package/plugins/pi/keiyaku.ts +57 -0
  193. package/skills/keiyaku/SKILL.md +44 -0
  194. package/skills/keiyaku-akuma/SKILL.md +130 -0
  195. package/skills/keiyaku-akuma/references/automation.md +269 -0
  196. package/skills/keiyaku-babysit/SKILL.md +65 -0
  197. package/skills/keiyaku-bind/SKILL.md +216 -0
  198. package/skills/keiyaku-bind/agents/openai.yaml +4 -0
  199. package/skills/keiyaku-task/SKILL.md +104 -0
  200. package/skills/keiyaku-workflow/SKILL.md +129 -0
  201. package/build/integrations/marketplace/.claude-plugin/marketplace.json +0 -5
  202. package/build/integrations/marketplace/plugins/keiyaku/package.json +0 -17
  203. package/build/src/cli/commands/amend.d.ts +0 -12
  204. package/build/src/cli/commands/amend.js +0 -10
  205. package/build/src/cli/commands/bind.d.ts +0 -11
  206. package/build/src/cli/commands/bind.js +0 -23
  207. package/build/src/dispatch/association.d.ts +0 -1
  208. package/build/src/dispatch/association.js +0 -1
  209. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku/SKILL.md +0 -0
  210. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/SKILL.md +0 -0
  211. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/references/automation.md +0 -0
  212. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-babysit/SKILL.md +0 -0
  213. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/SKILL.md +0 -0
  214. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/agents/openai.yaml +0 -0
  215. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-task/SKILL.md +0 -0
  216. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-workflow/SKILL.md +0 -0
  217. /package/build/{integrations/marketplace/plugins/keiyaku/opencode.js → plugins/opencode/index.js} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
2
  import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
3
3
  import { akumaExecutionEnvironment } from "../execution-environment.js";
4
+ import { providerLifecycle } from "../lifecycle.js";
4
5
  import { codexNotificationResult, codexObject, codexText } from "./events.js";
5
6
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
6
7
  function diagnostic(error) {
@@ -214,7 +215,6 @@ export function createCodexAppServerProvider(input = "codex") {
214
215
  };
215
216
  },
216
217
  fork: (input) => createProviderAttempt(new AbortController().signal, async (custody) => await forkCodex(execution, input, custody)),
217
- start: (input) => createProviderAttempt(input.signal, async (custody) => await startCodex(execution, { ...input, signal: custody.signal }, custody)),
218
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await startCodex(execution, { ...input, signal: custody.signal }, custody)),
218
+ ...providerLifecycle((input, custody) => startCodex(execution, input, custody)),
219
219
  };
220
220
  }
@@ -0,0 +1,25 @@
1
+ import type { SearchScope, ToolCall } from "../provider.js";
2
+ /**
3
+ * Native payload decoders shared by provider event adaptation. Every adapter
4
+ * reads the same untrusted native shapes; these are the only places that decide
5
+ * what a present value means, so each keeps one exact predicate and return.
6
+ */
7
+ export declare function isRecord(value: unknown): value is Readonly<Record<string, unknown>>;
8
+ export declare function object(value: unknown): Readonly<Record<string, unknown>> | undefined;
9
+ /** A string with non-blank trim, returned as supplied. */
10
+ export declare function nonblank(value: unknown): string | undefined;
11
+ /** A string with non-blank trim, returned trimmed. */
12
+ export declare function trimmed(value: unknown): string | undefined;
13
+ /** A nonempty string, returned as supplied; internal whitespace stays content. */
14
+ export declare function text(value: unknown): string | undefined;
15
+ /** A one-based line number. */
16
+ export declare function positiveLine(value: unknown): number | undefined;
17
+ export declare function nonnegativeCount(value: unknown): number | undefined;
18
+ export declare function finiteNumber(value: unknown): number | undefined;
19
+ /** One neutral search call carrying only the bounds the native input supplied. */
20
+ export declare function searchToolCall(query: string, scope: SearchScope | undefined, bounds?: Readonly<{
21
+ path?: string | undefined;
22
+ glob?: string | undefined;
23
+ }>): Extract<ToolCall, {
24
+ kind: "search";
25
+ }>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Native payload decoders shared by provider event adaptation. Every adapter
3
+ * reads the same untrusted native shapes; these are the only places that decide
4
+ * what a present value means, so each keeps one exact predicate and return.
5
+ */
6
+ export function isRecord(value) {
7
+ return value !== null && typeof value === "object" && !Array.isArray(value);
8
+ }
9
+ export function object(value) {
10
+ return isRecord(value) ? value : undefined;
11
+ }
12
+ /** A string with non-blank trim, returned as supplied. */
13
+ export function nonblank(value) {
14
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
15
+ }
16
+ /** A string with non-blank trim, returned trimmed. */
17
+ export function trimmed(value) {
18
+ const text = nonblank(value);
19
+ return text === undefined ? undefined : text.trim();
20
+ }
21
+ /** A nonempty string, returned as supplied; internal whitespace stays content. */
22
+ export function text(value) {
23
+ return typeof value === "string" && value.length > 0 ? value : undefined;
24
+ }
25
+ /** A one-based line number. */
26
+ export function positiveLine(value) {
27
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
28
+ }
29
+ export function nonnegativeCount(value) {
30
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
31
+ }
32
+ export function finiteNumber(value) {
33
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
34
+ }
35
+ /** One neutral search call carrying only the bounds the native input supplied. */
36
+ export function searchToolCall(query, scope, bounds = {}) {
37
+ return {
38
+ kind: "search",
39
+ query,
40
+ ...(scope === undefined ? {} : { scope }),
41
+ ...(bounds.path === undefined ? {} : { path: bounds.path }),
42
+ ...(bounds.glob === undefined ? {} : { glob: bounds.glob }),
43
+ };
44
+ }
@@ -1,5 +1,6 @@
1
1
  export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
- declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME"];
2
+ export declare const AKUMA_REQUESTS_ENTRY_ENV = "AKUMA_REQUESTS_ENTRY";
3
+ declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME", "KEIYAKU_EXTERNAL_CALLER"];
3
4
  type Environment = Readonly<Record<string, string | undefined>>;
4
5
  /** Construct the environment for one isolated Akuma execution or native child. */
5
6
  export declare function akumaExecutionEnvironment(inherited: Environment, overrides?: Environment, requests?: string, nativeIdentity?: readonly (typeof PARENT_HARNESS_IDENTITY_KEYS)[number][]): Record<string, string>;
@@ -1,4 +1,5 @@
1
1
  export const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
+ export const AKUMA_REQUESTS_ENTRY_ENV = "AKUMA_REQUESTS_ENTRY";
2
3
  const PARENT_HARNESS_IDENTITY_KEYS = [
3
4
  "CLAUDE_CODE_SESSION_ID",
4
5
  "CLAUDE_CODE_CHILD_SESSION",
@@ -9,6 +10,7 @@ const PARENT_HARNESS_IDENTITY_KEYS = [
9
10
  "PI_SESSION_FILE",
10
11
  "PASEO_AGENT_ID",
11
12
  "SQUARE_PARTICIPANT_NAME",
13
+ "KEIYAKU_EXTERNAL_CALLER",
12
14
  ];
13
15
  /** Construct the environment for one isolated Akuma execution or native child. */
14
16
  export function akumaExecutionEnvironment(inherited, overrides = {}, requests, nativeIdentity = []) {
@@ -18,6 +20,7 @@ export function akumaExecutionEnvironment(inherited, overrides = {}, requests, n
18
20
  delete environment[key];
19
21
  Object.assign(environment, preserved);
20
22
  delete environment[AKUMA_REQUESTS_ENV];
23
+ delete environment[AKUMA_REQUESTS_ENTRY_ENV];
21
24
  if (requests !== undefined)
22
25
  environment[AKUMA_REQUESTS_ENV] = requests;
23
26
  return environment;
@@ -1,15 +1,8 @@
1
- import { createProviderAttempt } from "../../provider.js";
1
+ import { nonblank, object, searchToolCall } from "../decode.js";
2
+ import { providerLifecycle } from "../lifecycle.js";
2
3
  import { startAcpSession, } from "../acp/core.js";
3
4
  const INTERJECT_METHOD = "_x.ai/interject";
4
5
  const INTERJECTION_METHOD = "_x.ai/session/interjection";
5
- function nonblank(value) {
6
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
7
- }
8
- function object(value) {
9
- return value !== null && typeof value === "object" && !Array.isArray(value)
10
- ? value
11
- : undefined;
12
- }
13
6
  function nativeName(update) {
14
7
  const wire = update;
15
8
  return nonblank(update.name) ?? nonblank(update.title) ?? nonblank(wire.toolName);
@@ -26,17 +19,9 @@ function contentSearchCall(name, input) {
26
19
  if (name !== "grep" && name !== "hashline_grep")
27
20
  return undefined;
28
21
  const query = nonblank(input.pattern);
29
- if (query === undefined)
30
- return undefined;
31
- const path = nonblank(input.path);
32
- const glob = nonblank(input.glob);
33
- return {
34
- kind: "search",
35
- query,
36
- scope: "content",
37
- ...(path === undefined ? {} : { path }),
38
- ...(glob === undefined ? {} : { glob }),
39
- };
22
+ return query === undefined
23
+ ? undefined
24
+ : searchToolCall(query, "content", { path: nonblank(input.path), glob: nonblank(input.glob) });
40
25
  }
41
26
  function runCall(name, input) {
42
27
  if (name !== "run_terminal_cmd")
@@ -177,7 +162,6 @@ export function createGrokBuildProvider(execution, dependencies = {}) {
177
162
  };
178
163
  return {
179
164
  admitOptions: optionAdmission,
180
- start: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
181
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
165
+ ...providerLifecycle(drive),
182
166
  };
183
167
  }
@@ -14,6 +14,8 @@ async function adapterFor(execution) {
14
14
  return (await import("./grok-build/index.js")).createGrokBuildProvider(execution);
15
15
  if (execution.kind === "opencode-sdk")
16
16
  return (await import("./opencode-sdk/index.js")).createOpencodeProvider(execution);
17
+ if (execution.kind === "paseo")
18
+ return (await import("./paseo/index.js")).createPaseoProvider(execution);
17
19
  if (execution.kind === "pi")
18
20
  return (await import("./pi/index.js")).createPiProvider(execution);
19
21
  throw new TypeError(`unknown Akuma provider kind ${execution.kind}`);
@@ -0,0 +1,9 @@
1
+ import { type AttemptCustody, type ProviderAdapter, type Session } from "../provider.js";
2
+ type DriveInput = Parameters<ProviderAdapter["start"]>[0] | Parameters<NonNullable<ProviderAdapter["resume"]>>[0];
3
+ /**
4
+ * Start and resume share one custody descriptor: each creates one attempt whose
5
+ * own controller signal reaches the adapter, and the caller's signal stays a
6
+ * cancellation notification.
7
+ */
8
+ export declare function providerLifecycle(drive: (input: DriveInput, custody: AttemptCustody) => Promise<Session>): Pick<ProviderAdapter, "start" | "resume">;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import { createProviderAttempt } from "../provider.js";
2
+ /**
3
+ * Start and resume share one custody descriptor: each creates one attempt whose
4
+ * own controller signal reaches the adapter, and the caller's signal stays a
5
+ * cancellation notification.
6
+ */
7
+ export function providerLifecycle(drive) {
8
+ const attempt = (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody));
9
+ return { start: attempt, resume: attempt };
10
+ }
@@ -1,4 +1,5 @@
1
1
  import { noteEvent, otherToolCall } from "../../provider.js";
2
+ import { nonnegativeCount, object, positiveLine, text } from "../decode.js";
2
3
  export const OPENCODE_EVENT_DISPOSITIONS = {
3
4
  "server.instance.disposed": "dropped",
4
5
  "installation.updated": "dropped",
@@ -44,25 +45,11 @@ const RUNTIME_DROPPED_EVENT_KINDS = new Set([
44
45
  "server.heartbeat",
45
46
  "message.part.delta",
46
47
  ]);
47
- function object(value) {
48
- return value !== null && typeof value === "object" && !Array.isArray(value)
49
- ? value
50
- : undefined;
51
- }
52
- function text(value) {
53
- return typeof value === "string" && value.length > 0 ? value : undefined;
54
- }
55
48
  function diagnostic(value) {
56
49
  const data = object(value);
57
50
  const nested = object(data?.data);
58
51
  return text(nested?.message) ?? text(data?.message) ?? "OpenCode session failed";
59
52
  }
60
- function positiveLine(value) {
61
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
62
- }
63
- function nonnegativeCount(value) {
64
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
65
- }
66
53
  function diffstat(value) {
67
54
  if (value === undefined)
68
55
  return undefined;
@@ -1,19 +1,13 @@
1
1
  import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
2
+ import { nonblank, object } from "../decode.js";
3
+ import { providerLifecycle } from "../lifecycle.js";
2
4
  import { ownEventStream } from "./event-stream.js";
3
5
  import { createEventState, mapEvent } from "./events.js";
4
6
  import { coordinate, loadOpencode, messageId, OPENCODE_SDK_PROVIDER, parseModel, } from "./session.js";
5
- function object(value) {
6
- return value !== null && typeof value === "object" && !Array.isArray(value)
7
- ? value
8
- : undefined;
9
- }
10
- function text(value) {
11
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
12
- }
13
7
  function diagnostic(error) {
14
8
  const value = object(error);
15
9
  const nested = object(value?.data);
16
- return text(nested?.message) ?? text(value?.message) ?? String(error);
10
+ return nonblank(nested?.message) ?? nonblank(value?.message) ?? String(error);
17
11
  }
18
12
  function opencodeSessionId(coordinateValue) {
19
13
  if (!("sessionId" in coordinateValue) || coordinateValue.sessionId === undefined) {
@@ -84,9 +78,9 @@ async function readTurnResult(input) {
84
78
  const user = rows.find((row) => row.info.role === "user" && row.info.id === input.messageID);
85
79
  if (user === undefined)
86
80
  return { kind: "failed", diagnostic: "OpenCode completed without the admitted user message" };
87
- const userId = text(user.info.id);
81
+ const userId = nonblank(user.info.id);
88
82
  const assistant = newest(rows.filter((row) => row.info.role === "assistant" && row.info.parentID === userId && row.info.summary !== true));
89
- const historyId = text(assistant?.info.id);
83
+ const historyId = nonblank(assistant?.info.id);
90
84
  if (input.state.failure !== undefined)
91
85
  return { kind: "failed", diagnostic: input.state.failure };
92
86
  if (assistant === undefined)
@@ -108,12 +102,12 @@ async function readTurnResult(input) {
108
102
  function nativeSessionId(value) {
109
103
  const event = object(value);
110
104
  const properties = object(event?.properties);
111
- const direct = text(properties?.sessionID);
105
+ const direct = nonblank(properties?.sessionID);
112
106
  if (direct !== undefined)
113
107
  return direct;
114
108
  const info = object(properties?.info);
115
109
  const part = object(properties?.part);
116
- return text(info?.sessionID) ?? text(part?.sessionID);
110
+ return nonblank(info?.sessionID) ?? nonblank(part?.sessionID);
117
111
  }
118
112
  function scopedProperties(value, sessionId) {
119
113
  const properties = object(object(value)?.properties);
@@ -328,7 +322,7 @@ async function openDriveSession(runtime, input, resumeSessionId, signal) {
328
322
  : session.get({ path: { id: resumeSessionId }, query: { directory: input.cwd }, throwOnError: true }));
329
323
  signal.throwIfAborted();
330
324
  const info = object(object(response)?.data) ?? object(response);
331
- const sessionId = text(info?.id) ?? resumeSessionId;
325
+ const sessionId = nonblank(info?.id) ?? resumeSessionId;
332
326
  if (sessionId === undefined)
333
327
  throw new Error("OpenCode did not return a session id");
334
328
  return { session, sessionId };
@@ -465,8 +459,7 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
465
459
  options: Object.freeze({ ...options }),
466
460
  };
467
461
  },
468
- start: (input) => createProviderAttempt(input.signal, async (custody) => await drive(execution, { ...input, signal: custody.signal }, loader, custody)),
469
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await drive(execution, { ...input, signal: custody.signal }, loader, custody)),
462
+ ...providerLifecycle((input, custody) => drive(execution, input, loader, custody)),
470
463
  fork: (input) => createProviderAttempt(new AbortController().signal, async (custody) => {
471
464
  const sessionId = opencodeSessionId(input.session);
472
465
  let close;
@@ -500,7 +493,7 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
500
493
  body: { messageID: input.at },
501
494
  });
502
495
  const info = object(object(result)?.data) ?? object(result);
503
- const id = text(info?.id);
496
+ const id = nonblank(info?.id);
504
497
  if (id === undefined || id === sessionId)
505
498
  throw new Error("OpenCode fork returned an invalid session id");
506
499
  return { session: coordinate(id) };
@@ -3,6 +3,7 @@ import { randomBytes } from "node:crypto";
3
3
  import { abortable } from "../../abort.js";
4
4
  import { akumaExecutionEnvironment } from "../execution-environment.js";
5
5
  import { spawnDetachedProcess } from "../../../runtime/proc/run.js";
6
+ import { isRecord } from "../decode.js";
6
7
  export const OPENCODE_SDK_PROVIDER = "opencode-sdk";
7
8
  /**
8
9
  * Adapt the installed client's generated event endpoint to the adapter's
@@ -60,9 +61,6 @@ const HEADLESS_PERMISSION_BASE = Object.freeze({
60
61
  read: "allow",
61
62
  question: "deny",
62
63
  });
63
- function isRecord(value) {
64
- return value !== null && typeof value === "object" && !Array.isArray(value);
65
- }
66
64
  /**
67
65
  * Compose the config handed to a headless opencode server. The permission base
68
66
  * layer fills only the classes the caller leaves unspecified: an explicit caller
@@ -0,0 +1,25 @@
1
+ import type { AgentStreamEventPayload } from "@getpaseo/protocol/messages";
2
+ import { AgentEventChannel, type TurnResult } from "../../provider.js";
3
+ /** Live fragments belong to a canonical admitted turn, not agent-wide status. */
4
+ export declare class PaseoTurn {
5
+ readonly messageId: string;
6
+ readonly events: AgentEventChannel;
7
+ readonly admission: Promise<string>;
8
+ readonly completion: Promise<TurnResult>;
9
+ private admit;
10
+ private rejectAdmission;
11
+ private finish;
12
+ private rejectCompletion;
13
+ private turnId;
14
+ private readonly messages;
15
+ private readonly messagesById;
16
+ private readonly calls;
17
+ private answer;
18
+ private assistantContiguous;
19
+ settled: boolean;
20
+ terminal: boolean;
21
+ constructor(messageId: string);
22
+ receive(event: AgentStreamEventPayload): void;
23
+ private appendAssistant;
24
+ fail(error: unknown): void;
25
+ }
@@ -0,0 +1,157 @@
1
+ import { AgentEventChannel, otherToolCall } from "../../provider.js";
2
+ function toolCall(item) {
3
+ const detail = item.detail;
4
+ switch (detail.type) {
5
+ case "shell":
6
+ return { kind: "run", command: detail.command };
7
+ case "read":
8
+ return {
9
+ kind: "read",
10
+ path: detail.filePath,
11
+ ...(detail.offset === undefined ? {} : { offset: detail.offset }),
12
+ ...(detail.limit === undefined ? {} : { limit: detail.limit }),
13
+ };
14
+ case "edit":
15
+ case "write":
16
+ return { kind: "fileChange", changes: [{ op: "unspecified", path: detail.filePath }] };
17
+ case "search":
18
+ return { kind: "search", query: detail.query, scope: detail.toolName === "web_search" ? "web" : "content" };
19
+ case "unknown":
20
+ return otherToolCall(item.name, detail.input);
21
+ default:
22
+ return otherToolCall(item.name);
23
+ }
24
+ }
25
+ function timelineNarration(item, calls) {
26
+ switch (item.type) {
27
+ case "tool_call": {
28
+ const call = calls.get(item.callId) ?? (item.status === "running" ? toolCall(item) : otherToolCall(item.name));
29
+ calls.set(item.callId, call);
30
+ return item.status === "running"
31
+ ? { type: "tool", phase: "started", id: item.callId, name: item.name, call }
32
+ : {
33
+ type: "tool",
34
+ phase: "completed",
35
+ id: item.callId,
36
+ name: item.name,
37
+ call,
38
+ result: { status: item.status === "completed" ? "ok" : "error" },
39
+ };
40
+ }
41
+ case "error":
42
+ case "notification":
43
+ return { type: "note", text: item.message };
44
+ case "compaction":
45
+ return { type: "note", text: `Context compaction ${item.status}` };
46
+ case "reasoning":
47
+ case "user_message":
48
+ case "assistant_message":
49
+ return undefined;
50
+ default:
51
+ return { type: "unknown", kind: item.type };
52
+ }
53
+ }
54
+ /** Live fragments belong to a canonical admitted turn, not agent-wide status. */
55
+ export class PaseoTurn {
56
+ messageId;
57
+ events = new AgentEventChannel();
58
+ admission;
59
+ completion;
60
+ admit;
61
+ rejectAdmission;
62
+ finish;
63
+ rejectCompletion;
64
+ turnId;
65
+ messages = [];
66
+ messagesById = new Map();
67
+ calls = new Map();
68
+ answer = "";
69
+ assistantContiguous = false;
70
+ settled = false;
71
+ terminal = false;
72
+ constructor(messageId) {
73
+ this.messageId = messageId;
74
+ this.admission = new Promise((resolve, reject) => {
75
+ this.admit = resolve;
76
+ this.rejectAdmission = reject;
77
+ });
78
+ this.completion = new Promise((resolve, reject) => {
79
+ this.finish = resolve;
80
+ this.rejectCompletion = reject;
81
+ });
82
+ void this.admission.catch(() => undefined);
83
+ void this.completion.catch(() => undefined);
84
+ }
85
+ receive(event) {
86
+ if (this.settled)
87
+ return;
88
+ if (event.type === "timeline" &&
89
+ event.item.type === "user_message" &&
90
+ event.item.clientMessageId === this.messageId) {
91
+ if (event.turnId === undefined)
92
+ return this.fail(new Error("Paseo native admission omitted turnId"));
93
+ if (this.turnId !== undefined) {
94
+ if (this.turnId !== event.turnId)
95
+ this.fail(new Error("Paseo canonical admission changed native turn"));
96
+ return;
97
+ }
98
+ this.turnId = event.turnId;
99
+ this.admit(event.turnId);
100
+ return;
101
+ }
102
+ if (!("turnId" in event) || this.turnId === undefined || event.turnId !== this.turnId)
103
+ return;
104
+ if (event.type === "timeline") {
105
+ if (event.item.type === "assistant_message")
106
+ this.appendAssistant(event.item);
107
+ else {
108
+ this.assistantContiguous = false;
109
+ const narration = timelineNarration(event.item, this.calls);
110
+ if (narration !== undefined)
111
+ this.events.emit(narration);
112
+ }
113
+ }
114
+ else if (event.type === "turn_completed") {
115
+ this.settled = true;
116
+ this.finish({
117
+ kind: "answered",
118
+ answer: this.answer,
119
+ historyId: this.turnId,
120
+ });
121
+ }
122
+ else if (event.type === "turn_failed" || event.type === "turn_canceled") {
123
+ this.settled = true;
124
+ this.finish({ kind: "failed", diagnostic: event.type === "turn_failed" ? event.error : event.reason });
125
+ }
126
+ if (this.settled) {
127
+ this.terminal = true;
128
+ for (const message of this.messages)
129
+ this.events.emit({ type: "assistant", text: message.text });
130
+ }
131
+ }
132
+ appendAssistant(item) {
133
+ // Native final text is the last contiguous assistant segment; narration keeps all messages.
134
+ this.answer = this.assistantContiguous ? this.answer + item.text : item.text;
135
+ const previous = item.messageId === undefined
136
+ ? this.assistantContiguous
137
+ ? this.messages.at(-1)
138
+ : undefined
139
+ : this.messagesById.get(item.messageId);
140
+ this.assistantContiguous = true;
141
+ if (previous !== undefined)
142
+ previous.text += item.text;
143
+ else {
144
+ const message = { ...(item.messageId === undefined ? {} : { id: item.messageId }), text: item.text };
145
+ this.messages.push(message);
146
+ if (item.messageId !== undefined)
147
+ this.messagesById.set(item.messageId, message);
148
+ }
149
+ }
150
+ fail(error) {
151
+ if (this.settled)
152
+ return;
153
+ this.settled = true;
154
+ this.rejectAdmission(error);
155
+ this.rejectCompletion(error);
156
+ }
157
+ }
@@ -0,0 +1,9 @@
1
+ import { DaemonClient, type DaemonClientConfig } from "@getpaseo/client/internal/daemon-client";
2
+ import { type ProviderAdapter } from "../../provider.js";
3
+ import type { ProviderExecution } from "../../provider-recipe.js";
4
+ type PaseoClient = Pick<DaemonClient, "connect" | "close" | "createAgent" | "fetchAgent" | "setAgentModel" | "listProviderModels" | "setAgentThinkingOption" | "sendMessage" | "cancelAgent" | "subscribeAgentTimeline" | "subscribeConnectionStatus">;
5
+ export type PaseoDependencies = Readonly<{
6
+ createClient?(config: DaemonClientConfig): PaseoClient;
7
+ }>;
8
+ export declare function createPaseoProvider(execution: ProviderExecution, dependencies?: PaseoDependencies): ProviderAdapter;
9
+ export {};