@narumitw/pi-subagents 2.0.0 → 2.0.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 (148) hide show
  1. package/README.md +21 -8
  2. package/dist/chunks/auto-transport-SY2VHUFH.ts +109 -0
  3. package/dist/chunks/auto-transport-SY2VHUFH.ts.map +7 -0
  4. package/dist/chunks/capability-grant-CGEWOEKE.ts +19 -0
  5. package/dist/chunks/capability-grant-CGEWOEKE.ts.map +7 -0
  6. package/dist/chunks/chunk-434NII74.ts +282 -0
  7. package/dist/chunks/chunk-434NII74.ts.map +7 -0
  8. package/dist/chunks/chunk-47SK2QYC.ts +56 -0
  9. package/dist/chunks/chunk-47SK2QYC.ts.map +7 -0
  10. package/dist/chunks/chunk-6KJ34M6S.ts +159 -0
  11. package/dist/chunks/chunk-6KJ34M6S.ts.map +7 -0
  12. package/dist/chunks/chunk-7OBINKFM.ts +80 -0
  13. package/dist/chunks/chunk-7OBINKFM.ts.map +7 -0
  14. package/dist/chunks/chunk-7QPPBBXZ.ts +335 -0
  15. package/dist/chunks/chunk-7QPPBBXZ.ts.map +7 -0
  16. package/dist/chunks/chunk-AEUYS7JC.ts +73 -0
  17. package/dist/chunks/chunk-AEUYS7JC.ts.map +7 -0
  18. package/dist/chunks/chunk-BFK2Z4ZF.ts +189 -0
  19. package/dist/chunks/chunk-BFK2Z4ZF.ts.map +7 -0
  20. package/dist/chunks/chunk-BOAXY55Y.ts +153 -0
  21. package/dist/chunks/chunk-BOAXY55Y.ts.map +7 -0
  22. package/dist/chunks/chunk-C4L6P266.ts +22 -0
  23. package/dist/chunks/chunk-C4L6P266.ts.map +7 -0
  24. package/dist/chunks/chunk-DPPVEQAM.ts +29 -0
  25. package/dist/chunks/chunk-DPPVEQAM.ts.map +7 -0
  26. package/dist/chunks/chunk-DQMN4OYM.ts +913 -0
  27. package/dist/chunks/chunk-DQMN4OYM.ts.map +7 -0
  28. package/dist/chunks/chunk-DSOOH73Y.ts +238 -0
  29. package/dist/chunks/chunk-DSOOH73Y.ts.map +7 -0
  30. package/dist/chunks/chunk-EFBPISNT.ts +421 -0
  31. package/dist/chunks/chunk-EFBPISNT.ts.map +7 -0
  32. package/dist/chunks/chunk-EWWXFU7N.ts +150 -0
  33. package/dist/chunks/chunk-EWWXFU7N.ts.map +7 -0
  34. package/dist/chunks/chunk-F4L2UVSK.ts +380 -0
  35. package/dist/chunks/chunk-F4L2UVSK.ts.map +7 -0
  36. package/dist/chunks/chunk-F5YWVHQX.ts +1543 -0
  37. package/dist/chunks/chunk-F5YWVHQX.ts.map +7 -0
  38. package/dist/chunks/chunk-G3RSMSXJ.ts +63 -0
  39. package/dist/chunks/chunk-G3RSMSXJ.ts.map +7 -0
  40. package/dist/chunks/chunk-G6VZTCFH.ts +70 -0
  41. package/dist/chunks/chunk-G6VZTCFH.ts.map +7 -0
  42. package/dist/chunks/chunk-H3FP6DLR.ts +160 -0
  43. package/dist/chunks/chunk-H3FP6DLR.ts.map +7 -0
  44. package/dist/chunks/chunk-HA36LPCO.ts +130 -0
  45. package/dist/chunks/chunk-HA36LPCO.ts.map +7 -0
  46. package/dist/chunks/chunk-HKC4ES4B.ts +65 -0
  47. package/dist/chunks/chunk-HKC4ES4B.ts.map +7 -0
  48. package/dist/chunks/chunk-HOP5FXDT.ts +27 -0
  49. package/dist/chunks/chunk-HOP5FXDT.ts.map +7 -0
  50. package/dist/chunks/chunk-I2FAK44T.ts +324 -0
  51. package/dist/chunks/chunk-I2FAK44T.ts.map +7 -0
  52. package/dist/chunks/chunk-IGAMVWFN.ts +139 -0
  53. package/dist/chunks/chunk-IGAMVWFN.ts.map +7 -0
  54. package/dist/chunks/chunk-KMGKCEO4.ts +38 -0
  55. package/dist/chunks/chunk-KMGKCEO4.ts.map +7 -0
  56. package/dist/chunks/chunk-N7BLVXKK.ts +73 -0
  57. package/dist/chunks/chunk-N7BLVXKK.ts.map +7 -0
  58. package/dist/chunks/chunk-NIF42QMF.ts +297 -0
  59. package/dist/chunks/chunk-NIF42QMF.ts.map +7 -0
  60. package/dist/chunks/chunk-O4VO6JUJ.ts +52 -0
  61. package/dist/chunks/chunk-O4VO6JUJ.ts.map +7 -0
  62. package/dist/chunks/chunk-ONDTY4EL.ts +91 -0
  63. package/dist/chunks/chunk-ONDTY4EL.ts.map +7 -0
  64. package/dist/chunks/chunk-OVPHFGKO.ts +1769 -0
  65. package/dist/chunks/chunk-OVPHFGKO.ts.map +7 -0
  66. package/dist/chunks/chunk-P7OH4XMF.ts +60 -0
  67. package/dist/chunks/chunk-P7OH4XMF.ts.map +7 -0
  68. package/dist/chunks/chunk-PSK43Y6A.ts +339 -0
  69. package/dist/chunks/chunk-PSK43Y6A.ts.map +7 -0
  70. package/dist/chunks/chunk-QBORTI4W.ts +468 -0
  71. package/dist/chunks/chunk-QBORTI4W.ts.map +7 -0
  72. package/dist/chunks/chunk-QDVGH2X7.ts +171 -0
  73. package/dist/chunks/chunk-QDVGH2X7.ts.map +7 -0
  74. package/dist/chunks/chunk-RHRQMT7Q.ts +490 -0
  75. package/dist/chunks/chunk-RHRQMT7Q.ts.map +7 -0
  76. package/dist/chunks/chunk-RRR66UWR.ts +28 -0
  77. package/dist/chunks/chunk-RRR66UWR.ts.map +7 -0
  78. package/dist/chunks/chunk-RSUXZD6S.ts +275 -0
  79. package/dist/chunks/chunk-RSUXZD6S.ts.map +7 -0
  80. package/dist/chunks/chunk-RTCVYIZA.ts +221 -0
  81. package/dist/chunks/chunk-RTCVYIZA.ts.map +7 -0
  82. package/dist/chunks/chunk-S2IWVK3J.ts +44 -0
  83. package/dist/chunks/chunk-S2IWVK3J.ts.map +7 -0
  84. package/dist/chunks/chunk-SCZ33MYW.ts +52 -0
  85. package/dist/chunks/chunk-SCZ33MYW.ts.map +7 -0
  86. package/dist/chunks/chunk-SWGQLFSD.ts +60 -0
  87. package/dist/chunks/chunk-SWGQLFSD.ts.map +7 -0
  88. package/dist/chunks/chunk-UMBPMVJW.ts +22 -0
  89. package/dist/chunks/chunk-UMBPMVJW.ts.map +7 -0
  90. package/dist/chunks/chunk-UVFVHIOP.ts +735 -0
  91. package/dist/chunks/chunk-UVFVHIOP.ts.map +7 -0
  92. package/dist/chunks/completion-delivery-YPOWSSV3.ts +16 -0
  93. package/dist/chunks/completion-delivery-YPOWSSV3.ts.map +7 -0
  94. package/dist/chunks/config-status-J4GPWP46.ts +34 -0
  95. package/dist/chunks/config-status-J4GPWP46.ts.map +7 -0
  96. package/dist/chunks/config-ui-3IBMHTQB.ts +1146 -0
  97. package/dist/chunks/config-ui-3IBMHTQB.ts.map +7 -0
  98. package/dist/chunks/consult-NYXVDN5G.ts +518 -0
  99. package/dist/chunks/consult-NYXVDN5G.ts.map +7 -0
  100. package/dist/chunks/context-QDKLVQXE.ts +11 -0
  101. package/dist/chunks/context-QDKLVQXE.ts.map +7 -0
  102. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts +130 -0
  103. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts.map +7 -0
  104. package/dist/chunks/cwd-policy-NB6XZ5GF.ts +17 -0
  105. package/dist/chunks/cwd-policy-NB6XZ5GF.ts.map +7 -0
  106. package/dist/chunks/delegation-contract-WJPT4FVS.ts +24 -0
  107. package/dist/chunks/delegation-contract-WJPT4FVS.ts.map +7 -0
  108. package/dist/chunks/discovery-K25T3SH4.ts +12 -0
  109. package/dist/chunks/discovery-K25T3SH4.ts.map +7 -0
  110. package/dist/chunks/execution-DS2DEIQZ.ts +4034 -0
  111. package/dist/chunks/execution-DS2DEIQZ.ts.map +7 -0
  112. package/dist/chunks/in-process-transport-TEYAWSEC.ts +38 -0
  113. package/dist/chunks/in-process-transport-TEYAWSEC.ts.map +7 -0
  114. package/dist/chunks/inspect-UOQQ3KNL.ts +619 -0
  115. package/dist/chunks/inspect-UOQQ3KNL.ts.map +7 -0
  116. package/dist/chunks/peer-communication-KL36Z6CO.ts +294 -0
  117. package/dist/chunks/peer-communication-KL36Z6CO.ts.map +7 -0
  118. package/dist/chunks/persistence-VSGXAW4P.ts +344 -0
  119. package/dist/chunks/persistence-VSGXAW4P.ts.map +7 -0
  120. package/dist/chunks/registry-E6XPJB7L.ts +1324 -0
  121. package/dist/chunks/registry-E6XPJB7L.ts.map +7 -0
  122. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts +81 -0
  123. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts.map +7 -0
  124. package/dist/chunks/rpc-transport-Y6LA5BOP.ts +1154 -0
  125. package/dist/chunks/rpc-transport-Y6LA5BOP.ts.map +7 -0
  126. package/dist/chunks/runtime-policy-5YELCOVC.ts +15 -0
  127. package/dist/chunks/runtime-policy-5YELCOVC.ts.map +7 -0
  128. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts +19 -0
  129. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts.map +7 -0
  130. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts +13 -0
  131. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts.map +7 -0
  132. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts +15 -0
  133. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts.map +7 -0
  134. package/dist/chunks/subprocess-transport-C2XVR25R.ts +158 -0
  135. package/dist/chunks/subprocess-transport-C2XVR25R.ts.map +7 -0
  136. package/dist/chunks/workspace-WDKLN72J.ts +11 -0
  137. package/dist/chunks/workspace-WDKLN72J.ts.map +7 -0
  138. package/dist/index.ts +1057 -0
  139. package/dist/index.ts.map +7 -0
  140. package/package.json +8 -4
  141. package/src/index.ts +1 -1
  142. package/src/settings-reader.ts +208 -0
  143. package/src/settings.ts +22 -187
  144. package/src/stateful-registration.ts +1230 -0
  145. package/src/stateful-safety.ts +1 -1
  146. package/src/stateful.ts +2 -1234
  147. package/src/subagents-extension.ts +307 -0
  148. package/src/subagents.ts +1 -308
@@ -0,0 +1,159 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+
4
+ // src/workspace.ts
5
+ import { execFile } from "node:child_process";
6
+ import * as fs from "node:fs";
7
+ import * as os from "node:os";
8
+ import * as path from "node:path";
9
+ import { promisify } from "node:util";
10
+ var execFileAsync = promisify(execFile);
11
+ var WORKTREE_PREFIX = "pi-subagent-worktree-";
12
+ async function assertWorkspaceIsolationReady(cwd) {
13
+ await resolveWorkspaceBase(cwd);
14
+ }
15
+ var WorkspaceManager = class {
16
+ owned = /* @__PURE__ */ new Map();
17
+ async create(ownerId, cwd) {
18
+ if (this.owned.has(ownerId)) throw new Error(`Workspace owner already exists: ${ownerId}`);
19
+ const { repositoryRoot, relativeCwd } = await resolveWorkspaceBase(cwd);
20
+ const rootPath = await fs.promises.mkdtemp(path.join(os.tmpdir(), WORKTREE_PREFIX));
21
+ let registered = false;
22
+ try {
23
+ await execFileAsync("git", [
24
+ "-C",
25
+ repositoryRoot,
26
+ "worktree",
27
+ "add",
28
+ "--detach",
29
+ rootPath,
30
+ "HEAD"
31
+ ]);
32
+ registered = true;
33
+ await fs.promises.writeFile(`${rootPath}.owner`, ownerId, { mode: 384 });
34
+ const workspace = {
35
+ mode: "worktree",
36
+ path: path.join(rootPath, relativeCwd),
37
+ rootPath,
38
+ repositoryRoot
39
+ };
40
+ this.owned.set(ownerId, workspace);
41
+ return workspace;
42
+ } catch (error) {
43
+ if (registered) {
44
+ await execFileAsync("git", [
45
+ "-C",
46
+ repositoryRoot,
47
+ "worktree",
48
+ "remove",
49
+ "--force",
50
+ rootPath
51
+ ]).catch(() => void 0);
52
+ }
53
+ await fs.promises.rm(rootPath, { recursive: true, force: true });
54
+ await fs.promises.rm(`${rootPath}.owner`, { force: true });
55
+ throw error;
56
+ }
57
+ }
58
+ async cleanupPersisted(ownerId, cwd) {
59
+ const rootPath = findGeneratedWorktreeRoot(cwd);
60
+ if (!rootPath || !await this.isOwned(rootPath, ownerId)) return;
61
+ let repositoryRoot;
62
+ try {
63
+ const commonDirectory = (await execFileAsync("git", ["-C", rootPath, "rev-parse", "--git-common-dir"])).stdout.trim();
64
+ const resolvedCommonDirectory = await fs.promises.realpath(
65
+ path.resolve(rootPath, commonDirectory)
66
+ );
67
+ repositoryRoot = path.dirname(resolvedCommonDirectory);
68
+ } catch {
69
+ }
70
+ if (repositoryRoot) {
71
+ await execFileAsync("git", [
72
+ "-C",
73
+ repositoryRoot,
74
+ "worktree",
75
+ "remove",
76
+ "--force",
77
+ rootPath
78
+ ]).catch(() => void 0);
79
+ }
80
+ await fs.promises.rm(rootPath, { recursive: true, force: true });
81
+ await fs.promises.rm(`${rootPath}.owner`, { force: true });
82
+ if (repositoryRoot) {
83
+ await execFileAsync("git", ["-C", repositoryRoot, "worktree", "prune"]).catch(
84
+ () => void 0
85
+ );
86
+ }
87
+ }
88
+ async cleanup(ownerId) {
89
+ const workspace = this.owned.get(ownerId);
90
+ if (!workspace) return;
91
+ if (!await this.isOwned(workspace.rootPath, ownerId)) {
92
+ throw new Error(`Refusing to clean unowned subagent workspace: ${workspace.rootPath}`);
93
+ }
94
+ this.owned.delete(ownerId);
95
+ await execFileAsync("git", [
96
+ "-C",
97
+ workspace.repositoryRoot,
98
+ "worktree",
99
+ "remove",
100
+ "--force",
101
+ workspace.rootPath
102
+ ]).catch(async () => {
103
+ await fs.promises.rm(workspace.rootPath, { recursive: true, force: true });
104
+ await execFileAsync("git", ["-C", workspace.repositoryRoot, "worktree", "prune"]).catch(
105
+ () => void 0
106
+ );
107
+ });
108
+ await fs.promises.rm(`${workspace.rootPath}.owner`, { force: true });
109
+ }
110
+ async cleanupAll() {
111
+ const results = await Promise.allSettled(
112
+ [...this.owned.keys()].map((ownerId) => this.cleanup(ownerId))
113
+ );
114
+ const failures = results.filter((result) => result.status === "rejected");
115
+ if (failures.length > 0) {
116
+ throw new AggregateError(
117
+ failures.map((failure) => failure.reason),
118
+ `Failed to clean ${failures.length} subagent workspace(s)`
119
+ );
120
+ }
121
+ }
122
+ async isOwned(rootPath, ownerId) {
123
+ if (!path.basename(rootPath).startsWith(WORKTREE_PREFIX)) return false;
124
+ try {
125
+ return await fs.promises.readFile(`${rootPath}.owner`, "utf8") === ownerId;
126
+ } catch {
127
+ return false;
128
+ }
129
+ }
130
+ };
131
+ async function resolveWorkspaceBase(cwd) {
132
+ const resolvedCwd = await fs.promises.realpath(path.resolve(cwd));
133
+ const reportedRepositoryRoot = (await execFileAsync("git", ["-C", resolvedCwd, "rev-parse", "--show-toplevel"])).stdout.trim();
134
+ const repositoryRoot = await fs.promises.realpath(reportedRepositoryRoot);
135
+ const relativeCwd = path.relative(repositoryRoot, resolvedCwd);
136
+ if (relativeCwd.startsWith("..") || path.isAbsolute(relativeCwd)) {
137
+ throw new Error("Subagent cwd is outside the Git repository");
138
+ }
139
+ const status = (await execFileAsync("git", ["-C", repositoryRoot, "status", "--porcelain"])).stdout;
140
+ if (status.trim()) {
141
+ throw new Error("Isolated subagent workspace requires a clean Git repository");
142
+ }
143
+ return { repositoryRoot, relativeCwd };
144
+ }
145
+ function findGeneratedWorktreeRoot(cwd) {
146
+ let current = path.resolve(cwd);
147
+ while (true) {
148
+ if (path.basename(current).startsWith(WORKTREE_PREFIX)) return current;
149
+ const parent = path.dirname(current);
150
+ if (parent === current) return void 0;
151
+ current = parent;
152
+ }
153
+ }
154
+
155
+ export {
156
+ assertWorkspaceIsolationReady,
157
+ WorkspaceManager
158
+ };
159
+ //# sourceMappingURL=chunk-6KJ34M6S.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/workspace.ts"],
4
+ "sourcesContent": ["import { execFile } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\nconst WORKTREE_PREFIX = \"pi-subagent-worktree-\";\n\nexport interface IsolatedWorkspace {\n\tmode: \"worktree\";\n\tpath: string;\n\trootPath: string;\n\trepositoryRoot: string;\n}\n\nexport async function assertWorkspaceIsolationReady(cwd: string): Promise<void> {\n\tawait resolveWorkspaceBase(cwd);\n}\n\nexport class WorkspaceManager {\n\tprivate readonly owned = new Map<string, IsolatedWorkspace>();\n\n\tasync create(ownerId: string, cwd: string): Promise<IsolatedWorkspace> {\n\t\tif (this.owned.has(ownerId)) throw new Error(`Workspace owner already exists: ${ownerId}`);\n\t\tconst { repositoryRoot, relativeCwd } = await resolveWorkspaceBase(cwd);\n\t\tconst rootPath = await fs.promises.mkdtemp(path.join(os.tmpdir(), WORKTREE_PREFIX));\n\t\tlet registered = false;\n\t\ttry {\n\t\t\tawait execFileAsync(\"git\", [\n\t\t\t\t\"-C\",\n\t\t\t\trepositoryRoot,\n\t\t\t\t\"worktree\",\n\t\t\t\t\"add\",\n\t\t\t\t\"--detach\",\n\t\t\t\trootPath,\n\t\t\t\t\"HEAD\",\n\t\t\t]);\n\t\t\tregistered = true;\n\t\t\tawait fs.promises.writeFile(`${rootPath}.owner`, ownerId, { mode: 0o600 });\n\t\t\tconst workspace = {\n\t\t\t\tmode: \"worktree\" as const,\n\t\t\t\tpath: path.join(rootPath, relativeCwd),\n\t\t\t\trootPath,\n\t\t\t\trepositoryRoot,\n\t\t\t};\n\t\t\tthis.owned.set(ownerId, workspace);\n\t\t\treturn workspace;\n\t\t} catch (error) {\n\t\t\tif (registered) {\n\t\t\t\tawait execFileAsync(\"git\", [\n\t\t\t\t\t\"-C\",\n\t\t\t\t\trepositoryRoot,\n\t\t\t\t\t\"worktree\",\n\t\t\t\t\t\"remove\",\n\t\t\t\t\t\"--force\",\n\t\t\t\t\trootPath,\n\t\t\t\t]).catch(() => undefined);\n\t\t\t}\n\t\t\tawait fs.promises.rm(rootPath, { recursive: true, force: true });\n\t\t\tawait fs.promises.rm(`${rootPath}.owner`, { force: true });\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync cleanupPersisted(ownerId: string, cwd: string): Promise<void> {\n\t\tconst rootPath = findGeneratedWorktreeRoot(cwd);\n\t\tif (!rootPath || !(await this.isOwned(rootPath, ownerId))) return;\n\t\tlet repositoryRoot: string | undefined;\n\t\ttry {\n\t\t\tconst commonDirectory = (\n\t\t\t\tawait execFileAsync(\"git\", [\"-C\", rootPath, \"rev-parse\", \"--git-common-dir\"])\n\t\t\t).stdout.trim();\n\t\t\tconst resolvedCommonDirectory = await fs.promises.realpath(\n\t\t\t\tpath.resolve(rootPath, commonDirectory),\n\t\t\t);\n\t\t\trepositoryRoot = path.dirname(resolvedCommonDirectory);\n\t\t} catch {\n\t\t\t// The ownership marker still permits bounded filesystem cleanup below.\n\t\t}\n\t\tif (repositoryRoot) {\n\t\t\tawait execFileAsync(\"git\", [\n\t\t\t\t\"-C\",\n\t\t\t\trepositoryRoot,\n\t\t\t\t\"worktree\",\n\t\t\t\t\"remove\",\n\t\t\t\t\"--force\",\n\t\t\t\trootPath,\n\t\t\t]).catch(() => undefined);\n\t\t}\n\t\tawait fs.promises.rm(rootPath, { recursive: true, force: true });\n\t\tawait fs.promises.rm(`${rootPath}.owner`, { force: true });\n\t\tif (repositoryRoot) {\n\t\t\tawait execFileAsync(\"git\", [\"-C\", repositoryRoot, \"worktree\", \"prune\"]).catch(\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync cleanup(ownerId: string): Promise<void> {\n\t\tconst workspace = this.owned.get(ownerId);\n\t\tif (!workspace) return;\n\t\tif (!(await this.isOwned(workspace.rootPath, ownerId))) {\n\t\t\tthrow new Error(`Refusing to clean unowned subagent workspace: ${workspace.rootPath}`);\n\t\t}\n\t\tthis.owned.delete(ownerId);\n\t\tawait execFileAsync(\"git\", [\n\t\t\t\"-C\",\n\t\t\tworkspace.repositoryRoot,\n\t\t\t\"worktree\",\n\t\t\t\"remove\",\n\t\t\t\"--force\",\n\t\t\tworkspace.rootPath,\n\t\t]).catch(async () => {\n\t\t\tawait fs.promises.rm(workspace.rootPath, { recursive: true, force: true });\n\t\t\tawait execFileAsync(\"git\", [\"-C\", workspace.repositoryRoot, \"worktree\", \"prune\"]).catch(\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t});\n\t\tawait fs.promises.rm(`${workspace.rootPath}.owner`, { force: true });\n\t}\n\n\tasync cleanupAll(): Promise<void> {\n\t\tconst results = await Promise.allSettled(\n\t\t\t[...this.owned.keys()].map((ownerId) => this.cleanup(ownerId)),\n\t\t);\n\t\tconst failures = results.filter((result) => result.status === \"rejected\");\n\t\tif (failures.length > 0) {\n\t\t\tthrow new AggregateError(\n\t\t\t\tfailures.map((failure) => (failure as PromiseRejectedResult).reason),\n\t\t\t\t`Failed to clean ${failures.length} subagent workspace(s)`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async isOwned(rootPath: string, ownerId: string): Promise<boolean> {\n\t\tif (!path.basename(rootPath).startsWith(WORKTREE_PREFIX)) return false;\n\t\ttry {\n\t\t\treturn (await fs.promises.readFile(`${rootPath}.owner`, \"utf8\")) === ownerId;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\nasync function resolveWorkspaceBase(\n\tcwd: string,\n): Promise<{ repositoryRoot: string; relativeCwd: string }> {\n\tconst resolvedCwd = await fs.promises.realpath(path.resolve(cwd));\n\tconst reportedRepositoryRoot = (\n\t\tawait execFileAsync(\"git\", [\"-C\", resolvedCwd, \"rev-parse\", \"--show-toplevel\"])\n\t).stdout.trim();\n\tconst repositoryRoot = await fs.promises.realpath(reportedRepositoryRoot);\n\tconst relativeCwd = path.relative(repositoryRoot, resolvedCwd);\n\tif (relativeCwd.startsWith(\"..\") || path.isAbsolute(relativeCwd)) {\n\t\tthrow new Error(\"Subagent cwd is outside the Git repository\");\n\t}\n\tconst status = (await execFileAsync(\"git\", [\"-C\", repositoryRoot, \"status\", \"--porcelain\"]))\n\t\t.stdout;\n\tif (status.trim()) {\n\t\tthrow new Error(\"Isolated subagent workspace requires a clean Git repository\");\n\t}\n\treturn { repositoryRoot, relativeCwd };\n}\n\nfunction findGeneratedWorktreeRoot(cwd: string): string | undefined {\n\tlet current = path.resolve(cwd);\n\twhile (true) {\n\t\tif (path.basename(current).startsWith(WORKTREE_PREFIX)) return current;\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,80 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+
4
+ // src/stateful-limits.ts
5
+ var STATEFUL_LIMIT_FIELDS = [
6
+ "maxAgents",
7
+ "maxActiveTurns",
8
+ "maxChildrenPerAgent",
9
+ "maxDepth",
10
+ "maxStoredAgents"
11
+ ];
12
+ var STATEFUL_LIMIT_DEFINITIONS = [
13
+ {
14
+ field: "maxAgents",
15
+ label: "Retained agents",
16
+ description: "Running, queued, and reusable idle detached agents",
17
+ defaultValue: 16,
18
+ minimum: 1
19
+ },
20
+ {
21
+ field: "maxActiveTurns",
22
+ label: "Active turns",
23
+ description: "Detached agent turns that may run at the same time",
24
+ defaultValue: 4,
25
+ minimum: 1
26
+ },
27
+ {
28
+ field: "maxChildrenPerAgent",
29
+ label: "Children per agent",
30
+ description: "Direct child agents retained beneath one parent",
31
+ defaultValue: 8,
32
+ minimum: 1
33
+ },
34
+ {
35
+ field: "maxDepth",
36
+ label: "Agent tree depth",
37
+ description: "Nested child levels below a root agent",
38
+ defaultValue: 3,
39
+ minimum: 0
40
+ },
41
+ {
42
+ field: "maxStoredAgents",
43
+ label: "Stored agents",
44
+ description: "Detached agent records kept per session on disk",
45
+ defaultValue: 50,
46
+ minimum: 1
47
+ }
48
+ ];
49
+ var definitionsByField = new Map(
50
+ STATEFUL_LIMIT_DEFINITIONS.map((definition) => [definition.field, definition])
51
+ );
52
+ function statefulLimitDefinition(field) {
53
+ const definition = definitionsByField.get(field);
54
+ if (!definition) throw new Error(`Unknown stateful limit: ${field}`);
55
+ return definition;
56
+ }
57
+ function isStatefulLimitField(value) {
58
+ return STATEFUL_LIMIT_FIELDS.includes(value);
59
+ }
60
+ function isValidStatefulLimit(field, value) {
61
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= statefulLimitDefinition(field).minimum;
62
+ }
63
+ function resolveStatefulLimits(settings) {
64
+ return Object.fromEntries(
65
+ STATEFUL_LIMIT_DEFINITIONS.map((definition) => [
66
+ definition.field,
67
+ settings?.[definition.field] ?? definition.defaultValue
68
+ ])
69
+ );
70
+ }
71
+
72
+ export {
73
+ STATEFUL_LIMIT_FIELDS,
74
+ STATEFUL_LIMIT_DEFINITIONS,
75
+ statefulLimitDefinition,
76
+ isStatefulLimitField,
77
+ isValidStatefulLimit,
78
+ resolveStatefulLimits
79
+ };
80
+ //# sourceMappingURL=chunk-7OBINKFM.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/stateful-limits.ts"],
4
+ "sourcesContent": ["import type { SubagentRuntimeSettings } from \"./agents/types.js\";\n\nexport const STATEFUL_LIMIT_FIELDS = [\n\t\"maxAgents\",\n\t\"maxActiveTurns\",\n\t\"maxChildrenPerAgent\",\n\t\"maxDepth\",\n\t\"maxStoredAgents\",\n] as const;\n\nexport type StatefulLimitField = (typeof STATEFUL_LIMIT_FIELDS)[number];\n\nexport interface StatefulLimits {\n\tmaxAgents: number;\n\tmaxActiveTurns: number;\n\tmaxChildrenPerAgent: number;\n\tmaxDepth: number;\n\tmaxStoredAgents: number;\n}\n\nexport interface StatefulLimitDefinition {\n\tfield: StatefulLimitField;\n\tlabel: string;\n\tdescription: string;\n\tdefaultValue: number;\n\tminimum: number;\n}\n\nexport const STATEFUL_LIMIT_DEFINITIONS: readonly StatefulLimitDefinition[] = [\n\t{\n\t\tfield: \"maxAgents\",\n\t\tlabel: \"Retained agents\",\n\t\tdescription: \"Running, queued, and reusable idle detached agents\",\n\t\tdefaultValue: 16,\n\t\tminimum: 1,\n\t},\n\t{\n\t\tfield: \"maxActiveTurns\",\n\t\tlabel: \"Active turns\",\n\t\tdescription: \"Detached agent turns that may run at the same time\",\n\t\tdefaultValue: 4,\n\t\tminimum: 1,\n\t},\n\t{\n\t\tfield: \"maxChildrenPerAgent\",\n\t\tlabel: \"Children per agent\",\n\t\tdescription: \"Direct child agents retained beneath one parent\",\n\t\tdefaultValue: 8,\n\t\tminimum: 1,\n\t},\n\t{\n\t\tfield: \"maxDepth\",\n\t\tlabel: \"Agent tree depth\",\n\t\tdescription: \"Nested child levels below a root agent\",\n\t\tdefaultValue: 3,\n\t\tminimum: 0,\n\t},\n\t{\n\t\tfield: \"maxStoredAgents\",\n\t\tlabel: \"Stored agents\",\n\t\tdescription: \"Detached agent records kept per session on disk\",\n\t\tdefaultValue: 50,\n\t\tminimum: 1,\n\t},\n];\n\nconst definitionsByField = new Map(\n\tSTATEFUL_LIMIT_DEFINITIONS.map((definition) => [definition.field, definition]),\n);\n\nexport function statefulLimitDefinition(field: StatefulLimitField): StatefulLimitDefinition {\n\tconst definition = definitionsByField.get(field);\n\tif (!definition) throw new Error(`Unknown stateful limit: ${field}`);\n\treturn definition;\n}\n\nexport function isStatefulLimitField(value: string): value is StatefulLimitField {\n\treturn (STATEFUL_LIMIT_FIELDS as readonly string[]).includes(value);\n}\n\nexport function isValidStatefulLimit(field: StatefulLimitField, value: unknown): value is number {\n\treturn (\n\t\ttypeof value === \"number\" &&\n\t\tNumber.isSafeInteger(value) &&\n\t\tvalue >= statefulLimitDefinition(field).minimum\n\t);\n}\n\nexport function resolveStatefulLimits(settings?: SubagentRuntimeSettings): StatefulLimits {\n\treturn Object.fromEntries(\n\t\tSTATEFUL_LIMIT_DEFINITIONS.map((definition) => [\n\t\t\tdefinition.field,\n\t\t\tsettings?.[definition.field] ?? definition.defaultValue,\n\t\t]),\n\t) as unknown as StatefulLimits;\n}\n"],
5
+ "mappings": ";;;;AAEO,IAAM,wBAAwB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAoBO,IAAM,6BAAiE;AAAA,EAC7E;AAAA,IACC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,EACV;AACD;AAEA,IAAM,qBAAqB,IAAI;AAAA,EAC9B,2BAA2B,IAAI,CAAC,eAAe,CAAC,WAAW,OAAO,UAAU,CAAC;AAC9E;AAEO,SAAS,wBAAwB,OAAoD;AAC3F,QAAM,aAAa,mBAAmB,IAAI,KAAK;AAC/C,MAAI,CAAC,WAAY,OAAM,IAAI,MAAM,2BAA2B,KAAK,EAAE;AACnE,SAAO;AACR;AAEO,SAAS,qBAAqB,OAA4C;AAChF,SAAQ,sBAA4C,SAAS,KAAK;AACnE;AAEO,SAAS,qBAAqB,OAA2B,OAAiC;AAChG,SACC,OAAO,UAAU,YACjB,OAAO,cAAc,KAAK,KAC1B,SAAS,wBAAwB,KAAK,EAAE;AAE1C;AAEO,SAAS,sBAAsB,UAAoD;AACzF,SAAO,OAAO;AAAA,IACb,2BAA2B,IAAI,CAAC,eAAe;AAAA,MAC9C,WAAW;AAAA,MACX,WAAW,WAAW,KAAK,KAAK,WAAW;AAAA,IAC5C,CAAC;AAAA,EACF;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,335 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+ import {
4
+ SUBAGENT_SETTINGS_FILE,
5
+ hasOwn,
6
+ isPlainObject,
7
+ isPositiveInteger,
8
+ normalizeSubagentSettings,
9
+ pathEntryExists,
10
+ resolveSubagentSettingsPaths
11
+ } from "./chunk-QBORTI4W.js";
12
+ import {
13
+ STATEFUL_LIMIT_FIELDS,
14
+ isValidStatefulLimit,
15
+ resolveStatefulLimits,
16
+ statefulLimitDefinition
17
+ } from "./chunk-7OBINKFM.js";
18
+ import {
19
+ MAX_CONFIGURABLE_PARALLEL_TASKS
20
+ } from "./chunk-H3FP6DLR.js";
21
+
22
+ // src/settings.ts
23
+ import { randomUUID } from "node:crypto";
24
+ import * as fs from "node:fs";
25
+ import { createRequire } from "node:module";
26
+ import * as path from "node:path";
27
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
28
+ var SETTINGS_FILE = SUBAGENT_SETTINGS_FILE;
29
+ var require2 = createRequire(import.meta.url);
30
+ var SETTINGS_LOCK_FS_ADAPTER = {
31
+ mkdir: fs.mkdir,
32
+ mkdirSync: fs.mkdirSync,
33
+ realpath: fs.realpath,
34
+ realpathSync: fs.realpathSync,
35
+ rmdir: fs.rmdir,
36
+ rmdirSync: fs.rmdirSync,
37
+ stat: fs.stat,
38
+ statSync: fs.statSync,
39
+ utimes: fs.utimes,
40
+ utimesSync: fs.utimesSync
41
+ };
42
+ function updateDelegationWorkflowSetting(value) {
43
+ withSettingsMutationLock(() => {
44
+ const update = readSettingsObjectForUpdate();
45
+ const raw = update.document;
46
+ const blocking = raw.blocking;
47
+ if (blocking !== void 0 && !isPlainObject(blocking)) {
48
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} blocking settings`);
49
+ }
50
+ const stateful = raw.stateful;
51
+ if (stateful !== void 0 && !isPlainObject(stateful)) {
52
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);
53
+ }
54
+ writeSettingsObjectUnlocked(
55
+ {
56
+ ...raw,
57
+ blocking: {
58
+ ...blocking ?? {},
59
+ enabled: value !== "async-only"
60
+ },
61
+ stateful: {
62
+ ...stateful ?? {},
63
+ enabled: value !== "blocking-only"
64
+ }
65
+ },
66
+ update.replaceCanonical
67
+ );
68
+ });
69
+ }
70
+ function updateStatefulTransportSetting(value) {
71
+ if (!["subprocess", "in-process", "rpc", "auto"].includes(value)) {
72
+ throw new Error(`Unsupported stateful transport: ${value}`);
73
+ }
74
+ withSettingsMutationLock(() => {
75
+ const update = readSettingsObjectForUpdate();
76
+ const raw = update.document;
77
+ const stateful = raw.stateful;
78
+ if (stateful !== void 0 && !isPlainObject(stateful)) {
79
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);
80
+ }
81
+ writeSettingsObjectUnlocked(
82
+ {
83
+ ...raw,
84
+ stateful: { ...stateful ?? {}, transport: value }
85
+ },
86
+ update.replaceCanonical
87
+ );
88
+ });
89
+ }
90
+ function updateCompletionDeliverySetting(value) {
91
+ withSettingsMutationLock(() => {
92
+ const update = readSettingsObjectForUpdate();
93
+ const raw = update.document;
94
+ const stateful = raw.stateful;
95
+ if (stateful !== void 0 && !isPlainObject(stateful)) {
96
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);
97
+ }
98
+ writeSettingsObjectUnlocked(
99
+ {
100
+ ...raw,
101
+ stateful: {
102
+ ...stateful ?? {},
103
+ completionDelivery: value
104
+ }
105
+ },
106
+ update.replaceCanonical
107
+ );
108
+ });
109
+ }
110
+ function updateBlockingMaxParallelTasksSetting(value) {
111
+ if (!isPositiveInteger(value) || value > MAX_CONFIGURABLE_PARALLEL_TASKS) {
112
+ throw new Error(
113
+ `Maximum parallel tasks must be an integer between 1 and ${MAX_CONFIGURABLE_PARALLEL_TASKS}`
114
+ );
115
+ }
116
+ withSettingsMutationLock(() => {
117
+ const update = readSettingsObjectForUpdate();
118
+ const raw = update.document;
119
+ const blocking = raw.blocking;
120
+ if (blocking !== void 0 && !isPlainObject(blocking)) {
121
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} blocking settings`);
122
+ }
123
+ writeSettingsObjectUnlocked(
124
+ {
125
+ ...raw,
126
+ blocking: {
127
+ ...blocking ?? {},
128
+ maxParallelTasks: value
129
+ }
130
+ },
131
+ update.replaceCanonical
132
+ );
133
+ });
134
+ }
135
+ function updateStatefulLimitSetting(field, value, expected) {
136
+ if (!isValidStatefulLimit(field, value)) {
137
+ throw new Error(
138
+ `${field} must be a safe integer greater than or equal to ${statefulLimitDefinition(field).minimum}`
139
+ );
140
+ }
141
+ withSettingsMutationLock(() => {
142
+ const update = readSettingsObjectForUpdate();
143
+ const raw = update.document;
144
+ const stateful = raw.stateful;
145
+ if (stateful !== void 0 && !isPlainObject(stateful)) {
146
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);
147
+ }
148
+ const normalized = normalizeSubagentSettings(raw);
149
+ if (!normalized) throw new Error(`Cannot update invalid ${SETTINGS_FILE}`);
150
+ if (expected && !sameStatefulLimits(resolveStatefulLimits(normalized.stateful), expected)) {
151
+ throw new Error("Detached limit settings changed; reopen settings and retry");
152
+ }
153
+ writeSettingsObjectUnlocked(
154
+ {
155
+ ...raw,
156
+ stateful: { ...stateful ?? {}, [field]: value }
157
+ },
158
+ update.replaceCanonical
159
+ );
160
+ });
161
+ }
162
+ function updateConsultResourceSetting(value) {
163
+ withSettingsMutationLock(() => {
164
+ const update = readSettingsObjectForUpdate();
165
+ const raw = update.document;
166
+ const consult = raw.consult;
167
+ if (consult !== void 0 && !isPlainObject(consult)) {
168
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} consult settings`);
169
+ }
170
+ writeSettingsObjectUnlocked(
171
+ {
172
+ ...raw,
173
+ consult: {
174
+ ...consult ?? {},
175
+ resources: value
176
+ }
177
+ },
178
+ update.replaceCanonical
179
+ );
180
+ });
181
+ }
182
+ function updateCwdPolicySetting(field, value) {
183
+ withSettingsMutationLock(() => {
184
+ const update = readSettingsObjectForUpdate();
185
+ const raw = update.document;
186
+ const cwdPolicy = raw.cwdPolicy;
187
+ if (cwdPolicy !== void 0 && !isPlainObject(cwdPolicy)) {
188
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} cwdPolicy settings`);
189
+ }
190
+ writeSettingsObjectUnlocked(
191
+ {
192
+ ...raw,
193
+ cwdPolicy: { ...cwdPolicy ?? {}, [field]: value }
194
+ },
195
+ update.replaceCanonical
196
+ );
197
+ });
198
+ }
199
+ function updateAgentToolsSetting(name, tools) {
200
+ updateAgentSettingsPatch({ [name]: { tools } });
201
+ }
202
+ function updateAgentSettingsPatch(patches) {
203
+ withSettingsMutationLock(() => {
204
+ const update = readSettingsObjectForUpdate();
205
+ const raw = update.document;
206
+ const rawAgents = raw.agents;
207
+ if (rawAgents !== void 0 && !isPlainObject(rawAgents)) {
208
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} agent settings`);
209
+ }
210
+ const agents = { ...rawAgents ?? {} };
211
+ for (const [name, patch] of Object.entries(patches)) {
212
+ const rawAgent = hasOwn(agents, name) ? agents[name] : void 0;
213
+ if (rawAgent !== void 0 && !isPlainObject(rawAgent)) {
214
+ throw new Error(`Cannot update invalid ${SETTINGS_FILE} settings for ${name}`);
215
+ }
216
+ const agent = { ...rawAgent ?? {} };
217
+ for (const field of ["tools", "model", "thinkingLevel", "timeoutMs"]) {
218
+ if (!hasOwn(patch, field)) continue;
219
+ const value = patch[field];
220
+ if (value === void 0) delete agent[field];
221
+ else
222
+ Object.defineProperty(agent, field, {
223
+ value,
224
+ enumerable: true,
225
+ configurable: true,
226
+ writable: true
227
+ });
228
+ }
229
+ if (Object.keys(agent).length > 0) {
230
+ Object.defineProperty(agents, name, {
231
+ value: agent,
232
+ enumerable: true,
233
+ configurable: true,
234
+ writable: true
235
+ });
236
+ } else {
237
+ delete agents[name];
238
+ }
239
+ }
240
+ const normalized = normalizeSubagentSettings({
241
+ ...raw,
242
+ ...Object.keys(agents).length > 0 ? { agents } : {}
243
+ });
244
+ if (!normalized) throw new Error(`Cannot update invalid ${SETTINGS_FILE} agent settings`);
245
+ const updated = { ...raw };
246
+ if (Object.keys(agents).length > 0) updated.agents = agents;
247
+ else delete updated.agents;
248
+ writeSettingsObjectUnlocked(updated, update.replaceCanonical);
249
+ });
250
+ }
251
+ function readSettingsObjectForUpdate() {
252
+ const { canonicalPath, activePath } = resolveSubagentSettingsPaths();
253
+ if (activePath === void 0) return { document: {}, replaceCanonical: false };
254
+ const activeFile = path.basename(activePath);
255
+ let parsed;
256
+ try {
257
+ parsed = JSON.parse(fs.readFileSync(activePath, "utf8"));
258
+ } catch {
259
+ throw new Error(`Cannot update malformed ${activeFile}`);
260
+ }
261
+ if (!isPlainObject(parsed) || !normalizeSubagentSettings(parsed)) {
262
+ throw new Error(`Cannot update invalid ${activeFile}`);
263
+ }
264
+ return { document: parsed, replaceCanonical: activePath === canonicalPath };
265
+ }
266
+ function writeSettingsObjectUnlocked(settings, replaceCanonical) {
267
+ const agentDir = getAgentDir();
268
+ fs.mkdirSync(agentDir, { recursive: true });
269
+ const configPath = path.join(agentDir, SETTINGS_FILE);
270
+ const tempFile = path.join(agentDir, `.${SETTINGS_FILE}.${randomUUID()}.tmp`);
271
+ const firstCanonicalPublication = !(replaceCanonical ?? pathEntryExists(configPath));
272
+ try {
273
+ fs.writeFileSync(tempFile, `${JSON.stringify(settings, null, " ")}
274
+ `, {
275
+ encoding: "utf8",
276
+ flag: "wx"
277
+ });
278
+ if (firstCanonicalPublication && pathEntryExists(configPath)) {
279
+ throw new Error(`${SETTINGS_FILE} was created concurrently; reopen settings and retry`);
280
+ }
281
+ fs.renameSync(tempFile, configPath);
282
+ } finally {
283
+ try {
284
+ fs.rmSync(tempFile, { force: true });
285
+ } catch {
286
+ }
287
+ }
288
+ }
289
+ function withSettingsMutationLock(mutate) {
290
+ const lockfile = require2("proper-lockfile");
291
+ const agentDir = getAgentDir();
292
+ fs.mkdirSync(agentDir, { recursive: true });
293
+ const configPath = path.join(agentDir, SETTINGS_FILE);
294
+ const release = lockfile.lockSync(configPath, {
295
+ fs: SETTINGS_LOCK_FS_ADAPTER,
296
+ lockfilePath: `${configPath}.mutation-lock`,
297
+ realpath: false
298
+ });
299
+ try {
300
+ return mutate();
301
+ } finally {
302
+ release();
303
+ }
304
+ }
305
+ function sameStatefulLimits(left, right) {
306
+ return STATEFUL_LIMIT_FIELDS.every((field) => left[field] === right[field]);
307
+ }
308
+ function uniqueToolNames(tools) {
309
+ return [...new Set(tools)];
310
+ }
311
+ function sameToolSet(left, right) {
312
+ const leftSet = new Set(left);
313
+ const rightSet = new Set(right);
314
+ if (leftSet.size !== rightSet.size) return false;
315
+ return [...leftSet].every((tool) => rightSet.has(tool));
316
+ }
317
+ function resolveSubagentThinkingLevel(agents, agentName, topLevelThinkingLevel, localThinkingLevel) {
318
+ return localThinkingLevel ?? topLevelThinkingLevel ?? agents.find((agent) => agent.name === agentName)?.thinkingLevel;
319
+ }
320
+
321
+ export {
322
+ updateDelegationWorkflowSetting,
323
+ updateStatefulTransportSetting,
324
+ updateCompletionDeliverySetting,
325
+ updateBlockingMaxParallelTasksSetting,
326
+ updateStatefulLimitSetting,
327
+ updateConsultResourceSetting,
328
+ updateCwdPolicySetting,
329
+ updateAgentToolsSetting,
330
+ updateAgentSettingsPatch,
331
+ uniqueToolNames,
332
+ sameToolSet,
333
+ resolveSubagentThinkingLevel
334
+ };
335
+ //# sourceMappingURL=chunk-7QPPBBXZ.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/settings.ts"],
4
+ "sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\nimport type {\n\tAgentConfig,\n\tCompletionDelivery,\n\tConsultationCwdPolicy,\n\tConsultResourcePolicy,\n\tDelegationCwdPolicy,\n\tSubagentAgentConfig,\n\tSubagentSettings,\n\tSubagentThinkingLevel,\n\tSubagentTransportKind,\n} from \"./agents/types.js\";\nimport { MAX_CONFIGURABLE_PARALLEL_TASKS } from \"./limits.js\";\nimport type { DelegationWorkflow } from \"./settings/inspection.js\";\nimport {\n\thasOwn,\n\tisPlainObject,\n\tisPositiveInteger,\n\tnormalizeSubagentSettings,\n} from \"./settings/schema.js\";\nimport {\n\tpathEntryExists,\n\tresolveSubagentSettingsPaths,\n\tSUBAGENT_SETTINGS_FILE,\n} from \"./settings-reader.js\";\nimport {\n\tisValidStatefulLimit,\n\tresolveStatefulLimits,\n\tSTATEFUL_LIMIT_FIELDS,\n\ttype StatefulLimitField,\n\ttype StatefulLimits,\n\tstatefulLimitDefinition,\n} from \"./stateful-limits.js\";\n\nexport {\n\ttype BlockingParallelLimitSettingsSnapshot,\n\ttype CompletionDeliverySettingsSnapshot,\n\ttype ConsultResourceSettingsSnapshot,\n\ttype CwdPolicyFieldSnapshot,\n\ttype CwdPolicySettingsSnapshot,\n\tconsumeSubagentSettingsNotice,\n\tDEFAULT_CONSULT_RESOURCE_POLICY,\n\tDEFAULT_CONSULTATION_CWD_POLICY,\n\tDEFAULT_DELEGATION_CWD_POLICY,\n\ttype DelegationWorkflow,\n\ttype DelegationWorkflowSettingsSnapshot,\n\thasOwn,\n\tinspectBlockingParallelLimitSettings,\n\tinspectCompletionDeliverySettings,\n\tinspectConsultResourceSettings,\n\tinspectCwdPolicySettings,\n\tinspectDelegationWorkflowSettings,\n\tinspectStatefulLimitSettings,\n\tinspectStatefulTransportSettings,\n\tinspectSubagentSettings,\n\tnormalizeAgentSettings,\n\tnormalizeSubagentSettings,\n\treadSubagentSettings,\n\tresolveBlockingMaxParallelTasks,\n\tresolveDelegationWorkflow,\n\ttype StatefulLimitFieldSnapshot,\n\ttype StatefulLimitSettingsSnapshot,\n\ttype StatefulTransportSettingsSnapshot,\n\ttype SubagentSettingsSnapshot,\n\tsubagentSettingsFilePath,\n} from \"./settings-reader.js\";\n\nconst SETTINGS_FILE = SUBAGENT_SETTINGS_FILE;\nconst require = createRequire(import.meta.url);\n\nconst SETTINGS_LOCK_FS_ADAPTER = {\n\tmkdir: fs.mkdir,\n\tmkdirSync: fs.mkdirSync,\n\trealpath: fs.realpath,\n\trealpathSync: fs.realpathSync,\n\trmdir: fs.rmdir,\n\trmdirSync: fs.rmdirSync,\n\tstat: fs.stat,\n\tstatSync: fs.statSync,\n\tutimes: fs.utimes,\n\tutimesSync: fs.utimesSync,\n};\n\nexport function saveSubagentConfig(settings: SubagentSettings): void {\n\twriteSettingsObject(settings);\n}\n\nexport function updateDelegationWorkflowSetting(\n\tvalue: Exclude<DelegationWorkflow, \"disabled\">,\n): void {\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst blocking = raw.blocking;\n\t\tif (blocking !== undefined && !isPlainObject(blocking)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} blocking settings`);\n\t\t}\n\t\tconst stateful = raw.stateful;\n\t\tif (stateful !== undefined && !isPlainObject(stateful)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tblocking: {\n\t\t\t\t\t...(blocking ?? {}),\n\t\t\t\t\tenabled: value !== \"async-only\",\n\t\t\t\t},\n\t\t\t\tstateful: {\n\t\t\t\t\t...(stateful ?? {}),\n\t\t\t\t\tenabled: value !== \"blocking-only\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateStatefulTransportSetting(value: SubagentTransportKind): void {\n\tif (![\"subprocess\", \"in-process\", \"rpc\", \"auto\"].includes(value)) {\n\t\tthrow new Error(`Unsupported stateful transport: ${value}`);\n\t}\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst stateful = raw.stateful;\n\t\tif (stateful !== undefined && !isPlainObject(stateful)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tstateful: { ...(stateful ?? {}), transport: value },\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateCompletionDeliverySetting(value: CompletionDelivery): void {\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst stateful = raw.stateful;\n\t\tif (stateful !== undefined && !isPlainObject(stateful)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tstateful: {\n\t\t\t\t\t...(stateful ?? {}),\n\t\t\t\t\tcompletionDelivery: value,\n\t\t\t\t},\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateBlockingMaxParallelTasksSetting(value: number): void {\n\tif (!isPositiveInteger(value) || value > MAX_CONFIGURABLE_PARALLEL_TASKS) {\n\t\tthrow new Error(\n\t\t\t`Maximum parallel tasks must be an integer between 1 and ${MAX_CONFIGURABLE_PARALLEL_TASKS}`,\n\t\t);\n\t}\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst blocking = raw.blocking;\n\t\tif (blocking !== undefined && !isPlainObject(blocking)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} blocking settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tblocking: {\n\t\t\t\t\t...(blocking ?? {}),\n\t\t\t\t\tmaxParallelTasks: value,\n\t\t\t\t},\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateStatefulLimitSetting(\n\tfield: StatefulLimitField,\n\tvalue: number,\n\texpected?: StatefulLimits,\n): void {\n\tif (!isValidStatefulLimit(field, value)) {\n\t\tthrow new Error(\n\t\t\t`${field} must be a safe integer greater than or equal to ${statefulLimitDefinition(field).minimum}`,\n\t\t);\n\t}\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst stateful = raw.stateful;\n\t\tif (stateful !== undefined && !isPlainObject(stateful)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} stateful settings`);\n\t\t}\n\t\tconst normalized = normalizeSubagentSettings(raw);\n\t\tif (!normalized) throw new Error(`Cannot update invalid ${SETTINGS_FILE}`);\n\t\tif (expected && !sameStatefulLimits(resolveStatefulLimits(normalized.stateful), expected)) {\n\t\t\tthrow new Error(\"Detached limit settings changed; reopen settings and retry\");\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tstateful: { ...(stateful ?? {}), [field]: value },\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateConsultResourceSetting(value: ConsultResourcePolicy): void {\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst consult = raw.consult;\n\t\tif (consult !== undefined && !isPlainObject(consult)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} consult settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tconsult: {\n\t\t\t\t\t...(consult ?? {}),\n\t\t\t\t\tresources: value,\n\t\t\t\t},\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport function updateCwdPolicySetting(field: \"consultation\", value: ConsultationCwdPolicy): void;\nexport function updateCwdPolicySetting(field: \"delegation\", value: DelegationCwdPolicy): void;\nexport function updateCwdPolicySetting(\n\tfield: \"consultation\" | \"delegation\",\n\tvalue: ConsultationCwdPolicy | DelegationCwdPolicy,\n): void {\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst cwdPolicy = raw.cwdPolicy;\n\t\tif (cwdPolicy !== undefined && !isPlainObject(cwdPolicy)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} cwdPolicy settings`);\n\t\t}\n\t\twriteSettingsObjectUnlocked(\n\t\t\t{\n\t\t\t\t...raw,\n\t\t\t\tcwdPolicy: { ...(cwdPolicy ?? {}), [field]: value },\n\t\t\t},\n\t\t\tupdate.replaceCanonical,\n\t\t);\n\t});\n}\n\nexport type AgentSettingsPatch = {\n\ttools?: string[] | undefined;\n\tmodel?: string | null | undefined;\n\tthinkingLevel?: SubagentThinkingLevel | null | undefined;\n\ttimeoutMs?: number | null | undefined;\n};\n\nexport function updateAgentToolsSetting(name: string, tools: string[] | undefined): void {\n\tupdateAgentSettingsPatch({ [name]: { tools } });\n}\n\nexport function updateAgentSettingsPatch(patches: Record<string, AgentSettingsPatch>): void {\n\twithSettingsMutationLock(() => {\n\t\tconst update = readSettingsObjectForUpdate();\n\t\tconst raw = update.document;\n\t\tconst rawAgents = raw.agents;\n\t\tif (rawAgents !== undefined && !isPlainObject(rawAgents)) {\n\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} agent settings`);\n\t\t}\n\t\tconst agents = { ...(rawAgents ?? {}) };\n\t\tfor (const [name, patch] of Object.entries(patches)) {\n\t\t\tconst rawAgent = hasOwn(agents, name) ? agents[name] : undefined;\n\t\t\tif (rawAgent !== undefined && !isPlainObject(rawAgent)) {\n\t\t\t\tthrow new Error(`Cannot update invalid ${SETTINGS_FILE} settings for ${name}`);\n\t\t\t}\n\t\t\tconst agent = { ...(rawAgent ?? {}) };\n\t\t\tfor (const field of [\"tools\", \"model\", \"thinkingLevel\", \"timeoutMs\"] as const) {\n\t\t\t\tif (!hasOwn(patch, field)) continue;\n\t\t\t\tconst value = patch[field];\n\t\t\t\tif (value === undefined) delete agent[field];\n\t\t\t\telse\n\t\t\t\t\tObject.defineProperty(agent, field, {\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tenumerable: true,\n\t\t\t\t\t\tconfigurable: true,\n\t\t\t\t\t\twritable: true,\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (Object.keys(agent).length > 0) {\n\t\t\t\tObject.defineProperty(agents, name, {\n\t\t\t\t\tvalue: agent,\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tdelete agents[name];\n\t\t\t}\n\t\t}\n\n\t\tconst normalized = normalizeSubagentSettings({\n\t\t\t...raw,\n\t\t\t...(Object.keys(agents).length > 0 ? { agents } : {}),\n\t\t});\n\t\tif (!normalized) throw new Error(`Cannot update invalid ${SETTINGS_FILE} agent settings`);\n\t\tconst updated = { ...raw };\n\t\tif (Object.keys(agents).length > 0) updated.agents = agents;\n\t\telse delete updated.agents;\n\t\twriteSettingsObjectUnlocked(updated, update.replaceCanonical);\n\t});\n}\n\ninterface SettingsObjectForUpdate {\n\tdocument: Record<string, unknown>;\n\treplaceCanonical: boolean;\n}\n\nfunction readSettingsObjectForUpdate(): SettingsObjectForUpdate {\n\tconst { canonicalPath, activePath } = resolveSubagentSettingsPaths();\n\tif (activePath === undefined) return { document: {}, replaceCanonical: false };\n\tconst activeFile = path.basename(activePath);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(fs.readFileSync(activePath, \"utf8\"));\n\t} catch {\n\t\tthrow new Error(`Cannot update malformed ${activeFile}`);\n\t}\n\tif (!isPlainObject(parsed) || !normalizeSubagentSettings(parsed)) {\n\t\tthrow new Error(`Cannot update invalid ${activeFile}`);\n\t}\n\treturn { document: parsed, replaceCanonical: activePath === canonicalPath };\n}\n\nfunction writeSettingsObject(settings: object, replaceCanonical?: boolean): void {\n\twithSettingsMutationLock(() => writeSettingsObjectUnlocked(settings, replaceCanonical));\n}\n\nfunction writeSettingsObjectUnlocked(settings: object, replaceCanonical?: boolean): void {\n\tconst agentDir = getAgentDir();\n\tfs.mkdirSync(agentDir, { recursive: true });\n\tconst configPath = path.join(agentDir, SETTINGS_FILE);\n\tconst tempFile = path.join(agentDir, `.${SETTINGS_FILE}.${randomUUID()}.tmp`);\n\t// Updates seeded from a missing or legacy document must remain exclusive even if the\n\t// canonical path appears after the read and before publication.\n\tconst firstCanonicalPublication = !(replaceCanonical ?? pathEntryExists(configPath));\n\ttry {\n\t\tfs.writeFileSync(tempFile, `${JSON.stringify(settings, null, \"\\t\")}\\n`, {\n\t\t\tencoding: \"utf8\",\n\t\t\tflag: \"wx\",\n\t\t});\n\t\tif (firstCanonicalPublication && pathEntryExists(configPath)) {\n\t\t\tthrow new Error(`${SETTINGS_FILE} was created concurrently; reopen settings and retry`);\n\t\t}\n\t\tfs.renameSync(tempFile, configPath);\n\t} finally {\n\t\ttry {\n\t\t\tfs.rmSync(tempFile, { force: true });\n\t\t} catch {\n\t\t\t// Preserve the save result if best-effort temp cleanup fails.\n\t\t}\n\t}\n}\n\nfunction withSettingsMutationLock<T>(mutate: () => T): T {\n\tconst lockfile = require(\"proper-lockfile\") as typeof import(\"proper-lockfile\");\n\tconst agentDir = getAgentDir();\n\tfs.mkdirSync(agentDir, { recursive: true });\n\tconst configPath = path.join(agentDir, SETTINGS_FILE);\n\tconst release = lockfile.lockSync(configPath, {\n\t\tfs: SETTINGS_LOCK_FS_ADAPTER,\n\t\tlockfilePath: `${configPath}.mutation-lock`,\n\t\trealpath: false,\n\t});\n\ttry {\n\t\treturn mutate();\n\t} finally {\n\t\trelease();\n\t}\n}\n\nfunction sameStatefulLimits(left: StatefulLimits, right: StatefulLimits): boolean {\n\treturn STATEFUL_LIMIT_FIELDS.every((field) => left[field] === right[field]);\n}\n\nexport function uniqueToolNames(tools: string[]): string[] {\n\treturn [...new Set(tools)];\n}\n\nexport function sameToolSet(left: string[], right: string[]): boolean {\n\tconst leftSet = new Set(left);\n\tconst rightSet = new Set(right);\n\tif (leftSet.size !== rightSet.size) return false;\n\treturn [...leftSet].every((tool) => rightSet.has(tool));\n}\n\nexport function resolveSubagentThinkingLevel(\n\tagents: readonly Pick<AgentConfig, \"name\" | \"thinkingLevel\">[],\n\tagentName: string,\n\ttopLevelThinkingLevel?: SubagentThinkingLevel,\n\tlocalThinkingLevel?: SubagentThinkingLevel,\n): SubagentThinkingLevel | undefined {\n\treturn (\n\t\tlocalThinkingLevel ??\n\t\ttopLevelThinkingLevel ??\n\t\tagents.find((agent) => agent.name === agentName)?.thinkingLevel\n\t);\n}\n\nexport function hasAnyAgentOverride(config: SubagentAgentConfig): boolean {\n\treturn (\n\t\thasOwn(config, \"tools\") ||\n\t\thasOwn(config, \"model\") ||\n\t\thasOwn(config, \"thinkingLevel\") ||\n\t\thasOwn(config, \"timeoutMs\")\n\t);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["require", "require"]
7
+ }