@themoltnet/agent-daemon 0.32.0 → 0.32.2

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 (3) hide show
  1. package/README.md +23 -2
  2. package/dist/main.js +1275 -33
  3. package/package.json +4 -4
package/dist/main.js CHANGED
@@ -12,8 +12,9 @@ import { parseArgs, promisify } from "node:util";
12
12
  import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource } from "@themoltnet/agent-runtime";
13
13
  import { createPiRetryTriage, createPiTaskExecutor, findMainWorktree, normalizeRetryTriageResult, redactRetryTriageSecrets } from "@themoltnet/pi-extension";
14
14
  import { execFile, execFileSync } from "node:child_process";
15
- import { accessSync, constants, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync } from "node:fs";
15
+ import { accessSync, constants, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, realpathSync, rmSync } from "node:fs";
16
16
  import { AuthenticationError, MoltNetError, connect } from "@themoltnet/sdk";
17
+ import { createHash, randomUUID } from "node:crypto";
17
18
  import { once } from "node:events";
18
19
  import { pino, transport } from "pino";
19
20
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
@@ -25,7 +26,6 @@ import { AsyncLocalStorage } from "node:async_hooks";
25
26
  import { getModel } from "@earendil-works/pi-ai";
26
27
  import { mkdir, realpath, stat } from "node:fs/promises";
27
28
  import { pipeline } from "node:stream/promises";
28
- import { createHash } from "node:crypto";
29
29
  import { Writable } from "node:stream";
30
30
  import { createGzip } from "node:zlib";
31
31
  //#region ../../libs/observability/src/instrumentation.ts
@@ -4454,6 +4454,875 @@ function deepFreeze(value) {
4454
4454
  deepFreeze(RUNTIME_PROFILE_CONTEXT_CATALOGUE);
4455
4455
  Object.freeze(Object.keys(RUNTIME_PROFILE_CONTEXT_CATALOGUE.recipes));
4456
4456
  //#endregion
4457
+ //#region ../../libs/models/src/preview-sign.ts
4458
+ function schemaRef$1(schema, id) {
4459
+ return Unsafe(Ref$1(id));
4460
+ }
4461
+ var PreviewSignBase64UrlSchema = String$1({
4462
+ $id: "PreviewSignBase64Url",
4463
+ minLength: 1,
4464
+ maxLength: 5462,
4465
+ pattern: "^[A-Za-z0-9_-]+$"
4466
+ });
4467
+ var PreviewSignSha256Base64UrlSchema = String$1({
4468
+ $id: "PreviewSignSha256Base64Url",
4469
+ minLength: 43,
4470
+ maxLength: 43,
4471
+ pattern: "^[A-Za-z0-9_-]+$"
4472
+ });
4473
+ var PreviewSignP256DerSignatureBase64UrlSchema = String$1({
4474
+ $id: "PreviewSignP256DerSignatureBase64Url",
4475
+ minLength: 11,
4476
+ maxLength: 96,
4477
+ pattern: "^[A-Za-z0-9_-]+$"
4478
+ });
4479
+ var PreviewSignEs256PublicKeySchema = _Object_({
4480
+ kty: Literal(2),
4481
+ algorithm: Literal(-7),
4482
+ curve: Literal(1),
4483
+ x: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url"),
4484
+ y: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url")
4485
+ }, {
4486
+ $id: "PreviewSignEs256PublicKey",
4487
+ additionalProperties: false
4488
+ });
4489
+ var PreviewSignEcdhEsHkdf256PublicKeySchema = _Object_({
4490
+ kty: Literal(2),
4491
+ algorithm: Literal(-25),
4492
+ curve: Literal(1),
4493
+ x: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url"),
4494
+ y: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url")
4495
+ }, {
4496
+ $id: "PreviewSignEcdhEsHkdf256PublicKey",
4497
+ additionalProperties: false
4498
+ });
4499
+ var PreviewSignEsp256PublicKeySchema = _Object_({
4500
+ kty: Literal(2),
4501
+ algorithm: Literal(-9),
4502
+ curve: Literal(1),
4503
+ x: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url"),
4504
+ y: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url")
4505
+ }, {
4506
+ $id: "PreviewSignEsp256PublicKey",
4507
+ additionalProperties: false
4508
+ });
4509
+ var PreviewSignArkgSeedPublicKeySchema = _Object_({
4510
+ kty: Literal(-65537),
4511
+ algorithm: Literal(-65700),
4512
+ derivedAlgorithm: Literal(-9),
4513
+ blindingKey: schemaRef$1(PreviewSignEs256PublicKeySchema, "PreviewSignEs256PublicKey"),
4514
+ kemKey: schemaRef$1(PreviewSignEcdhEsHkdf256PublicKeySchema, "PreviewSignEcdhEsHkdf256PublicKey")
4515
+ }, {
4516
+ $id: "PreviewSignArkgSeedPublicKey",
4517
+ additionalProperties: false
4518
+ });
4519
+ var PreviewSignPublicMaterialSchema = _Object_({
4520
+ version: Literal(1),
4521
+ outerCredentialId: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url"),
4522
+ outerPublicKey: schemaRef$1(PreviewSignEs256PublicKeySchema, "PreviewSignEs256PublicKey"),
4523
+ previewKeyHandle: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url"),
4524
+ seedPublicKey: schemaRef$1(PreviewSignArkgSeedPublicKeySchema, "PreviewSignArkgSeedPublicKey")
4525
+ }, {
4526
+ $id: "PreviewSignPublicMaterial",
4527
+ additionalProperties: false
4528
+ });
4529
+ var PreviewSignChallengeSchema = _Object_({
4530
+ verificationMethod: Literal("human-hardware-previewsign"),
4531
+ version: Literal(1),
4532
+ envelope: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url"),
4533
+ digest: schemaRef$1(PreviewSignSha256Base64UrlSchema, "PreviewSignSha256Base64Url"),
4534
+ additionalArguments: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url"),
4535
+ outerCredentialId: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url"),
4536
+ outerPublicKey: schemaRef$1(PreviewSignEs256PublicKeySchema, "PreviewSignEs256PublicKey"),
4537
+ previewKeyHandle: schemaRef$1(PreviewSignBase64UrlSchema, "PreviewSignBase64Url")
4538
+ }, {
4539
+ $id: "PreviewSignChallenge",
4540
+ additionalProperties: false
4541
+ });
4542
+ var PreviewSignChallengeValueSchema = _Object_({
4543
+ verificationMethod: Literal("human-hardware-previewsign"),
4544
+ value: schemaRef$1(PreviewSignChallengeSchema, "PreviewSignChallenge")
4545
+ }, {
4546
+ $id: "PreviewSignChallengeValue",
4547
+ additionalProperties: false
4548
+ });
4549
+ var PreviewSignChallengeOperationSchema = Union([Literal("credential-registration"), Literal("signing-request")], { $id: "PreviewSignChallengeOperation" });
4550
+ var PreviewSignReceiptSchema = _Object_({
4551
+ version: Literal(1),
4552
+ signature: schemaRef$1(PreviewSignP256DerSignatureBase64UrlSchema, "PreviewSignP256DerSignatureBase64Url")
4553
+ }, {
4554
+ $id: "PreviewSignReceipt",
4555
+ additionalProperties: false
4556
+ });
4557
+ var PreviewSignReceiptValueSchema = _Object_({
4558
+ verificationMethod: Literal("human-hardware-previewsign"),
4559
+ value: schemaRef$1(PreviewSignReceiptSchema, "PreviewSignReceipt")
4560
+ }, {
4561
+ $id: "PreviewSignReceiptValue",
4562
+ additionalProperties: false
4563
+ });
4564
+ var previewSignSchemaContext = {
4565
+ PreviewSignBase64Url: PreviewSignBase64UrlSchema,
4566
+ PreviewSignSha256Base64Url: PreviewSignSha256Base64UrlSchema,
4567
+ PreviewSignP256DerSignatureBase64Url: PreviewSignP256DerSignatureBase64UrlSchema,
4568
+ PreviewSignEs256PublicKey: PreviewSignEs256PublicKeySchema,
4569
+ PreviewSignEcdhEsHkdf256PublicKey: PreviewSignEcdhEsHkdf256PublicKeySchema,
4570
+ PreviewSignEsp256PublicKey: PreviewSignEsp256PublicKeySchema,
4571
+ PreviewSignArkgSeedPublicKey: PreviewSignArkgSeedPublicKeySchema,
4572
+ PreviewSignPublicMaterial: PreviewSignPublicMaterialSchema,
4573
+ PreviewSignChallenge: PreviewSignChallengeSchema,
4574
+ PreviewSignChallengeValue: PreviewSignChallengeValueSchema,
4575
+ PreviewSignChallengeOperation: PreviewSignChallengeOperationSchema,
4576
+ PreviewSignReceipt: PreviewSignReceiptSchema,
4577
+ PreviewSignReceiptValue: PreviewSignReceiptValueSchema
4578
+ };
4579
+ //#endregion
4580
+ //#region ../../libs/models/src/verification-method.ts
4581
+ /**
4582
+ * Persisted and wire-level signing verification method identifiers.
4583
+ *
4584
+ * This vocabulary is append-only. Never rename, remove, or change an existing
4585
+ * value: PostgreSQL rows, workflow inputs, and API clients persist these exact
4586
+ * strings. Future signing methods must add a new property and value.
4587
+ */
4588
+ var VERIFICATION_METHOD = {
4589
+ AgentEd25519: "agent-ed25519",
4590
+ HumanHardwarePreviewSign: "human-hardware-previewsign"
4591
+ };
4592
+ VERIFICATION_METHOD.AgentEd25519, VERIFICATION_METHOD.HumanHardwarePreviewSign;
4593
+ //#endregion
4594
+ //#region ../../libs/models/src/schemas.ts
4595
+ var UuidSchema = String$1({
4596
+ format: "uuid",
4597
+ description: "UUID v4 identifier"
4598
+ });
4599
+ var TimestampSchema = String$1({
4600
+ format: "date-time",
4601
+ description: "ISO 8601 timestamp"
4602
+ });
4603
+ Union([Literal(VERIFICATION_METHOD.AgentEd25519), Literal(VERIFICATION_METHOD.HumanHardwarePreviewSign)], { description: "Stable signing verification method identifier" });
4604
+ Union([
4605
+ Literal("private"),
4606
+ Literal("moltnet"),
4607
+ Literal("public")
4608
+ ], { description: "Entry visibility level" });
4609
+ var ENTRY_TYPE_VALUES = [
4610
+ "episodic",
4611
+ "semantic",
4612
+ "procedural",
4613
+ "reflection"
4614
+ ];
4615
+ var EntryTypeSchema = Union([
4616
+ Literal("episodic"),
4617
+ Literal("semantic"),
4618
+ Literal("procedural"),
4619
+ Literal("reflection")
4620
+ ], { description: "Entry memory type" });
4621
+ /** Regex fragment matching a single entry type value. */
4622
+ var ENTRY_TYPE_PATTERN = `(${ENTRY_TYPE_VALUES.join("|")})`;
4623
+ `${ENTRY_TYPE_PATTERN}${ENTRY_TYPE_PATTERN}`, ENTRY_TYPE_VALUES.length - 1;
4624
+ var PublicKeySchema = String$1({
4625
+ pattern: "^ed25519:[A-Za-z0-9+/=]+$",
4626
+ description: "Ed25519 public key with prefix"
4627
+ });
4628
+ var FingerprintSchema = String$1({
4629
+ pattern: "^[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}$",
4630
+ description: "Key fingerprint (A1B2-C3D4-E5F6-G7H8)"
4631
+ });
4632
+ _Object_({
4633
+ title: Optional(String$1({ maxLength: 255 })),
4634
+ content: String$1({
4635
+ minLength: 1,
4636
+ maxLength: 1e5
4637
+ }),
4638
+ tags: Optional(_Array_(String$1({ maxLength: 128 }), { maxItems: 20 }))
4639
+ });
4640
+ _Object_({
4641
+ title: Optional(String$1({ maxLength: 255 })),
4642
+ content: Optional(String$1({
4643
+ minLength: 1,
4644
+ maxLength: 1e5
4645
+ })),
4646
+ tags: Optional(_Array_(String$1({ maxLength: 128 }), { maxItems: 20 }))
4647
+ });
4648
+ _Object_({
4649
+ query: Optional(String$1({
4650
+ minLength: 1,
4651
+ maxLength: 500
4652
+ })),
4653
+ tags: Optional(_Array_(String$1({ maxLength: 128 }), {
4654
+ minItems: 1,
4655
+ maxItems: 20,
4656
+ description: "Filter: entry must have ALL specified tags"
4657
+ })),
4658
+ limit: Optional(Number$1({
4659
+ minimum: 1,
4660
+ maximum: 100,
4661
+ default: 20
4662
+ })),
4663
+ offset: Optional(Number$1({
4664
+ minimum: 0,
4665
+ default: 0
4666
+ }))
4667
+ });
4668
+ _Object_({
4669
+ identityId: UuidSchema,
4670
+ publicKey: PublicKeySchema,
4671
+ fingerprint: FingerprintSchema,
4672
+ createdAt: TimestampSchema
4673
+ });
4674
+ _Object_({
4675
+ publicKey: PublicKeySchema,
4676
+ fingerprint: FingerprintSchema
4677
+ });
4678
+ _Object_({ message: String$1({
4679
+ minLength: 1,
4680
+ maxLength: 1e4
4681
+ }) });
4682
+ _Object_({
4683
+ message: String$1(),
4684
+ signature: String$1({ description: "Base64 encoded Ed25519 signature" }),
4685
+ publicKey: PublicKeySchema
4686
+ });
4687
+ _Object_({
4688
+ message: String$1({
4689
+ minLength: 1,
4690
+ maxLength: 1e4
4691
+ }),
4692
+ signature: String$1({ description: "Base64 encoded signature" }),
4693
+ publicKey: PublicKeySchema
4694
+ });
4695
+ _Object_({
4696
+ valid: Boolean$1(),
4697
+ signer: Optional(_Object_({ fingerprint: FingerprintSchema }))
4698
+ });
4699
+ var BaseAuthContextSchema = _Object_({
4700
+ identityId: UuidSchema,
4701
+ scopes: _Array_(String$1()),
4702
+ subjectType: Union([Literal("agent"), Literal("human")]),
4703
+ currentTeamId: Union([UuidSchema, Null()])
4704
+ });
4705
+ Union([Intersect([BaseAuthContextSchema, _Object_({
4706
+ subjectType: Literal("agent"),
4707
+ publicKey: PublicKeySchema,
4708
+ fingerprint: FingerprintSchema,
4709
+ clientId: String$1()
4710
+ })]), Intersect([BaseAuthContextSchema, _Object_({
4711
+ subjectType: Literal("human"),
4712
+ clientId: Union([String$1(), Null()])
4713
+ })])]);
4714
+ _Object_({
4715
+ success: Boolean$1(),
4716
+ message: Optional(String$1())
4717
+ });
4718
+ _Object_({ diaryId: UuidSchema });
4719
+ _Object_({
4720
+ diaryId: UuidSchema,
4721
+ entryId: UuidSchema
4722
+ });
4723
+ _Object_({ entryId: UuidSchema });
4724
+ _Object_({ id: UuidSchema });
4725
+ _Object_({
4726
+ publicKey: PublicKeySchema,
4727
+ fingerprint: FingerprintSchema,
4728
+ agentName: String$1({
4729
+ minLength: 1,
4730
+ maxLength: 34
4731
+ }),
4732
+ org: Optional(String$1({
4733
+ minLength: 1,
4734
+ maxLength: 39,
4735
+ pattern: "^[a-zA-Z0-9-]+$",
4736
+ description: "GitHub organization name. When provided, the GitHub App will be created under this org instead of the personal account."
4737
+ }))
4738
+ });
4739
+ _Object_({
4740
+ workflowId: String$1(),
4741
+ manifestFormUrl: String$1()
4742
+ });
4743
+ _Object_({
4744
+ status: Union([
4745
+ Literal("awaiting_github"),
4746
+ Literal("github_code_ready"),
4747
+ Literal("awaiting_installation"),
4748
+ Literal("completed"),
4749
+ Literal("failed")
4750
+ ]),
4751
+ githubCode: Optional(String$1()),
4752
+ identityId: Optional(String$1()),
4753
+ clientId: Optional(String$1()),
4754
+ clientSecret: Optional(String$1()),
4755
+ installationId: Optional(String$1())
4756
+ });
4757
+ _Object_({
4758
+ wf: String$1({
4759
+ minLength: 1,
4760
+ description: "Workflow ID baked into setup_url"
4761
+ }),
4762
+ installation_id: String$1({ minLength: 1 }),
4763
+ setup_action: Optional(String$1())
4764
+ });
4765
+ _Object_({ id: UuidSchema });
4766
+ _Object_({
4767
+ id: UuidSchema,
4768
+ subjectId: UuidSchema
4769
+ });
4770
+ _Object_({
4771
+ id: UuidSchema,
4772
+ inviteId: UuidSchema
4773
+ });
4774
+ _Object_({ name: String$1({
4775
+ minLength: 1,
4776
+ maxLength: 255
4777
+ }) });
4778
+ _Object_({
4779
+ role: Optional(Union([Literal("manager"), Literal("member")])),
4780
+ maxUses: Optional(Integer({
4781
+ minimum: 1,
4782
+ default: 1
4783
+ })),
4784
+ expiresInHours: Optional(Integer({
4785
+ minimum: 1,
4786
+ maximum: 720,
4787
+ default: 168
4788
+ }))
4789
+ });
4790
+ _Object_({ code: String$1({ minLength: 1 }) });
4791
+ _Object_({ role: Union([Literal("manager"), Literal("member")]) });
4792
+ var TeamRoleSchema = Union([
4793
+ Literal("owner"),
4794
+ Literal("manager"),
4795
+ Literal("member")
4796
+ ]);
4797
+ _Object_({
4798
+ id: UuidSchema,
4799
+ name: String$1()
4800
+ });
4801
+ var DateTimeUnsafe = Unsafe(String$1({ format: "date-time" }));
4802
+ _Object_({
4803
+ id: UuidSchema,
4804
+ code: String$1(),
4805
+ role: Union([Literal("manager"), Literal("member")]),
4806
+ maxUses: Integer(),
4807
+ useCount: Integer(),
4808
+ expiresAt: DateTimeUnsafe,
4809
+ createdAt: DateTimeUnsafe
4810
+ });
4811
+ var TeamMemberSchema = _Object_({
4812
+ subjectId: UuidSchema,
4813
+ subjectType: Union([Literal("agent"), Literal("human")]),
4814
+ role: TeamRoleSchema,
4815
+ displayName: String$1(),
4816
+ fingerprint: Optional(String$1()),
4817
+ email: Optional(String$1())
4818
+ });
4819
+ _Object_({
4820
+ id: UuidSchema,
4821
+ name: String$1(),
4822
+ personal: Boolean$1(),
4823
+ status: String$1(),
4824
+ role: TeamRoleSchema
4825
+ });
4826
+ _Object_({
4827
+ id: UuidSchema,
4828
+ name: String$1(),
4829
+ status: String$1(),
4830
+ personal: Boolean$1(),
4831
+ createdAt: DateTimeUnsafe,
4832
+ updatedAt: DateTimeUnsafe,
4833
+ members: _Array_(TeamMemberSchema)
4834
+ });
4835
+ _Object_({
4836
+ teamId: UuidSchema,
4837
+ role: Union([Literal("manager"), Literal("member")])
4838
+ });
4839
+ _Object_({
4840
+ updated: Boolean$1(),
4841
+ role: Union([Literal("manager"), Literal("member")])
4842
+ });
4843
+ _Object_({ deleted: Boolean$1() });
4844
+ _Object_({ removed: Boolean$1() });
4845
+ var FoundingMemberSchema = _Object_({
4846
+ subjectId: UuidSchema,
4847
+ subjectNs: Union([Literal("Agent"), Literal("Human")]),
4848
+ role: Union([
4849
+ Literal("owner"),
4850
+ Literal("manager"),
4851
+ Literal("member")
4852
+ ])
4853
+ });
4854
+ _Object_({
4855
+ name: String$1({
4856
+ minLength: 1,
4857
+ maxLength: 255
4858
+ }),
4859
+ foundingMembers: Optional(_Array_(FoundingMemberSchema, { minItems: 1 }))
4860
+ });
4861
+ _Object_({
4862
+ id: UuidSchema,
4863
+ name: String$1(),
4864
+ status: String$1(),
4865
+ workflowId: Optional(String$1())
4866
+ });
4867
+ _Object_({});
4868
+ _Object_({
4869
+ accepted: Boolean$1(),
4870
+ teamStatus: String$1()
4871
+ });
4872
+ _Object_({ destinationTeamId: UuidSchema });
4873
+ _Object_({ transferId: UuidSchema });
4874
+ _Object_({ items: _Array_(_Object_({
4875
+ id: UuidSchema,
4876
+ diaryId: UuidSchema,
4877
+ sourceTeamId: UuidSchema,
4878
+ destinationTeamId: UuidSchema,
4879
+ status: String$1(),
4880
+ initiatedBy: UuidSchema,
4881
+ expiresAt: Unsafe(String$1({ format: "date-time" })),
4882
+ createdAt: Unsafe(String$1({ format: "date-time" }))
4883
+ })) });
4884
+ _Object_({ groupId: UuidSchema });
4885
+ _Object_({
4886
+ groupId: UuidSchema,
4887
+ subjectId: UuidSchema
4888
+ });
4889
+ _Object_({ name: String$1({
4890
+ minLength: 1,
4891
+ maxLength: 255
4892
+ }) });
4893
+ _Object_({
4894
+ subjectId: UuidSchema,
4895
+ subjectNs: Optional(Union([Literal("Agent"), Literal("Human")]))
4896
+ });
4897
+ _Object_({
4898
+ id: UuidSchema,
4899
+ name: String$1(),
4900
+ teamId: UuidSchema
4901
+ });
4902
+ var GroupMemberResponseSchema = _Object_({
4903
+ subjectId: UuidSchema,
4904
+ subjectNs: String$1()
4905
+ });
4906
+ _Object_({
4907
+ id: UuidSchema,
4908
+ name: String$1(),
4909
+ teamId: UuidSchema,
4910
+ createdAt: DateTimeUnsafe,
4911
+ members: _Array_(GroupMemberResponseSchema)
4912
+ });
4913
+ var DiaryGrantRoleSchema = Union([Literal("writer"), Literal("manager")]);
4914
+ var GrantSubjectNsSchema = Union([
4915
+ Literal("Agent"),
4916
+ Literal("Human"),
4917
+ Literal("Group")
4918
+ ]);
4919
+ _Object_({
4920
+ subjectId: UuidSchema,
4921
+ subjectNs: GrantSubjectNsSchema,
4922
+ role: DiaryGrantRoleSchema
4923
+ });
4924
+ _Object_({
4925
+ subjectId: UuidSchema,
4926
+ subjectNs: GrantSubjectNsSchema,
4927
+ role: DiaryGrantRoleSchema
4928
+ });
4929
+ _Object_({ grants: _Array_(_Object_({
4930
+ subjectId: UuidSchema,
4931
+ subjectNs: GrantSubjectNsSchema,
4932
+ role: DiaryGrantRoleSchema
4933
+ })) });
4934
+ _Object_({ revoked: Boolean$1() });
4935
+ _Object_({ "x-moltnet-team-id": String$1({
4936
+ format: "uuid",
4937
+ description: "Team ID (UUID) that will own the resource. Required."
4938
+ }) });
4939
+ _Object_({ "x-moltnet-team-id": Optional(String$1({
4940
+ format: "uuid",
4941
+ description: "Team ID (UUID) for scoping the request. Optional."
4942
+ })) });
4943
+ _Object_({
4944
+ kind: Literal("agent"),
4945
+ identityId: UuidSchema,
4946
+ fingerprint: FingerprintSchema,
4947
+ publicKey: PublicKeySchema
4948
+ }, {
4949
+ $id: "AgentPrincipal",
4950
+ additionalProperties: false
4951
+ });
4952
+ _Object_({
4953
+ kind: Literal("human"),
4954
+ humanId: UuidSchema,
4955
+ identityId: Union([UuidSchema, Null()])
4956
+ }, {
4957
+ $id: "HumanPrincipal",
4958
+ additionalProperties: false
4959
+ });
4960
+ var principalUnionVariants = [_Object_({
4961
+ kind: Literal("agent"),
4962
+ identityId: UuidSchema,
4963
+ fingerprint: FingerprintSchema,
4964
+ publicKey: PublicKeySchema
4965
+ }, { additionalProperties: false }), _Object_({
4966
+ kind: Literal("human"),
4967
+ humanId: UuidSchema,
4968
+ identityId: Union([UuidSchema, Null()])
4969
+ }, { additionalProperties: false })];
4970
+ Union(principalUnionVariants, {
4971
+ $id: "PrincipalIdentity",
4972
+ discriminator: { propertyName: "kind" }
4973
+ });
4974
+ /**
4975
+ * `$id`-less twin of `PrincipalIdentitySchema`. Required anywhere the
4976
+ * schema is **embedded** inline into another schema (MCP `outputSchema`
4977
+ * — every tool that returns a creator-bearing object embeds its own
4978
+ * copy; provenance-graph node `meta.creator`, etc.). Ajv 8 throws
4979
+ * `reference "PrincipalIdentity" resolves to more than one schema` if
4980
+ * the same `$id` appears twice in the same compilation pass, which is
4981
+ * exactly what happens when the MCP server lists tools and Ajv
4982
+ * traverses every advertised `outputSchema`.
4983
+ *
4984
+ * Structurally identical to `PrincipalIdentitySchema` (they share the
4985
+ * variants array); change one, change both.
4986
+ */
4987
+ var PrincipalIdentitySchemaInline = Union(principalUnionVariants, { discriminator: { propertyName: "kind" } });
4988
+ //#endregion
4989
+ //#region ../../libs/models/src/problem-details.ts
4990
+ var ProblemCodeSchema = Union([
4991
+ Literal("UNAUTHORIZED"),
4992
+ Literal("FORBIDDEN"),
4993
+ Literal("NOT_FOUND"),
4994
+ Literal("CONFLICT"),
4995
+ Literal("UNSUPPORTED_MEDIA_TYPE"),
4996
+ Literal("VALIDATION_FAILED"),
4997
+ Literal("INVALID_CHALLENGE"),
4998
+ Literal("INVALID_SIGNATURE"),
4999
+ Literal("VOUCHER_LIMIT"),
5000
+ Literal("RATE_LIMIT_EXCEEDED"),
5001
+ Literal("SERIALIZATION_EXHAUSTED"),
5002
+ Literal("SIGNING_REQUEST_EXPIRED"),
5003
+ Literal("SIGNING_REQUEST_ALREADY_COMPLETED"),
5004
+ Literal("SIGNING_REQUEST_LIMIT_REACHED"),
5005
+ Literal("REGISTRATION_FAILED"),
5006
+ Literal("UPSTREAM_ERROR"),
5007
+ Literal("SERVICE_UNAVAILABLE"),
5008
+ Literal("INTERNAL_SERVER_ERROR"),
5009
+ Literal("TEAM_PERSONAL_IMMUTABLE"),
5010
+ Literal("TEAM_NOT_ACTIVE"),
5011
+ Literal("INVITE_EXPIRED"),
5012
+ Literal("INVITE_EXHAUSTED"),
5013
+ Literal("TEAM_LAST_OWNER"),
5014
+ Literal("TEAM_ALREADY_ACTIVE"),
5015
+ Literal("TEAM_NOT_FOUNDING"),
5016
+ Literal("FOUNDING_ALREADY_ACCEPTED"),
5017
+ Literal("DIARY_TRANSFER_PENDING"),
5018
+ Literal("DIARY_TRANSFER_NOT_FOUND"),
5019
+ Literal("DIARY_TRANSFER_ALREADY_RESOLVED")
5020
+ ]);
5021
+ var ProblemDetailsSchema = _Object_({
5022
+ type: String$1({ format: "uri" }),
5023
+ title: String$1(),
5024
+ status: Integer({
5025
+ minimum: 100,
5026
+ maximum: 599
5027
+ }),
5028
+ code: ProblemCodeSchema,
5029
+ detail: Optional(String$1()),
5030
+ instance: Optional(String$1())
5031
+ }, {
5032
+ $id: "ProblemDetails",
5033
+ additionalProperties: true
5034
+ });
5035
+ _Object_({
5036
+ field: String$1(),
5037
+ message: String$1(),
5038
+ code: Optional(String$1())
5039
+ }, {
5040
+ $id: "ValidationError",
5041
+ additionalProperties: false
5042
+ });
5043
+ _Object_({
5044
+ resource: String$1(),
5045
+ id: Optional(String$1({ format: "uuid" })),
5046
+ keys: Optional(Record(String$1(), String$1()))
5047
+ }, {
5048
+ $id: "ConflictTarget",
5049
+ additionalProperties: false
5050
+ });
5051
+ _Object_({
5052
+ constraint: Optional(String$1()),
5053
+ target: Optional(Ref$1("ConflictTarget"))
5054
+ }, {
5055
+ $id: "ConflictError",
5056
+ additionalProperties: false
5057
+ });
5058
+ var ConflictProblemDetailsSchema = Intersect([ProblemDetailsSchema, _Object_({ conflict: Ref$1("ConflictError") })], { $id: "ConflictProblemDetails" });
5059
+ _Object_({
5060
+ type: String$1(),
5061
+ severity: Number$1(),
5062
+ match: String$1()
5063
+ }, {
5064
+ $id: "InjectionThreat",
5065
+ additionalProperties: false
5066
+ });
5067
+ Intersect([ConflictProblemDetailsSchema, _Object_({ flagged: Optional(_Array_(_Object_({
5068
+ id: String$1({ format: "uuid" }),
5069
+ threats: _Array_(Ref$1("InjectionThreat"))
5070
+ }, { additionalProperties: false }))) })], { $id: "InjectionConflictProblemDetails" });
5071
+ Intersect([ProblemDetailsSchema, _Object_({ errors: _Array_(Ref$1("ValidationError")) })], { $id: "ValidationProblemDetails" });
5072
+ Union([
5073
+ Literal("pack"),
5074
+ Literal("entry"),
5075
+ Literal("rendered_pack")
5076
+ ]);
5077
+ var ProvenanceGraphEdgeKindSchema = Union([
5078
+ Literal("includes"),
5079
+ Literal("supersedes"),
5080
+ Literal("rendered_from")
5081
+ ]);
5082
+ var ProvenanceGraphPackMetaSchema = _Object_({
5083
+ packId: UuidSchema,
5084
+ diaryId: UuidSchema,
5085
+ packCid: String$1(),
5086
+ packType: String$1(),
5087
+ packCodec: String$1(),
5088
+ pinned: Boolean$1(),
5089
+ createdAt: TimestampSchema,
5090
+ expiresAt: Union([TimestampSchema, Null()]),
5091
+ supersedesPackId: Union([UuidSchema, Null()])
5092
+ });
5093
+ /**
5094
+ * Discriminated creator embedded inside provenance-node response
5095
+ * payloads. Re-uses the shared `PrincipalIdentitySchemaInline` (the
5096
+ * `$id`-less twin) — embedding the named `PrincipalIdentitySchema`
5097
+ * here would clash with the top-level registration via @fastify/swagger
5098
+ * (`reference "PrincipalIdentity" resolves to more than one schema`).
5099
+ */
5100
+ var ProvenanceGraphCreatorSchema = PrincipalIdentitySchemaInline;
5101
+ var ProvenanceGraphEntryMetaSchema = _Object_({
5102
+ entryId: UuidSchema,
5103
+ diaryId: UuidSchema,
5104
+ entryType: EntryTypeSchema,
5105
+ contentHash: Union([String$1(), Null()]),
5106
+ createdAt: TimestampSchema,
5107
+ updatedAt: TimestampSchema,
5108
+ signed: Boolean$1(),
5109
+ title: Union([String$1(), Null()]),
5110
+ tags: _Array_(String$1()),
5111
+ creator: Optional(ProvenanceGraphCreatorSchema)
5112
+ });
5113
+ var ProvenanceGraphPackNodeSchema = _Object_({
5114
+ id: String$1(),
5115
+ kind: Literal("pack"),
5116
+ label: String$1(),
5117
+ cid: Union([String$1(), Null()]),
5118
+ meta: Intersect([ProvenanceGraphPackMetaSchema, _Object_({ creator: Optional(ProvenanceGraphCreatorSchema) })])
5119
+ });
5120
+ var ProvenanceGraphEntryNodeSchema = _Object_({
5121
+ id: String$1(),
5122
+ kind: Literal("entry"),
5123
+ label: String$1(),
5124
+ cid: Union([String$1(), Null()]),
5125
+ meta: ProvenanceGraphEntryMetaSchema
5126
+ });
5127
+ var ProvenanceGraphRenderedPackMetaSchema = _Object_({
5128
+ renderedPackId: UuidSchema,
5129
+ sourcePackId: UuidSchema,
5130
+ diaryId: UuidSchema,
5131
+ packCid: String$1(),
5132
+ renderMethod: String$1(),
5133
+ totalTokens: Number$1(),
5134
+ pinned: Boolean$1(),
5135
+ createdAt: TimestampSchema,
5136
+ expiresAt: Union([TimestampSchema, Null()]),
5137
+ creator: Optional(ProvenanceGraphCreatorSchema)
5138
+ });
5139
+ var ProvenanceGraphNodeSchema = Union([
5140
+ ProvenanceGraphPackNodeSchema,
5141
+ ProvenanceGraphEntryNodeSchema,
5142
+ _Object_({
5143
+ id: String$1(),
5144
+ kind: Literal("rendered_pack"),
5145
+ label: String$1(),
5146
+ cid: Union([String$1(), Null()]),
5147
+ meta: ProvenanceGraphRenderedPackMetaSchema
5148
+ })
5149
+ ]);
5150
+ var ProvenanceGraphEdgeSchema = _Object_({
5151
+ id: String$1(),
5152
+ from: String$1(),
5153
+ to: String$1(),
5154
+ kind: ProvenanceGraphEdgeKindSchema,
5155
+ label: Optional(String$1()),
5156
+ meta: Optional(Record(String$1(), Union([
5157
+ String$1(),
5158
+ Number$1(),
5159
+ Boolean$1(),
5160
+ Null()
5161
+ ])))
5162
+ });
5163
+ _Object_({
5164
+ metadata: _Object_({
5165
+ format: Literal("moltnet.provenance-graph/v1"),
5166
+ generatedAt: TimestampSchema,
5167
+ rootNodeId: String$1(),
5168
+ rootPackId: UuidSchema,
5169
+ depth: Number$1({ minimum: 0 })
5170
+ }),
5171
+ nodes: _Array_(ProvenanceGraphNodeSchema),
5172
+ edges: _Array_(ProvenanceGraphEdgeSchema)
5173
+ }, { $id: "ProvenanceGraph" });
5174
+ //#endregion
5175
+ //#region ../../libs/models/src/signer-constraint.ts
5176
+ var SIGNER_CONSTRAINT_TYPE = {
5177
+ Human: "human",
5178
+ TeamRole: "team-role",
5179
+ Group: "group"
5180
+ };
5181
+ Union([
5182
+ _Object_({
5183
+ type: Literal(SIGNER_CONSTRAINT_TYPE.Human),
5184
+ id: String$1({ format: "uuid" })
5185
+ }),
5186
+ _Object_({
5187
+ type: Literal(SIGNER_CONSTRAINT_TYPE.TeamRole),
5188
+ id: TeamRoleSchema
5189
+ }),
5190
+ _Object_({
5191
+ type: Literal(SIGNER_CONSTRAINT_TYPE.Group),
5192
+ id: String$1({ format: "uuid" })
5193
+ })
5194
+ ]);
5195
+ //#endregion
5196
+ //#region ../../libs/models/src/signer-protocol.ts
5197
+ function schemaRef(schema) {
5198
+ return Ref$1(schemaId(schema));
5199
+ }
5200
+ function schemaId(schema) {
5201
+ const id = schema.$id;
5202
+ if (typeof id !== "string" || id.length === 0) throw new Error("Signer protocol schemas must have an identifier");
5203
+ return id;
5204
+ }
5205
+ var SignerBase64UrlSchema = PreviewSignBase64UrlSchema;
5206
+ var SignerUuidSchema = String$1({
5207
+ $id: "SignerUuid",
5208
+ pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
5209
+ });
5210
+ var SignerOperationSchema = Union([
5211
+ Literal("credential-enrollment"),
5212
+ Literal("credential-registration"),
5213
+ Literal("signing-request")
5214
+ ], { $id: "SignerOperation" });
5215
+ var SignerChallengeOperationSchema = PreviewSignChallengeOperationSchema;
5216
+ var SignerPreviewSignPublicMaterialSchema = PreviewSignPublicMaterialSchema;
5217
+ var SignerPreviewSignChallengeValueSchema = PreviewSignChallengeValueSchema;
5218
+ var SignerProblemSchema = _Object_({
5219
+ code: String$1({ minLength: 1 }),
5220
+ message: String$1({ minLength: 1 })
5221
+ }, {
5222
+ $id: "SignerProblem",
5223
+ additionalProperties: false
5224
+ });
5225
+ var SignerCeremonyParamsSchema = _Object_({ ceremonyId: Unsafe(schemaRef(SignerBase64UrlSchema)) }, {
5226
+ $id: "SignerCeremonyParams",
5227
+ additionalProperties: false
5228
+ });
5229
+ var SignerSessionSchema = _Object_({
5230
+ version: Literal(1),
5231
+ token: Unsafe(schemaRef(SignerBase64UrlSchema)),
5232
+ expiresAt: String$1()
5233
+ }, {
5234
+ $id: "SignerSession",
5235
+ additionalProperties: false
5236
+ });
5237
+ var SignerEnrollmentCeremonyRequestSchema = _Object_({
5238
+ version: Literal(1),
5239
+ operation: Literal("credential-enrollment"),
5240
+ label: String$1({
5241
+ minLength: 1,
5242
+ maxLength: 255
5243
+ }),
5244
+ teamId: Unsafe(schemaRef(SignerUuidSchema))
5245
+ }, {
5246
+ $id: "SignerEnrollmentCeremonyRequest",
5247
+ additionalProperties: false
5248
+ });
5249
+ var SignerChallengeCeremonyRequestSchema = _Object_({
5250
+ version: Literal(1),
5251
+ operation: Unsafe(schemaRef(SignerChallengeOperationSchema)),
5252
+ resourceId: Unsafe(schemaRef(SignerUuidSchema)),
5253
+ challenge: Unsafe(schemaRef(SignerPreviewSignChallengeValueSchema))
5254
+ }, {
5255
+ $id: "SignerChallengeCeremonyRequest",
5256
+ additionalProperties: false
5257
+ });
5258
+ var SignerCeremonyRequestSchema = Union([Unsafe(schemaRef(SignerEnrollmentCeremonyRequestSchema)), Unsafe(schemaRef(SignerChallengeCeremonyRequestSchema))], { $id: "SignerCeremonyRequest" });
5259
+ var SignerCeremonySchema = _Object_({
5260
+ version: Literal(1),
5261
+ id: Unsafe(schemaRef(SignerBase64UrlSchema)),
5262
+ operation: Unsafe(schemaRef(SignerOperationSchema)),
5263
+ approvalUrl: String$1(),
5264
+ expiresAt: String$1()
5265
+ }, {
5266
+ $id: "SignerCeremony",
5267
+ additionalProperties: false
5268
+ });
5269
+ var SignerPendingResultSchema = _Object_({
5270
+ version: Literal(1),
5271
+ status: Literal("pending"),
5272
+ operation: Unsafe(schemaRef(SignerOperationSchema))
5273
+ }, {
5274
+ $id: "SignerPendingResult",
5275
+ additionalProperties: false
5276
+ });
5277
+ var SignerEnrollmentResultSchema = _Object_({
5278
+ version: Literal(1),
5279
+ status: Literal("completed"),
5280
+ operation: Literal("credential-enrollment"),
5281
+ publicMaterial: Unsafe(schemaRef(SignerPreviewSignPublicMaterialSchema))
5282
+ }, {
5283
+ $id: "SignerEnrollmentResult",
5284
+ additionalProperties: false
5285
+ });
5286
+ var SignerReceiptSchema = PreviewSignReceiptValueSchema;
5287
+ var SignerSignatureResultSchema = _Object_({
5288
+ version: Literal(1),
5289
+ status: Literal("completed"),
5290
+ operation: Unsafe(schemaRef(SignerChallengeOperationSchema)),
5291
+ receipt: Unsafe(schemaRef(SignerReceiptSchema))
5292
+ }, {
5293
+ $id: "SignerSignatureResult",
5294
+ additionalProperties: false
5295
+ });
5296
+ var SignerFailedResultSchema = _Object_({
5297
+ version: Literal(1),
5298
+ status: Literal("failed"),
5299
+ operation: Unsafe(schemaRef(SignerOperationSchema)),
5300
+ code: String$1(),
5301
+ message: String$1()
5302
+ }, {
5303
+ $id: "SignerFailedResult",
5304
+ additionalProperties: false
5305
+ });
5306
+ var SignerCeremonyResultSchema = Union([
5307
+ Unsafe(schemaRef(SignerPendingResultSchema)),
5308
+ Unsafe(schemaRef(SignerEnrollmentResultSchema)),
5309
+ Unsafe(schemaRef(SignerSignatureResultSchema)),
5310
+ Unsafe(schemaRef(SignerFailedResultSchema))
5311
+ ], { $id: "SignerCeremonyResult" });
5312
+ ({ ...previewSignSchemaContext }), schemaId(SignerUuidSchema), schemaId(SignerOperationSchema), schemaId(SignerProblemSchema), schemaId(SignerCeremonyParamsSchema), schemaId(SignerSessionSchema), schemaId(SignerEnrollmentCeremonyRequestSchema), schemaId(SignerChallengeCeremonyRequestSchema), schemaId(SignerCeremonyRequestSchema), schemaId(SignerCeremonySchema), schemaId(SignerPendingResultSchema), schemaId(SignerEnrollmentResultSchema), schemaId(SignerSignatureResultSchema), schemaId(SignerFailedResultSchema), schemaId(SignerCeremonyResultSchema);
5313
+ //#endregion
5314
+ //#region ../../libs/models/src/tool-enforcement.ts
5315
+ var TOOL_ENFORCEMENT_VALUES = [
5316
+ "off",
5317
+ "watch",
5318
+ "enforce"
5319
+ ];
5320
+ var ToolEnforcementSchema = Union([
5321
+ Literal(TOOL_ENFORCEMENT_VALUES[0]),
5322
+ Literal(TOOL_ENFORCEMENT_VALUES[1]),
5323
+ Literal(TOOL_ENFORCEMENT_VALUES[2])
5324
+ ], { description: "Runtime tool-policy enforcement mode: off (inert), watch (audit only), enforce (block disallowed tools, fail-closed)." });
5325
+ //#endregion
4457
5326
  //#region ../../libs/tasks/src/runtime-profiles.ts
4458
5327
  var RuntimeProfileName = String$1({
4459
5328
  minLength: 1,
@@ -4480,11 +5349,7 @@ var RuntimeProfileWorkspaceMode = Union([
4480
5349
  * `off` (inert), `watch` (audit only), `enforce` (block disallowed tools,
4481
5350
  * fail-closed). Read by the daemon via `GET /runtime-profiles/:id/allowed-tools`.
4482
5351
  */
4483
- var RuntimeProfileToolEnforcement = Union([
4484
- Literal("off"),
4485
- Literal("watch"),
4486
- Literal("enforce")
4487
- ]);
5352
+ var RuntimeProfileToolEnforcement = ToolEnforcementSchema;
4488
5353
  var RuntimeProfileAllowedWorkspaceModes = _Array_(RuntimeProfileWorkspaceMode, {
4489
5354
  minItems: 1,
4490
5355
  maxItems: 3,
@@ -6537,7 +7402,7 @@ var BUILT_IN_TASK_TYPES = {
6537
7402
  outputKind: "artifact",
6538
7403
  resumable: true,
6539
7404
  workspaceMode: "shared_mount",
6540
- workspaceScope: "session",
7405
+ workspaceScope: "attempt",
6541
7406
  sessionScope: "correlation",
6542
7407
  acceptsInputWorkspaceOverride: true,
6543
7408
  requiresReferences: false,
@@ -9880,6 +10745,11 @@ function createGhCliClient() {
9880
10745
  };
9881
10746
  }
9882
10747
  //#endregion
10748
+ //#region src/lib/daemon-slot-identity.ts
10749
+ function createRuntimeInstanceId() {
10750
+ return randomUUID();
10751
+ }
10752
+ //#endregion
9883
10753
  //#region src/lib/session-files.ts
9884
10754
  function resolveLatestPiSessionPath(sessionDir) {
9885
10755
  try {
@@ -9950,10 +10820,10 @@ function slugifySessionComponent(input) {
9950
10820
  }
9951
10821
  //#endregion
9952
10822
  //#region src/lib/task-execution-plan.ts
9953
- function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlSec, runtimeProfileWorkspacePolicy = {}) {
10823
+ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlSec, runtimeProfileWorkspacePolicy = {}, attemptN) {
9954
10824
  const descriptor = deriveTaskSessionDescriptor(task);
9955
10825
  const workspaceMode = resolveTaskWorkspaceMode(task, descriptor.policy, runtimeProfileWorkspacePolicy);
9956
- const slotKey = warmSessionTtlSec > 0 ? descriptor.sessionKey : null;
10826
+ const slotKey = warmSessionTtlSec > 0 && descriptor.sessionKey ? buildRuntimeSlotKey(descriptor.sessionKey, identity.runtimeInstanceId) : null;
9957
10827
  const workspaceScope = slotKey !== null ? descriptor.policy.workspaceScope : "attempt";
9958
10828
  const slotId = slotKey ? buildDaemonSlotId(identity, slotKey) : null;
9959
10829
  const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${encodeURIComponent(slotId)}` : null;
@@ -9961,7 +10831,8 @@ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlS
9961
10831
  const workspaceId = workspaceMode !== "shared_mount" ? resolveTaskWorkspaceId(task, {
9962
10832
  sessionKey: slotId,
9963
10833
  workspaceScope,
9964
- sessionPersistence: sessionDir ? { sessionDir } : null
10834
+ sessionPersistence: sessionDir ? { sessionDir } : null,
10835
+ attemptN
9965
10836
  }) : null;
9966
10837
  return {
9967
10838
  descriptor,
@@ -9985,6 +10856,12 @@ function buildDaemonSlotId(identity, slotKey) {
9985
10856
  slotKey
9986
10857
  ].join(":");
9987
10858
  }
10859
+ function buildRuntimeSlotKey(logicalSessionKey, runtimeInstanceId) {
10860
+ return runtimeInstanceId ? `${logicalSessionKey}:worker:${slugSlotIdentityComponent(runtimeInstanceId)}` : logicalSessionKey;
10861
+ }
10862
+ function runtimeSlotKeyBelongsToInstance(slotKey, runtimeInstanceId) {
10863
+ return slotKey.endsWith(`:worker:${slugSlotIdentityComponent(runtimeInstanceId)}`);
10864
+ }
9988
10865
  function slugSlotIdentityComponent(input) {
9989
10866
  return slugifyAsciiLower(input.trim(), 64, [
9990
10867
  ".",
@@ -10039,7 +10916,7 @@ function toDaemonWorkspaceMode(mode) {
10039
10916
  }
10040
10917
  function resolveTaskWorkspaceId(task, executionPlan) {
10041
10918
  if (executionPlan.workspaceScope === "session" && executionPlan.sessionKey !== null) return `session-${encodeURIComponent(executionPlan.sessionKey)}`;
10042
- return `task-${task.id}`;
10919
+ return executionPlan.attemptN ? `daemon-task-${task.id}-attempt-${executionPlan.attemptN}` : `task-${task.id}`;
10043
10920
  }
10044
10921
  //#endregion
10045
10922
  //#region src/lib/execution-plan-cache.ts
@@ -10058,7 +10935,7 @@ function createExecutionPlanCache(args) {
10058
10935
  const key = buildClaimedTaskKey(claimedTask);
10059
10936
  const existing = cache.get(key);
10060
10937
  if (existing) return existing;
10061
- const plan = await maybeAttachWarmSlotContext(claimedTask, buildDaemonTaskExecutionPlan(claimedTask.task, args.stateDirs, args.slotIdentity, args.warmSessionTtlSec, args.workspacePolicy), args.stateDirs, args.slotRegistry, runtimeSessionStore, sourceAttemptResolver);
10938
+ const plan = await maybeAttachWarmSlotContext(claimedTask, buildDaemonTaskExecutionPlan(claimedTask.task, args.stateDirs, args.slotIdentity, args.warmSessionTtlSec, args.workspacePolicy, claimedTask.attemptN), args.stateDirs, args.slotRegistry, runtimeSessionStore, sourceAttemptResolver);
10062
10939
  assertPlanAllowedByWorkspacePolicy(plan, args.workspacePolicy);
10063
10940
  cache.set(key, plan);
10064
10941
  return plan;
@@ -10125,14 +11002,13 @@ async function resolveWarmSlot(slotRegistry, runtimeSessionStore, teamId, source
10125
11002
  return {
10126
11003
  kind: "found",
10127
11004
  producerSlot: producerContext,
10128
- sessionPath: sourceSessionPath,
10129
- workspacePath: resolveProducerWorkspaceCopySource(producerContext, stateDirs)
11005
+ sessionPath: sourceSessionPath
10130
11006
  };
10131
11007
  }
10132
11008
  async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slotRegistry, runtimeSessionStore, sourceAttemptResolver) {
10133
11009
  if (claimedTask.task.taskType === "freeform") {
10134
11010
  const continueFrom = claimedTask.task.input.continueFrom;
10135
- if (!continueFrom) return basePlan;
11011
+ if (!continueFrom) return maybeAttachRetrySession(claimedTask, basePlan, stateDirs, slotRegistry, runtimeSessionStore);
10136
11012
  const resolution = await resolveWarmSlot(slotRegistry, runtimeSessionStore, claimedTask.task.teamId, continueFrom.taskId, continueFrom.attemptN, stateDirs);
10137
11013
  if (resolution.kind === "missing") throw new ProducerContextResolutionError(`Continuation source task ${continueFrom.taskId} attempt ${continueFrom.attemptN} has no local runtime slot or durable runtime session — claim affinity filter should have prevented this claim`);
10138
11014
  if (resolution.kind === "no-session-path") throw new ProducerContextResolutionError(`Continuation source attempt ${continueFrom.taskId}/${continueFrom.attemptN} has no persisted Pi session path`);
@@ -10164,7 +11040,7 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
10164
11040
  return {
10165
11041
  ...basePlan,
10166
11042
  workspaceMode: "dedicated_worktree",
10167
- workspaceId: recoveredBranch ? `extend-${continueFrom.taskId}-attempt-${continueFrom.attemptN}` : null,
11043
+ workspaceId: recoveredBranch ? buildAttemptWorkspaceId(claimedTask) : null,
10168
11044
  worktreeBranch: recoveredBranch,
10169
11045
  sessionPersistence: {
10170
11046
  sessionDir,
@@ -10193,7 +11069,7 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
10193
11069
  return {
10194
11070
  ...basePlan,
10195
11071
  workspaceMode: "dedicated_worktree",
10196
- workspaceId: resolution.producerSlot.workspace?.workspaceId ?? null,
11072
+ workspaceId: parentBranch ? buildAttemptWorkspaceId(claimedTask) : null,
10197
11073
  worktreeBranch: parentBranch,
10198
11074
  sessionPersistence: {
10199
11075
  sessionDir,
@@ -10215,7 +11091,7 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
10215
11091
  worktreeBranch: null,
10216
11092
  workspaceKind: "scratch",
10217
11093
  workspaceSeed: {
10218
- copyFromPath: resolution.workspacePath,
11094
+ copyFromPath: resolveProducerWorkspaceCopySource(resolution.producerSlot, stateDirs),
10219
11095
  source: "producer"
10220
11096
  },
10221
11097
  sessionPersistence: {
@@ -10224,6 +11100,25 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
10224
11100
  }
10225
11101
  };
10226
11102
  }
11103
+ function buildAttemptWorkspaceId(claimedTask) {
11104
+ return `daemon-task-${claimedTask.task.id}-attempt-${claimedTask.attemptN}`;
11105
+ }
11106
+ async function maybeAttachRetrySession(claimedTask, basePlan, stateDirs, slotRegistry, runtimeSessionStore) {
11107
+ if (claimedTask.attemptN <= 1 || !basePlan.sessionPersistence?.sessionDir) return basePlan;
11108
+ const resolution = await resolveWarmSlot(slotRegistry, runtimeSessionStore, claimedTask.task.teamId, claimedTask.task.id, claimedTask.attemptN - 1, stateDirs);
11109
+ if (resolution.kind === "missing" || resolution.kind === "no-session-path") return basePlan;
11110
+ const sourceSessionDir = dirname(resolution.sessionPath);
11111
+ const targetSessionDir = basePlan.sessionPersistence.sessionDir;
11112
+ if (sourceSessionDir === targetSessionDir) return basePlan;
11113
+ return {
11114
+ ...basePlan,
11115
+ worktreeBranch: basePlan.workspaceMode === "dedicated_worktree" && resolution.kind === "found" ? resolution.producerSlot.workspace?.worktreeBranch ?? basePlan.worktreeBranch : basePlan.worktreeBranch,
11116
+ sessionPersistence: {
11117
+ sessionDir: targetSessionDir,
11118
+ forkFromSessionPath: resolution.sessionPath
11119
+ }
11120
+ };
11121
+ }
10227
11122
  function buildForkBranch(parentBranch, childTaskId, childAttemptN) {
10228
11123
  return `${parentBranch}-fork-${childTaskId.slice(0, 8)}-${childAttemptN}`;
10229
11124
  }
@@ -10267,6 +11162,7 @@ var RETRYABLE_CODES = new Set([
10267
11162
  ]);
10268
11163
  var NON_RETRYABLE_CODES = new Set([
10269
11164
  "bad_api_key",
11165
+ "executor_threw",
10270
11166
  "invalid_api_key",
10271
11167
  "invalid_model",
10272
11168
  "max_turns_exceeded",
@@ -10309,17 +11205,18 @@ var NON_RETRYABLE_MESSAGE_PATTERNS = [
10309
11205
  /\bmax (?:turn|bash)/i
10310
11206
  ];
10311
11207
  async function classifyAttemptFailure(input) {
10312
- if (input.remainingAttempts !== null && input.remainingAttempts !== void 0) {
10313
- if (input.remainingAttempts <= 0) return {
11208
+ const deterministic = classifyDeterministically(input.error);
11209
+ if (input.remainingAttempts !== null && input.remainingAttempts !== void 0 && input.remainingAttempts <= 0) {
11210
+ const deterministicReason = deterministic === "ambiguous" ? "" : ` Deterministic policy classified the failure as ${deterministic}.`;
11211
+ return {
10314
11212
  error: withRetryInfo(input.error, {
10315
11213
  retryable: false,
10316
11214
  source: "attempts_exhausted",
10317
- reason: `Attempt budget exhausted at attempt ${input.attemptN}${input.maxAttempts ? ` of ${input.maxAttempts}` : ""}.`
11215
+ reason: `Attempt budget exhausted at attempt ${input.attemptN}${input.maxAttempts ? ` of ${input.maxAttempts}` : ""}.${deterministicReason}`
10318
11216
  }),
10319
11217
  source: "attempts_exhausted"
10320
11218
  };
10321
11219
  }
10322
- const deterministic = classifyDeterministically(input.error);
10323
11220
  if (deterministic !== "ambiguous") {
10324
11221
  const retryable = deterministic === "retryable";
10325
11222
  const source = input.error.retryable === retryable ? "explicit" : "deterministic";
@@ -10895,6 +11792,269 @@ function createRuntimeProfileRetryTriage(options) {
10895
11792
  });
10896
11793
  }
10897
11794
  //#endregion
11795
+ //#region src/lib/runtime-resource-reaper.ts
11796
+ var RUNTIME_SLOT_PAGE_LIMIT = 200;
11797
+ var ATTEMPT_LOOKUP_CONCURRENCY = 8;
11798
+ var TERMINAL_ATTEMPT_STATUSES = new Set([
11799
+ "completed",
11800
+ "failed",
11801
+ "cancelled",
11802
+ "aborted",
11803
+ "timed_out"
11804
+ ]);
11805
+ /**
11806
+ * Reap daemon-owned local resources whose runtime slot is no longer usable.
11807
+ * The destructive path is deliberately conservative: uncertainty about slot
11808
+ * ownership, attempt state, listing completeness, or real filesystem
11809
+ * containment retains resources rather than risking another daemon's data.
11810
+ */
11811
+ async function reapRuntimeSlotResources(deps, input) {
11812
+ const now = input.now ?? Date.now();
11813
+ const [activePage, idlePage] = await Promise.all([listOwnedSlots(deps.runtimeSlotStore, input, "active"), listOwnedSlots(deps.runtimeSlotStore, input, "idle")]);
11814
+ const active = activePage.items;
11815
+ const idle = idlePage.items;
11816
+ const slots = [...active, ...idle];
11817
+ const result = {
11818
+ failed: 0,
11819
+ failures: [],
11820
+ removedSessions: 0,
11821
+ removedWorkspaces: 0,
11822
+ scanned: slots.length,
11823
+ truncated: activePage.truncated || idlePage.truncated,
11824
+ unsafePathDetails: [],
11825
+ unsafePaths: 0
11826
+ };
11827
+ const reaped = new Set(idle.filter((item) => item.slot.expiresAtMs <= now).map((item) => item.slot.id));
11828
+ for (const slotId of await findTerminalActiveSlotIds(deps, active, result)) reaped.add(slotId);
11829
+ const retainedSessionDirs = new Set(slots.filter((item) => !reaped.has(item.slot.id)).flatMap((item) => item.session?.sessionDir ? [resolve(item.session.sessionDir)] : []));
11830
+ const retainedWorkspacePaths = new Set(slots.filter((item) => !reaped.has(item.slot.id)).flatMap((item) => item.workspace?.worktreePath ? [resolve(item.workspace.worktreePath)] : []));
11831
+ const worktrees = input.mainWorktree ? await listRegisteredWorktrees(input.mainWorktree) : {
11832
+ kind: "ready",
11833
+ paths: /* @__PURE__ */ new Set()
11834
+ };
11835
+ for (const item of slots) {
11836
+ if (!reaped.has(item.slot.id)) continue;
11837
+ if (!await slotStillQualifiesForReaping(deps, input, item, now, result)) continue;
11838
+ const sessionDir = item.session?.sessionDir;
11839
+ if (sessionDir && !retainedSessionDirs.has(resolve(sessionDir)) && existsSync(sessionDir)) if (!isRealPathInsideRoot(sessionDir, input.sessionRootDir)) recordUnsafePath(deps, result, item.slot.id, sessionDir, input.sessionRootDir);
11840
+ else try {
11841
+ rmSync(sessionDir, {
11842
+ force: true,
11843
+ recursive: true
11844
+ });
11845
+ result.removedSessions++;
11846
+ } catch (err) {
11847
+ recordFailure(deps, result, item.slot.id, sessionDir, input.sessionRootDir, err);
11848
+ }
11849
+ const workspacePath = item.workspace?.worktreePath;
11850
+ if (!workspacePath || retainedWorkspacePaths.has(resolve(workspacePath))) continue;
11851
+ const workspaceRoot = item.workspace?.kind === "scratch" ? input.scratchRootDir : input.mainWorktree ? resolve(input.mainWorktree, ".worktrees") : null;
11852
+ if (!workspaceRoot) {
11853
+ recordUnsafePath(deps, result, item.slot.id, workspacePath, null);
11854
+ continue;
11855
+ }
11856
+ await removeWorkspace(deps, result, worktrees, input.mainWorktree, item.slot.id, workspacePath, workspaceRoot, item.workspace?.kind === "scratch");
11857
+ }
11858
+ if (!result.truncated) await reapLegacyOrphanWorktrees(deps, input, worktrees, retainedSessionDirs, retainedWorkspacePaths, result);
11859
+ return result;
11860
+ }
11861
+ async function listOwnedSlots(store, input, state) {
11862
+ const listed = await store.listSlots({
11863
+ agentName: input.agentName,
11864
+ limit: RUNTIME_SLOT_PAGE_LIMIT,
11865
+ runtimeProfileId: input.runtimeProfileId,
11866
+ state,
11867
+ teamId: input.teamId
11868
+ });
11869
+ return {
11870
+ items: listed.filter((item) => runtimeSlotKeyBelongsToInstance(item.slot.slotKey, input.runtimeInstanceId)),
11871
+ truncated: listed.length === RUNTIME_SLOT_PAGE_LIMIT
11872
+ };
11873
+ }
11874
+ async function findTerminalActiveSlotIds(deps, active, result) {
11875
+ const byTask = /* @__PURE__ */ new Map();
11876
+ for (const item of active) {
11877
+ const taskSlots = byTask.get(item.slot.lastTaskId) ?? [];
11878
+ taskSlots.push(item);
11879
+ byTask.set(item.slot.lastTaskId, taskSlots);
11880
+ }
11881
+ const terminal = /* @__PURE__ */ new Set();
11882
+ await mapWithConcurrency([...byTask.entries()], ATTEMPT_LOOKUP_CONCURRENCY, async ([taskId, taskSlots]) => {
11883
+ let attempts;
11884
+ try {
11885
+ attempts = await deps.taskReader.listAttempts(taskId);
11886
+ } catch (err) {
11887
+ recordFailure(deps, result, null, `task:${taskId}`, null, err);
11888
+ return;
11889
+ }
11890
+ for (const item of taskSlots) {
11891
+ const attempt = attempts.find((candidate) => candidate.attemptN === item.slot.lastAttemptN);
11892
+ if (attempt && TERMINAL_ATTEMPT_STATUSES.has(attempt.status)) terminal.add(item.slot.id);
11893
+ }
11894
+ });
11895
+ return terminal;
11896
+ }
11897
+ async function slotStillQualifiesForReaping(deps, input, original, now, result) {
11898
+ let page;
11899
+ try {
11900
+ page = await listOwnedSlots(deps.runtimeSlotStore, input, original.slot.state);
11901
+ } catch (err) {
11902
+ recordFailure(deps, result, original.slot.id, `slot:${original.slot.id}`, null, err);
11903
+ return false;
11904
+ }
11905
+ const current = page.items.find((candidate) => candidate.slot.id === original.slot.id);
11906
+ if (!current) return false;
11907
+ if (current.slot.lastTaskId !== original.slot.lastTaskId || current.slot.lastAttemptN !== original.slot.lastAttemptN) return false;
11908
+ return current.slot.state === "active" || current.slot.state === "idle" && current.slot.expiresAtMs <= now;
11909
+ }
11910
+ async function reapLegacyOrphanWorktrees(deps, input, worktrees, retainedSessionDirs, retainedWorkspacePaths, result) {
11911
+ if (!input.mainWorktree) return;
11912
+ const workspaceRoot = resolve(input.mainWorktree, ".worktrees");
11913
+ if (!existsSync(workspaceRoot)) return;
11914
+ let entries;
11915
+ try {
11916
+ entries = readdirSync(workspaceRoot, { withFileTypes: true });
11917
+ } catch (err) {
11918
+ recordFailure(deps, result, null, workspaceRoot, workspaceRoot, err);
11919
+ return;
11920
+ }
11921
+ for (const entry of entries) {
11922
+ if (!entry.isDirectory() || !entry.name.startsWith("session-agent%3A")) continue;
11923
+ const workspacePath = resolve(workspaceRoot, entry.name);
11924
+ if (retainedWorkspacePaths.has(workspacePath)) continue;
11925
+ const sessionDir = resolve(input.sessionRootDir, entry.name.slice(8));
11926
+ if (retainedSessionDirs.has(sessionDir) || existsSync(sessionDir)) continue;
11927
+ await removeWorkspace(deps, result, worktrees, input.mainWorktree, null, workspacePath, workspaceRoot, false);
11928
+ }
11929
+ }
11930
+ async function removeWorkspace(deps, result, worktrees, mainWorktree, slotId, workspacePath, workspaceRoot, scratch) {
11931
+ if (!existsSync(workspacePath)) return;
11932
+ if (!isRealPathInsideRoot(workspacePath, workspaceRoot)) {
11933
+ recordUnsafePath(deps, result, slotId, workspacePath, workspaceRoot);
11934
+ return;
11935
+ }
11936
+ if (scratch || !mainWorktree) {
11937
+ try {
11938
+ rmSync(workspacePath, {
11939
+ force: true,
11940
+ recursive: true
11941
+ });
11942
+ result.removedWorkspaces++;
11943
+ } catch (err) {
11944
+ recordFailure(deps, result, slotId, workspacePath, workspaceRoot, err);
11945
+ }
11946
+ return;
11947
+ }
11948
+ if (worktrees.kind === "unavailable") {
11949
+ recordFailure(deps, result, slotId, workspacePath, workspaceRoot, new Error(worktrees.reason));
11950
+ return;
11951
+ }
11952
+ try {
11953
+ const canonical = realpathSync(workspacePath);
11954
+ if (worktrees.paths.has(canonical)) {
11955
+ await execFileText("git", [
11956
+ "-C",
11957
+ mainWorktree,
11958
+ "worktree",
11959
+ "remove",
11960
+ "--force",
11961
+ workspacePath
11962
+ ]);
11963
+ worktrees.paths.delete(canonical);
11964
+ } else rmSync(workspacePath, {
11965
+ force: true,
11966
+ recursive: true
11967
+ });
11968
+ result.removedWorkspaces++;
11969
+ } catch (err) {
11970
+ recordFailure(deps, result, slotId, workspacePath, workspaceRoot, err);
11971
+ }
11972
+ }
11973
+ async function listRegisteredWorktrees(mainWorktree) {
11974
+ try {
11975
+ const list = await execFileText("git", [
11976
+ "-C",
11977
+ mainWorktree,
11978
+ "worktree",
11979
+ "list",
11980
+ "--porcelain"
11981
+ ]);
11982
+ return {
11983
+ kind: "ready",
11984
+ paths: new Set(list.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => canonicalPath(line.slice(9))))
11985
+ };
11986
+ } catch (err) {
11987
+ return {
11988
+ kind: "unavailable",
11989
+ reason: errorMessage(err)
11990
+ };
11991
+ }
11992
+ }
11993
+ function isRealPathInsideRoot(path, root) {
11994
+ try {
11995
+ return isResolvedPathInsideRoot$1(realpathSync(path), realpathSync(root));
11996
+ } catch {
11997
+ return false;
11998
+ }
11999
+ }
12000
+ function isResolvedPathInsideRoot$1(path, root) {
12001
+ const rel = relative(root, path);
12002
+ return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
12003
+ }
12004
+ function canonicalPath(path) {
12005
+ try {
12006
+ return realpathSync(path);
12007
+ } catch {
12008
+ return resolve(path);
12009
+ }
12010
+ }
12011
+ function recordUnsafePath(deps, result, slotId, path, root) {
12012
+ const issue = {
12013
+ kind: "unsafe_path",
12014
+ path,
12015
+ reason: root === null ? "No daemon-owned root was available for this workspace." : "Candidate or root could not be resolved inside the daemon-owned root.",
12016
+ root,
12017
+ slotId
12018
+ };
12019
+ result.unsafePaths++;
12020
+ result.unsafePathDetails.push(issue);
12021
+ emitIssue(deps, issue);
12022
+ }
12023
+ function recordFailure(deps, result, slotId, path, root, err) {
12024
+ const issue = {
12025
+ kind: "failure",
12026
+ path,
12027
+ reason: errorMessage(err),
12028
+ root,
12029
+ slotId
12030
+ };
12031
+ result.failed++;
12032
+ result.failures.push(issue);
12033
+ emitIssue(deps, issue);
12034
+ }
12035
+ function emitIssue(deps, issue) {
12036
+ try {
12037
+ deps.onIssue?.(issue);
12038
+ } catch {}
12039
+ }
12040
+ function errorMessage(err) {
12041
+ return err instanceof Error ? err.message : String(err);
12042
+ }
12043
+ async function execFileText(file, args) {
12044
+ return new Promise((resolvePromise, reject) => {
12045
+ execFile(file, args, {
12046
+ encoding: "utf8",
12047
+ maxBuffer: 10 * 1024 * 1024
12048
+ }, (err, stdout) => {
12049
+ if (err) reject(err instanceof Error ? err : /* @__PURE__ */ new Error("Child process failed without an Error instance."));
12050
+ else resolvePromise(stdout);
12051
+ });
12052
+ });
12053
+ }
12054
+ async function mapWithConcurrency(items, concurrency, worker) {
12055
+ for (let index = 0; index < items.length; index += concurrency) await Promise.all(items.slice(index, index + concurrency).map(worker));
12056
+ }
12057
+ //#endregion
10898
12058
  //#region src/lib/runtime-sessions.ts
10899
12059
  function resolveRuntimeSessionKind(claimedTask) {
10900
12060
  const continueFrom = resolveContinueFrom(claimedTask);
@@ -11031,6 +12191,8 @@ function createApiRuntimeSlotStore(args) {
11031
12191
  lastAttemptN: resolved.slot.lastAttemptN,
11032
12192
  lastTaskId: resolved.slot.lastTaskId,
11033
12193
  runtimeProfileId: resolved.slot.runtimeProfileId,
12194
+ slotKey: resolved.slot.slotKey,
12195
+ state: resolved.slot.state,
11034
12196
  taskType: resolved.slot.taskType
11035
12197
  },
11036
12198
  session: resolved.slot.sessionDir ? {
@@ -11202,12 +12364,13 @@ async function runPolling(opts) {
11202
12364
  agent: ctx.agent,
11203
12365
  profiles: profileValues,
11204
12366
  teamId,
11205
- cwd: process.cwd()
12367
+ cwd: ctx.agentRootDir
11206
12368
  });
11207
12369
  for (const profile of profiles) validateRuntimeProfilePrerequisites(profile, cfg.profilePrerequisiteEnv, cfg.profilePrerequisitePath);
11208
12370
  const slotRegistry = createApiRuntimeSlotStore({ agent: ctx.agent });
11209
12371
  const runtimeSessionStore = createApiRuntimeSessionStore({ agent: ctx.agent });
11210
12372
  const sourceAttemptResolver = createApiSourceAttemptResolver({ agent: ctx.agent });
12373
+ const runtimeInstanceId = createRuntimeInstanceId();
11211
12374
  const runtimes = /* @__PURE__ */ new Map();
11212
12375
  for (const profile of profiles) {
11213
12376
  const common = parseCommonOptions(values, { runtimeDefaults: {
@@ -11227,7 +12390,8 @@ async function runPolling(opts) {
11227
12390
  const stateDirs = ensureDaemonStateDirs(sandbox.rootDir);
11228
12391
  const slotIdentity = {
11229
12392
  agentName: common.agent,
11230
- runtimeProfileId: profile.id
12393
+ runtimeProfileId: profile.id,
12394
+ runtimeInstanceId
11231
12395
  };
11232
12396
  const executionPlans = createExecutionPlanCache({
11233
12397
  stateDirs,
@@ -11335,6 +12499,47 @@ async function runPolling(opts) {
11335
12499
  piAgentDir: piAgentDir.path,
11336
12500
  piAgentDirSource: piAgentDir.source
11337
12501
  }, "agent-daemon.starting");
12502
+ let reaperRunning = false;
12503
+ const reapRuntimeResources = async () => {
12504
+ if (reaperRunning) return;
12505
+ reaperRunning = true;
12506
+ try {
12507
+ for (const profile of profiles) {
12508
+ const selected = requireRuntime(runtimes, profile.id);
12509
+ const result = await reapRuntimeSlotResources({
12510
+ onIssue: (issue) => {
12511
+ rootLogger.warn({
12512
+ ...issue,
12513
+ runtimeProfileId: profile.id
12514
+ }, "agent-daemon.runtime_resource_reap_issue");
12515
+ },
12516
+ runtimeSlotStore: slotRegistry,
12517
+ taskReader: ctx.agent.tasks
12518
+ }, {
12519
+ agentName: selected.common.agent,
12520
+ mainWorktree: resolveMainWorktree$1(selected.sandbox.rootDir),
12521
+ runtimeInstanceId,
12522
+ runtimeProfileId: profile.id,
12523
+ sessionRootDir: selected.stateDirs.piSessionsDir,
12524
+ scratchRootDir: join(selected.stateDirs.rootDir, "task-workspaces"),
12525
+ teamId
12526
+ });
12527
+ if (result.removedSessions > 0 || result.removedWorkspaces > 0 || result.failed > 0 || result.unsafePaths > 0 || result.truncated) rootLogger.info({
12528
+ ...result,
12529
+ runtimeProfileId: profile.id
12530
+ }, "agent-daemon.runtime_resources_reaped");
12531
+ }
12532
+ } catch (err) {
12533
+ rootLogger.warn({ err }, "agent-daemon.runtime_resource_reap_failed");
12534
+ } finally {
12535
+ reaperRunning = false;
12536
+ }
12537
+ };
12538
+ await reapRuntimeResources();
12539
+ const reaperTimer = setInterval(() => {
12540
+ reapRuntimeResources();
12541
+ }, 6e4);
12542
+ reaperTimer.unref();
11338
12543
  const outputs = [];
11339
12544
  try {
11340
12545
  runtime = new AgentRuntime({
@@ -11512,7 +12717,7 @@ async function runPolling(opts) {
11512
12717
  sessionDir: executionPlan.sessionPersistence.sessionDir,
11513
12718
  sessionPath: resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir),
11514
12719
  workspaceId: executionPlan.workspaceId,
11515
- worktreePath: resolveRecordedWorkspacePath$1(stateDirs.rootDir, executionPlan),
12720
+ worktreePath: resolveRecordedWorkspacePath$1(stateDirs.rootDir, sandbox.rootDir, executionPlan),
11516
12721
  worktreeBranch: executionPlan.worktreeBranch,
11517
12722
  workspaceKind: executionPlan.workspaceKind,
11518
12723
  lastTaskId: claimedTask.task.id,
@@ -11568,15 +12773,23 @@ async function runPolling(opts) {
11568
12773
  rootLogger.info({ processed: drained.length }, "agent-daemon.drained");
11569
12774
  return drained.some((o) => o.status !== "completed") ? 1 : 0;
11570
12775
  } finally {
12776
+ clearInterval(reaperTimer);
11571
12777
  signalHandlers.dispose();
11572
12778
  await slotRegistry.close();
11573
12779
  await otelShutdown();
11574
12780
  await shutdownLogger();
11575
12781
  }
11576
12782
  }
11577
- function resolveRecordedWorkspacePath$1(stateRootDir, executionPlan) {
12783
+ function resolveRecordedWorkspacePath$1(stateRootDir, mountPath, executionPlan) {
11578
12784
  if (!executionPlan.workspaceId) return null;
11579
- return executionPlan.workspaceMode === "scratch_mount" ? join(stateRootDir, "task-workspaces", executionPlan.workspaceId) : join(findMainWorktree(), ".worktrees", executionPlan.workspaceId);
12785
+ return executionPlan.workspaceMode === "scratch_mount" ? join(stateRootDir, "task-workspaces", executionPlan.workspaceId) : join(findMainWorktree(mountPath), ".worktrees", executionPlan.workspaceId);
12786
+ }
12787
+ function resolveMainWorktree$1(mountPath) {
12788
+ try {
12789
+ return findMainWorktree(mountPath);
12790
+ } catch {
12791
+ return null;
12792
+ }
11580
12793
  }
11581
12794
  function runtimeForClaimedTask(runtimes, claimedTask) {
11582
12795
  if (!claimedTask.profileId) throw new Error(`Claimed task ${claimedTask.task.id} did not include a selected runtime profile`);
@@ -11668,7 +12881,7 @@ async function runOnce(argv) {
11668
12881
  agent: ctx.agent,
11669
12882
  profile: values.profile,
11670
12883
  teamId: values.team,
11671
- cwd: process.cwd()
12884
+ cwd: ctx.agentRootDir
11672
12885
  });
11673
12886
  validateRuntimeProfilePrerequisites(profile, cfg.profilePrerequisiteEnv, cfg.profilePrerequisitePath);
11674
12887
  opts = parseCommonOptions(values, { runtimeDefaults: {
@@ -11690,9 +12903,11 @@ async function runOnce(argv) {
11690
12903
  const slotRegistry = createApiRuntimeSlotStore({ agent: ctx.agent });
11691
12904
  const runtimeSessionStore = createApiRuntimeSessionStore({ agent: ctx.agent });
11692
12905
  const sourceAttemptResolver = createApiSourceAttemptResolver({ agent: ctx.agent });
12906
+ const runtimeInstanceId = createRuntimeInstanceId();
11693
12907
  const slotIdentity = {
11694
12908
  agentName: opts.agent,
11695
- runtimeProfileId: profile.id
12909
+ runtimeProfileId: profile.id,
12910
+ runtimeInstanceId
11696
12911
  };
11697
12912
  const executionPlans = createExecutionPlanCache({
11698
12913
  stateDirs,
@@ -11754,6 +12969,26 @@ async function runOnce(argv) {
11754
12969
  piAgentDir: piAgentDir.path,
11755
12970
  piAgentDirSource: piAgentDir.source
11756
12971
  }, "agent-daemon.starting");
12972
+ try {
12973
+ const reaped = await reapRuntimeSlotResources({
12974
+ onIssue: (issue) => {
12975
+ rootLogger.warn(issue, "agent-daemon.runtime_resource_reap_issue");
12976
+ },
12977
+ runtimeSlotStore: slotRegistry,
12978
+ taskReader: ctx.agent.tasks
12979
+ }, {
12980
+ agentName: opts.agent,
12981
+ mainWorktree: resolveMainWorktree(sandbox.rootDir),
12982
+ runtimeInstanceId,
12983
+ runtimeProfileId: profile.id,
12984
+ sessionRootDir: stateDirs.piSessionsDir,
12985
+ scratchRootDir: join(stateDirs.rootDir, "task-workspaces"),
12986
+ teamId: profile.teamId
12987
+ });
12988
+ if (reaped.removedSessions > 0 || reaped.removedWorkspaces > 0 || reaped.failed > 0 || reaped.unsafePaths > 0 || reaped.truncated) rootLogger.info(reaped, "agent-daemon.runtime_resources_reaped");
12989
+ } catch (err) {
12990
+ rootLogger.warn({ err }, "agent-daemon.runtime_resource_reap_failed");
12991
+ }
11757
12992
  let runtime = null;
11758
12993
  let activeAttemptN = null;
11759
12994
  const signalHandlers = installShutdownSignalHandlers({
@@ -11843,7 +13078,7 @@ async function runOnce(argv) {
11843
13078
  sessionDir: executionPlan.sessionPersistence.sessionDir,
11844
13079
  sessionPath: resolveLatestPiSessionPath(executionPlan.sessionPersistence.sessionDir),
11845
13080
  workspaceId: executionPlan.workspaceId,
11846
- worktreePath: resolveRecordedWorkspacePath(stateDirs.rootDir, executionPlan),
13081
+ worktreePath: resolveRecordedWorkspacePath(stateDirs.rootDir, sandbox.rootDir, executionPlan),
11847
13082
  worktreeBranch: executionPlan.worktreeBranch,
11848
13083
  workspaceKind: executionPlan.workspaceKind,
11849
13084
  lastTaskId: claimedTask.task.id,
@@ -11939,9 +13174,16 @@ async function runOnce(argv) {
11939
13174
  await shutdownLogger();
11940
13175
  }
11941
13176
  }
11942
- function resolveRecordedWorkspacePath(stateRootDir, executionPlan) {
13177
+ function resolveRecordedWorkspacePath(stateRootDir, mountPath, executionPlan) {
11943
13178
  if (!executionPlan.workspaceId) return null;
11944
- return executionPlan.workspaceMode === "scratch_mount" ? join(stateRootDir, "task-workspaces", executionPlan.workspaceId) : join(findMainWorktree(), ".worktrees", executionPlan.workspaceId);
13179
+ return executionPlan.workspaceMode === "scratch_mount" ? join(stateRootDir, "task-workspaces", executionPlan.workspaceId) : join(findMainWorktree(mountPath), ".worktrees", executionPlan.workspaceId);
13180
+ }
13181
+ function resolveMainWorktree(mountPath) {
13182
+ try {
13183
+ return findMainWorktree(mountPath);
13184
+ } catch {
13185
+ return null;
13186
+ }
11945
13187
  }
11946
13188
  //#endregion
11947
13189
  //#region src/cli/poll.ts