@toddzheng024/dscode-bundle 0.7.27 → 0.7.29

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 (103) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +10 -10
  3. package/bootstrap.mjs +1 -1
  4. package/cordis.patch.yml +433 -46
  5. package/package.json +280 -245
  6. package/plugins/account/index.mjs +178 -0
  7. package/plugins/account/state.mjs +123 -0
  8. package/plugins/auto-review/index.mjs +8 -5
  9. package/plugins/code-review/index.mjs +1 -1
  10. package/plugins/computer-use/index.mjs +37 -0
  11. package/plugins/cordis-config/plain.mjs +31 -0
  12. package/plugins/dscode/index.mjs +1 -1
  13. package/plugins/exec/cli.mjs +1 -1
  14. package/plugins/grok/index.mjs +28 -24
  15. package/plugins/i18n/messages.mjs +204 -0
  16. package/plugins/memory/index.mjs +1 -1
  17. package/plugins/message-source/kind.mjs +20 -0
  18. package/plugins/openrouter/adapter.mjs +29 -13
  19. package/plugins/openrouter/index.mjs +31 -28
  20. package/plugins/session-bridge/communication.mjs +6 -3
  21. package/plugins/session-bridge/server.mjs +3 -2
  22. package/plugins/session-bridge/tasks.mjs +3 -1
  23. package/plugins/session-cards/index.mjs +1 -1
  24. package/plugins/time-marks/index.mjs +3 -2
  25. package/plugins/time-marks/marks.mjs +6 -5
  26. package/plugins/triggers/config.mjs +1 -1
  27. package/plugins/triggers/tools.mjs +1 -1
  28. package/plugins/tui-tools/doctor.mjs +1 -1
  29. package/plugins/tui-tools/index.mjs +16 -4
  30. package/plugins/ultra/policy.mjs +16 -0
  31. package/vendor/bash/index.js +455 -186
  32. package/vendor/bash/types/background.d.ts +38 -7
  33. package/vendor/bash/types/index.d.ts +20 -4
  34. package/vendor/bash/types/render.d.ts +28 -9
  35. package/vendor/command-goal/index.js +3 -1
  36. package/vendor/deepseek/index.js +1378 -1246
  37. package/vendor/deepseek/types/adapter.d.ts +16 -155
  38. package/vendor/deepseek/types/config.d.ts +127 -0
  39. package/vendor/deepseek/types/defaults.d.ts +24 -0
  40. package/vendor/deepseek/types/file-store.d.ts +5 -3
  41. package/vendor/deepseek/types/files-api.d.ts +12 -9
  42. package/vendor/deepseek/types/image-tokens.d.ts +24 -9
  43. package/vendor/deepseek/types/images.d.ts +35 -0
  44. package/vendor/deepseek/types/index.d.ts +10 -94
  45. package/vendor/deepseek/types/messages-api.d.ts +10 -0
  46. package/vendor/deepseek/types/model-info.d.ts +16 -0
  47. package/vendor/deepseek/types/models.d.ts +4 -0
  48. package/vendor/deepseek/types/replay.d.ts +27 -0
  49. package/vendor/deepseek/types/request-extensions.d.ts +16 -0
  50. package/vendor/deepseek/types/request-files.d.ts +49 -0
  51. package/vendor/deepseek/types/request-pricing.d.ts +32 -20
  52. package/vendor/deepseek/types/serialize.d.ts +17 -82
  53. package/vendor/deepseek/types/sse.d.ts +6 -22
  54. package/vendor/deepseek/types/translate.d.ts +13 -36
  55. package/vendor/deepseek/types/transport.d.ts +15 -0
  56. package/vendor/deepseek/types/types.d.ts +106 -167
  57. package/vendor/deepseek/types/wire-types.d.ts +62 -0
  58. package/vendor/persistent/index.js +9 -3
  59. package/vendor/subagent/index.js +11 -8
  60. package/vendor/subagent/model-selection-settings.js +12 -38
  61. package/vendor/subagent/types/index.d.ts +4 -3
  62. package/vendor/subagent/types/model-selection-settings.d.ts +12 -10
  63. package/vendor/subagent-core/index.js +401 -264
  64. package/vendor/subagent-core/typert.host.js +103 -113
  65. package/vendor/subagent-core/typert.remote-client.d.ts +1 -3
  66. package/vendor/subagent-core/typert.remote-client.js +23 -69
  67. package/vendor/subagent-core/types/archive-admission.d.ts +16 -0
  68. package/vendor/subagent-core/types/archive-admission.js +151 -0
  69. package/vendor/subagent-core/types/assistant-output.d.ts +2 -2
  70. package/vendor/subagent-core/types/catalog.d.ts +17 -10
  71. package/vendor/subagent-core/types/catalog.js +12 -6
  72. package/vendor/subagent-core/types/child-agent.d.ts +8 -5
  73. package/vendor/subagent-core/types/child-agent.js +11 -5
  74. package/vendor/subagent-core/types/continuation-activation.d.ts +17 -1
  75. package/vendor/subagent-core/types/continuation-activation.js +41 -4
  76. package/vendor/subagent-core/types/continuation-messages.d.ts +1 -1
  77. package/vendor/subagent-core/types/continuation-messages.js +7 -3
  78. package/vendor/subagent-core/types/continuation.d.ts +1 -1
  79. package/vendor/subagent-core/types/continuation.js +2 -2
  80. package/vendor/subagent-core/types/control-types.d.ts +29 -36
  81. package/vendor/subagent-core/types/control-types.js +2 -3
  82. package/vendor/subagent-core/types/control.d.ts +2 -28
  83. package/vendor/subagent-core/types/control.js +3 -40
  84. package/vendor/subagent-core/types/index.d.ts +45 -41
  85. package/vendor/subagent-core/types/index.js +46 -82
  86. package/vendor/subagent-core/types/internal.d.ts +2 -2
  87. package/vendor/subagent-core/types/internal.js +2 -2
  88. package/vendor/subagent-core/types/lifecycle.d.ts +1 -1
  89. package/vendor/subagent-core/types/lifecycle.js +5 -3
  90. package/vendor/subagent-core/types/list-children.d.ts +15 -32
  91. package/vendor/subagent-core/types/list-children.js +45 -49
  92. package/vendor/subagent-core/types/out-of-process.d.ts +1 -1
  93. package/vendor/subagent-core/types/projection-types.d.ts +9 -1
  94. package/vendor/subagent-core/types/projection.d.ts +5 -0
  95. package/vendor/subagent-core/types/projection.js +10 -4
  96. package/vendor/subagent-core/types/run-settlement.js +1 -1
  97. package/vendor/subagent-core/types/types.d.ts +2 -2
  98. package/vendor/terminal/index.js +94 -30
  99. package/vendor/tui/lib/index.mjs +2 -1
  100. package/vendor/tui/lib/kernel-panels.mjs +1 -1
  101. package/vendor/tui/lib/render/projection.mjs +50 -36
  102. package/presets/dscode/agent.cordis.yml +0 -321
  103. package/presets/dscode/preset.yml +0 -3
@@ -1,10 +1,11 @@
1
1
  // dscode-child-cwd-v1
2
+ import z from "@deepseek-ai/schemastery";
2
3
  import { scopeTarget } from "@deepseek-ai/dsh-scope";
3
4
  import { assertObjectJsonSchema } from "@deepseek-ai/dsh-tools";
4
5
  import { canonicalClientTimeZone } from "@deepseek-ai/dsh-util-time";
5
6
  import { Remote, RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
6
7
  import { AttachmentError } from "@deepseek-ai/dsh-attachment";
7
- import { z } from "zod";
8
+ import { z as z$1 } from "zod";
8
9
  import { HarnessError, ReasoningEffortId, boundContextSummary, contentHasImage, createUserMessage, errorChain, joinAssistantStreamText } from "@deepseek-ai/dsh-llm";
9
10
  import { randomUUID } from "node:crypto";
10
11
  import { foldConsumedWork } from "@deepseek-ai/dsh-agent";
@@ -30,25 +31,23 @@ var SubagentError = class extends HarnessError {
30
31
  //#endregion
31
32
  //#region lib/types/control.js
32
33
  /**
33
- * Browser-facing subagent control assembly: the catalog view sampled against
34
- * the live Agent registry, one browser zone's validation, and the stable
35
- * failure codes the Remote surface answers with.
34
+ * Browser-facing subagent prompt and interrupt request validation plus the
35
+ * stable prompt failure codes returned by the Remote surface.
36
36
  *
37
37
  * @module @deepseek-ai/dsh-subagent
38
38
  */
39
- const SESSION_ID_SCHEMA = z.string().min(1);
39
+ const SESSION_ID_SCHEMA = z$1.string().min(1);
40
40
  const CONTROL_ID_SCHEMAS = {
41
- "subagent.list": z.object({ parentSessionId: SESSION_ID_SCHEMA }),
42
- "subagent.prompt": z.object({
41
+ "subagent.prompt": z$1.object({
43
42
  parentSessionId: SESSION_ID_SCHEMA,
44
43
  childSessionId: SESSION_ID_SCHEMA,
45
- mode: z.literal("continuable"),
46
- delivery: z.enum(["queue", "steer"])
44
+ mode: z$1.literal("continuable"),
45
+ delivery: z$1.enum(["queue", "steer"])
47
46
  }),
48
- "subagent.interrupt": z.object({
47
+ "subagent.interrupt": z$1.object({
49
48
  parentSessionId: SESSION_ID_SCHEMA,
50
49
  childSessionId: SESSION_ID_SCHEMA,
51
- mode: z.literal("continuable")
50
+ mode: z$1.literal("continuable")
52
51
  })
53
52
  };
54
53
  /**
@@ -63,39 +62,6 @@ function validateControlRequest(method, payload) {
63
62
  if (!parsed.success) throw new RemoteError("gateway/bad-request", `invalid payload for ${method}`, { issues: parsed.error.issues });
64
63
  }
65
64
  /**
66
- * Project one durable listing onto the catalog view, replacing each row's
67
- * store-derived activity with the live Agent driver's status and reporting
68
- * whether the exact parent Agent is live. Without an Agent registry no driver
69
- * runs at all, so every row is inactive and the parent is unavailable.
70
- * @param ctx - Host context that may carry the Agent registry.
71
- * @param parentSessionId - the listed parent.
72
- * @param entries - the durable direct-child listing.
73
- * @returns the catalog view answered to one browser.
74
- */
75
- function catalogView(ctx, parentSessionId, entries) {
76
- const agents = ctx.get("agents");
77
- return {
78
- entries: entries.map((entry) => entry.kind === "child" ? {
79
- ...entry,
80
- activity: agents?.get(entry.id)?.status === "running" ? "running" : "inactive"
81
- } : entry),
82
- parentAvailable: agents?.get(parentSessionId) !== void 0
83
- };
84
- }
85
- /**
86
- * Refuse one catalog read while preserving cancellation and a missing
87
- * projections registry as distinct failures.
88
- * @param error - the thrown value.
89
- * @param signal - the caller's cancellation.
90
- * @returns Never — the refusal is thrown.
91
- * @throws {RemoteError} always.
92
- */
93
- function rejectCatalogRead(error, signal) {
94
- if (isCancellation(error, signal)) throw new RemoteError("gateway/cancelled", "subagent catalog read was cancelled", {}, { cause: error });
95
- if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") throw new RemoteError("subagent/projections-unavailable", "subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", {}, { cause: error });
96
- throw new RemoteError("gateway/internal", "subagent catalog read failed", {}, { cause: error });
97
- }
98
- /**
99
65
  * Refuse one continuation prompt without exposing provider detail: admission
100
66
  * failures the caller can act on keep their own code, everything else is
101
67
  * internal.
@@ -114,6 +80,7 @@ function rejectPrompt(error, childSessionId, signal) {
114
80
  case "UNAUTHORIZED": throw new RemoteError("subagent/unauthorized", "subagent does not belong to this parent", { childSessionId }, { cause: error });
115
81
  case "DRAINING":
116
82
  case "ACTIVATION_CLOSING":
83
+ case "ACTIVATION_LIMIT_REACHED":
117
84
  case "CONTINUATION_UNAVAILABLE":
118
85
  case "PERSISTENCE_UNAVAILABLE": throw new RemoteError("subagent/delivery-unavailable", "subagent follow-up is temporarily unavailable", { childSessionId }, { cause: error });
119
86
  default: break;
@@ -384,9 +351,10 @@ function epochStopReason(events) {
384
351
  case "blocked": return "refusal";
385
352
  case void 0:
386
353
  case "completed": return droppedUnrun ? "aborted" : "completed";
387
- /* v8 ignore next 3 -- `TurnEndReason` is merge-extensible, so this arm needs a
388
- * backend that adds a variant; treating an unnameable reason as success would
389
- * report failed work as completed. */
354
+ /* v8 ignore next 4 -- `forked` appears only in constructor seed history, while
355
+ * this function reads an epoch-owned suffix. `TurnEndReason` is merge-extensible,
356
+ * so a backend-added variant cannot be listed; treating an unnameable reason as
357
+ * success would report failed work as completed. */
390
358
  default: return "error";
391
359
  }
392
360
  }
@@ -555,17 +523,20 @@ function applyChildComposition(childCtx, parent, composition) {
555
523
  if (composition.toolFilter !== void 0) childCtx.tools.restrict(composition.toolFilter);
556
524
  }
557
525
  /**
558
- * Capture the policy to seed into one delegation. Call synchronously before
526
+ * Capture the permission state to seed into one delegation. Call synchronously before
559
527
  * the child start's first await: a later parent switch belongs to the
560
- * parent's future, not to this child. Only the parent session's explicit
561
- * sandbox override is captured never deployment defaults or one-shot
562
- * grants and the approval policy is pinned to `'never'` regardless of the
563
- * parent's own policy.
528
+ * parent's future, not to this child. Auto and Full access identities are
529
+ * inherited only through the in-process DSH path so either can replace a stale
530
+ * same-bundle fork value. Only the parent session's explicit sandbox override
531
+ * is captured — never deployment defaults or one-shot grants — and the approval
532
+ * policy is pinned to `'never'` regardless of the parent's own policy.
564
533
  * @param parent - the delegating parent agent.
565
534
  * @returns the sandbox override (or `undefined` without one) and the approval pin.
566
535
  */
567
536
  function captureDelegatedPolicyOverrides(parent) {
537
+ const preset = parent.ctx.get("permissionPresets")?.current(parent.session);
568
538
  return {
539
+ permissionPreset: preset === "auto" || preset === "danger-full-access" ? preset : void 0,
569
540
  sandboxMode: parent.ctx.get("sandboxPolicy")?.overrideOf(parent.session),
570
541
  approvalPolicy: parent.ctx.get("approval") === void 0 ? void 0 : "never"
571
542
  };
@@ -588,6 +559,7 @@ function appendDelegatedPolicyOverrides(childSession, overrides) {
588
559
  policy: overrides.approvalPolicy,
589
560
  source: "delegation"
590
561
  });
562
+ if (overrides.permissionPreset !== void 0) childSession.append("permission/preset", { preset: overrides.permissionPreset });
591
563
  }
592
564
  //#endregion
593
565
  //#region lib/types/continuation-messages.js
@@ -654,24 +626,25 @@ function settlementSummary(childId, stopReason) {
654
626
  }
655
627
  }
656
628
  /**
657
- * Build the runtime-owned settlement notice delivered to a child's parent.
629
+ * Build the runtime-owned settlement notice from the child's nonempty closing text.
658
630
  * @param childId - durable child session id named in the notice.
659
631
  * @param terminal - recorded terminal state for the settled Activation.
660
632
  * @returns the durable user-message representation delivered to the parent.
661
633
  */
662
634
  function createSettlementMessage(childId, terminal) {
663
635
  const summary = settlementSummary(childId, terminal.stopReason);
636
+ const closingText = (terminal.output ?? []).flatMap((block) => block.type === "text" && block.text.length > 0 ? [block] : []);
664
637
  return createUserMessage({
665
638
  content: [{
666
639
  type: "text",
667
640
  text: summary
668
- }, ...terminal.output === void 0 ? [{
641
+ }, ...closingText.length === 0 ? [{
669
642
  type: "text",
670
643
  text: "It left no closing message."
671
644
  }] : [{
672
645
  type: "text",
673
646
  text: "Its closing message:"
674
- }, ...terminal.output]],
647
+ }, ...closingText]],
675
648
  source: {
676
649
  kind: "subagent-settled",
677
650
  form: "notice",
@@ -748,6 +721,19 @@ var SubagentInbox = class {
748
721
  *
749
722
  * @module @deepseek-ai/dsh-subagent/continuation-activation
750
723
  */
724
+ /** Process-local slots shared through uninterrupted continuable parent links. */
725
+ var ActivationPool = class {
726
+ slots = /* @__PURE__ */ new Set();
727
+ /** Reserve before reconstruction; the returned release also tolerates unpublished rollback. */
728
+ reserve(capacity) {
729
+ if (this.slots.size >= capacity) throw new SubagentError(`subagent limit reached (active child limit: ${capacity}); wait for an existing child to finish or complete this work with the current agents`, "ACTIVATION_LIMIT_REACHED");
730
+ const slot = Symbol();
731
+ this.slots.add(slot);
732
+ return () => {
733
+ this.slots.delete(slot);
734
+ };
735
+ }
736
+ };
751
737
  /** Serialize each durable child's delivery, release, and disposal. */
752
738
  var ChildLock = class {
753
739
  tails = /* @__PURE__ */ new Map();
@@ -771,8 +757,11 @@ var ChildLock = class {
771
757
  var ContinuableActivationRegistry = class {
772
758
  ctx;
773
759
  observeActivation;
760
+ maxActiveSubagents;
774
761
  /** Child session id → its live Activation. Process-local, never durable. */
775
762
  resident = /* @__PURE__ */ new Map();
763
+ /** Root identities retain their pool across child settlement without retaining dead roots. */
764
+ rootPools = /* @__PURE__ */ new WeakMap();
776
765
  /** Materializations admitted before drain, tracked through publication or rollback. */
777
766
  materializations = /* @__PURE__ */ new Set();
778
767
  /** Per-child serializer shared by delivery, release, and disposal. */
@@ -792,9 +781,10 @@ var ContinuableActivationRegistry = class {
792
781
  * @param ctx - context providing Agents, Sessions, and teardown ownership.
793
782
  * @param observeActivation - build the lifecycle observer for one residency epoch.
794
783
  */
795
- constructor(ctx, observeActivation) {
784
+ constructor(ctx, observeActivation, maxActiveSubagents) {
796
785
  this.ctx = ctx;
797
786
  this.observeActivation = observeActivation;
787
+ this.maxActiveSubagents = maxActiveSubagents;
798
788
  const scope = ctx.plugin(function activationOwner() {});
799
789
  this.ownerCtx = scope.ctx;
800
790
  ctx.on("agent/disposed", ({ agent }) => {
@@ -975,14 +965,20 @@ var ContinuableActivationRegistry = class {
975
965
  */
976
966
  materialize(inputs) {
977
967
  this.assertAdmitting(inputs.parent);
978
- const settled = Promise.withResolvers();
968
+ inputs.signal.throwIfAborted();
979
969
  const lineage = this.liveLineage(inputs.parent);
970
+ const pool = this.resident.get(inputs.parent.id)?.pool ?? this.rootPool(inputs.parent);
971
+ const releaseSlot = pool.reserve(this.maxActiveSubagents());
972
+ const settled = Promise.withResolvers();
980
973
  const materialization = {
981
974
  lineage,
982
975
  settled: settled.promise
983
976
  };
984
977
  this.materializations.add(materialization);
985
- return this.materializeTracked(inputs, lineage).finally(() => {
978
+ return this.materializeTracked(inputs, lineage, pool, releaseSlot).catch((error) => {
979
+ releaseSlot();
980
+ throw error;
981
+ }).finally(() => {
986
982
  this.materializations.delete(materialization);
987
983
  settled.resolve();
988
984
  });
@@ -1057,8 +1053,17 @@ var ContinuableActivationRegistry = class {
1057
1053
  const lineage = this.liveLineage(agent);
1058
1054
  for (const [root, members] of this.closingScopes) if (members.has(agent) || lineage.includes(root)) return root;
1059
1055
  }
1056
+ /** Resolve a root's pool once; descendants inherit their resident parent's pool directly. */
1057
+ rootPool(parent) {
1058
+ let pool = this.rootPools.get(parent);
1059
+ if (pool === void 0) {
1060
+ pool = new ActivationPool();
1061
+ this.rootPools.set(parent, pool);
1062
+ }
1063
+ return pool;
1064
+ }
1060
1065
  /** Perform one tracked materialization through publication or rollback. */
1061
- async materializeTracked(inputs, parentLineage) {
1066
+ async materializeTracked(inputs, parentLineage, pool, releaseSlot) {
1062
1067
  const { childId, provider, parent, create } = inputs;
1063
1068
  inputs.signal.throwIfAborted();
1064
1069
  const setup = (childCtx, child) => {
@@ -1086,6 +1091,8 @@ var ContinuableActivationRegistry = class {
1086
1091
  setup
1087
1092
  });
1088
1093
  const activation = {
1094
+ pool,
1095
+ releaseSlot,
1089
1096
  childId,
1090
1097
  parentSession: parent.id,
1091
1098
  provider,
@@ -1124,6 +1131,7 @@ var ContinuableActivationRegistry = class {
1124
1131
  await activation.handle.dispose();
1125
1132
  } finally {
1126
1133
  this.resident.delete(activation.childId);
1134
+ activation.releaseSlot();
1127
1135
  this.releaseOwnership(activation.childId);
1128
1136
  }
1129
1137
  });
@@ -1237,6 +1245,7 @@ var ContinuableActivationRegistry = class {
1237
1245
  if (failures.length === 1) failure = failures[0];
1238
1246
  else if (failures.length > 1) failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + failures.map((item) => errorChain(item)).join("; "), "ACTIVATION_TEARDOWN_FAILED", { cause: new AggregateError(failures) });
1239
1247
  this.resident.delete(childId);
1248
+ activation.releaseSlot();
1240
1249
  this.notifySettlement(activation, activation.observer.terminal(failure));
1241
1250
  this.releaseOwnership(childId);
1242
1251
  activation.observer.settle(failure);
@@ -1428,49 +1437,68 @@ function foldSubagentDescriptor(events) {
1428
1437
  if (event === void 0) return void 0;
1429
1438
  return parseSubagentDescriptor(event.data);
1430
1439
  }
1431
- const sessionIdSchema = z.string();
1432
- const oneShotCatalogSchema = z.object({
1433
- version: z.literal(0),
1440
+ const sessionIdSchema = z$1.string();
1441
+ const oneShotCatalogSchema = z$1.object({
1442
+ version: z$1.union([z$1.literal(0), z$1.literal(1)]),
1434
1443
  childId: sessionIdSchema,
1435
- childCreatedAt: z.number().int().nonnegative(),
1436
- mode: z.literal("one-shot"),
1437
- label: z.string().optional()
1444
+ childCreatedAt: z$1.number().int().nonnegative(),
1445
+ mode: z$1.literal("one-shot"),
1446
+ label: z$1.string().optional()
1438
1447
  }).strict();
1439
- const continuableCatalogSchema = z.object({
1440
- version: z.literal(0),
1448
+ const continuableCatalogSchema = z$1.object({
1449
+ version: z$1.union([z$1.literal(0), z$1.literal(1)]),
1441
1450
  childId: sessionIdSchema,
1442
- childCreatedAt: z.number().int().nonnegative(),
1443
- mode: z.literal("continuable"),
1444
- label: z.string()
1451
+ childCreatedAt: z$1.number().int().nonnegative(),
1452
+ mode: z$1.literal("continuable"),
1453
+ label: z$1.string()
1445
1454
  }).strict();
1446
- const eventDataSchema = z.union([oneShotCatalogSchema, continuableCatalogSchema]);
1447
- const viewSchema = z.array(z.union([oneShotCatalogSchema.omit({
1448
- version: true,
1449
- childId: true,
1450
- childCreatedAt: true
1451
- }).extend({
1452
- id: sessionIdSchema,
1453
- createdAt: oneShotCatalogSchema.shape.childCreatedAt
1454
- }), continuableCatalogSchema.omit({
1455
- version: true,
1456
- childId: true,
1457
- childCreatedAt: true
1458
- }).extend({
1459
- id: sessionIdSchema,
1460
- createdAt: continuableCatalogSchema.shape.childCreatedAt
1461
- })]));
1462
- const stateSchema = z.object({
1463
- inheritedEventCount: z.number().int().nonnegative(),
1455
+ const unknownCatalogSchema = oneShotCatalogSchema.extend({
1456
+ version: z$1.literal(1),
1457
+ mode: z$1.literal("unknown")
1458
+ });
1459
+ const eventDataSchema = z$1.union([
1460
+ oneShotCatalogSchema,
1461
+ continuableCatalogSchema,
1462
+ unknownCatalogSchema
1463
+ ]);
1464
+ const viewSchema = z$1.array(z$1.union([
1465
+ oneShotCatalogSchema.omit({
1466
+ version: true,
1467
+ childId: true,
1468
+ childCreatedAt: true
1469
+ }).extend({
1470
+ id: sessionIdSchema,
1471
+ createdAt: oneShotCatalogSchema.shape.childCreatedAt
1472
+ }),
1473
+ continuableCatalogSchema.omit({
1474
+ version: true,
1475
+ childId: true,
1476
+ childCreatedAt: true
1477
+ }).extend({
1478
+ id: sessionIdSchema,
1479
+ createdAt: continuableCatalogSchema.shape.childCreatedAt
1480
+ }),
1481
+ unknownCatalogSchema.omit({
1482
+ version: true,
1483
+ childId: true,
1484
+ childCreatedAt: true
1485
+ }).extend({
1486
+ id: sessionIdSchema,
1487
+ createdAt: unknownCatalogSchema.shape.childCreatedAt
1488
+ })
1489
+ ]));
1490
+ const stateSchema = z$1.object({
1491
+ inheritedEventCount: z$1.number().int().nonnegative(),
1464
1492
  head: chunkedListSchema(eventDataSchema).optional()
1465
1493
  }).strict();
1466
1494
  /**
1467
- * Materialize direct children from their parent's successful creation facts.
1495
+ * Materialize complete and unknown-mode child identities from parent catalog events.
1468
1496
  * @param state - parent catalog fold state.
1469
1497
  * @returns current direct-child rows in parent catalog event order.
1470
1498
  */
1471
1499
  function subagentCatalogEntries(state) {
1472
1500
  const entries = [];
1473
- for (const data of iterateChunkedList(state.head)) entries.push(data.mode === "one-shot" ? {
1501
+ for (const data of iterateChunkedList(state.head)) entries.push(data.mode !== "continuable" ? {
1474
1502
  id: data.childId,
1475
1503
  createdAt: data.childCreatedAt,
1476
1504
  mode: data.mode,
@@ -1495,7 +1523,7 @@ const subagentCatalogProjectionDefinition = {
1495
1523
  head: appendChunkedList(state.head, eventDataSchema.parse(event.data))
1496
1524
  };
1497
1525
  },
1498
- stateVersion: 2,
1526
+ stateVersion: 3,
1499
1527
  wire: {
1500
1528
  viewSchema,
1501
1529
  view: subagentCatalogEntries
@@ -1561,7 +1589,7 @@ const deliverSubagentPrompt = Symbol.for("dsh.subagent.deliverPrompt");
1561
1589
  *
1562
1590
  * @module @deepseek-ai/dsh-subagent
1563
1591
  */
1564
- var __addDisposableResource$1 = function(env, value, async) {
1592
+ var __addDisposableResource$2 = function(env, value, async) {
1565
1593
  if (value !== null && value !== void 0) {
1566
1594
  if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1567
1595
  var dispose, inner;
@@ -1590,7 +1618,7 @@ var __addDisposableResource$1 = function(env, value, async) {
1590
1618
  } else if (async) env.stack.push({ async: true });
1591
1619
  return value;
1592
1620
  };
1593
- var __disposeResources$1 = (function(SuppressedError) {
1621
+ var __disposeResources$2 = (function(SuppressedError) {
1594
1622
  return function(env) {
1595
1623
  function fail(e) {
1596
1624
  env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
@@ -1629,10 +1657,10 @@ var SubagentContinuationManager = class {
1629
1657
  ctx;
1630
1658
  host;
1631
1659
  activations;
1632
- constructor(ctx, host) {
1660
+ constructor(ctx, host, maxActiveSubagents) {
1633
1661
  this.ctx = ctx;
1634
1662
  this.host = host;
1635
- this.activations = new ContinuableActivationRegistry(ctx, (provider, childId, parent) => host.observeActivation(provider, childId, parent));
1663
+ this.activations = new ContinuableActivationRegistry(ctx, (provider, childId, parent) => host.observeActivation(provider, childId, parent), maxActiveSubagents);
1636
1664
  }
1637
1665
  /**
1638
1666
  * Start one continuable background child and resolve at initial inbox acceptance.
@@ -1883,7 +1911,7 @@ var SubagentContinuationManager = class {
1883
1911
  options.signal.throwIfAborted();
1884
1912
  throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error });
1885
1913
  }
1886
- const source = __addDisposableResource$1(env_1, observation, false);
1914
+ const source = __addDisposableResource$2(env_1, observation, false);
1887
1915
  this.activations.assertAdmitting(parent);
1888
1916
  this.activations.authorizeLineage(parent, childId, source.header.parentSession);
1889
1917
  const descriptor = foldSubagentDescriptor(source.events.slice(source.inheritedEventCount));
@@ -1915,7 +1943,7 @@ var SubagentContinuationManager = class {
1915
1943
  env_1.error = e_1;
1916
1944
  env_1.hasError = true;
1917
1945
  } finally {
1918
- __disposeResources$1(env_1);
1946
+ __disposeResources$2(env_1);
1919
1947
  }
1920
1948
  }
1921
1949
  /** Admit a materialized child, commit its creation fact, and release it on failure. */
@@ -1972,24 +2000,15 @@ var SubagentContinuationManager = class {
1972
2000
  //#endregion
1973
2001
  //#region lib/types/list-children.js
1974
2002
  /**
1975
- * Read-only enumeration of durable subagent children and descendant trees
1976
- * through the Session query service. Candidates come from one live-preferred
1977
- * corpus; each child's mode/label is the registered `subagent` projection
1978
- * unit's value, resolved
1979
- * down a three-rung ladder: the registry's watermark cache for a live child,
1980
- * an unseeded durable projection-cache row, and one shared Session observation
1981
- * otherwise. A seeded header deliberately lacks its exact inherited cut, so
1982
- * it takes the body-bearing observation path before classifying an identity.
1983
- * The projection fold is the single classification
1984
- * authority — this module parses no descriptor
1985
- * itself. Absent persistence, enumeration is live-only: a cold child is
1986
- * unreachable for resume anyway, so its absence is capability absence, not an
1987
- * error. The module owns no catalog state and does not consult Activation,
1988
- * Agent-registry, continuation-manager, or provider state.
2003
+ * Direct-child discovery from a parent-owned `subagent/catalog` projection,
2004
+ * plus complete descendant-tree enumeration from the Session corpus. A direct
2005
+ * listing owns one parent observation and reads no child log. Descendant
2006
+ * enumeration retains the complete corpus and the child identity projection
2007
+ * because ordinary Sessions and one-shot children remain traversal nodes.
1989
2008
  *
1990
2009
  * @module @deepseek-ai/dsh-subagent
1991
2010
  */
1992
- var __addDisposableResource = function(env, value, async) {
2011
+ var __addDisposableResource$1 = function(env, value, async) {
1993
2012
  if (value !== null && value !== void 0) {
1994
2013
  if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1995
2014
  var dispose, inner;
@@ -2018,7 +2037,7 @@ var __addDisposableResource = function(env, value, async) {
2018
2037
  } else if (async) env.stack.push({ async: true });
2019
2038
  return value;
2020
2039
  };
2021
- var __disposeResources = (function(SuppressedError) {
2040
+ var __disposeResources$1 = (function(SuppressedError) {
2022
2041
  return function(env) {
2023
2042
  function fail(e) {
2024
2043
  env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
@@ -2054,37 +2073,43 @@ var __disposeResources = (function(SuppressedError) {
2054
2073
  */
2055
2074
  const COLD_READ_CONCURRENCY = 4;
2056
2075
  /**
2057
- * Enumerate one parent's origin-classified direct children from the
2058
- * live-preferred merge of `ctx.sessions` and optional session persistence,
2059
- * serving each identity from the `subagent` projection unit: the registry's
2060
- * watermark snapshot for a live child; for a cold one, a durable
2061
- * projection-cache read for an unseeded lifecycle, else one bounded-concurrency
2062
- * shared Session observation carrying the exact inherited cut.
2063
- * @see SubagentRuntime.listChildren for the public cancellation and failure contract.
2064
- * @param ctx - context carrying the session store, the projection registry,
2065
- * optional persistence, and the optional projection cache.
2066
- * @param parentSessionId - parent session whose direct children are listed.
2067
- * @param signal - caller-owned cancellation observed around every persistence read.
2068
- * @returns children and per-child diagnostics ordered by `createdAt`, then id.
2069
- * @throws {@link SubagentError} when the projection registry or the session
2070
- * store is not mounted, or the caller cancels the listing.
2076
+ * Read one parent's durable catalog through a live-preferred Session observation.
2077
+ * @param ctx - context carrying the Session query service.
2078
+ * @param parentSessionId - parent whose direct children are requested.
2079
+ * @param signal - cancellation forwarded to the Session observation.
2080
+ * @returns direct-child rows in parent catalog event order.
2081
+ * @throws {@link SubagentError} when query or catalog projection is unavailable.
2071
2082
  */
2072
2083
  async function listChildren(ctx, parentSessionId, signal) {
2073
- const listing = await prepareListing(ctx, signal);
2074
- return (await resolveCandidateRows([...listing.corpus.values()].filter((record) => record.header.parentSession === parentSessionId && record.header.origin === "subagent").sort(compareCorpusRecords), listing, signal)).filter((row) => row !== void 0);
2084
+ const env_1 = {
2085
+ stack: [],
2086
+ error: void 0,
2087
+ hasError: false
2088
+ };
2089
+ try {
2090
+ const query = ctx.get("sessionQuery");
2091
+ if (query === void 0) throw new SubagentError("listing subagents requires the sessionQuery service (load @deepseek-ai/dsh-session-query)", "SUBAGENT_CONTROL_QUERY_UNAVAILABLE");
2092
+ const entries = __addDisposableResource$1(env_1, await query.observeSession(parentSessionId, { ...signal === void 0 ? {} : { signal } }), false).projections?.values.subagentCatalog;
2093
+ if (entries === void 0) throw new SubagentError("listing subagents requires the registered subagentCatalog projection", "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE");
2094
+ return entries;
2095
+ } catch (e_1) {
2096
+ env_1.error = e_1;
2097
+ env_1.hasError = true;
2098
+ } finally {
2099
+ __disposeResources$1(env_1);
2100
+ }
2075
2101
  }
2076
2102
  /**
2077
2103
  * Enumerate every session-backed subagent below one root in stable pre-order.
2078
2104
  * Ordinary sessions and one-shot children remain traversal nodes, so a
2079
2105
  * continuable child below either is still discovered. Classification uses the
2080
- * same projection-backed runtime as {@link listChildren}; no Agent is loaded or
2081
- * resumed.
2106
+ * registered child identity projection; no Agent is loaded or resumed.
2082
2107
  * @see SubagentRuntime.listDescendants for the public cancellation and failure contract.
2083
2108
  * @param ctx - context carrying the session store, projection registry, and optional persistence/cache.
2084
2109
  * @param rootSessionId - session whose complete descendant tree is listed.
2085
2110
  * @param signal - caller-owned cancellation observed around every persistence read.
2086
2111
  * @returns interpreted subagents with durable direct-parent and root-relative depth.
2087
- * @throws {@link SubagentError} under the same conditions as {@link listChildren}.
2112
+ * @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
2088
2113
  */
2089
2114
  async function listDescendants(ctx, rootSessionId, signal) {
2090
2115
  const listing = await prepareListing(ctx, signal);
@@ -2220,7 +2245,7 @@ function compareCorpusRecords(a, b) {
2220
2245
  * throw — are final, so they report `corrupt`.
2221
2246
  */
2222
2247
  async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
2223
- const env_1 = {
2248
+ const env_2 = {
2224
2249
  stack: [],
2225
2250
  error: void 0,
2226
2251
  hasError: false
@@ -2230,7 +2255,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
2230
2255
  if (cache !== void 0 && !header.isSeeded) {
2231
2256
  let cached;
2232
2257
  try {
2233
- cached = cache.cachedSnapshot(header, SessionLogOffset(0), ["subagent"])?.values.subagent;
2258
+ cached = cache.cachedSnapshot(header, ["subagent"])?.values.subagent;
2234
2259
  } catch {
2235
2260
  cached = void 0;
2236
2261
  }
@@ -2248,7 +2273,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
2248
2273
  reason: sessionQueryCode(error) === "SESSION_QUERY_CORRUPT_SESSION" || sessionQueryCode(error) === "SESSION_QUERY_SOURCE_CONFLICT" ? "corrupt" : "unavailable"
2249
2274
  };
2250
2275
  }
2251
- const ownedObservation = __addDisposableResource(env_1, observation, false);
2276
+ const ownedObservation = __addDisposableResource$1(env_2, observation, false);
2252
2277
  assertListingNotCancelled(signal);
2253
2278
  if (!sameLifecycle(ownedObservation.header, header)) return {
2254
2279
  kind: "diagnostic",
@@ -2262,11 +2287,11 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
2262
2287
  reason: "corrupt"
2263
2288
  };
2264
2289
  return childRow(childId, identity, "inactive", hasChildren);
2265
- } catch (e_1) {
2266
- env_1.error = e_1;
2267
- env_1.hasError = true;
2290
+ } catch (e_2) {
2291
+ env_2.error = e_2;
2292
+ env_2.hasError = true;
2268
2293
  } finally {
2269
- __disposeResources(env_1);
2294
+ __disposeResources$1(env_2);
2270
2295
  }
2271
2296
  }
2272
2297
  /** Materialize one served identity as its child row. */
@@ -2311,6 +2336,159 @@ function sessionQueryCode(error) {
2311
2336
  return error instanceof Error && "code" in error ? error.code : void 0;
2312
2337
  }
2313
2338
  //#endregion
2339
+ //#region lib/types/archive-admission.js
2340
+ /**
2341
+ * The `subagent` family of the Workspace registry's archive admission: which
2342
+ * subagent descendants of a Session are still inside a turn, and how they
2343
+ * stop when the Session is archived with its work.
2344
+ *
2345
+ * @module @deepseek-ai/dsh-subagent
2346
+ */
2347
+ var __addDisposableResource = function(env, value, async) {
2348
+ if (value !== null && value !== void 0) {
2349
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
2350
+ var dispose, inner;
2351
+ if (async) {
2352
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
2353
+ dispose = value[Symbol.asyncDispose];
2354
+ }
2355
+ if (dispose === void 0) {
2356
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
2357
+ dispose = value[Symbol.dispose];
2358
+ if (async) inner = dispose;
2359
+ }
2360
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
2361
+ if (inner) dispose = function() {
2362
+ try {
2363
+ inner.call(this);
2364
+ } catch (e) {
2365
+ return Promise.reject(e);
2366
+ }
2367
+ };
2368
+ env.stack.push({
2369
+ value,
2370
+ dispose,
2371
+ async
2372
+ });
2373
+ } else if (async) env.stack.push({ async: true });
2374
+ return value;
2375
+ };
2376
+ var __disposeResources = (function(SuppressedError) {
2377
+ return function(env) {
2378
+ function fail(e) {
2379
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
2380
+ env.hasError = true;
2381
+ }
2382
+ var r, s = 0;
2383
+ function next() {
2384
+ while (r = env.stack.pop()) try {
2385
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
2386
+ if (r.dispose) {
2387
+ var result = r.dispose.call(r.value);
2388
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
2389
+ fail(e);
2390
+ return next();
2391
+ });
2392
+ } else s |= 1;
2393
+ } catch (e) {
2394
+ fail(e);
2395
+ }
2396
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
2397
+ if (env.hasError) throw env.error;
2398
+ }
2399
+ return next();
2400
+ };
2401
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
2402
+ var e = new Error(message);
2403
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2404
+ });
2405
+ /**
2406
+ * Answer `workspace/session-activity` with the running subagent descendants of
2407
+ * the asked Session, and `workspace/session-stop` by cancelling each of them
2408
+ * as their parent would. Both listeners live as long as `ctx`'s fiber.
2409
+ * @param ctx - context carrying the Agent registry; the Session query service is optional and only supplies labels.
2410
+ */
2411
+ function installSubagentArchiveAdmission(ctx) {
2412
+ ctx.on("workspace/session-activity", async ({ sessionId }, next) => {
2413
+ const running = runningDescendants(ctx, sessionId);
2414
+ const rest = await next();
2415
+ if (running.length === 0) return rest;
2416
+ return [{
2417
+ kind: "subagent",
2418
+ items: await Promise.all(running.map((child) => describe(ctx, child)))
2419
+ }, ...rest];
2420
+ });
2421
+ ctx.on("workspace/session-stop", ({ sessionId }) => {
2422
+ for (const child of runningDescendants(ctx, sessionId)) try {
2423
+ child.cancel({ kind: "parent" });
2424
+ } catch (error) {
2425
+ ctx.logger.warn(`subagent: cancelling "${child.id}" for an archived Session failed: ${String(error)}`);
2426
+ }
2427
+ });
2428
+ }
2429
+ /**
2430
+ * Live subagent descendants inside a turn, by durable lineage: a child whose
2431
+ * header names its parent and carries the subagent origin this package
2432
+ * records, at any depth. A fork shares the lineage field without the origin
2433
+ * and is an independent conversation, so it never holds its source. Lineage
2434
+ * is read as data, so a damaged header chain that loops is visited once.
2435
+ */
2436
+ function runningDescendants(ctx, rootId) {
2437
+ const childrenOf = /* @__PURE__ */ new Map();
2438
+ for (const agent of ctx.agents.list()) {
2439
+ const { parentSession, origin } = agent.session.header;
2440
+ if (parentSession === void 0 || origin !== "subagent") continue;
2441
+ const siblings = childrenOf.get(parentSession) ?? [];
2442
+ siblings.push(agent);
2443
+ childrenOf.set(parentSession, siblings);
2444
+ }
2445
+ const running = [];
2446
+ const pending = [rootId];
2447
+ const visited = /* @__PURE__ */ new Set();
2448
+ while (pending.length > 0) {
2449
+ const parentId = pending.shift();
2450
+ if (visited.has(parentId)) continue;
2451
+ visited.add(parentId);
2452
+ for (const child of childrenOf.get(parentId) ?? []) {
2453
+ if (child.status === "running") running.push(child);
2454
+ pending.push(child.id);
2455
+ }
2456
+ }
2457
+ return running;
2458
+ }
2459
+ /**
2460
+ * The child's activity item: its id, plus the durable creation label its
2461
+ * descriptor carries, read through a live Session observation. Without the
2462
+ * Session query service, or with a descriptor that is absent or unreadable,
2463
+ * the item names the child by id alone.
2464
+ */
2465
+ async function describe(ctx, child) {
2466
+ const query = ctx.get("sessionQuery");
2467
+ if (query === void 0) return { id: child.id };
2468
+ try {
2469
+ const env_1 = {
2470
+ stack: [],
2471
+ error: void 0,
2472
+ hasError: false
2473
+ };
2474
+ try {
2475
+ const observation = __addDisposableResource(env_1, await query.observeSession(child.id, { projectionMode: "none" }), false);
2476
+ const label = foldSubagentDescriptor(observation.events.slice(observation.inheritedEventCount))?.label;
2477
+ return label === void 0 ? { id: child.id } : {
2478
+ id: child.id,
2479
+ label
2480
+ };
2481
+ } catch (e_1) {
2482
+ env_1.error = e_1;
2483
+ env_1.hasError = true;
2484
+ } finally {
2485
+ __disposeResources(env_1);
2486
+ }
2487
+ } catch {
2488
+ return { id: child.id };
2489
+ }
2490
+ }
2491
+ //#endregion
2314
2492
  //#region lib/types/projection.js
2315
2493
  /**
2316
2494
  * Pure session projections for subagent identity (mode/label) and active-turn
@@ -2318,16 +2496,18 @@ function sessionQueryCode(error) {
2318
2496
  *
2319
2497
  * @module @deepseek-ai/dsh-subagent/projection
2320
2498
  */
2321
- const activeIntervalSchema = z.object({
2322
- since: z.number().int().nonnegative(),
2323
- through: z.number().int().nonnegative()
2499
+ const activeIntervalSchema = z$1.object({
2500
+ since: z$1.number().int().nonnegative(),
2501
+ through: z$1.number().int().nonnegative()
2324
2502
  }).strict();
2325
- const projectionSchema = z.object({
2326
- settledMs: z.number().int().nonnegative(),
2327
- active: activeIntervalSchema.optional()
2328
- }).strict().transform(({ settledMs, active }) => ({
2503
+ const projectionSchema = z$1.object({
2504
+ settledMs: z$1.number().int().nonnegative(),
2505
+ active: activeIntervalSchema.optional(),
2506
+ lastTurnCompleted: z$1.boolean().optional()
2507
+ }).strict().transform(({ settledMs, active, lastTurnCompleted }) => ({
2329
2508
  settledMs,
2330
- ...active === void 0 ? {} : { active }
2509
+ ...active === void 0 ? {} : { active },
2510
+ ...lastTurnCompleted === void 0 ? {} : { lastTurnCompleted }
2331
2511
  }));
2332
2512
  /**
2333
2513
  * Fold turn boundaries around the child's own durable descriptor.
@@ -2339,27 +2519,31 @@ const projectionSchema = z.object({
2339
2519
  */
2340
2520
  const subagentTimingProjectionDefinition = {
2341
2521
  key: "subagentTiming",
2342
- stateSchema: z.object({
2343
- settledMs: z.number().int().nonnegative(),
2522
+ stateSchema: z$1.object({
2523
+ settledMs: z$1.number().int().nonnegative(),
2344
2524
  active: activeIntervalSchema.optional(),
2345
- pendingTurnStart: z.number().int().nonnegative().optional(),
2346
- descriptorSeen: z.boolean()
2525
+ pendingTurnStart: z$1.number().int().nonnegative().optional(),
2526
+ descriptorSeen: z$1.boolean(),
2527
+ lastTurnCompleted: z$1.boolean().optional()
2347
2528
  }).strict(),
2348
2529
  init: () => ({
2349
2530
  descriptorSeen: false,
2350
2531
  settledMs: 0
2351
2532
  }),
2352
2533
  apply: (state, event) => {
2353
- if (event.type === "turn/start") return state.descriptorSeen ? {
2354
- ...state,
2355
- active: {
2356
- since: event.time,
2357
- through: event.time
2358
- }
2359
- } : {
2360
- ...state,
2361
- pendingTurnStart: event.time
2362
- };
2534
+ if (event.type === "turn/start") {
2535
+ const { lastTurnCompleted: _closed, ...openState } = state;
2536
+ return state.descriptorSeen ? {
2537
+ ...openState,
2538
+ active: {
2539
+ since: event.time,
2540
+ through: event.time
2541
+ }
2542
+ } : {
2543
+ ...openState,
2544
+ pendingTurnStart: event.time
2545
+ };
2546
+ }
2363
2547
  if (event.type === "subagent/descriptor") {
2364
2548
  const activeSince = state.active?.since ?? state.pendingTurnStart;
2365
2549
  return {
@@ -2381,7 +2565,8 @@ const subagentTimingProjectionDefinition = {
2381
2565
  const { active, ...rest } = state;
2382
2566
  return {
2383
2567
  ...rest,
2384
- settledMs: state.settledMs + Math.max(0, event.time - active.since)
2568
+ settledMs: state.settledMs + Math.max(0, event.time - active.since),
2569
+ lastTurnCompleted: event.data.reason.kind === "completed"
2385
2570
  };
2386
2571
  }
2387
2572
  if (state.active === void 0) return state;
@@ -2397,22 +2582,23 @@ const subagentTimingProjectionDefinition = {
2397
2582
  viewSchema: projectionSchema,
2398
2583
  view: (state) => ({
2399
2584
  settledMs: state.settledMs,
2400
- ...state.active === void 0 ? {} : { active: state.active }
2585
+ ...state.active === void 0 ? {} : { active: state.active },
2586
+ ...state.lastTurnCompleted === void 0 ? {} : { lastTurnCompleted: state.lastTurnCompleted }
2401
2587
  })
2402
2588
  },
2403
- stateVersion: 2
2589
+ stateVersion: 3
2404
2590
  };
2405
- const identityValueSchema = z.discriminatedUnion("mode", [z.object({
2406
- mode: z.literal("one-shot"),
2407
- label: z.string().optional(),
2408
- seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
2409
- }).strict(), z.object({
2410
- mode: z.literal("continuable"),
2411
- label: z.string(),
2412
- seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
2591
+ const identityValueSchema = z$1.discriminatedUnion("mode", [z$1.object({
2592
+ mode: z$1.literal("one-shot"),
2593
+ label: z$1.string().optional(),
2594
+ seq: z$1.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
2595
+ }).strict(), z$1.object({
2596
+ mode: z$1.literal("continuable"),
2597
+ label: z$1.string(),
2598
+ seq: z$1.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
2413
2599
  }).strict()]);
2414
2600
  const identitySchema = identityValueSchema.nullable();
2415
- const identityStateSchema = z.object({ identity: identityValueSchema.optional() }).strict();
2601
+ const identityStateSchema = z$1.object({ identity: identityValueSchema.optional() }).strict();
2416
2602
  /** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */
2417
2603
  function descriptorIdentity(event) {
2418
2604
  let descriptor;
@@ -2675,7 +2861,7 @@ function runOutcome(result) {
2675
2861
  switch (result.stopReason) {
2676
2862
  case "completed": return {
2677
2863
  status: "completed",
2678
- output: finalText(result.output)
2864
+ result: finalText(result.output)
2679
2865
  };
2680
2866
  case "aborted": return result.diagnostic === void 0 ? { status: "killed" } : {
2681
2867
  status: "failed",
@@ -2721,36 +2907,6 @@ async function settleRun(run) {
2721
2907
  }
2722
2908
  //#endregion
2723
2909
  //#region lib/types/index.js
2724
- /**
2725
- * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a
2726
- * capability-validating asynchronous start API. Providers establish a
2727
- * child before returning its run, so fulfillment is the single publication and
2728
- * ownership-transfer boundary.
2729
- *
2730
- * Multiple providers coexist: each registers under a unique name and callers
2731
- * select one by name.
2732
- *
2733
- * This package owns the Service Definition role of the capability seam. Service Providers
2734
- * (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing
2735
- * consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages.
2736
- *
2737
- * Public operations express caller intent: `start` returns one published owned
2738
- * one-shot run, `startContinuable` establishes a durable continuable child, and
2739
- * `sendMessage` steers between adjacent Agents without exposing whether a child
2740
- * is resident. Continuable children never become a {@link SubagentRun}: the
2741
- * continuation manager holds their `AgentHandle` directly and orders every turn
2742
- * through the child's own inbox, so providers contribute only the detached
2743
- * creation spec and see no handle, turn, or teardown. Child and descendant
2744
- * discovery read the live session store and optional session persistence
2745
- * directly and do not require that continuation runtime.
2746
- *
2747
- * Same-process providers are trusted typed collaborators. Requests, provider
2748
- * descriptors, results, and lifecycle payloads are borrowed immutable values;
2749
- * serialization and hostile-input validation belong at real process, worker,
2750
- * persistence, and model boundaries.
2751
- *
2752
- * @module @deepseek-ai/dsh-subagent
2753
- */
2754
2910
  var __runInitializers = function(thisArg, initializers, value) {
2755
2911
  var useValue = arguments.length > 2;
2756
2912
  for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
@@ -2793,26 +2949,13 @@ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializ
2793
2949
  let SubagentRuntime = (() => {
2794
2950
  let _classSuper = TypertRemoteService;
2795
2951
  let _instanceExtraInitializers = [];
2796
- let _remoteExportList_decorators;
2797
2952
  let _prompt_decorators;
2798
2953
  let _interruptByParent_decorators;
2799
2954
  return class SubagentRuntime extends _classSuper {
2800
2955
  static {
2801
2956
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2802
- _remoteExportList_decorators = [Remote("list")];
2803
2957
  _prompt_decorators = [Remote("prompt")];
2804
2958
  _interruptByParent_decorators = [Remote("interruptByParent")];
2805
- __esDecorate(this, null, _remoteExportList_decorators, {
2806
- kind: "method",
2807
- name: "remoteExportList",
2808
- static: false,
2809
- private: false,
2810
- access: {
2811
- has: (obj) => "remoteExportList" in obj,
2812
- get: (obj) => obj.remoteExportList
2813
- },
2814
- metadata: _metadata
2815
- }, null, _instanceExtraInitializers);
2816
2959
  __esDecorate(this, null, _prompt_decorators, {
2817
2960
  kind: "method",
2818
2961
  name: "prompt",
@@ -2842,7 +2985,12 @@ let SubagentRuntime = (() => {
2842
2985
  value: _metadata
2843
2986
  });
2844
2987
  }
2845
- providers = (__runInitializers(this, _instanceExtraInitializers), /* @__PURE__ */ new Map());
2988
+ config = __runInitializers(this, _instanceExtraInitializers);
2989
+ static Config = z.object({
2990
+ maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(1).volatile(),
2991
+ maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8).volatile()
2992
+ });
2993
+ providers = /* @__PURE__ */ new Map();
2846
2994
  continuations;
2847
2995
  /**
2848
2996
  * The contained lifecycle-edge publisher. Built here because scoped dispatch
@@ -2850,14 +2998,15 @@ let SubagentRuntime = (() => {
2850
2998
  * composes into the carrier.
2851
2999
  */
2852
3000
  emitLifecycle;
2853
- constructor(ctx) {
3001
+ constructor(ctx, config) {
2854
3002
  super(ctx, "subagents");
3003
+ this.config = config;
2855
3004
  this.emitLifecycle = createLifecycleEmitter(this.ctx, (parent) => scopeTarget(this, parent));
2856
3005
  ctx.inject(["agents"], (childCtx) => {
2857
3006
  const manager = new SubagentContinuationManager(childCtx, {
2858
3007
  prepareContinuable: (name, request) => this.prepareContinuable(name, request),
2859
3008
  observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent)
2860
- });
3009
+ }, () => this.config.maxActiveSubagents.get());
2861
3010
  this.continuations = manager;
2862
3011
  childCtx.effect(() => () => {
2863
3012
  /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
@@ -2865,10 +3014,26 @@ let SubagentRuntime = (() => {
2865
3014
  }, "subagents.continuationBinding()");
2866
3015
  });
2867
3016
  ctx.inject(["sessionProjections"], (projectionCtx) => {
2868
- projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
2869
- projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
2870
- projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
3017
+ const projections = projectionCtx.sessionProjections;
3018
+ projections.register(subagentCatalogProjectionDefinition);
3019
+ projections.register(subagentTimingProjectionDefinition);
3020
+ projections.register(subagentIdentityProjectionDefinition);
2871
3021
  });
3022
+ ctx.inject(["agents"], (agentsCtx) => {
3023
+ installSubagentArchiveAdmission(agentsCtx);
3024
+ });
3025
+ }
3026
+ /**
3027
+ * Resolve a delegation tool's depth policy against the current user setting.
3028
+ * @param configured - Explicit tool limit, or provider-managed for external delegation.
3029
+ * @returns The numeric limit, or undefined when the provider owns depth enforcement.
3030
+ */
3031
+ resolveMaxDepth(configured) {
3032
+ if (configured === "provider-managed") return void 0;
3033
+ if (configured !== void 0) return configured;
3034
+ const depth = this.config.maxDepth.get();
3035
+ assertSubagentMaxDepth(depth);
3036
+ return depth;
2872
3037
  }
2873
3038
  /**
2874
3039
  * Establish one durable continuable child and deliver its initial prompt.
@@ -2901,12 +3066,12 @@ let SubagentRuntime = (() => {
2901
3066
  }
2902
3067
  /**
2903
3068
  * Deliver one host-protocol message to a direct continuable child.
2904
- * Symbol-keyed so host adapters can preserve their own provenance without
3069
+ * Symbol-keyed so host adapters can preserve their own source descriptors without
2905
3070
  * widening the public Service Definition or impersonating an Agent sender.
2906
3071
  * @param parent - exact live direct parent authorizing delivery.
2907
3072
  * @param childId - durable direct-child session id.
2908
3073
  * @param content - host-authored content to deliver.
2909
- * @param source - durable host-protocol provenance.
3074
+ * @param source - durable host-protocol source descriptor.
2910
3075
  * @param signal - caller cancellation before inbox acceptance.
2911
3076
  * @param delivery - Queue as a distinct turn or Steer at the nearest step.
2912
3077
  * @returns the accepted message's inbox id.
@@ -2963,21 +3128,13 @@ let SubagentRuntime = (() => {
2963
3128
  await manager.drainChildren(parent, childIds);
2964
3129
  }
2965
3130
  /**
2966
- * Enumerate the parent's direct session-backed subagents without loading or
2967
- * resuming an Agent. The Session query service supplies one live-preferred
2968
- * corpus and shared point observations; the projection cache supplies
2969
- * immutable descriptor hits without opening cold logs. The registered
2970
- * `subagent` projection remains the sole mode/label classifier.
2971
- *
2972
- * Every query receives `signal`, and the listing rechecks cancellation
2973
- * around each await. Read rejections that settle
2974
- * after an abort become a stable `SubagentError` with code `CANCELLED`.
2975
- * @param parentSessionId - parent session whose direct children are listed.
2976
- * @param signal - caller-owned cancellation forwarded to Session queries
2977
- * and observed around every read await.
2978
- * @returns children and per-child diagnostics ordered by `createdAt`, then id.
2979
- * @throws {@link SubagentError} when the projection registry or the session
2980
- * store is not mounted, or the caller cancels the listing.
3131
+ * Read the parent's durable direct-child catalog without loading or resuming an Agent.
3132
+ * The service owns and releases the live-preferred Session observation.
3133
+ * @param parentSessionId - parent whose direct children are requested.
3134
+ * @param signal - cancellation forwarded to the Session query.
3135
+ * @returns catalog children in parent event order.
3136
+ * @throws {@link SubagentError} when query or catalog projection is unavailable.
3137
+ * @throws SessionQueryError when the parent cannot be read or the query is cancelled.
2981
3138
  */
2982
3139
  listChildren(parentSessionId, signal) {
2983
3140
  return listChildren(this.ctx, parentSessionId, signal);
@@ -2988,40 +3145,19 @@ let SubagentRuntime = (() => {
2988
3145
  * Agent. Ordinary sessions and one-shot children remain traversal nodes so
2989
3146
  * continuable descendants below them are discovered; each returned entry
2990
3147
  * adds its durable `parentId` and root-relative `depth`. Identity resolution,
2991
- * diagnostics, optional persistence, and cancellation follow the same
2992
- * projection-backed contract as {@link listChildren}.
3148
+ * diagnostics, optional persistence, and cancellation use the registered
3149
+ * child identity projection and complete Session corpus.
2993
3150
  * @param rootSessionId - session whose complete descendant tree is listed.
2994
3151
  * @param signal - caller-owned cancellation forwarded to persistence reads
2995
3152
  * and observed around every read await.
2996
3153
  * @returns children and per-candidate diagnostics with tree position, in
2997
3154
  * stable pre-order.
2998
- * @throws {@link SubagentError} under the same conditions as {@link listChildren}.
3155
+ * @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
2999
3156
  */
3000
3157
  listDescendants(rootSessionId, signal) {
3001
3158
  return listDescendants(this.ctx, rootSessionId, signal);
3002
3159
  }
3003
3160
  /**
3004
- * Remote face of {@link listChildren} for one browser: the durable listing
3005
- * plus live Agent activity and the delivery-time parent availability hint.
3006
- * Parent availability is a hint; {@link prompt} performs the authoritative
3007
- * check. Named apart from the provider-name {@link list}, which owns the
3008
- * member.
3009
- * @param parentSessionId - parent session whose direct children are listed.
3010
- * @param signal - carrier cancellation forwarded to Session queries.
3011
- * @returns the catalog view for that parent.
3012
- * @throws {RemoteError} `gateway/bad-request` for an empty parent id,
3013
- * `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when
3014
- * the deployment has no projection registry, otherwise `gateway/internal`.
3015
- */
3016
- async remoteExportList(parentSessionId, signal) {
3017
- validateControlRequest("subagent.list", { parentSessionId });
3018
- try {
3019
- return catalogView(this.ctx, parentSessionId, await this.listChildren(parentSessionId, signal));
3020
- } catch (error) {
3021
- return rejectCatalogRead(error, signal);
3022
- }
3023
- }
3024
- /**
3025
3161
  * Deliver one browser-authored message to a continuable child through the
3026
3162
  * exact live direct parent, retaining the caller-minted request identity and
3027
3163
  * validated browser zone on the accepted message. Success identifies the
@@ -3030,6 +3166,7 @@ let SubagentRuntime = (() => {
3030
3166
  * nearest step and retains the Agent loop's best-effort fallback semantics.
3031
3167
  * Image parts are admitted and persisted through the attachment store
3032
3168
  * before delivery, and the child's model must accept image input.
3169
+ * Cold resume at capacity rejects with `subagent/delivery-unavailable`.
3033
3170
  * @param request - durable address, delivery, minted identity, content, and optional browser zone.
3034
3171
  * @param signal - carrier cancellation, owning the call until inbox acceptance.
3035
3172
  * @returns the accepted message's inbox identity.