@agentproto/runtime 5.1.0 → 5.3.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.
@@ -1,7 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { DaemonConfig, TunnelConfig, FeaturesConfig, PairingConfig, WorktreesConfig, SpawnConfig, SessionsConfig, ProvenanceConfig, AgentsMdConfig, TitlerConfig, ProfileConfig, AcpAgentConfigEntry, TerminalPreset } from './config.js';
3
- import { S as SpawnDefaultsConfig } from './spawn-defaults-wQV9AeiG.js';
4
- import './context-continuity-Bn99UtVC.js';
2
+ import { D as DaemonConfig, T as TunnelConfig, F as FeaturesConfig, P as PairingConfig, W as WorktreesConfig, S as SpawnConfig, a as SessionsConfig, b as ProvenanceConfig, A as ApprovalsConfig, c as AgentsMdConfig, d as TitlerConfig, C as CatalogConfig, e as ProfileConfig, f as AcpAgentConfigEntry, g as TerminalPreset } from './config-DcESQDmZ.js';
3
+ import { S as SpawnDefaultsConfig } from './spawn-defaults-Cp9SGZex.js';
5
4
  import '@agentproto/acp';
6
5
  import '@agentproto/command-sandbox';
7
6
  import '@agentproto/model-catalog';
@@ -37,8 +36,15 @@ declare const agentprotoConfigSchema: z.ZodObject<{
37
36
  spawn: z.ZodOptional<z.ZodType<SpawnConfig, unknown, z.core.$ZodTypeInternals<SpawnConfig, unknown>>>;
38
37
  sessions: z.ZodOptional<z.ZodType<SessionsConfig, unknown, z.core.$ZodTypeInternals<SessionsConfig, unknown>>>;
39
38
  provenance: z.ZodOptional<z.ZodType<ProvenanceConfig, unknown, z.core.$ZodTypeInternals<ProvenanceConfig, unknown>>>;
39
+ approvals: z.ZodOptional<z.ZodType<ApprovalsConfig, unknown, z.core.$ZodTypeInternals<ApprovalsConfig, unknown>>>;
40
40
  agentsMd: z.ZodOptional<z.ZodType<AgentsMdConfig, unknown, z.core.$ZodTypeInternals<AgentsMdConfig, unknown>>>;
41
+ models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
42
+ model: z.ZodString;
43
+ route: z.ZodOptional<z.ZodString>;
44
+ profile: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$loose>]>>>;
41
46
  titler: z.ZodOptional<z.ZodType<TitlerConfig, unknown, z.core.$ZodTypeInternals<TitlerConfig, unknown>>>;
47
+ catalog: z.ZodOptional<z.ZodType<CatalogConfig, unknown, z.core.$ZodTypeInternals<CatalogConfig, unknown>>>;
42
48
  profiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<ProfileConfig, unknown, z.core.$ZodTypeInternals<ProfileConfig, unknown>>>>;
43
49
  activeProfile: z.ZodOptional<z.ZodString>;
44
50
  defaults: z.ZodOptional<z.ZodType<SpawnDefaultsConfig, unknown, z.core.$ZodTypeInternals<SpawnDefaultsConfig, unknown>>>;
@@ -11,11 +11,12 @@ import '@agentproto/provider-presets';
11
11
  import '@agentproto/secrets/provision/recipe';
12
12
  import { z } from 'zod';
13
13
  import '@agentproto/auth';
14
- import 'child_process';
15
14
  import '@agentproto/command-sandbox';
15
+ import 'child_process';
16
16
  import '@agentproto/plugin-local-browser';
17
17
  import '@modelcontextprotocol/sdk/types.js';
18
18
  import '@agentproto/provider-kit';
19
+ import '@agentproto/llm-endpoint';
19
20
  import '@modelcontextprotocol/sdk/client/index.js';
20
21
  import '@modelcontextprotocol/sdk/client/streamableHttp.js';
21
22
  import 'net';
@@ -61,11 +62,13 @@ var init_config = __esm({
61
62
  });
62
63
 
63
64
  // src/worktree-isolation.ts
64
- var WORKTREE_ISOLATION_ENV, DEFAULT_WORKTREE_ISOLATION;
65
+ var WORKTREE_ISOLATION_ENV, WORKTREE_PROVISION_CONCURRENCY_ENV, DEFAULT_WORKTREE_PROVISION_CONCURRENCY, DEFAULT_WORKTREE_ISOLATION;
65
66
  var init_worktree_isolation = __esm({
66
67
  "src/worktree-isolation.ts"() {
67
68
  init_config();
68
69
  WORKTREE_ISOLATION_ENV = "AGENTPROTO_WORKTREES_ISOLATION";
70
+ WORKTREE_PROVISION_CONCURRENCY_ENV = "AGENTPROTO_WORKTREES_PROVISION_CONCURRENCY";
71
+ DEFAULT_WORKTREE_PROVISION_CONCURRENCY = 2;
69
72
  DEFAULT_WORKTREE_ISOLATION = "on-request";
70
73
  }
71
74
  });
@@ -323,9 +326,9 @@ async function exportClaudeCodeSession(adapterSessionId, cwd, configDir) {
323
326
  let stream;
324
327
  try {
325
328
  stream = createReadStream(filePath, { encoding: "utf8" });
326
- await new Promise((resolve16, reject) => {
329
+ await new Promise((resolve17, reject) => {
327
330
  stream.once("error", reject);
328
- stream.once("open", resolve16);
331
+ stream.once("open", resolve17);
329
332
  });
330
333
  } catch (err) {
331
334
  const code = err.code;
@@ -599,7 +602,7 @@ async function discoverHermesSessions(cwd, since, expectedId) {
599
602
  }
600
603
  async function defaultHermesRunner(adapterSessionId) {
601
604
  const { spawn: spawn5 } = await import('child_process');
602
- return new Promise((resolve16, reject) => {
605
+ return new Promise((resolve17, reject) => {
603
606
  const chunks = [];
604
607
  const errChunks = [];
605
608
  const proc = spawn5(
@@ -618,7 +621,7 @@ async function defaultHermesRunner(adapterSessionId) {
618
621
  )
619
622
  );
620
623
  } else {
621
- resolve16(Buffer.concat(chunks).toString("utf8"));
624
+ resolve17(Buffer.concat(chunks).toString("utf8"));
622
625
  }
623
626
  });
624
627
  });
@@ -655,9 +658,9 @@ async function exportDaemonEventsSession(sessionId, desc) {
655
658
  let stream;
656
659
  try {
657
660
  stream = createReadStream(filePath, { encoding: "utf8" });
658
- await new Promise((resolve16, reject) => {
661
+ await new Promise((resolve17, reject) => {
659
662
  stream.once("error", reject);
660
- stream.once("open", resolve16);
663
+ stream.once("open", resolve17);
661
664
  });
662
665
  } catch (err) {
663
666
  const code = err.code;
@@ -1928,6 +1931,10 @@ var init_pr_provenance_stamp = __esm({
1928
1931
  init_pr_provenance();
1929
1932
  }
1930
1933
  });
1934
+ var init_app_boundary = __esm({
1935
+ "src/app-boundary.ts"() {
1936
+ }
1937
+ });
1931
1938
  var init_command_allowlist = __esm({
1932
1939
  "src/command-allowlist.ts"() {
1933
1940
  }
@@ -1936,10 +1943,16 @@ var init_command_tools = __esm({
1936
1943
  "src/command-tools.ts"() {
1937
1944
  init_sessions();
1938
1945
  init_pr_provenance_stamp();
1946
+ init_app_boundary();
1939
1947
  init_command_allowlist();
1940
1948
  init_command_allowlist();
1941
1949
  }
1942
1950
  });
1951
+ var init_process_stats = __esm({
1952
+ "src/process-stats.ts"() {
1953
+ z.preprocess((v) => v === "true" ? true : v === "false" ? false : v, z.union([z.boolean(), z.literal("full")])).optional();
1954
+ }
1955
+ });
1943
1956
  var init_workspaces_config = __esm({
1944
1957
  "src/workspaces-config.ts"() {
1945
1958
  }
@@ -1962,7 +1975,7 @@ var init_bundles = __esm({
1962
1975
  id: bundleIdSchema,
1963
1976
  label: z.string().min(1),
1964
1977
  description: z.string().min(1).optional(),
1965
- mcpImports: z.array(z.string().min(1)),
1978
+ mcpImports: z.union([z.array(z.string().min(1)), z.literal("*")]),
1966
1979
  includeDaemon: z.boolean().optional(),
1967
1980
  skills: z.array(z.string().min(1))
1968
1981
  });
@@ -1991,6 +2004,12 @@ var init_launch_config = __esm({
1991
2004
  }
1992
2005
  });
1993
2006
 
2007
+ // src/adapter-slug-hint.ts
2008
+ var init_adapter_slug_hint = __esm({
2009
+ "src/adapter-slug-hint.ts"() {
2010
+ }
2011
+ });
2012
+
1994
2013
  // src/context-continuity.ts
1995
2014
  var init_context_continuity = __esm({
1996
2015
  "src/context-continuity.ts"() {
@@ -2024,6 +2043,41 @@ var init_canonical_posture = __esm({
2024
2043
  })();
2025
2044
  }
2026
2045
  });
2046
+ var effortSchema, postureSchema, routeSchema, userPresetSchema;
2047
+ var init_user_presets = __esm({
2048
+ "src/user-presets.ts"() {
2049
+ effortSchema = z.enum(["low", "medium", "high", "xhigh", "max", "ultracode"]);
2050
+ postureSchema = z.union([
2051
+ z.enum(["default", "plan", "accept-edits", "bypass", "read-only"]),
2052
+ z.object({ harnessModeId: z.string().min(1) })
2053
+ ]);
2054
+ routeSchema = z.object({
2055
+ gateway: z.string().min(1),
2056
+ baseUrl: z.string().url().optional()
2057
+ });
2058
+ userPresetSchema = z.object({
2059
+ id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),
2060
+ label: z.string().min(1),
2061
+ adapter: z.string().min(1).optional(),
2062
+ harness: z.string().min(1).optional(),
2063
+ model: z.string().min(1).optional(),
2064
+ route: routeSchema.optional(),
2065
+ access: z.object({ profileRef: z.string().min(1).optional() }).optional(),
2066
+ posture: postureSchema.optional(),
2067
+ effort: effortSchema.optional(),
2068
+ contextProfile: z.string().min(1).optional(),
2069
+ cwd: z.string().min(1).optional(),
2070
+ skills: z.array(z.string().min(1)).optional(),
2071
+ bundles: z.array(z.string().min(1)).optional(),
2072
+ browser: z.union([z.literal("headless"), z.literal(false)]).optional(),
2073
+ lastUsedAt: z.string().min(1).optional()
2074
+ });
2075
+ z.object({
2076
+ version: z.literal(1),
2077
+ presets: z.array(userPresetSchema)
2078
+ });
2079
+ }
2080
+ });
2027
2081
  var harnessPresetSchema;
2028
2082
  var init_harness_preset_store = __esm({
2029
2083
  "src/harness-preset-store.ts"() {
@@ -2124,6 +2178,10 @@ var init_session_title = __esm({
2124
2178
  "src/session-title.ts"() {
2125
2179
  }
2126
2180
  });
2181
+ var init_inference_binding = __esm({
2182
+ "src/inference-binding.ts"() {
2183
+ }
2184
+ });
2127
2185
 
2128
2186
  // src/mcp-credential-deps.ts
2129
2187
  var init_mcp_credential_deps = __esm({
@@ -2174,6 +2232,7 @@ var init_sandbox_adapters = __esm({
2174
2232
  });
2175
2233
  var init_session_spawn = __esm({
2176
2234
  "src/session-spawn.ts"() {
2235
+ init_process_stats();
2177
2236
  init_sessions();
2178
2237
  init_transcript_writer();
2179
2238
  init_workspaces_config();
@@ -2186,8 +2245,10 @@ var init_session_spawn = __esm({
2186
2245
  init_claude_code_oauth_source();
2187
2246
  init_providers_store();
2188
2247
  init_catalog_models();
2248
+ init_adapter_slug_hint();
2189
2249
  init_context_continuity();
2190
2250
  init_canonical_posture();
2251
+ init_user_presets();
2191
2252
  init_harness_preset_store();
2192
2253
  init_browser_mount();
2193
2254
  init_role();
@@ -2196,6 +2257,8 @@ var init_session_spawn = __esm({
2196
2257
  init_agents_md();
2197
2258
  init_workspace_rules();
2198
2259
  init_session_title();
2260
+ init_app_boundary();
2261
+ init_inference_binding();
2199
2262
  init_mcp_credential_deps();
2200
2263
  init_sandbox_agent_session_proxy();
2201
2264
  init_sandbox_ledger();
@@ -2359,6 +2422,16 @@ var init_agent_start_schema = __esm({
2359
2422
  route: jsonTolerant(
2360
2423
  z.object({ gateway: z.string().min(1), baseUrl: z.string().url().optional() })
2361
2424
  ).optional().describe("Billing route/gateway. Independent of `model` and `access`."),
2425
+ inference: jsonTolerant(
2426
+ z.object({
2427
+ endpoint: z.string().min(1).optional().describe('A registered local/LAN inference endpoint id (`agentproto llm endpoints list`), or "<id>@<device>" for a paired device\'s own shared endpoint.'),
2428
+ model: z.string().min(1).optional().describe('A bare model id (paired with `endpoint`), or the shorthand "<model>@<device|endpoint>" when `endpoint` is omitted.'),
2429
+ force: mcpBool.optional().describe("Skip the fit-check refusal on a clear miss (the check still runs and still warns)."),
2430
+ headroomPct: z.number().min(0).max(95).optional().describe("Headroom percentage held back from the endpoint's loaded ctx for the fit check. Default 25.")
2431
+ })
2432
+ ).optional().describe(
2433
+ `Bind this spawn to a local/LAN inference endpoint instead of a cloud model: \`{endpoint}\`, \`{endpoint, model}\`, or the shorthand \`{model: "<model>@<device|endpoint>"}\`. Runs a fit check (the harness's known first-request size vs the endpoint's loaded ctx) BEFORE spawning and refuses with an actionable error on a clear miss (\`force\` overrides). Defaults \`adapter\`/\`harness\` to "pi" when neither is set. Mutually exclusive with \`model\`/\`route\`/\`access\` \u2014 set those directly instead of \`inference\`, never both. ${help("inference")}`
2434
+ ),
2362
2435
  access: jsonTolerant(z.object({ profileRef: z.string().min(1).optional() })).optional().describe("Named auth profile to bill at initial spawn; resolved from the local keychain."),
2363
2436
  posture: z.string().optional().describe("Canonical agent posture (plan, bypass, accept-edits, read-only) or native harness mode."),
2364
2437
  contextProfile: z.string().optional().describe("Context intake profile (for example full or lean)."),
@@ -2497,40 +2570,6 @@ var init_agent_start_schema = __esm({
2497
2570
  agentStartInputSchema.omit({ wait: true });
2498
2571
  }
2499
2572
  });
2500
- var effortSchema, postureSchema, routeSchema, userPresetSchema;
2501
- var init_user_presets = __esm({
2502
- "src/user-presets.ts"() {
2503
- effortSchema = z.enum(["low", "medium", "high", "xhigh", "max", "ultracode"]);
2504
- postureSchema = z.union([
2505
- z.enum(["default", "plan", "accept-edits", "bypass", "read-only"]),
2506
- z.object({ harnessModeId: z.string().min(1) })
2507
- ]);
2508
- routeSchema = z.object({
2509
- gateway: z.string().min(1),
2510
- baseUrl: z.string().url().optional()
2511
- });
2512
- userPresetSchema = z.object({
2513
- id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),
2514
- label: z.string().min(1),
2515
- adapter: z.string().min(1).optional(),
2516
- harness: z.string().min(1).optional(),
2517
- model: z.string().min(1).optional(),
2518
- route: routeSchema.optional(),
2519
- access: z.object({ profileRef: z.string().min(1).optional() }).optional(),
2520
- posture: postureSchema.optional(),
2521
- effort: effortSchema.optional(),
2522
- contextProfile: z.string().min(1).optional(),
2523
- cwd: z.string().min(1).optional(),
2524
- skills: z.array(z.string().min(1)).optional(),
2525
- bundles: z.array(z.string().min(1)).optional(),
2526
- browser: z.union([z.literal("headless"), z.literal(false)]).optional()
2527
- });
2528
- z.object({
2529
- version: z.literal(1),
2530
- presets: z.array(userPresetSchema)
2531
- });
2532
- }
2533
- });
2534
2573
  var init_catalog_provider_models = __esm({
2535
2574
  "src/catalog-provider-models.ts"() {
2536
2575
  }
@@ -2570,6 +2609,7 @@ var init_agent_tools = __esm({
2570
2609
  "src/agent-tools.ts"() {
2571
2610
  init_transcript_export();
2572
2611
  init_agent_start_schema();
2612
+ init_process_stats();
2573
2613
  init_spawn_field_schemas();
2574
2614
  init_session_spawn();
2575
2615
  init_canonical_posture();
@@ -2660,6 +2700,7 @@ var init_context_checkpoint = __esm({
2660
2700
  // src/session-continue-fresh.ts
2661
2701
  var init_session_continue_fresh = __esm({
2662
2702
  "src/session-continue-fresh.ts"() {
2703
+ init_app_boundary();
2663
2704
  init_context_checkpoint();
2664
2705
  init_context_continuity();
2665
2706
  init_session_spawn();
@@ -2720,6 +2761,21 @@ var init_gh_provenance_shim = __esm({
2720
2761
  DEFAULT_WRAP_GH = false;
2721
2762
  }
2722
2763
  });
2764
+ var DEFAULT_MODEL_ROLES;
2765
+ var init_model_roles = __esm({
2766
+ "src/model-roles.ts"() {
2767
+ DEFAULT_MODEL_ROLES = {
2768
+ /** Reviewer for a small residual (repo-maintenance `review` step). */
2769
+ "review.small": "claude-sonnet-5-5",
2770
+ /** Reviewer for a large residual + the retry reviewer. */
2771
+ "review.large": "claude-opus-5-5",
2772
+ /** CI pull-request reviewer (mirrors `.github/agentic-review.json`'s `reviewerModel`). */
2773
+ "review.pr": "openrouter/z-ai/glm-5.3-flash",
2774
+ /** The session-steward's agent judge. */
2775
+ "judge.session": "claude-sonnet-5-5"
2776
+ };
2777
+ }
2778
+ });
2723
2779
  function pathSegmentsMatch(entryPath, concretePath) {
2724
2780
  const entrySegs = entryPath.split(".");
2725
2781
  const concreteSegs = concretePath.split(".");
@@ -2727,7 +2783,8 @@ function pathSegmentsMatch(entryPath, concretePath) {
2727
2783
  return entrySegs.every((seg, i) => seg === "*" || seg === concreteSegs[i]);
2728
2784
  }
2729
2785
  function findConfigKey(path) {
2730
- return CONFIG_KEYS.find((entry) => pathSegmentsMatch(entry.path, path));
2786
+ const lookup = path.startsWith("models.") && path.length > "models.".length ? "models.*" : path;
2787
+ return CONFIG_KEYS.find((entry) => pathSegmentsMatch(entry.path, lookup));
2731
2788
  }
2732
2789
  function isKnownConfigPath(path) {
2733
2790
  return CONFIG_KEYS.some((entry) => entry.path === path) || CONFIG_KEYS_NOT_EXPOSED.some((entry) => entry.path === path);
@@ -2813,7 +2870,7 @@ function redactConfigValue(path, value) {
2813
2870
  }
2814
2871
  return { set: true };
2815
2872
  }
2816
- var contextContinuityPolicySchema, deferredToolsConfigSchema, spawnBrowserModeSchema, optionsMapSchema, defaultsAdapterAuthConfigSchema, defaultsAdapterConfigSchema, mcpDefaultsConfigSchema, spawnDefaultsConfigSchema, daemonConfigSchema, titlerConfigSchema, tunnelConfigSchema, featuresConfigSchema, worktreesConfigSchema, spawnConfigSchema, provenanceConfigSchema, sessionsConfigSchema, agentsMdConfigSchema, pairPageSchema, pairingConfigSchema, profileConfigSchema, acpAgentConfigEntrySchema, terminalPresetSchema, agentprotoConfigSchema, bool, str, num, strArray, CONFIG_KEYS, CONFIG_KEYS_NOT_EXPOSED;
2873
+ var contextContinuityPolicySchema, deferredToolsConfigSchema, spawnBrowserModeSchema, optionsMapSchema, defaultsAdapterAuthConfigSchema, defaultsAdapterConfigSchema, mcpDefaultsConfigSchema, spawnDefaultsConfigSchema, daemonConfigSchema, titlerConfigSchema, catalogConfigSchema, tunnelConfigSchema, featuresConfigSchema, worktreesConfigSchema, spawnConfigSchema, provenanceConfigSchema, approvalsConfigSchema, sessionsConfigSchema, agentsMdConfigSchema, pairPageSchema, pairingConfigSchema, modelRoleValueSchema, profileConfigSchema, acpAgentConfigEntrySchema, terminalPresetSchema, agentprotoConfigSchema, bool, str, num, strArray, CONFIG_KEYS, CONFIG_KEYS_NOT_EXPOSED;
2817
2874
  var init_config_schema = __esm({
2818
2875
  "src/config-schema.ts"() {
2819
2876
  init_worktree_isolation();
@@ -2823,6 +2880,7 @@ var init_config_schema = __esm({
2823
2880
  init_gh_provenance_shim();
2824
2881
  init_agents_md();
2825
2882
  init_session_titler();
2883
+ init_model_roles();
2826
2884
  init_background_task_wake();
2827
2885
  init_role();
2828
2886
  contextContinuityPolicySchema = z.object({
@@ -2908,6 +2966,9 @@ var init_config_schema = __esm({
2908
2966
  enabled: z.boolean().optional(),
2909
2967
  model: z.string().optional()
2910
2968
  }).passthrough();
2969
+ catalogConfigSchema = z.object({
2970
+ sources: z.array(z.object({ url: z.string() }).passthrough()).optional()
2971
+ }).passthrough();
2911
2972
  tunnelConfigSchema = z.object({
2912
2973
  host: z.string().optional(),
2913
2974
  token: z.string().optional(),
@@ -2917,17 +2978,22 @@ var init_config_schema = __esm({
2917
2978
  featuresConfigSchema = z.object({
2918
2979
  pty: z.boolean().optional(),
2919
2980
  llmEndpoint: z.boolean().optional(),
2920
- deviceInferenceShare: z.boolean().optional()
2981
+ deviceInferenceShare: z.boolean().optional(),
2982
+ deviceSpawnAllow: z.boolean().optional()
2921
2983
  }).passthrough();
2922
2984
  worktreesConfigSchema = z.object({
2923
2985
  root: z.string().optional(),
2924
- isolation: z.enum(["always", "on-request", "never"]).optional()
2986
+ isolation: z.enum(["always", "on-request", "never"]).optional(),
2987
+ provisionConcurrency: z.number().int().min(0).optional(),
2988
+ provisionConcurrencyByRepo: z.record(z.string(), z.number().int().min(0)).optional(),
2989
+ provisionLoadFactor: z.number().min(0).optional()
2925
2990
  }).passthrough();
2926
2991
  spawnConfigSchema = z.object({
2927
2992
  attach: z.enum(["always", "on-request"]).optional(),
2928
2993
  dedupe: z.enum(["always", "on-request"]).optional()
2929
2994
  }).passthrough();
2930
2995
  provenanceConfigSchema = z.object({ wrapGh: z.boolean().optional() }).passthrough();
2996
+ approvalsConfigSchema = z.object({ webOrigins: z.array(z.string()).optional() }).passthrough();
2931
2997
  sessionsConfigSchema = z.object({
2932
2998
  attentionDelaySec: z.number().optional(),
2933
2999
  eventsDir: z.string().optional()
@@ -2945,6 +3011,14 @@ var init_config_schema = __esm({
2945
3011
  autoconnect: z.boolean().optional(),
2946
3012
  pairPage: pairPageSchema.optional()
2947
3013
  }).passthrough();
3014
+ modelRoleValueSchema = z.union([
3015
+ z.string().min(1),
3016
+ z.object({
3017
+ model: z.string().min(1),
3018
+ route: z.string().optional(),
3019
+ profile: z.string().optional()
3020
+ }).passthrough()
3021
+ ]);
2948
3022
  profileConfigSchema = z.object({
2949
3023
  daemon: daemonConfigSchema.optional(),
2950
3024
  tunnel: tunnelConfigSchema.optional(),
@@ -2983,8 +3057,11 @@ var init_config_schema = __esm({
2983
3057
  spawn: spawnConfigSchema.optional(),
2984
3058
  sessions: sessionsConfigSchema.optional(),
2985
3059
  provenance: provenanceConfigSchema.optional(),
3060
+ approvals: approvalsConfigSchema.optional(),
2986
3061
  agentsMd: agentsMdConfigSchema.optional(),
3062
+ models: z.record(z.string(), modelRoleValueSchema).optional(),
2987
3063
  titler: titlerConfigSchema.optional(),
3064
+ catalog: catalogConfigSchema.optional(),
2988
3065
  profiles: z.record(z.string(), profileConfigSchema).optional(),
2989
3066
  activeProfile: z.string().optional(),
2990
3067
  defaults: spawnDefaultsConfigSchema.optional(),
@@ -3035,6 +3112,16 @@ var init_config_schema = __esm({
3035
3112
  label: "Allowed origins",
3036
3113
  help: "Trusted browser origins for mutating /sessions/* routes, in addition to the hardcoded localhost defaults. Lockout: a bad value can lock a browser UI out."
3037
3114
  },
3115
+ {
3116
+ path: "approvals.webOrigins",
3117
+ schema: strArray,
3118
+ apply: "restart",
3119
+ writable: false,
3120
+ section: "daemon",
3121
+ label: "Approval web-click origins",
3122
+ help: "Origins allowed to decide a pending approval via POST /approvals/:id/decision (web_click channel). Empty (default) turns the channel off entirely. A SEPARATE allowlist from daemon.allowedOrigins, which is not automatically trusted to decide approvals. Lockout: a bad value can lock the web decision UI out.",
3123
+ default: []
3124
+ },
3038
3125
  {
3039
3126
  path: "daemon.strictOrigins",
3040
3127
  schema: bool,
@@ -3228,6 +3315,20 @@ var init_config_schema = __esm({
3228
3315
  default: DEFAULT_PAIR_PAGE
3229
3316
  },
3230
3317
  // ── models ──
3318
+ {
3319
+ // One row per configured role. Role names are dotted (`review.pr`), so a
3320
+ // concrete key is `models.review.pr` — `findConfigKey` maps any
3321
+ // `models.<role>` onto this entry, and `splitConfigPath` (config.ts) keeps
3322
+ // the role as ONE segment. The full role list (incl. built-in defaults and
3323
+ // where each value comes from) is the `model_roles` tool.
3324
+ path: "models.*",
3325
+ schema: modelRoleValueSchema,
3326
+ apply: "hot",
3327
+ writable: true,
3328
+ section: "models",
3329
+ label: "Model role",
3330
+ help: `Model for a role (review.small, review.large, review.pr, judge.session, \u2026): a model id, or { model, route?, profile? }. Precedence: explicit run input > the repo's agentproto.json \`models\` > this daemon config > built-in default (\`model_roles\` lists every role and its source). Built-in defaults: ${Object.entries(DEFAULT_MODEL_ROLES).map(([r, m]) => `${r}=${m}`).join(", ")}.`
3331
+ },
3231
3332
  {
3232
3333
  path: "titler.model",
3233
3334
  schema: str,
@@ -3238,6 +3339,16 @@ var init_config_schema = __esm({
3238
3339
  help: "OpenRouter model id used to generate session titles. Requires OPENROUTER_API_KEY.",
3239
3340
  default: DEFAULT_TITLER_MODEL
3240
3341
  },
3342
+ // ── daemon: app catalog ──
3343
+ {
3344
+ path: "catalog.sources",
3345
+ schema: z.array(z.object({ url: str }).passthrough()),
3346
+ apply: "hot",
3347
+ writable: true,
3348
+ section: "daemon",
3349
+ label: "App catalog sources",
3350
+ help: "Remote catalogs merged into `app_catalog`: an array of `{ url }`, each returning `{ entries: AppCatalogEntry[] }`. Wins over `sources` in ~/.agentproto/app-catalog.json when both are set."
3351
+ },
3241
3352
  // ── defaults: spawn ──
3242
3353
  {
3243
3354
  path: "defaults.skills",
@@ -3317,6 +3428,36 @@ var init_config_schema = __esm({
3317
3428
  help: "Whether a freshly-spawned agent_start session is isolated into its own git worktree.",
3318
3429
  default: DEFAULT_WORKTREE_ISOLATION
3319
3430
  },
3431
+ {
3432
+ path: "worktrees.provisionConcurrency",
3433
+ schema: z.number().int().min(0),
3434
+ apply: "hot",
3435
+ env: WORKTREE_PROVISION_CONCURRENCY_ENV,
3436
+ writable: true,
3437
+ section: "defaults",
3438
+ label: "Worktree provisioning concurrency",
3439
+ help: "Max worktree provisionings running their heavy phases (depsCmd, clones, setup hooks) at once; the rest queue FIFO. 0 = unlimited.",
3440
+ default: DEFAULT_WORKTREE_PROVISION_CONCURRENCY
3441
+ },
3442
+ {
3443
+ path: "worktrees.provisionConcurrencyByRepo",
3444
+ schema: z.record(str, z.number().int().min(0)),
3445
+ apply: "hot",
3446
+ writable: true,
3447
+ section: "defaults",
3448
+ label: "Per-repo provisioning concurrency",
3449
+ help: "Per-repo caps on concurrent heavy provisioning, keyed by repo path or directory name; never looser than the global cap."
3450
+ },
3451
+ {
3452
+ path: "worktrees.provisionLoadFactor",
3453
+ schema: z.number().min(0),
3454
+ apply: "hot",
3455
+ writable: true,
3456
+ section: "defaults",
3457
+ label: "Provisioning load guard factor",
3458
+ help: "Hold back a new heavy provisioning while the 1-minute load average exceeds cores x this factor. 0 or unset = off.",
3459
+ default: 0
3460
+ },
3320
3461
  {
3321
3462
  path: "spawn.attach",
3322
3463
  schema: z.enum(["always", "on-request"]),
@@ -3764,6 +3905,16 @@ var init_config_schema = __esm({
3764
3905
  label: "Device inference sharing",
3765
3906
  help: "Expose this daemon's local inference endpoint(s) to a paired HOST-scoped controller. Toggle via `agentproto devices share-inference on|off`.",
3766
3907
  default: false
3908
+ },
3909
+ {
3910
+ path: "features.deviceSpawnAllow",
3911
+ schema: bool,
3912
+ apply: "restart",
3913
+ writable: true,
3914
+ section: "daemon",
3915
+ label: "Device spawn allow",
3916
+ help: 'Allow a paired HOST-scoped controller to spawn/drive agent sessions on this daemon (`agent_start({ sandbox: "device:<name>" })`). Toggle via `agentproto devices allow-spawn on|off`.',
3917
+ default: false
3767
3918
  }
3768
3919
  ];
3769
3920
  CONFIG_KEYS_NOT_EXPOSED = [