@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,5 +1,5 @@
1
1
  import { CostBudget } from '@agentproto/auth';
2
- import { C as ContextContinuityPolicy } from './context-continuity-Bn99UtVC.js';
2
+ import { C as ContextContinuityPolicy } from './spawn-defaults-Cp9SGZex.js';
3
3
 
4
4
  /**
5
5
  * SessionConfig — the unified per-session config surface, decomposed into
@@ -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';
@@ -56,11 +57,13 @@ var __copyProps = (to, from, except, desc) => {
56
57
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget);
57
58
 
58
59
  // src/worktree-isolation.ts
59
- var WORKTREE_ISOLATION_ENV, DEFAULT_WORKTREE_ISOLATION;
60
+ var WORKTREE_ISOLATION_ENV, WORKTREE_PROVISION_CONCURRENCY_ENV, DEFAULT_WORKTREE_PROVISION_CONCURRENCY, DEFAULT_WORKTREE_ISOLATION;
60
61
  var init_worktree_isolation = __esm({
61
62
  "src/worktree-isolation.ts"() {
62
63
  init_config();
63
64
  WORKTREE_ISOLATION_ENV = "AGENTPROTO_WORKTREES_ISOLATION";
65
+ WORKTREE_PROVISION_CONCURRENCY_ENV = "AGENTPROTO_WORKTREES_PROVISION_CONCURRENCY";
66
+ DEFAULT_WORKTREE_PROVISION_CONCURRENCY = 2;
64
67
  DEFAULT_WORKTREE_ISOLATION = "on-request";
65
68
  }
66
69
  });
@@ -308,9 +311,9 @@ async function exportClaudeCodeSession(adapterSessionId, cwd, configDir) {
308
311
  let stream;
309
312
  try {
310
313
  stream = createReadStream(filePath, { encoding: "utf8" });
311
- await new Promise((resolve16, reject) => {
314
+ await new Promise((resolve17, reject) => {
312
315
  stream.once("error", reject);
313
- stream.once("open", resolve16);
316
+ stream.once("open", resolve17);
314
317
  });
315
318
  } catch (err) {
316
319
  const code = err.code;
@@ -584,7 +587,7 @@ async function discoverHermesSessions(cwd, since, expectedId) {
584
587
  }
585
588
  async function defaultHermesRunner(adapterSessionId) {
586
589
  const { spawn: spawn5 } = await import('child_process');
587
- return new Promise((resolve16, reject) => {
590
+ return new Promise((resolve17, reject) => {
588
591
  const chunks = [];
589
592
  const errChunks = [];
590
593
  const proc = spawn5(
@@ -603,7 +606,7 @@ async function defaultHermesRunner(adapterSessionId) {
603
606
  )
604
607
  );
605
608
  } else {
606
- resolve16(Buffer.concat(chunks).toString("utf8"));
609
+ resolve17(Buffer.concat(chunks).toString("utf8"));
607
610
  }
608
611
  });
609
612
  });
@@ -640,9 +643,9 @@ async function exportDaemonEventsSession(sessionId, desc) {
640
643
  let stream;
641
644
  try {
642
645
  stream = createReadStream(filePath, { encoding: "utf8" });
643
- await new Promise((resolve16, reject) => {
646
+ await new Promise((resolve17, reject) => {
644
647
  stream.once("error", reject);
645
- stream.once("open", resolve16);
648
+ stream.once("open", resolve17);
646
649
  });
647
650
  } catch (err) {
648
651
  const code = err.code;
@@ -1913,6 +1916,10 @@ var init_pr_provenance_stamp = __esm({
1913
1916
  init_pr_provenance();
1914
1917
  }
1915
1918
  });
1919
+ var init_app_boundary = __esm({
1920
+ "src/app-boundary.ts"() {
1921
+ }
1922
+ });
1916
1923
  var init_command_allowlist = __esm({
1917
1924
  "src/command-allowlist.ts"() {
1918
1925
  }
@@ -1921,10 +1928,16 @@ var init_command_tools = __esm({
1921
1928
  "src/command-tools.ts"() {
1922
1929
  init_sessions();
1923
1930
  init_pr_provenance_stamp();
1931
+ init_app_boundary();
1924
1932
  init_command_allowlist();
1925
1933
  init_command_allowlist();
1926
1934
  }
1927
1935
  });
1936
+ var init_process_stats = __esm({
1937
+ "src/process-stats.ts"() {
1938
+ z.preprocess((v) => v === "true" ? true : v === "false" ? false : v, z.union([z.boolean(), z.literal("full")])).optional();
1939
+ }
1940
+ });
1928
1941
  var init_workspaces_config = __esm({
1929
1942
  "src/workspaces-config.ts"() {
1930
1943
  }
@@ -1947,7 +1960,7 @@ var init_bundles = __esm({
1947
1960
  id: bundleIdSchema,
1948
1961
  label: z.string().min(1),
1949
1962
  description: z.string().min(1).optional(),
1950
- mcpImports: z.array(z.string().min(1)),
1963
+ mcpImports: z.union([z.array(z.string().min(1)), z.literal("*")]),
1951
1964
  includeDaemon: z.boolean().optional(),
1952
1965
  skills: z.array(z.string().min(1))
1953
1966
  });
@@ -1976,6 +1989,12 @@ var init_launch_config = __esm({
1976
1989
  }
1977
1990
  });
1978
1991
 
1992
+ // src/adapter-slug-hint.ts
1993
+ var init_adapter_slug_hint = __esm({
1994
+ "src/adapter-slug-hint.ts"() {
1995
+ }
1996
+ });
1997
+
1979
1998
  // src/context-continuity.ts
1980
1999
  var init_context_continuity = __esm({
1981
2000
  "src/context-continuity.ts"() {
@@ -2009,6 +2028,41 @@ var init_canonical_posture = __esm({
2009
2028
  })();
2010
2029
  }
2011
2030
  });
2031
+ var effortSchema, postureSchema, routeSchema, userPresetSchema;
2032
+ var init_user_presets = __esm({
2033
+ "src/user-presets.ts"() {
2034
+ effortSchema = z.enum(["low", "medium", "high", "xhigh", "max", "ultracode"]);
2035
+ postureSchema = z.union([
2036
+ z.enum(["default", "plan", "accept-edits", "bypass", "read-only"]),
2037
+ z.object({ harnessModeId: z.string().min(1) })
2038
+ ]);
2039
+ routeSchema = z.object({
2040
+ gateway: z.string().min(1),
2041
+ baseUrl: z.string().url().optional()
2042
+ });
2043
+ userPresetSchema = z.object({
2044
+ id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),
2045
+ label: z.string().min(1),
2046
+ adapter: z.string().min(1).optional(),
2047
+ harness: z.string().min(1).optional(),
2048
+ model: z.string().min(1).optional(),
2049
+ route: routeSchema.optional(),
2050
+ access: z.object({ profileRef: z.string().min(1).optional() }).optional(),
2051
+ posture: postureSchema.optional(),
2052
+ effort: effortSchema.optional(),
2053
+ contextProfile: z.string().min(1).optional(),
2054
+ cwd: z.string().min(1).optional(),
2055
+ skills: z.array(z.string().min(1)).optional(),
2056
+ bundles: z.array(z.string().min(1)).optional(),
2057
+ browser: z.union([z.literal("headless"), z.literal(false)]).optional(),
2058
+ lastUsedAt: z.string().min(1).optional()
2059
+ });
2060
+ z.object({
2061
+ version: z.literal(1),
2062
+ presets: z.array(userPresetSchema)
2063
+ });
2064
+ }
2065
+ });
2012
2066
  var harnessPresetSchema;
2013
2067
  var init_harness_preset_store = __esm({
2014
2068
  "src/harness-preset-store.ts"() {
@@ -2109,6 +2163,10 @@ var init_session_title = __esm({
2109
2163
  "src/session-title.ts"() {
2110
2164
  }
2111
2165
  });
2166
+ var init_inference_binding = __esm({
2167
+ "src/inference-binding.ts"() {
2168
+ }
2169
+ });
2112
2170
 
2113
2171
  // src/mcp-credential-deps.ts
2114
2172
  var init_mcp_credential_deps = __esm({
@@ -2159,6 +2217,7 @@ var init_sandbox_adapters = __esm({
2159
2217
  });
2160
2218
  var init_session_spawn = __esm({
2161
2219
  "src/session-spawn.ts"() {
2220
+ init_process_stats();
2162
2221
  init_sessions();
2163
2222
  init_transcript_writer();
2164
2223
  init_workspaces_config();
@@ -2171,8 +2230,10 @@ var init_session_spawn = __esm({
2171
2230
  init_claude_code_oauth_source();
2172
2231
  init_providers_store();
2173
2232
  init_catalog_models();
2233
+ init_adapter_slug_hint();
2174
2234
  init_context_continuity();
2175
2235
  init_canonical_posture();
2236
+ init_user_presets();
2176
2237
  init_harness_preset_store();
2177
2238
  init_browser_mount();
2178
2239
  init_role();
@@ -2181,6 +2242,8 @@ var init_session_spawn = __esm({
2181
2242
  init_agents_md();
2182
2243
  init_workspace_rules();
2183
2244
  init_session_title();
2245
+ init_app_boundary();
2246
+ init_inference_binding();
2184
2247
  init_mcp_credential_deps();
2185
2248
  init_sandbox_agent_session_proxy();
2186
2249
  init_sandbox_ledger();
@@ -2344,6 +2407,16 @@ var init_agent_start_schema = __esm({
2344
2407
  route: jsonTolerant(
2345
2408
  z.object({ gateway: z.string().min(1), baseUrl: z.string().url().optional() })
2346
2409
  ).optional().describe("Billing route/gateway. Independent of `model` and `access`."),
2410
+ inference: jsonTolerant(
2411
+ z.object({
2412
+ 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.'),
2413
+ model: z.string().min(1).optional().describe('A bare model id (paired with `endpoint`), or the shorthand "<model>@<device|endpoint>" when `endpoint` is omitted.'),
2414
+ force: mcpBool.optional().describe("Skip the fit-check refusal on a clear miss (the check still runs and still warns)."),
2415
+ 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.")
2416
+ })
2417
+ ).optional().describe(
2418
+ `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")}`
2419
+ ),
2347
2420
  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."),
2348
2421
  posture: z.string().optional().describe("Canonical agent posture (plan, bypass, accept-edits, read-only) or native harness mode."),
2349
2422
  contextProfile: z.string().optional().describe("Context intake profile (for example full or lean)."),
@@ -2482,40 +2555,6 @@ var init_agent_start_schema = __esm({
2482
2555
  agentStartInputSchema.omit({ wait: true });
2483
2556
  }
2484
2557
  });
2485
- var effortSchema, postureSchema, routeSchema, userPresetSchema;
2486
- var init_user_presets = __esm({
2487
- "src/user-presets.ts"() {
2488
- effortSchema = z.enum(["low", "medium", "high", "xhigh", "max", "ultracode"]);
2489
- postureSchema = z.union([
2490
- z.enum(["default", "plan", "accept-edits", "bypass", "read-only"]),
2491
- z.object({ harnessModeId: z.string().min(1) })
2492
- ]);
2493
- routeSchema = z.object({
2494
- gateway: z.string().min(1),
2495
- baseUrl: z.string().url().optional()
2496
- });
2497
- userPresetSchema = z.object({
2498
- id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/),
2499
- label: z.string().min(1),
2500
- adapter: z.string().min(1).optional(),
2501
- harness: z.string().min(1).optional(),
2502
- model: z.string().min(1).optional(),
2503
- route: routeSchema.optional(),
2504
- access: z.object({ profileRef: z.string().min(1).optional() }).optional(),
2505
- posture: postureSchema.optional(),
2506
- effort: effortSchema.optional(),
2507
- contextProfile: z.string().min(1).optional(),
2508
- cwd: z.string().min(1).optional(),
2509
- skills: z.array(z.string().min(1)).optional(),
2510
- bundles: z.array(z.string().min(1)).optional(),
2511
- browser: z.union([z.literal("headless"), z.literal(false)]).optional()
2512
- });
2513
- z.object({
2514
- version: z.literal(1),
2515
- presets: z.array(userPresetSchema)
2516
- });
2517
- }
2518
- });
2519
2558
  var init_catalog_provider_models = __esm({
2520
2559
  "src/catalog-provider-models.ts"() {
2521
2560
  }
@@ -2555,6 +2594,7 @@ var init_agent_tools = __esm({
2555
2594
  "src/agent-tools.ts"() {
2556
2595
  init_transcript_export();
2557
2596
  init_agent_start_schema();
2597
+ init_process_stats();
2558
2598
  init_spawn_field_schemas();
2559
2599
  init_session_spawn();
2560
2600
  init_canonical_posture();
@@ -2645,6 +2685,7 @@ var init_context_checkpoint = __esm({
2645
2685
  // src/session-continue-fresh.ts
2646
2686
  var init_session_continue_fresh = __esm({
2647
2687
  "src/session-continue-fresh.ts"() {
2688
+ init_app_boundary();
2648
2689
  init_context_checkpoint();
2649
2690
  init_context_continuity();
2650
2691
  init_session_spawn();
@@ -2705,6 +2746,21 @@ var init_gh_provenance_shim = __esm({
2705
2746
  DEFAULT_WRAP_GH = false;
2706
2747
  }
2707
2748
  });
2749
+ var DEFAULT_MODEL_ROLES;
2750
+ var init_model_roles = __esm({
2751
+ "src/model-roles.ts"() {
2752
+ DEFAULT_MODEL_ROLES = {
2753
+ /** Reviewer for a small residual (repo-maintenance `review` step). */
2754
+ "review.small": "claude-sonnet-5-5",
2755
+ /** Reviewer for a large residual + the retry reviewer. */
2756
+ "review.large": "claude-opus-5-5",
2757
+ /** CI pull-request reviewer (mirrors `.github/agentic-review.json`'s `reviewerModel`). */
2758
+ "review.pr": "openrouter/z-ai/glm-5.3-flash",
2759
+ /** The session-steward's agent judge. */
2760
+ "judge.session": "claude-sonnet-5-5"
2761
+ };
2762
+ }
2763
+ });
2708
2764
  function validateConfig(raw) {
2709
2765
  const result = agentprotoConfigSchema.safeParse(raw);
2710
2766
  if (result.success) return { ok: true, issues: [] };
@@ -2714,7 +2770,7 @@ function validateConfig(raw) {
2714
2770
  });
2715
2771
  return { ok: false, issues };
2716
2772
  }
2717
- 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;
2773
+ 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;
2718
2774
  var init_config_schema = __esm({
2719
2775
  "src/config-schema.ts"() {
2720
2776
  init_worktree_isolation();
@@ -2724,6 +2780,7 @@ var init_config_schema = __esm({
2724
2780
  init_gh_provenance_shim();
2725
2781
  init_agents_md();
2726
2782
  init_session_titler();
2783
+ init_model_roles();
2727
2784
  init_background_task_wake();
2728
2785
  init_role();
2729
2786
  contextContinuityPolicySchema = z.object({
@@ -2809,6 +2866,9 @@ var init_config_schema = __esm({
2809
2866
  enabled: z.boolean().optional(),
2810
2867
  model: z.string().optional()
2811
2868
  }).passthrough();
2869
+ catalogConfigSchema = z.object({
2870
+ sources: z.array(z.object({ url: z.string() }).passthrough()).optional()
2871
+ }).passthrough();
2812
2872
  tunnelConfigSchema = z.object({
2813
2873
  host: z.string().optional(),
2814
2874
  token: z.string().optional(),
@@ -2818,17 +2878,22 @@ var init_config_schema = __esm({
2818
2878
  featuresConfigSchema = z.object({
2819
2879
  pty: z.boolean().optional(),
2820
2880
  llmEndpoint: z.boolean().optional(),
2821
- deviceInferenceShare: z.boolean().optional()
2881
+ deviceInferenceShare: z.boolean().optional(),
2882
+ deviceSpawnAllow: z.boolean().optional()
2822
2883
  }).passthrough();
2823
2884
  worktreesConfigSchema = z.object({
2824
2885
  root: z.string().optional(),
2825
- isolation: z.enum(["always", "on-request", "never"]).optional()
2886
+ isolation: z.enum(["always", "on-request", "never"]).optional(),
2887
+ provisionConcurrency: z.number().int().min(0).optional(),
2888
+ provisionConcurrencyByRepo: z.record(z.string(), z.number().int().min(0)).optional(),
2889
+ provisionLoadFactor: z.number().min(0).optional()
2826
2890
  }).passthrough();
2827
2891
  spawnConfigSchema = z.object({
2828
2892
  attach: z.enum(["always", "on-request"]).optional(),
2829
2893
  dedupe: z.enum(["always", "on-request"]).optional()
2830
2894
  }).passthrough();
2831
2895
  provenanceConfigSchema = z.object({ wrapGh: z.boolean().optional() }).passthrough();
2896
+ approvalsConfigSchema = z.object({ webOrigins: z.array(z.string()).optional() }).passthrough();
2832
2897
  sessionsConfigSchema = z.object({
2833
2898
  attentionDelaySec: z.number().optional(),
2834
2899
  eventsDir: z.string().optional()
@@ -2846,6 +2911,14 @@ var init_config_schema = __esm({
2846
2911
  autoconnect: z.boolean().optional(),
2847
2912
  pairPage: pairPageSchema.optional()
2848
2913
  }).passthrough();
2914
+ modelRoleValueSchema = z.union([
2915
+ z.string().min(1),
2916
+ z.object({
2917
+ model: z.string().min(1),
2918
+ route: z.string().optional(),
2919
+ profile: z.string().optional()
2920
+ }).passthrough()
2921
+ ]);
2849
2922
  profileConfigSchema = z.object({
2850
2923
  daemon: daemonConfigSchema.optional(),
2851
2924
  tunnel: tunnelConfigSchema.optional(),
@@ -2884,8 +2957,11 @@ var init_config_schema = __esm({
2884
2957
  spawn: spawnConfigSchema.optional(),
2885
2958
  sessions: sessionsConfigSchema.optional(),
2886
2959
  provenance: provenanceConfigSchema.optional(),
2960
+ approvals: approvalsConfigSchema.optional(),
2887
2961
  agentsMd: agentsMdConfigSchema.optional(),
2962
+ models: z.record(z.string(), modelRoleValueSchema).optional(),
2888
2963
  titler: titlerConfigSchema.optional(),
2964
+ catalog: catalogConfigSchema.optional(),
2889
2965
  profiles: z.record(z.string(), profileConfigSchema).optional(),
2890
2966
  activeProfile: z.string().optional(),
2891
2967
  defaults: spawnDefaultsConfigSchema.optional(),
@@ -2936,6 +3012,16 @@ var init_config_schema = __esm({
2936
3012
  label: "Allowed origins",
2937
3013
  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."
2938
3014
  },
3015
+ {
3016
+ path: "approvals.webOrigins",
3017
+ schema: strArray,
3018
+ apply: "restart",
3019
+ writable: false,
3020
+ section: "daemon",
3021
+ label: "Approval web-click origins",
3022
+ 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.",
3023
+ default: []
3024
+ },
2939
3025
  {
2940
3026
  path: "daemon.strictOrigins",
2941
3027
  schema: bool,
@@ -3129,6 +3215,20 @@ var init_config_schema = __esm({
3129
3215
  default: DEFAULT_PAIR_PAGE
3130
3216
  },
3131
3217
  // ── models ──
3218
+ {
3219
+ // One row per configured role. Role names are dotted (`review.pr`), so a
3220
+ // concrete key is `models.review.pr` — `findConfigKey` maps any
3221
+ // `models.<role>` onto this entry, and `splitConfigPath` (config.ts) keeps
3222
+ // the role as ONE segment. The full role list (incl. built-in defaults and
3223
+ // where each value comes from) is the `model_roles` tool.
3224
+ path: "models.*",
3225
+ schema: modelRoleValueSchema,
3226
+ apply: "hot",
3227
+ writable: true,
3228
+ section: "models",
3229
+ label: "Model role",
3230
+ 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(", ")}.`
3231
+ },
3132
3232
  {
3133
3233
  path: "titler.model",
3134
3234
  schema: str,
@@ -3139,6 +3239,16 @@ var init_config_schema = __esm({
3139
3239
  help: "OpenRouter model id used to generate session titles. Requires OPENROUTER_API_KEY.",
3140
3240
  default: DEFAULT_TITLER_MODEL
3141
3241
  },
3242
+ // ── daemon: app catalog ──
3243
+ {
3244
+ path: "catalog.sources",
3245
+ schema: z.array(z.object({ url: str }).passthrough()),
3246
+ apply: "hot",
3247
+ writable: true,
3248
+ section: "daemon",
3249
+ label: "App catalog sources",
3250
+ 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."
3251
+ },
3142
3252
  // ── defaults: spawn ──
3143
3253
  {
3144
3254
  path: "defaults.skills",
@@ -3218,6 +3328,36 @@ var init_config_schema = __esm({
3218
3328
  help: "Whether a freshly-spawned agent_start session is isolated into its own git worktree.",
3219
3329
  default: DEFAULT_WORKTREE_ISOLATION
3220
3330
  },
3331
+ {
3332
+ path: "worktrees.provisionConcurrency",
3333
+ schema: z.number().int().min(0),
3334
+ apply: "hot",
3335
+ env: WORKTREE_PROVISION_CONCURRENCY_ENV,
3336
+ writable: true,
3337
+ section: "defaults",
3338
+ label: "Worktree provisioning concurrency",
3339
+ help: "Max worktree provisionings running their heavy phases (depsCmd, clones, setup hooks) at once; the rest queue FIFO. 0 = unlimited.",
3340
+ default: DEFAULT_WORKTREE_PROVISION_CONCURRENCY
3341
+ },
3342
+ {
3343
+ path: "worktrees.provisionConcurrencyByRepo",
3344
+ schema: z.record(str, z.number().int().min(0)),
3345
+ apply: "hot",
3346
+ writable: true,
3347
+ section: "defaults",
3348
+ label: "Per-repo provisioning concurrency",
3349
+ help: "Per-repo caps on concurrent heavy provisioning, keyed by repo path or directory name; never looser than the global cap."
3350
+ },
3351
+ {
3352
+ path: "worktrees.provisionLoadFactor",
3353
+ schema: z.number().min(0),
3354
+ apply: "hot",
3355
+ writable: true,
3356
+ section: "defaults",
3357
+ label: "Provisioning load guard factor",
3358
+ help: "Hold back a new heavy provisioning while the 1-minute load average exceeds cores x this factor. 0 or unset = off.",
3359
+ default: 0
3360
+ },
3221
3361
  {
3222
3362
  path: "spawn.attach",
3223
3363
  schema: z.enum(["always", "on-request"]),
@@ -3665,6 +3805,16 @@ var init_config_schema = __esm({
3665
3805
  label: "Device inference sharing",
3666
3806
  help: "Expose this daemon's local inference endpoint(s) to a paired HOST-scoped controller. Toggle via `agentproto devices share-inference on|off`.",
3667
3807
  default: false
3808
+ },
3809
+ {
3810
+ path: "features.deviceSpawnAllow",
3811
+ schema: bool,
3812
+ apply: "restart",
3813
+ writable: true,
3814
+ section: "daemon",
3815
+ label: "Device spawn allow",
3816
+ 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`.',
3817
+ default: false
3668
3818
  }
3669
3819
  ];
3670
3820
  }