salmon-loop 0.2.13 → 0.2.16

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 (218) hide show
  1. package/dist/cli/argv/headless-detection.js +27 -0
  2. package/dist/cli/chat-flow.js +11 -0
  3. package/dist/cli/chat.js +160 -24
  4. package/dist/cli/commands/chat.js +14 -7
  5. package/dist/cli/commands/flow-mode.js +63 -0
  6. package/dist/cli/commands/registry.js +2 -0
  7. package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
  8. package/dist/cli/commands/run/early-errors.js +23 -0
  9. package/dist/cli/commands/run/handler.js +115 -27
  10. package/dist/cli/commands/run/headless-error-writer.js +8 -0
  11. package/dist/cli/commands/run/loop-params.js +2 -0
  12. package/dist/cli/commands/run/mode.js +2 -5
  13. package/dist/cli/commands/run/parse-options.js +16 -0
  14. package/dist/cli/commands/run/persist-session.js +10 -1
  15. package/dist/cli/commands/run/preflight.js +10 -0
  16. package/dist/cli/commands/run/reporter-factory.js +4 -0
  17. package/dist/cli/commands/run/runtime-llm.js +38 -11
  18. package/dist/cli/commands/run/runtime-options.js +2 -2
  19. package/dist/cli/commands/serve.js +91 -71
  20. package/dist/cli/commands/tool-names.js +78 -78
  21. package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
  22. package/dist/cli/headless/json-protocol.js +37 -0
  23. package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
  24. package/dist/cli/headless/protocol-metadata.js +22 -0
  25. package/dist/cli/headless/stream-json-protocol.js +34 -1
  26. package/dist/cli/index.js +6 -4
  27. package/dist/cli/locales/en.js +30 -6
  28. package/dist/cli/program-bootstrap.js +8 -3
  29. package/dist/cli/program-commands.js +5 -1
  30. package/dist/cli/reporters/anthropic-stream.js +7 -1
  31. package/dist/cli/reporters/json.js +4 -0
  32. package/dist/cli/reporters/stream-json.js +17 -2
  33. package/dist/cli/run-cli.js +5 -3
  34. package/dist/cli/slash/runtime.js +27 -12
  35. package/dist/cli/ui/components/CommandInput.js +7 -3
  36. package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
  37. package/dist/cli/utils/command-option-source.js +13 -0
  38. package/dist/cli/utils/verify-resolver.js +8 -4
  39. package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
  40. package/dist/core/adapters/fs/file-adapter.js +6 -0
  41. package/dist/core/adapters/fs/filesystem.js +2 -1
  42. package/dist/core/adapters/git/git-adapter.js +78 -1
  43. package/dist/core/benchmark/patch-artifact.js +124 -0
  44. package/dist/core/benchmark/swe-bench.js +25 -0
  45. package/dist/core/config/load.js +18 -11
  46. package/dist/core/config/resolve-llm.js +12 -0
  47. package/dist/core/config/resolvers/server.js +0 -6
  48. package/dist/core/config/validate.js +73 -21
  49. package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
  50. package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
  51. package/dist/core/context/keywords.js +18 -4
  52. package/dist/core/context/service-deps.js +2 -2
  53. package/dist/core/context/service.js +8 -0
  54. package/dist/core/context/steps/context-gather.js +38 -0
  55. package/dist/core/context/summarization/summarizer.js +55 -12
  56. package/dist/core/context/targeting/target-resolver.js +4 -4
  57. package/dist/core/extensions/index.js +23 -5
  58. package/dist/core/extensions/paths.js +31 -0
  59. package/dist/core/extensions/schemas.js +8 -5
  60. package/dist/core/facades/cli-chat.js +6 -2
  61. package/dist/core/facades/cli-command-chat.js +1 -0
  62. package/dist/core/facades/cli-command-tool-names.js +2 -0
  63. package/dist/core/facades/cli-observability.js +1 -1
  64. package/dist/core/facades/cli-run-handler.js +4 -2
  65. package/dist/core/facades/cli-run-persist-session.js +1 -0
  66. package/dist/core/facades/cli-serve.js +2 -4
  67. package/dist/core/facades/cli-utils-worktree.js +1 -1
  68. package/dist/core/failure/diagnostics.js +53 -1
  69. package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
  70. package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
  71. package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
  72. package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
  73. package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
  74. package/dist/core/grizzco/engine/transaction/transaction-runner.js +165 -7
  75. package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
  76. package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
  77. package/dist/core/grizzco/steps/answer.js +13 -14
  78. package/dist/core/grizzco/steps/autopilot.js +396 -0
  79. package/dist/core/grizzco/steps/cache-sharing.js +29 -0
  80. package/dist/core/grizzco/steps/explore.js +37 -21
  81. package/dist/core/grizzco/steps/generateReview.js +2 -5
  82. package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
  83. package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
  84. package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
  85. package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
  86. package/dist/core/grizzco/steps/patch.js +105 -146
  87. package/dist/core/grizzco/steps/plan.js +101 -25
  88. package/dist/core/grizzco/steps/preflight.js +5 -6
  89. package/dist/core/grizzco/steps/request-assembly.js +78 -0
  90. package/dist/core/grizzco/steps/research.js +39 -36
  91. package/dist/core/grizzco/steps/tool-runtime.js +47 -0
  92. package/dist/core/grizzco/steps/verify-shared.js +23 -0
  93. package/dist/core/grizzco/steps/verify.js +13 -21
  94. package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
  95. package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
  96. package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
  97. package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
  98. package/dist/core/llm/ai-sdk/request-params.js +73 -0
  99. package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
  100. package/dist/core/llm/ai-sdk.js +112 -27
  101. package/dist/core/llm/capabilities.js +12 -0
  102. package/dist/core/llm/contracts/repair.js +36 -30
  103. package/dist/core/llm/errors.js +83 -2
  104. package/dist/core/llm/message-composition.js +7 -22
  105. package/dist/core/llm/phase-router.js +29 -10
  106. package/dist/core/llm/redact.js +28 -3
  107. package/dist/core/llm/registry.js +2 -0
  108. package/dist/core/llm/request-augmentation.js +55 -0
  109. package/dist/core/llm/request-envelope.js +334 -0
  110. package/dist/core/llm/shared-request-assembly.js +35 -0
  111. package/dist/core/llm/stream-utils.js +13 -4
  112. package/dist/core/llm/utils.js +18 -29
  113. package/dist/core/memory/relevant-retrieval.js +144 -0
  114. package/dist/core/observability/logger.js +11 -2
  115. package/dist/core/patch/diff.js +1 -0
  116. package/dist/core/prompts/registry.js +39 -2
  117. package/dist/core/prompts/runtime.js +50 -12
  118. package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
  119. package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
  120. package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
  121. package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
  122. package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
  123. package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
  124. package/dist/core/prompts/templates/system/main_system.hbs +4 -16
  125. package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
  126. package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
  127. package/dist/core/prompts/templates/system/research_system.hbs +2 -0
  128. package/dist/core/protocols/a2a/agent-card.js +3 -2
  129. package/dist/core/protocols/a2a/sdk/executor.js +2 -1
  130. package/dist/core/protocols/a2a/sdk/server.js +0 -1
  131. package/dist/core/protocols/acp/formal-agent.js +74 -51
  132. package/dist/core/protocols/acp/handlers.js +5 -1
  133. package/dist/core/protocols/acp/permission-provider.js +1 -1
  134. package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
  135. package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
  136. package/dist/core/public-capabilities/projections.js +29 -0
  137. package/dist/core/public-capabilities/registry.js +26 -0
  138. package/dist/core/public-capabilities/types.js +2 -0
  139. package/dist/core/runtime/agent-server-runtime.js +47 -43
  140. package/dist/core/runtime/execution-profile.js +67 -0
  141. package/dist/core/session/artifact-state.js +160 -0
  142. package/dist/core/session/compaction/index.js +183 -0
  143. package/dist/core/session/compaction/microcompact.js +78 -0
  144. package/dist/core/session/compaction/tracking.js +48 -0
  145. package/dist/core/session/compaction/types.js +11 -0
  146. package/dist/core/session/compression.js +8 -0
  147. package/dist/core/session/manager.js +244 -8
  148. package/dist/core/session/pruning-strategy.js +55 -9
  149. package/dist/core/session/replacement-preview-provider.js +24 -0
  150. package/dist/core/session/replacement-state.js +131 -0
  151. package/dist/core/session/resume-repair/pipeline.js +79 -0
  152. package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
  153. package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
  154. package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
  155. package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
  156. package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
  157. package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
  158. package/dist/core/session/resume-repair/types.js +2 -0
  159. package/dist/core/session/summary-sync.js +164 -13
  160. package/dist/core/session/token-tracker.js +6 -0
  161. package/dist/core/skills/audit.js +34 -0
  162. package/dist/core/skills/bridge.js +84 -7
  163. package/dist/core/skills/discovery.js +94 -0
  164. package/dist/core/skills/feature-flags.js +52 -0
  165. package/dist/core/skills/index.js +1 -1
  166. package/dist/core/skills/loader.js +195 -20
  167. package/dist/core/skills/parser.js +296 -24
  168. package/dist/core/skills/permissions.js +117 -0
  169. package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
  170. package/dist/core/skills/runtime/SkillRunner.js +240 -61
  171. package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
  172. package/dist/core/strata/layers/worktree.js +67 -10
  173. package/dist/core/strata/runtime/synchronizer.js +29 -2
  174. package/dist/core/streaming/stream-assembler.js +75 -31
  175. package/dist/core/sub-agent/context-snapshot.js +156 -0
  176. package/dist/core/sub-agent/core/loop.js +1 -1
  177. package/dist/core/sub-agent/core/manager.js +119 -20
  178. package/dist/core/sub-agent/dispatch-policy.js +29 -0
  179. package/dist/core/sub-agent/prefix-consistency.js +48 -0
  180. package/dist/core/sub-agent/registry-defaults.js +4 -0
  181. package/dist/core/sub-agent/tools/task-spawn.js +79 -2
  182. package/dist/core/sub-agent/types.js +134 -5
  183. package/dist/core/tools/audit.js +13 -4
  184. package/dist/core/tools/builtin/ast-grep.js +1 -1
  185. package/dist/core/tools/builtin/ast.js +1 -1
  186. package/dist/core/tools/builtin/benchmark.js +360 -0
  187. package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
  188. package/dist/core/tools/builtin/code-search/executor.js +6 -1
  189. package/dist/core/tools/builtin/code-search/spec.js +26 -2
  190. package/dist/core/tools/builtin/fs.js +256 -23
  191. package/dist/core/tools/builtin/git.js +2 -2
  192. package/dist/core/tools/builtin/index.js +51 -2
  193. package/dist/core/tools/builtin/interaction.js +8 -1
  194. package/dist/core/tools/builtin/plan.js +37 -15
  195. package/dist/core/tools/builtin/shell.js +1 -1
  196. package/dist/core/tools/loader.js +39 -16
  197. package/dist/core/tools/mapper.js +17 -3
  198. package/dist/core/tools/parallel/scheduler.js +35 -4
  199. package/dist/core/tools/permissions/permission-rules.js +5 -10
  200. package/dist/core/tools/policy.js +6 -1
  201. package/dist/core/tools/recoverable-tool-errors.js +10 -0
  202. package/dist/core/tools/router.js +24 -6
  203. package/dist/core/tools/session.js +458 -48
  204. package/dist/core/tools/tool-visibility.js +62 -0
  205. package/dist/core/tools/types.js +9 -1
  206. package/dist/core/types/execution.js +4 -0
  207. package/dist/core/types/flow-mode.js +8 -0
  208. package/dist/core/utils/path.js +52 -0
  209. package/dist/core/verification/runner.js +4 -1
  210. package/dist/languages/typescript/index.js +4 -1
  211. package/dist/locales/en.js +35 -2
  212. package/dist/utils/eol.js +1 -1
  213. package/package.json +13 -6
  214. package/scripts/fix-es-abstract-compat.js +77 -0
  215. package/dist/core/runtime/fastify-server-bundle.js +0 -26
  216. package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
  217. package/dist/core/runtime/sidecar-paths.js +0 -47
  218. package/dist/core/runtime/sidecar-route-catalog.js +0 -103
@@ -6,8 +6,11 @@ import { defaultPathAdapter } from '../../adapters/path/path-adapter.js';
6
6
  import { inferTurnStopReasonFromFailure } from '../../interaction/turn-stop-reason.js';
7
7
  import { recordAuditEvent } from '../../observability/audit-trail.js';
8
8
  import { readPlan } from '../../plan/index.js';
9
+ import { toAcpPublicModes } from '../../public-capabilities/projections.js';
10
+ import { buildPublicCapabilityRegistry } from '../../public-capabilities/registry.js';
9
11
  import { parseSlashInput } from '../../slash/parser.js';
10
12
  import { buildCanonicalExecutionRequest } from '../shared/execution-request.js';
13
+ import { parseAcpFlowMode } from '../shared/flow-mode-mapping.js';
11
14
  import { createAcpCommandRunner } from './acp-command-runner.js';
12
15
  import { createAcpFileSystem } from './acp-filesystem.js';
13
16
  import { createAcpSessionStore, isTerminalTaskEvent } from './handlers.js';
@@ -35,7 +38,8 @@ const ACP_PERMISSION_POLICY_CONFIG_ID = '_salmonloop_permission_policy';
35
38
  const ACP_MODE_CONFIG_ID = '_salmonloop_mode';
36
39
  const ACP_PERMISSION_POLICY_ASK = 'ask';
37
40
  const ACP_PERMISSION_POLICY_DENY_ALL = 'deny_all';
38
- const ACP_DEFAULT_MODE_ID = 'interactive';
41
+ const ACP_PERMISSION_POLICY_ALLOW_ALL = 'allow_all';
42
+ const ACP_DEFAULT_MODE_ID = 'autopilot';
39
43
  const ACP_SESSION_STORE_MAX_ENTRIES = 200;
40
44
  const ACP_SESSION_STORE_MAX_AGE_MS = 1000 * 60 * 60 * 24 * 30;
41
45
  const ACP_SESSION_STORE_LOCK_STALE_MS = 1000 * 30;
@@ -85,6 +89,15 @@ function buildJsonResourceContentBlock(data) {
85
89
  const ACP_AVAILABLE_COMMANDS = [
86
90
  { name: 'help', description: text.acp.slashHelpDescription },
87
91
  ];
92
+ const ACP_PUBLIC_MODES = toAcpPublicModes(buildPublicCapabilityRegistry());
93
+ const ACP_PUBLIC_MODE_IDS = new Set(ACP_PUBLIC_MODES.map((mode) => mode.id));
94
+ function resolveExposedAcpModeId(value, fallback = ACP_DEFAULT_MODE_ID) {
95
+ const resolvedModeId = parseAcpFlowMode(value);
96
+ if (resolvedModeId && ACP_PUBLIC_MODE_IDS.has(resolvedModeId)) {
97
+ return resolvedModeId;
98
+ }
99
+ return fallback;
100
+ }
88
101
  function formatResourceLink(block) {
89
102
  const title = block.title ?? block.name ?? block.uri;
90
103
  const description = block.description ? ` - ${block.description}` : '';
@@ -230,11 +243,10 @@ function loopEventToSessionUpdate(event) {
230
243
  return null;
231
244
  }
232
245
  }
233
- function createSessionRuntimeState() {
234
- return createSessionRuntimeStateFromPersisted();
235
- }
236
246
  function isPermissionPolicyValue(value) {
237
- return value === ACP_PERMISSION_POLICY_ASK || value === ACP_PERMISSION_POLICY_DENY_ALL;
247
+ return (value === ACP_PERMISSION_POLICY_ASK ||
248
+ value === ACP_PERMISSION_POLICY_DENY_ALL ||
249
+ value === ACP_PERMISSION_POLICY_ALLOW_ALL);
238
250
  }
239
251
  function buildConfigOptions(state) {
240
252
  return [
@@ -255,26 +267,24 @@ function buildConfigOptions(state) {
255
267
  name: text.acp.permissionPolicyDenyAllName,
256
268
  description: text.acp.permissionPolicyDenyAllDescription,
257
269
  },
270
+ {
271
+ value: ACP_PERMISSION_POLICY_ALLOW_ALL,
272
+ name: text.acp.permissionPolicyAllowAllName,
273
+ description: text.acp.permissionPolicyAllowAllDescription,
274
+ },
258
275
  ],
259
276
  },
260
277
  {
261
278
  type: 'select',
262
279
  id: ACP_MODE_CONFIG_ID,
263
- name: 'Session Mode',
264
- description: text.acp.modeInteractiveDescription,
280
+ name: 'Execution Flow',
281
+ description: 'Choose how the agent should execute this session.',
265
282
  currentValue: state.modeId,
266
- options: [
267
- {
268
- value: 'interactive',
269
- name: 'Interactive',
270
- description: text.acp.modeInteractiveDescription,
271
- },
272
- {
273
- value: 'yolo',
274
- name: 'YOLO',
275
- description: text.acp.modeYoloDescription,
276
- },
277
- ],
283
+ options: ACP_PUBLIC_MODES.map((mode) => ({
284
+ value: mode.id,
285
+ name: mode.name,
286
+ description: mode.description,
287
+ })),
278
288
  },
279
289
  ];
280
290
  }
@@ -313,27 +323,13 @@ function buildSessionInfoUpdateIfChanged(session, state) {
313
323
  updatedAt,
314
324
  };
315
325
  }
316
- function isSessionModeId(value) {
317
- return value === 'interactive' || value === 'yolo';
318
- }
319
326
  function buildCurrentModeUpdate(modeId) {
320
327
  return { sessionUpdate: 'current_mode_update', currentModeId: modeId };
321
328
  }
322
329
  function buildModesState(modeId) {
323
330
  return {
324
331
  currentModeId: modeId,
325
- availableModes: [
326
- {
327
- id: 'interactive',
328
- name: 'Interactive',
329
- description: text.acp.modeInteractiveDescription,
330
- },
331
- {
332
- id: 'yolo',
333
- name: 'YOLO',
334
- description: text.acp.modeYoloDescription,
335
- },
336
- ],
332
+ availableModes: ACP_PUBLIC_MODES.map((mode) => ({ ...mode })),
337
333
  };
338
334
  }
339
335
  function buildCurrentModeUpdateIfChanged(state) {
@@ -343,18 +339,28 @@ function buildCurrentModeUpdateIfChanged(state) {
343
339
  state.lastModeDigest = digest;
344
340
  return buildCurrentModeUpdate(state.modeId);
345
341
  }
342
+ function getLegacyPermissionPolicyForModeValue(value) {
343
+ const normalized = String(value ?? '')
344
+ .trim()
345
+ .toLowerCase();
346
+ if (normalized === 'interactive')
347
+ return ACP_PERMISSION_POLICY_ASK;
348
+ if (normalized === 'yolo')
349
+ return ACP_PERMISSION_POLICY_ALLOW_ALL;
350
+ return null;
351
+ }
346
352
  function getPermissionPolicyForAuthorization(state) {
347
- if (state.modeId === 'yolo')
348
- return 'allow_all';
349
353
  return state.permissionPolicy;
350
354
  }
351
355
  function createSessionRuntimeStateFromPersisted(input) {
356
+ const defaultPermissionPolicy = isPermissionPolicyValue(String(input?.defaultPermissionPolicy))
357
+ ? input?.defaultPermissionPolicy
358
+ : ACP_PERMISSION_POLICY_ASK;
352
359
  const permissionPolicy = isPermissionPolicyValue(String(input?.permissionPolicy))
353
360
  ? input?.permissionPolicy
354
- : ACP_PERMISSION_POLICY_ASK;
355
- const modeId = isSessionModeId(String(input?.modeId))
356
- ? input?.modeId
357
- : (input?.defaultModeId ?? ACP_DEFAULT_MODE_ID);
361
+ : defaultPermissionPolicy;
362
+ const defaultModeId = resolveExposedAcpModeId(input?.defaultModeId);
363
+ const modeId = resolveExposedAcpModeId(input?.modeId, defaultModeId);
358
364
  const state = {
359
365
  runtimePlanSessionId: null,
360
366
  runtimePlanPathHint: null,
@@ -546,8 +552,10 @@ export function createAcpFormalAgent(deps) {
546
552
  title: entry.title,
547
553
  taskId: undefined,
548
554
  history: [],
549
- permissionPolicy: ACP_PERMISSION_POLICY_ASK,
550
- modeId: deps.defaultModeId ?? ACP_DEFAULT_MODE_ID,
555
+ permissionPolicy: isPermissionPolicyValue(String(deps.defaultPermissionPolicy))
556
+ ? deps.defaultPermissionPolicy
557
+ : ACP_PERMISSION_POLICY_ASK,
558
+ modeId: resolveExposedAcpModeId(deps.defaultModeId),
551
559
  })),
552
560
  };
553
561
  }
@@ -757,6 +765,7 @@ export function createAcpFormalAgent(deps) {
757
765
  if (!sessionRuntime.has(stored.id)) {
758
766
  sessionRuntime.set(stored.id, createSessionRuntimeStateFromPersisted({
759
767
  permissionPolicy: stored.permissionPolicy,
768
+ defaultPermissionPolicy: deps.defaultPermissionPolicy,
760
769
  modeId: stored.modeId,
761
770
  defaultModeId: deps.defaultModeId,
762
771
  }));
@@ -894,10 +903,10 @@ export function createAcpFormalAgent(deps) {
894
903
  const existing = sessionRuntime.get(sessionId);
895
904
  if (existing)
896
905
  return existing;
897
- const created = createSessionRuntimeState();
898
- if (deps.defaultModeId) {
899
- created.modeId = deps.defaultModeId;
900
- }
906
+ const created = createSessionRuntimeStateFromPersisted({
907
+ defaultPermissionPolicy: deps.defaultPermissionPolicy,
908
+ defaultModeId: deps.defaultModeId,
909
+ });
901
910
  sessionRuntime.set(sessionId, created);
902
911
  return created;
903
912
  }
@@ -1095,10 +1104,15 @@ export function createAcpFormalAgent(deps) {
1095
1104
  runtimeState.permissionPolicy = params.value;
1096
1105
  }
1097
1106
  else if (params.configId === ACP_MODE_CONFIG_ID) {
1098
- if (!isSessionModeId(params.value)) {
1107
+ const parsedModeId = parseAcpFlowMode(params.value);
1108
+ if (!parsedModeId || !ACP_PUBLIC_MODE_IDS.has(parsedModeId)) {
1099
1109
  throw new RequestError(-32602, `Invalid params: unsupported value "${params.value}" for "${params.configId}"`);
1100
1110
  }
1101
- runtimeState.modeId = params.value;
1111
+ runtimeState.modeId = parsedModeId;
1112
+ const legacyPermissionPolicy = getLegacyPermissionPolicyForModeValue(params.value);
1113
+ if (legacyPermissionPolicy) {
1114
+ runtimeState.permissionPolicy = legacyPermissionPolicy;
1115
+ }
1102
1116
  }
1103
1117
  else {
1104
1118
  throw new RequestError(-32602, `Invalid params: unsupported configId "${params.configId}"`);
@@ -1122,13 +1136,22 @@ export function createAcpFormalAgent(deps) {
1122
1136
  throw new RequestError(-32004, `Session not found: ${params.sessionId}`);
1123
1137
  }
1124
1138
  const runtimeState = ensureSessionRuntimeState(params.sessionId);
1125
- if (!isSessionModeId(params.modeId)) {
1139
+ const resolvedModeId = parseAcpFlowMode(params.modeId);
1140
+ if (!resolvedModeId || !ACP_PUBLIC_MODE_IDS.has(resolvedModeId)) {
1126
1141
  throw new RequestError(-32602, `Invalid params: unsupported modeId "${params.modeId}"`);
1127
1142
  }
1128
- runtimeState.modeId = params.modeId;
1143
+ runtimeState.modeId = resolvedModeId;
1144
+ const legacyPermissionPolicy = getLegacyPermissionPolicyForModeValue(params.modeId);
1145
+ if (legacyPermissionPolicy) {
1146
+ runtimeState.permissionPolicy = legacyPermissionPolicy;
1147
+ }
1129
1148
  sessions.update(params.sessionId, (current) => ({ ...current }));
1130
1149
  await persistSessionsBestEffort();
1131
1150
  await emitSessionInfoUpdateBestEffort(params.sessionId);
1151
+ const configUpdate = buildConfigOptionUpdateIfChanged(runtimeState);
1152
+ if (configUpdate) {
1153
+ await emitSessionUpdate(params.sessionId, configUpdate);
1154
+ }
1132
1155
  // Send mode update notification
1133
1156
  const modeUpdate = buildCurrentModeUpdateIfChanged(runtimeState);
1134
1157
  if (modeUpdate) {
@@ -1209,7 +1232,7 @@ export function createAcpFormalAgent(deps) {
1209
1232
  }
1210
1233
  const pendingUpdates = [];
1211
1234
  const executionRequest = buildCanonicalExecutionRequest({
1212
- capability: 'patch',
1235
+ capability: runtimeState.modeId,
1213
1236
  instruction: promptText,
1214
1237
  checkpointSessionId: params.sessionId,
1215
1238
  repoPath: session.cwd,
@@ -30,7 +30,11 @@ export function createAcpSessionStore() {
30
30
  if (!current)
31
31
  return undefined;
32
32
  const updated = mutate(current);
33
- updated.updatedAt = new Date().toISOString();
33
+ const nextUpdatedAt = new Date().toISOString();
34
+ updated.updatedAt =
35
+ nextUpdatedAt > current.updatedAt
36
+ ? nextUpdatedAt
37
+ : new Date(Date.parse(current.updatedAt) + 1).toISOString();
34
38
  sessions.set(id, updated);
35
39
  return updated;
36
40
  },
@@ -104,7 +104,7 @@ export function createAcpToolAuthorizationProvider(params) {
104
104
  const permissionPolicy = params.getPermissionPolicy?.() ?? 'ask';
105
105
  if (permissionPolicy === 'allow_all') {
106
106
  await emitInProgressBestEffort(request.id);
107
- return { outcome: 'allow_session', source: 'auto', reason: 'session_mode:yolo' };
107
+ return { outcome: 'allow_session', source: 'auto', reason: 'session_config:allow_all' };
108
108
  }
109
109
  const hasSideEffects = request.sideEffects.some((effect) => effect !== 'fs_read');
110
110
  if (permissionPolicy === 'deny_all' && hasSideEffects) {
@@ -0,0 +1,23 @@
1
+ import { FLOW_MODE_PUBLIC_METADATA } from '../../public-capabilities/flow-mode-metadata.js';
2
+ import { FLOW_MODES, parseFlowMode } from '../../types/flow-mode.js';
3
+ export const SUPPORTED_PROTOCOL_FLOW_MODES = FLOW_MODES;
4
+ export function parseAcpFlowMode(value) {
5
+ const normalized = String(value ?? '')
6
+ .trim()
7
+ .toLowerCase();
8
+ if (normalized === 'interactive' || normalized === 'yolo') {
9
+ return 'autopilot';
10
+ }
11
+ return parseFlowMode(normalized);
12
+ }
13
+ export function parseA2ASkillFlowMode(value) {
14
+ return parseFlowMode(value);
15
+ }
16
+ export function buildA2AFlowSkills() {
17
+ return SUPPORTED_PROTOCOL_FLOW_MODES.map((mode) => ({
18
+ id: mode,
19
+ title: FLOW_MODE_PUBLIC_METADATA[mode].a2aTitle,
20
+ description: FLOW_MODE_PUBLIC_METADATA[mode].description,
21
+ }));
22
+ }
23
+ //# sourceMappingURL=flow-mode-mapping.js.map
@@ -0,0 +1,39 @@
1
+ export const FLOW_MODE_PUBLIC_METADATA = {
2
+ autopilot: {
3
+ publicTitle: 'Autopilot',
4
+ a2aTitle: 'Autopilot',
5
+ acpName: 'Autopilot',
6
+ description: 'Let the agent decide which actions and tools to use.',
7
+ },
8
+ patch: {
9
+ publicTitle: 'Patch code',
10
+ a2aTitle: 'Patch code',
11
+ acpName: 'Patch',
12
+ description: 'Apply code changes with verification.',
13
+ },
14
+ review: {
15
+ publicTitle: 'Review code',
16
+ a2aTitle: 'Review code',
17
+ acpName: 'Review',
18
+ description: 'Inspect code and report findings without mutating files.',
19
+ },
20
+ debug: {
21
+ publicTitle: 'Debug issue',
22
+ a2aTitle: 'Debug issue',
23
+ acpName: 'Debug',
24
+ description: 'Investigate issues and make targeted fixes when needed.',
25
+ },
26
+ research: {
27
+ publicTitle: 'Research request',
28
+ a2aTitle: 'Research request',
29
+ acpName: 'Research',
30
+ description: 'Explore the codebase and summarize relevant findings.',
31
+ },
32
+ answer: {
33
+ publicTitle: 'Answer question',
34
+ a2aTitle: 'Answer question',
35
+ acpName: 'Answer',
36
+ description: 'Answer questions directly without editing files.',
37
+ },
38
+ };
39
+ //# sourceMappingURL=flow-mode-metadata.js.map
@@ -0,0 +1,29 @@
1
+ import { FLOW_MODE_PUBLIC_METADATA } from './flow-mode-metadata.js';
2
+ import { buildPublicCapabilityRegistry } from './registry.js';
3
+ export function selectPublicCapabilitiesForSurface(surface, entries = buildPublicCapabilityRegistry()) {
4
+ return entries.filter((entry) => entry.reachability === 'reachable' && entry.surfaces[surface]);
5
+ }
6
+ function isFlowModeCapability(entry) {
7
+ return entry.kind === 'flow_mode';
8
+ }
9
+ export function toAcpPublicModes(entries = buildPublicCapabilityRegistry()) {
10
+ return selectPublicCapabilitiesForSurface('acp', entries)
11
+ .filter(isFlowModeCapability)
12
+ .map((entry) => ({
13
+ id: entry.target,
14
+ name: FLOW_MODE_PUBLIC_METADATA[entry.target].acpName,
15
+ description: entry.description,
16
+ }));
17
+ }
18
+ export function toA2APublicSkills(entries = buildPublicCapabilityRegistry()) {
19
+ return selectPublicCapabilitiesForSurface('a2a', entries).map((entry) => ({
20
+ id: entry.id,
21
+ title: entry.title,
22
+ description: entry.description,
23
+ tags: entry.tags,
24
+ examples: entry.examples,
25
+ inputModes: entry.inputModes,
26
+ outputModes: entry.outputModes,
27
+ }));
28
+ }
29
+ //# sourceMappingURL=projections.js.map
@@ -0,0 +1,26 @@
1
+ import { FLOW_MODES } from '../types/flow-mode.js';
2
+ import { FLOW_MODE_PUBLIC_METADATA } from './flow-mode-metadata.js';
3
+ function getFlowModeSurfaces(mode) {
4
+ if (mode === 'autopilot') {
5
+ return {
6
+ a2a: true,
7
+ acp: true,
8
+ };
9
+ }
10
+ return {
11
+ a2a: false,
12
+ acp: true,
13
+ };
14
+ }
15
+ export function buildPublicCapabilityRegistry() {
16
+ return FLOW_MODES.map((mode) => ({
17
+ id: mode,
18
+ kind: 'flow_mode',
19
+ target: mode,
20
+ title: FLOW_MODE_PUBLIC_METADATA[mode].publicTitle,
21
+ description: FLOW_MODE_PUBLIC_METADATA[mode].description,
22
+ surfaces: getFlowModeSurfaces(mode),
23
+ reachability: 'reachable',
24
+ }));
25
+ }
26
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -3,7 +3,6 @@ import { createTaskEventBus } from '../interaction/events/bus.js';
3
3
  import { createInteractionFacade } from '../interaction/orchestration/facade.js';
4
4
  import { createA2AInteractionExecutor } from '../protocols/a2a/sdk/executor.js';
5
5
  import { createA2ASdkExpressApp } from '../protocols/a2a/sdk/server.js';
6
- import { createSidecarFastifyPlugin, } from './sidecar-fastify-plugin.js';
7
6
  export function createAgentServerRuntime(deps) {
8
7
  const eventBus = deps.a2a.eventBus ?? createTaskEventBus();
9
8
  const taskStore = deps.a2a.taskStore ?? new InMemoryTaskStore();
@@ -20,67 +19,72 @@ export function createAgentServerRuntime(deps) {
20
19
  taskEventBus: eventBus,
21
20
  taskStore,
22
21
  });
23
- const agentCard = deps.a2a.buildAgentCard();
24
- const a2aApp = createA2ASdkExpressApp({
25
- agentCard,
22
+ const a2aServer = (deps.createA2AServerApp ?? createA2ASdkExpressApp)({
23
+ agentCard: deps.a2a.buildAgentCard(),
26
24
  agentExecutor: executor,
27
25
  taskStore,
28
26
  userBuilder: deps.a2a.userBuilder,
29
27
  authMiddleware: deps.a2a.authMiddleware,
30
28
  });
31
- const sidecarPlugin = createSidecarFastifyPlugin({
32
- routes: deps.sidecar.routes,
33
- scope: deps.listen.sidecar.type === 'tcp' ? 'tcp' : 'uds',
34
- allowConditional: deps.sidecar.allowConditional,
35
- authorize: deps.sidecar.authorize,
36
- baseUrl: deps.sidecar.baseUrl,
37
- });
38
- const sidecarServer = deps.createFastify();
39
29
  let a2aServerInstance = null;
40
- let sidecarServerInstance = null;
41
30
  let started = false;
31
+ let starting = false;
42
32
  async function start() {
43
- if (started) {
33
+ if (started || starting) {
44
34
  throw new Error('Runtime already started');
45
35
  }
46
- if (deps.configureA2A) {
47
- await deps.configureA2A(a2aApp);
48
- }
49
- if (deps.configureSidecar) {
50
- await deps.configureSidecar(sidecarServer);
51
- }
52
- await sidecarServer.register(sidecarPlugin);
53
- a2aServerInstance = await new Promise((resolve, reject) => {
54
- const server = a2aApp.listen(deps.listen.a2a.port, deps.listen.a2a.host ?? '0.0.0.0', (err) => {
55
- if (err)
56
- reject(err);
57
- else
36
+ starting = true;
37
+ try {
38
+ if (deps.configureA2A) {
39
+ await deps.configureA2A(a2aServer);
40
+ }
41
+ a2aServerInstance = await new Promise((resolve, reject) => {
42
+ const server = a2aServer.listen(deps.listen.a2a.port, deps.listen.a2a.host ?? '0.0.0.0');
43
+ const cleanup = () => {
44
+ server.off('error', onError);
45
+ server.off('listening', onListening);
46
+ };
47
+ const onError = (error) => {
48
+ cleanup();
49
+ reject(error);
50
+ };
51
+ const onListening = () => {
52
+ cleanup();
58
53
  resolve(server);
54
+ };
55
+ server.once('error', onError);
56
+ server.once('listening', onListening);
59
57
  });
60
- });
61
- const sidecarListenOpts = deps.listen.sidecar.type === 'tcp'
62
- ? { port: deps.listen.sidecar.port, host: deps.listen.sidecar.host }
63
- : { path: deps.listen.sidecar.path };
64
- sidecarServerInstance = await sidecarServer.listen(sidecarListenOpts);
65
- started = true;
66
- }
67
- async function close() {
68
- if (a2aServerInstance) {
69
- await new Promise((resolve) => {
70
- a2aServerInstance.close(() => resolve());
71
- });
58
+ started = true;
59
+ }
60
+ catch (error) {
72
61
  a2aServerInstance = null;
62
+ throw error;
63
+ }
64
+ finally {
65
+ starting = false;
73
66
  }
74
- if (sidecarServerInstance) {
75
- await sidecarServer.close();
76
- sidecarServerInstance = null;
67
+ }
68
+ async function close() {
69
+ if (!a2aServerInstance) {
70
+ started = false;
71
+ return;
77
72
  }
73
+ await new Promise((resolve, reject) => {
74
+ a2aServerInstance.close((error) => {
75
+ if (error) {
76
+ reject(error);
77
+ return;
78
+ }
79
+ resolve();
80
+ });
81
+ });
82
+ a2aServerInstance = null;
78
83
  started = false;
79
84
  }
80
85
  return {
81
86
  eventBus,
82
- a2aServer: a2aApp,
83
- sidecarServer,
87
+ a2aServer,
84
88
  start,
85
89
  close,
86
90
  };
@@ -0,0 +1,67 @@
1
+ import { Phase } from '../types/runtime.js';
2
+ const RECIPE_ENTRY_PHASE = Phase.PLAN;
3
+ const RECIPE_PROFILES = {
4
+ patch: {
5
+ mode: 'patch',
6
+ driver: 'recipe',
7
+ readOnly: false,
8
+ ignoreDirtyPreflight: false,
9
+ failurePolicy: 'rollback',
10
+ verifyPolicy: 'required_before_success_if_mutated',
11
+ entryPhase: RECIPE_ENTRY_PHASE,
12
+ },
13
+ review: {
14
+ mode: 'review',
15
+ driver: 'recipe',
16
+ readOnly: true,
17
+ ignoreDirtyPreflight: true,
18
+ failurePolicy: 'rollback',
19
+ verifyPolicy: 'never',
20
+ entryPhase: RECIPE_ENTRY_PHASE,
21
+ },
22
+ debug: {
23
+ mode: 'debug',
24
+ driver: 'recipe',
25
+ readOnly: false,
26
+ ignoreDirtyPreflight: false,
27
+ failurePolicy: 'rollback',
28
+ verifyPolicy: 'required_before_success_if_mutated',
29
+ entryPhase: RECIPE_ENTRY_PHASE,
30
+ },
31
+ research: {
32
+ mode: 'research',
33
+ driver: 'recipe',
34
+ readOnly: true,
35
+ ignoreDirtyPreflight: true,
36
+ failurePolicy: 'rollback',
37
+ verifyPolicy: 'never',
38
+ entryPhase: RECIPE_ENTRY_PHASE,
39
+ },
40
+ answer: {
41
+ mode: 'answer',
42
+ driver: 'recipe',
43
+ readOnly: true,
44
+ ignoreDirtyPreflight: true,
45
+ failurePolicy: 'rollback',
46
+ verifyPolicy: 'never',
47
+ entryPhase: RECIPE_ENTRY_PHASE,
48
+ },
49
+ };
50
+ const AUTOPILOT_PROFILE = {
51
+ mode: 'autopilot',
52
+ driver: 'agent',
53
+ readOnly: false,
54
+ defaultPermissionMode: 'yolo',
55
+ defaultCheckpointStrategy: 'direct',
56
+ ignoreDirtyPreflight: true,
57
+ failurePolicy: 'preserve',
58
+ verifyPolicy: 'required_before_success_if_mutated',
59
+ entryPhase: Phase.AUTOPILOT,
60
+ };
61
+ export function resolveExecutionProfile(mode) {
62
+ if (mode === 'autopilot') {
63
+ return AUTOPILOT_PROFILE;
64
+ }
65
+ return RECIPE_PROFILES[mode];
66
+ }
67
+ //# sourceMappingURL=execution-profile.js.map