nolo-cli 0.8.0-alpha.2 → 0.8.0-alpha.20

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 (188) hide show
  1. package/README.md +1 -1
  2. package/_executeModel-WRUCQIV5.js +205 -0
  3. package/action-R4M4ORGA.js +28 -0
  4. package/addContentAction-UYFFTEWJ.js +26 -0
  5. package/addDialogAgentAction-OT4XZAVP.js +68 -0
  6. package/agentDeleteCommand-5DD2IM3J.js +327 -0
  7. package/agentEmailCommands-IASM2YBQ.js +628 -0
  8. package/agentListCommands-I6KZYCIG.js +223 -0
  9. package/agentMachineCommands-OUP3YQP7.js +425 -0
  10. package/agentPullCommand-O2MTUAFR.js +122 -0
  11. package/agentRecordCommands-QKGE2JTA.js +96 -0
  12. package/agentRunCommand-TVZXUBQ5.js +114 -0
  13. package/agentRunControl-K4VKNEHF.js +57 -0
  14. package/agentRuntimeLocal-ZYEIPTY4.js +104 -0
  15. package/agentSlice-T4PMW7W6.js +42 -0
  16. package/authCommand-EB5JSOX5.js +581 -0
  17. package/authCommands-XPEHTKSM.js +35 -0
  18. package/chunk-2EHX7F5G.js +1948 -0
  19. package/chunk-2FTTDCD4.js +675 -0
  20. package/chunk-3ASDTTEI.js +1774 -0
  21. package/chunk-3EUW3WEO.js +8 -0
  22. package/chunk-3LY4F7SV.js +9293 -0
  23. package/chunk-4CQLVGRV.js +50 -0
  24. package/chunk-4FBRSEV4.js +573 -0
  25. package/chunk-4IJYA27C.js +342 -0
  26. package/chunk-4QEWT7KD.js +933 -0
  27. package/chunk-4SN6J65J.js +38 -0
  28. package/chunk-4VNS5WPM.js +42 -0
  29. package/chunk-4ZDM73SD.js +34 -0
  30. package/chunk-5CS33IBL.js +301 -0
  31. package/chunk-5KLGBAAR.js +386 -0
  32. package/chunk-5MIDPSSK.js +206 -0
  33. package/chunk-5MMAK75Q.js +15 -0
  34. package/chunk-5W3VUFOX.js +34 -0
  35. package/chunk-63W5N6P3.js +150 -0
  36. package/chunk-6HYVJV7B.js +102 -0
  37. package/chunk-6WD3OOJS.js +20 -0
  38. package/chunk-7DAJ4AI4.js +191 -0
  39. package/chunk-7KCUSYT2.js +354 -0
  40. package/chunk-7T5PWAZN.js +171 -0
  41. package/chunk-AFON4QUU.js +112 -0
  42. package/chunk-AGFH73SK.js +239 -0
  43. package/chunk-ATNTHIZI.js +13 -0
  44. package/chunk-AVMKZHBC.js +85 -0
  45. package/chunk-AZPCASRE.js +36 -0
  46. package/chunk-BBYVOSU2.js +792 -0
  47. package/chunk-BCIOM4NZ.js +1078 -0
  48. package/chunk-C3RUNRHT.js +51 -0
  49. package/chunk-C4FTUXVF.js +146 -0
  50. package/chunk-CF2WZF4N.js +134 -0
  51. package/chunk-CF7PE763.js +10 -0
  52. package/chunk-CKOJQDKR.js +198 -0
  53. package/chunk-CMKUBIGW.js +1550 -0
  54. package/chunk-CWMSB67P.js +34 -0
  55. package/chunk-DCOA4QSN.js +105 -0
  56. package/chunk-DFFIZ25G.js +30 -0
  57. package/chunk-DWLEOOGR.js +8 -0
  58. package/chunk-DZ3XJVET.js +231 -0
  59. package/chunk-EHLHSX7R.js +1433 -0
  60. package/chunk-FM5IVZXO.js +4723 -0
  61. package/chunk-FVYY6MCS.js +1447 -0
  62. package/chunk-G3SUCT4W.js +8 -0
  63. package/chunk-GAKEBQD6.js +30 -0
  64. package/chunk-GBRG75BQ.js +86 -0
  65. package/chunk-GLYVN7EQ.js +238 -0
  66. package/chunk-H33743XH.js +25 -0
  67. package/chunk-HNMXYYJR.js +12 -0
  68. package/chunk-HNW7IJSK.js +71 -0
  69. package/chunk-I42VC5KR.js +15 -0
  70. package/chunk-IDZTNRP2.js +85 -0
  71. package/chunk-IHBCLYEE.js +22310 -0
  72. package/chunk-IJGXKGXW.js +421 -0
  73. package/chunk-ISNCLGUZ.js +146 -0
  74. package/chunk-IWX4UW2E.js +548 -0
  75. package/chunk-JBTJAPUF.js +35 -0
  76. package/chunk-JEXVIMYZ.js +55 -0
  77. package/chunk-JRKKFRAV.js +537 -0
  78. package/chunk-JZPBVBIY.js +94 -0
  79. package/chunk-K6BPOQLF.js +2052 -0
  80. package/chunk-K777STIO.js +478 -0
  81. package/chunk-KKY4B2Q2.js +21 -0
  82. package/chunk-KQHGZWSV.js +63 -0
  83. package/chunk-KUG52IAP.js +8 -0
  84. package/chunk-KX6YBIHG.js +8 -0
  85. package/chunk-LCBAMY2M.js +60 -0
  86. package/chunk-LM6IYQ3F.js +16 -0
  87. package/chunk-LTRXGFMS.js +83 -0
  88. package/chunk-M76ECQRD.js +13658 -0
  89. package/chunk-MNJDFJND.js +222 -0
  90. package/chunk-MRC4Q34M.js +188 -0
  91. package/chunk-MTU75CZ2.js +91 -0
  92. package/chunk-N54XAP77.js +19 -0
  93. package/chunk-O2ZNTTET.js +3272 -0
  94. package/chunk-O4BU24WZ.js +3212 -0
  95. package/chunk-OLZBQWZU.js +6 -0
  96. package/chunk-OPZYGHUC.js +89 -0
  97. package/chunk-OWOHNGCN.js +50 -0
  98. package/chunk-P3PKED2I.js +962 -0
  99. package/chunk-PFTAG6DY.js +1939 -0
  100. package/chunk-PMKQGGGM.js +221 -0
  101. package/chunk-PP4S6RTL.js +175 -0
  102. package/chunk-QJ7FZNYN.js +939 -0
  103. package/chunk-QSJ3HFEF.js +8 -0
  104. package/chunk-RGIM3WLT.js +113 -0
  105. package/chunk-RL776AGR.js +190 -0
  106. package/chunk-ROWQEJRP.js +139 -0
  107. package/chunk-S7Z2HMCN.js +25 -0
  108. package/chunk-SDJDLO5W.js +628 -0
  109. package/chunk-SOTZ6RDN.js +69 -0
  110. package/chunk-TILFE6LV.js +381 -0
  111. package/chunk-TIMLUWQA.js +231 -0
  112. package/chunk-TISCADJH.js +807 -0
  113. package/chunk-U4TRT5V4.js +246 -0
  114. package/chunk-U6VC4MU4.js +8 -0
  115. package/chunk-UAD2WT54.js +64 -0
  116. package/chunk-VC6OZXO5.js +298 -0
  117. package/chunk-VF4K2QE6.js +21 -0
  118. package/chunk-VHBWHNVT.js +59 -0
  119. package/chunk-VIDPVFP3.js +20 -0
  120. package/chunk-VP4WJWKW.js +8882 -0
  121. package/chunk-VVX233PH.js +482 -0
  122. package/chunk-W4NVOSFF.js +37 -0
  123. package/chunk-WI4XWASA.js +208 -0
  124. package/chunk-WWC7I6TA.js +8 -0
  125. package/chunk-WZSRQNQG.js +2587 -0
  126. package/chunk-XBROXIGL.js +3066 -0
  127. package/chunk-XENYHRUE.js +104 -0
  128. package/chunk-Y5GCAMGP.js +9 -0
  129. package/chunk-YN4XDB7B.js +9036 -0
  130. package/chunk-YPRZSPF3.js +148 -0
  131. package/chunk-Z4NR32XR.js +50 -0
  132. package/chunk-Z6EKEXJW.js +138 -0
  133. package/chunk-ZDRZMLKO.js +27339 -0
  134. package/chunk-ZNFJWEN4.js +56 -0
  135. package/cliExecutor-K3F7DMRO.js +36 -0
  136. package/clipboardy-BVE3LVEH.js +12001 -0
  137. package/createAgentAutomationAction-CCABEOM6.js +866 -0
  138. package/createDialogAction-YPKF5ITI.js +55 -0
  139. package/createPageAction-YEZ7EK5F.js +172 -0
  140. package/db-HCJ5PRB5.js +271 -0
  141. package/dbSlice-QPVZHBOE.js +60 -0
  142. package/deleteFile-SV5MS23W.js +41 -0
  143. package/dialogCommands-4IX4XIZE.js +63 -0
  144. package/dialogSlice-OVTO7QGW.js +148 -0
  145. package/docCreateCommands-SIL3NPGT.js +220 -0
  146. package/docDeleteCommands-7IOMLUS4.js +181 -0
  147. package/docReadCommands-FNFXUA5L.js +134 -0
  148. package/docStore-ZAYLW2HN.js +98 -0
  149. package/docUpdateCommands-X2HNDVUC.js +318 -0
  150. package/fetchMessages-KTNM7QAR.js +17 -0
  151. package/getPricing-3E6UNPKL.js +30 -0
  152. package/handleSendMessageAction-TZMZ4EP5.js +185 -0
  153. package/index.js +188 -112958
  154. package/lib-FYYBQIXS.js +19839 -0
  155. package/localDialogRead-2VRI24F4.js +26 -0
  156. package/localFirstLog-DHNOY2NA.js +19 -0
  157. package/localRuntimeAuthority-TEGCOWX4.js +471 -0
  158. package/localRuntimeDb-LGDF6FQP.js +12 -0
  159. package/machineCommands-M4ZJZIMS.js +781 -0
  160. package/machineInfo-M6KB6HZN.js +10 -0
  161. package/machineWsRunDispatch-TPJAUGLP.js +112 -0
  162. package/memoryCommands-O4MIPIWQ.js +476 -0
  163. package/models-4OPOOLFS.js +9 -0
  164. package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
  165. package/package.json +4 -23
  166. package/read-EBMWX4Z6.js +17 -0
  167. package/readDocTool-2MWHSTQE.js +16 -0
  168. package/readlineWorkspace-OMCIU3WT.js +5682 -0
  169. package/removeDialogAgentAction-SNZ662NP.js +73 -0
  170. package/runAgentClientLoop-H6NGOUAM.js +293 -0
  171. package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
  172. package/setDialogExtraReferencesAction-XDI2KM2N.js +60 -0
  173. package/setPrimaryDialogAgentAction-PYEC4N4Z.js +80 -0
  174. package/settingSlice-NOWHY2FK.js +199 -0
  175. package/skillDiscovery-UGSQGX2U.js +16 -0
  176. package/skillSummaryMarker-42HKSXYY.js +9 -0
  177. package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
  178. package/slateUtils-2M7MUTWX.js +19 -0
  179. package/spaceCommands-E7VOF4LO.js +450 -0
  180. package/spaceSlice-QHBPICA2.js +149 -0
  181. package/streamAgentChatTurn-3XTBA2HN.js +4510 -0
  182. package/tableCommands-R5UCM63M.js +1286 -0
  183. package/toolApiClient-QI3YBNWB.js +26 -0
  184. package/tools-GHLZ3XD6.js +87 -0
  185. package/tuiSummaryLlmCaller-RV3THLZF.js +78 -0
  186. package/understanding-3CUQQ6SV.js +271 -0
  187. package/updateCommands-VOSPKXFF.js +31 -0
  188. package/updateDialogTitleAction-XA2OZTLP.js +188 -0
@@ -0,0 +1,962 @@
1
+ import {
2
+ asRecordOrEmpty
3
+ } from "./chunk-KX6YBIHG.js";
4
+ import {
5
+ asNonEmptyStringArray,
6
+ asTrimmedNonEmptyStringArray
7
+ } from "./chunk-I42VC5KR.js";
8
+ import {
9
+ asOptionalFiniteNumber
10
+ } from "./chunk-WWC7I6TA.js";
11
+ import {
12
+ asOptionalTrimmedString
13
+ } from "./chunk-G3SUCT4W.js";
14
+ import {
15
+ isRecord
16
+ } from "./chunk-KUG52IAP.js";
17
+
18
+ // packages/agent-runtime/toolNameAliases.ts
19
+ var LEGACY_TOOL_NAME_ALIASES = {
20
+ createPage: "createDoc",
21
+ updatePage: "updateDoc",
22
+ update_page: "updateDoc",
23
+ create_page: "createDoc",
24
+ fetchwebpage: "fetchWebpage",
25
+ fetch_webpage: "fetchWebpage",
26
+ "fetch-page": "fetchWebpage",
27
+ exasearch: "exa_search",
28
+ "exa-search": "exa_search",
29
+ exa_search: "exa_search",
30
+ firecrawlscrape: "firecrawl_scrape",
31
+ "firecrawl-scrape": "firecrawl_scrape",
32
+ firecrawl_scrape: "firecrawl_scrape",
33
+ firecrawlsearch: "firecrawl_search",
34
+ "firecrawl-search": "firecrawl_search",
35
+ firecrawl_search: "firecrawl_search",
36
+ readDoc: "readDoc",
37
+ readpage: "readDoc",
38
+ read_page: "readDoc",
39
+ read_doc: "readDoc",
40
+ createdoc: "createDoc",
41
+ updateDocTool: "updateDoc",
42
+ terminalCommand: "execShell",
43
+ terminal_command: "execShell",
44
+ runCommand: "execShell",
45
+ run_command: "execShell",
46
+ runInBash: "execShell",
47
+ run_in_bash: "execShell",
48
+ executeCommand: "execShell",
49
+ execute_command: "execShell",
50
+ // Codex CLI 风格工具名 → nolo 原生工具名
51
+ bash: "execShell",
52
+ shell: "execShell",
53
+ read: "readFile",
54
+ edit: "editFile",
55
+ write: "writeFile",
56
+ glob: "globFiles",
57
+ grep: "searchFiles",
58
+ // 联网搜索别名
59
+ web_search: "exa_search",
60
+ websearch: "exa_search",
61
+ search_web: "exa_search",
62
+ searchweb: "exa_search",
63
+ webfetch: "fetchWebpage",
64
+ web_fetch: "fetchWebpage",
65
+ fetchweb: "fetchWebpage",
66
+ fetch_web: "fetchWebpage"
67
+ };
68
+ var normalizeToolName = (name) => name.replace(/[-_]/g, "").toLowerCase();
69
+ var canonicalizeToolName = (rawName) => {
70
+ const trimmedName = rawName.trim();
71
+ if (!trimmedName) return rawName;
72
+ if (LEGACY_TOOL_NAME_ALIASES[trimmedName]) {
73
+ return LEGACY_TOOL_NAME_ALIASES[trimmedName];
74
+ }
75
+ const normalizedRawName = normalizeToolName(trimmedName);
76
+ const matchedAlias = Object.entries(LEGACY_TOOL_NAME_ALIASES).find(
77
+ ([alias]) => normalizeToolName(alias) === normalizedRawName
78
+ );
79
+ return matchedAlias?.[1] ?? trimmedName;
80
+ };
81
+ var canonicalizeToolNames = (toolNames) => Array.from(
82
+ new Set(
83
+ toolNames.filter((toolName) => typeof toolName === "string").map(canonicalizeToolName)
84
+ )
85
+ );
86
+ var prioritizeToolNames = (toolNames, preferredToolNames) => {
87
+ const canonicalTools = canonicalizeToolNames(toolNames);
88
+ const preferred = new Set(canonicalizeToolNames(preferredToolNames));
89
+ const prioritized = canonicalTools.filter((toolName) => preferred.has(toolName));
90
+ const remaining = canonicalTools.filter((toolName) => !preferred.has(toolName));
91
+ return [...prioritized, ...remaining];
92
+ };
93
+
94
+ // packages/agent-runtime/runtimeToolSurface.ts
95
+ var DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOLS = [
96
+ "listDialogs",
97
+ "readDialog",
98
+ "queryDialogsBySubjectRef",
99
+ "listAgents",
100
+ "readAgent",
101
+ "listSpaces",
102
+ "readSpace",
103
+ "readDoc",
104
+ "readSkillDoc",
105
+ "loadSkill",
106
+ "listTables",
107
+ "queryTableRows",
108
+ "cliWhoami",
109
+ "cliDoctor"
110
+ ];
111
+ function uniqueToolNames(values) {
112
+ return [...new Set(asTrimmedNonEmptyStringArray(values))];
113
+ }
114
+ function canInjectPrivateDefaults(args) {
115
+ if (!args.currentUserId) return false;
116
+ if (args.invocationVisibility !== "private") return false;
117
+ if (args.agentOwnerId && args.agentOwnerId === args.currentUserId) return true;
118
+ if (args.trustedPrivateInvocation === true) return true;
119
+ return false;
120
+ }
121
+ function explicitOnlyReason(args) {
122
+ if (!args.currentUserId || !args.agentOwnerId) {
123
+ return "explicit-only-missing-identity";
124
+ }
125
+ if (args.invocationVisibility === "public") return "explicit-only-public";
126
+ if (args.invocationVisibility === "shared") return "explicit-only-shared";
127
+ if (args.agentOwnerId !== args.currentUserId) {
128
+ return "explicit-only-owner-mismatch";
129
+ }
130
+ return "explicit-only-anonymous";
131
+ }
132
+ function resolveRuntimeToolSurface(args) {
133
+ const explicitToolNames = uniqueToolNames(args.explicitToolNames ?? []);
134
+ if (canInjectPrivateDefaults(args)) {
135
+ const injectedToolNames = [...DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOLS];
136
+ return {
137
+ explicitToolNames,
138
+ injectedToolNames,
139
+ finalToolNames: uniqueToolNames([
140
+ ...explicitToolNames,
141
+ ...injectedToolNames
142
+ ]),
143
+ auditReason: "private-authenticated-defaults"
144
+ };
145
+ }
146
+ return {
147
+ explicitToolNames,
148
+ injectedToolNames: [],
149
+ finalToolNames: explicitToolNames,
150
+ auditReason: explicitOnlyReason(args)
151
+ };
152
+ }
153
+ function isPublicRuntimeAgentRef(value) {
154
+ return typeof value === "string" && value.startsWith("agent-pub-");
155
+ }
156
+ function inferOwnerIdFromRuntimeAgentKey(value) {
157
+ if (typeof value !== "string") return null;
158
+ const privateAgentMatch = value.match(/^agent-([^-]+)-(.+)$/);
159
+ if (privateAgentMatch && privateAgentMatch[1] !== "pub") {
160
+ return privateAgentMatch[1];
161
+ }
162
+ return null;
163
+ }
164
+ function resolveRuntimeToolSurfaceForAgent(args) {
165
+ const agentKey = typeof args.agentKey === "string" ? args.agentKey : "";
166
+ const currentUserId = typeof args.currentUserId === "string" ? args.currentUserId : "";
167
+ const inferredOwnerId = args.agentOwnerId ?? (currentUserId && agentKey.startsWith(`agent-${currentUserId}-`) ? currentUserId : inferOwnerIdFromRuntimeAgentKey(agentKey));
168
+ const publicRef = isPublicRuntimeAgentRef(agentKey);
169
+ const visibility = args.trustedPrivateInvocation === true ? "private" : publicRef || args.isPublic === true || args.sharingLevel === "public" ? "public" : "private";
170
+ return resolveRuntimeToolSurface({
171
+ explicitToolNames: args.explicitToolNames,
172
+ currentUserId: args.currentUserId,
173
+ agentOwnerId: inferredOwnerId,
174
+ invocationVisibility: visibility,
175
+ runtimeHost: args.runtimeHost,
176
+ trustedPrivateInvocation: args.trustedPrivateInvocation
177
+ });
178
+ }
179
+ var SECRET_FIELD_NAMES = [
180
+ "apikey",
181
+ "api_key",
182
+ "secret",
183
+ "token",
184
+ "authorization",
185
+ "credential",
186
+ "password"
187
+ ];
188
+ function isSecretFieldName(key) {
189
+ const normalized = key.toLowerCase();
190
+ return SECRET_FIELD_NAMES.some((name) => normalized.includes(name));
191
+ }
192
+ function redactAgentRecordForWorkspaceTool(record) {
193
+ if (Array.isArray(record)) return record.map(redactAgentRecordForWorkspaceTool);
194
+ if (!isRecord(record)) return record;
195
+ const redacted = {};
196
+ for (const [key, value] of Object.entries(record)) {
197
+ if (isSecretFieldName(key)) {
198
+ redacted[key] = "[redacted]";
199
+ continue;
200
+ }
201
+ redacted[key] = Array.isArray(value) || isRecord(value) ? redactAgentRecordForWorkspaceTool(value) : value;
202
+ }
203
+ return redacted;
204
+ }
205
+
206
+ // packages/agent-runtime/runtimeCompat.ts
207
+ import { existsSync, readdirSync, statSync } from "node:fs";
208
+ import { join } from "node:path";
209
+ import { spawn } from "node:child_process";
210
+ var IS_WINDOWS = process.platform === "win32";
211
+ function isExecutableFile(candidate) {
212
+ if (!existsSync(candidate)) return false;
213
+ try {
214
+ return statSync(candidate).isFile();
215
+ } catch {
216
+ return false;
217
+ }
218
+ }
219
+ function resolveExecutableOnPath(name) {
220
+ if (IS_WINDOWS && !/\.[a-z]+$/i.test(name)) {
221
+ const exts = (process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";").filter(Boolean);
222
+ for (const ext of exts) {
223
+ const found = resolveExecutableOnPath(name + ext);
224
+ if (found) return found;
225
+ }
226
+ return null;
227
+ }
228
+ const pathEnv = process.env.PATH ?? "";
229
+ const sep = pathEnv.includes(";") && IS_WINDOWS ? ";" : ":";
230
+ const pathDirs = pathEnv.split(sep).filter(Boolean);
231
+ const fallbackDirs = IS_WINDOWS ? [] : [
232
+ "/opt/homebrew/bin",
233
+ "/usr/local/bin",
234
+ "/usr/bin",
235
+ "/bin",
236
+ `${process.env.HOME ?? ""}/.local/bin`
237
+ ].filter(Boolean);
238
+ for (const dir of [...pathDirs, ...fallbackDirs]) {
239
+ const candidate = join(dir, name);
240
+ if (isExecutableFile(candidate)) return candidate;
241
+ }
242
+ return null;
243
+ }
244
+ function createGlob(pattern) {
245
+ const regex = globToRegExp(pattern);
246
+ return {
247
+ match(path) {
248
+ return regex.test(path);
249
+ },
250
+ scanSync(opts) {
251
+ const dot = opts.dot ?? false;
252
+ const results = [];
253
+ walkDir(opts.cwd, "", dot, results);
254
+ return results.filter((rel) => regex.test(rel));
255
+ }
256
+ };
257
+ }
258
+ function walkDir(dir, prefix, dot, out) {
259
+ let entries;
260
+ try {
261
+ entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
262
+ } catch {
263
+ return;
264
+ }
265
+ for (const entry of entries) {
266
+ const name = String(entry.name);
267
+ if (!dot && name.startsWith(".")) continue;
268
+ const rel = prefix ? `${prefix}/${name}` : name;
269
+ const full = join(dir, name);
270
+ if (entry.isDirectory()) {
271
+ walkDir(full, rel, dot, out);
272
+ } else if (entry.isFile()) {
273
+ out.push(rel);
274
+ }
275
+ }
276
+ }
277
+ function globToRegExp(pattern) {
278
+ const trailingDir = pattern.endsWith("/");
279
+ const src = trailingDir ? pattern.slice(0, -1) : pattern;
280
+ const anchored = src.startsWith("/");
281
+ const body = anchored ? src.slice(1) : src;
282
+ let regex = "^";
283
+ if (!anchored) regex += "(?:.*/)?";
284
+ regex += convertBody(body);
285
+ if (trailingDir) {
286
+ regex += "(?:/.*)?";
287
+ }
288
+ regex += "$";
289
+ return new RegExp(regex);
290
+ }
291
+ function convertBody(p) {
292
+ let out = "";
293
+ let i = 0;
294
+ while (i < p.length) {
295
+ const c = p[i];
296
+ if (c === "*") {
297
+ if (p[i + 1] === "*") {
298
+ i += 2;
299
+ if (p[i] === "/") {
300
+ out += "(?:.*/)?";
301
+ i += 1;
302
+ } else {
303
+ out += ".*";
304
+ }
305
+ } else {
306
+ out += "[^/]*";
307
+ i += 1;
308
+ }
309
+ } else if (c === "?") {
310
+ out += "[^/]";
311
+ i += 1;
312
+ } else if (c === "[") {
313
+ out += "[";
314
+ i += 1;
315
+ if (p[i] === "!") {
316
+ out += "^";
317
+ i += 1;
318
+ }
319
+ while (i < p.length && p[i] !== "]") {
320
+ out += p[i] === "\\" ? "\\\\" : p[i];
321
+ i += 1;
322
+ }
323
+ if (p[i] === "]") {
324
+ out += "]";
325
+ i += 1;
326
+ }
327
+ } else if (c === "{") {
328
+ let depth = 1;
329
+ let j = i + 1;
330
+ let bodyStr = "";
331
+ while (j < p.length && depth > 0) {
332
+ if (p[j] === "{") depth += 1;
333
+ else if (p[j] === "}") depth -= 1;
334
+ if (depth > 0) bodyStr += p[j];
335
+ j += 1;
336
+ }
337
+ const alts = bodyStr.split(",").map((alt) => convertBody(alt));
338
+ out += `(?:${alts.join("|")})`;
339
+ i = j;
340
+ } else {
341
+ out += escapeRegexChar(c);
342
+ i += 1;
343
+ }
344
+ }
345
+ return out;
346
+ }
347
+ function escapeRegexChar(c) {
348
+ if ("\\^$.|+()".includes(c)) {
349
+ return `\\${c}`;
350
+ }
351
+ return c;
352
+ }
353
+ function spawnToWebStreams(options) {
354
+ const [command, ...args] = options.cmd;
355
+ const child = spawn(command, args, {
356
+ env: options.env,
357
+ stdio: ["ignore", "pipe", "pipe"]
358
+ });
359
+ const exited = new Promise((resolve) => {
360
+ child.on("exit", (code) => resolve(code ?? 1));
361
+ child.on("error", () => resolve(127));
362
+ });
363
+ const toWeb = (stream) => {
364
+ if (!stream) return null;
365
+ return stream.toWeb?.() ?? new ReadableStream({
366
+ start(controller) {
367
+ stream.on("data", (chunk) => controller.enqueue(new Uint8Array(chunk)));
368
+ stream.on("end", () => controller.close());
369
+ stream.on("error", (e) => controller.error(e));
370
+ }
371
+ });
372
+ };
373
+ return {
374
+ stdout: toWeb(child.stdout),
375
+ stderr: toWeb(child.stderr),
376
+ exited
377
+ };
378
+ }
379
+
380
+ // packages/agent-runtime/noloWorkspaceTools.ts
381
+ var NOLO_WORKSPACE_TOOL_NAMES = [
382
+ "listDialogs",
383
+ "readDialog",
384
+ "queryDialogsBySubjectRef",
385
+ "deleteDialogs",
386
+ "listAgents",
387
+ "readAgent",
388
+ "listSpaces",
389
+ "readSpace",
390
+ "readDoc",
391
+ "readSkillDoc",
392
+ "loadSkill",
393
+ "listTables",
394
+ "queryTableRows",
395
+ "cliWhoami",
396
+ "cliDoctor"
397
+ ];
398
+ var NOLO_WORKSPACE_TOOL_NAME_SET = new Set(NOLO_WORKSPACE_TOOL_NAMES);
399
+ var DIALOG_ID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/i;
400
+ var DIALOG_PATH_RE = /^\/(?:space\/([^/]+)\/)?dialog-(.+)-([0-9A-HJKMNP-TV-Z]{26})\/?$/i;
401
+ function stringToolParam(description) {
402
+ return { type: "string", description };
403
+ }
404
+ function isNoloWorkspaceToolName(toolName) {
405
+ return typeof toolName === "string" && NOLO_WORKSPACE_TOOL_NAME_SET.has(toolName);
406
+ }
407
+ function filterNoloWorkspaceToolNames(toolNames) {
408
+ return (toolNames ?? []).filter(isNoloWorkspaceToolName);
409
+ }
410
+ function buildNoloWorkspaceOpenAiTools(args) {
411
+ const toolNames = new Set(args.toolNames ?? []);
412
+ const tools = [];
413
+ function add(name, description, properties, required = []) {
414
+ if (!toolNames.has(name)) return;
415
+ tools.push({
416
+ type: "function",
417
+ function: {
418
+ name,
419
+ description,
420
+ parameters: {
421
+ type: "object",
422
+ properties,
423
+ ...required.length ? { required } : {}
424
+ }
425
+ }
426
+ });
427
+ }
428
+ add("listDialogs", "List the current user's dialogs in the Nolo workspace.", {
429
+ limit: { type: "integer", description: "Maximum dialogs to return." },
430
+ space: stringToolParam("Optional space id or URL.")
431
+ });
432
+ add("readDialog", "Read one persisted dialog in the Nolo workspace.", {
433
+ dialog: stringToolParam("Dialog id, dialog db key, or dialog URL."),
434
+ limit: { type: "integer", description: "Optional message limit." }
435
+ }, ["dialog"]);
436
+ add("queryDialogsBySubjectRef", "Query persisted dialog evidence by a generic dialog.subjectRefs target.", {
437
+ rowDbKey: stringToolParam("Optional convenience alias for subjectKind=table-row, subjectId=<rowDbKey>, subjectRole=task."),
438
+ subjectKind: stringToolParam("Generic subject ref kind, for example table-row, page, file, commit, or artifact."),
439
+ subjectId: stringToolParam("Generic subject ref id."),
440
+ subjectRole: stringToolParam("Optional subject ref role."),
441
+ limit: { type: "integer", description: "Maximum matching dialog summaries to return." },
442
+ status: stringToolParam("Optional dialog status filter, for example running, done, or failed."),
443
+ checkpointStatus: stringToolParam("Optional runtimeCheckpoint.status filter."),
444
+ hasArtifacts: { type: "boolean", description: "When true, only return dialogs with artifact evidence." },
445
+ excludeDialogId: stringToolParam("Optional dialog id or dialog dbKey to exclude from evidence results, typically the current caller dialog.")
446
+ });
447
+ add("deleteDialogs", "Find and delete the current user's dialogs by title/id/dbKey. This is destructive: preview matches first and wait for explicit user confirmation before deleting.", {
448
+ query: stringToolParam("Dialog title/id/dbKey search text, for example \u4E2D\u533B\u8BC4\u6D4B or a dialog id."),
449
+ matchMode: {
450
+ type: "string",
451
+ enum: ["contains", "exact", "prefix", "dialogId"],
452
+ description: "Matching mode. Default contains."
453
+ },
454
+ confirmedDialogIds: {
455
+ type: "array",
456
+ items: { type: "string" },
457
+ description: "Confirmed dialog ids or dbKeys to delete."
458
+ }
459
+ }, ["query"]);
460
+ add("listAgents", "List the current user's agents in the Nolo workspace.", {
461
+ space: stringToolParam("Optional space id or URL."),
462
+ publicOnly: { type: "boolean", description: "Only show public agents." }
463
+ });
464
+ add("readAgent", "Read one agent config in the Nolo workspace.", {
465
+ agent: stringToolParam("Agent key, id, alias, or URL.")
466
+ }, ["agent"]);
467
+ add("listSpaces", "List joined spaces in the Nolo workspace.", {});
468
+ add("readSpace", "Read one space in the Nolo workspace.", {
469
+ space: stringToolParam("Space id or URL."),
470
+ contentKey: stringToolParam("Optional content key inside the space."),
471
+ brief: { type: "boolean", description: "Return brief output when supported." }
472
+ }, ["space"]);
473
+ add("readDoc", "Read one normal doc/page in the Nolo workspace.", {
474
+ doc: stringToolParam("Doc/page key.")
475
+ }, ["doc"]);
476
+ add("readSkillDoc", "Read one skill doc in the Nolo workspace.", {
477
+ doc: stringToolParam("Skill doc/page key.")
478
+ }, ["doc"]);
479
+ add("loadSkill", "Load a Skill by name from the workspace skill directories (.agents/skills/<name>/SKILL.md, then docs/skills/<name>.md) and return its full SKILL.md content inline so you can follow its instructions. Use this instead of readFile when you want to activate a skill. On an unknown name the tool returns a plain text list of available skill names rather than failing.", {
480
+ name: stringToolParam("Skill name (the name advertised in the skill-discovery layer).")
481
+ }, ["name"]);
482
+ add("listTables", "List tables in the current user scope or an optional space scope.", {
483
+ limit: { type: "integer", description: "Maximum tables to return." },
484
+ space: stringToolParam("Optional space id or URL."),
485
+ titleQuery: stringToolParam("Optional case-insensitive title substring."),
486
+ purpose: stringToolParam("Optional purpose value such as agent_eval_workbench.")
487
+ });
488
+ add("queryTableRows", "Query rows from a Nolo table.", {
489
+ table: stringToolParam("Table id or meta key."),
490
+ limit: { type: "integer", description: "Optional row limit." },
491
+ row: stringToolParam("Optional row id or row db key."),
492
+ output: stringToolParam("Optional output format such as json, jsonl, or items.")
493
+ }, ["table"]);
494
+ add("cliWhoami", "Show the current Nolo CLI login state.", {});
495
+ add("cliDoctor", "Show Nolo CLI doctor diagnostics.", {});
496
+ return tools;
497
+ }
498
+ function noloPositiveIntegerString(value) {
499
+ const parsed = Number(value);
500
+ return Number.isInteger(parsed) && parsed > 0 ? String(parsed) : null;
501
+ }
502
+ function noloStringArg(value) {
503
+ return asOptionalTrimmedString(value) ?? null;
504
+ }
505
+ function parseNoloWorkspaceToolArguments(raw) {
506
+ try {
507
+ return asRecordOrEmpty(JSON.parse(raw || "{}"));
508
+ } catch {
509
+ return {};
510
+ }
511
+ }
512
+ function clampNoloPositiveInteger(value, fallback, max = 500) {
513
+ const parsed = Number(value);
514
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
515
+ return Math.min(Math.floor(parsed), max);
516
+ }
517
+ function getNoloDialogIdFromKey(dbKey) {
518
+ const index = dbKey.lastIndexOf("-");
519
+ return index >= 0 ? dbKey.slice(index + 1) : dbKey;
520
+ }
521
+ function resolveNoloDialogInput(rawInput, userId) {
522
+ const raw = rawInput.trim();
523
+ if (raw.startsWith("http://") || raw.startsWith("https://")) {
524
+ const url = new URL(raw);
525
+ const match = url.pathname.match(DIALOG_PATH_RE);
526
+ if (!match) throw new Error(`Unsupported dialog URL path: ${url.pathname}`);
527
+ const [, spaceId, ownerId, dialogId] = match;
528
+ return {
529
+ dbKey: `dialog-${ownerId}-${dialogId}`,
530
+ dialogId,
531
+ ownerId,
532
+ spaceId: spaceId ? decodeURIComponent(spaceId) : null
533
+ };
534
+ }
535
+ if (raw.startsWith("dialog-")) {
536
+ const dialogId = getNoloDialogIdFromKey(raw);
537
+ return {
538
+ dbKey: raw,
539
+ dialogId,
540
+ ownerId: raw.slice("dialog-".length, Math.max("dialog-".length, raw.length - dialogId.length - 1)),
541
+ spaceId: null
542
+ };
543
+ }
544
+ if (!DIALOG_ID_RE.test(raw)) {
545
+ throw new Error(`Unsupported dialog id: ${raw}`);
546
+ }
547
+ return {
548
+ dbKey: `dialog-${userId}-${raw}`,
549
+ dialogId: raw,
550
+ ownerId: userId,
551
+ spaceId: null
552
+ };
553
+ }
554
+ function normalizeNoloSpaceInput(raw) {
555
+ const value = raw.trim();
556
+ if (!value) return "";
557
+ if (value.startsWith("http://") || value.startsWith("https://")) {
558
+ const match = new URL(value).pathname.match(/^\/space\/([^/]+)/);
559
+ return match?.[1] ? decodeURIComponent(match[1]).replace(/^space-/, "") : "";
560
+ }
561
+ return value.replace(/^space-/, "");
562
+ }
563
+ function getNoloComparableUpdatedAt(record) {
564
+ const raw = record?.updatedAt ?? record?.updated_at ?? record?.createdAt ?? record?.created;
565
+ const asNumber = asOptionalFiniteNumber(raw);
566
+ if (asNumber !== void 0) return asNumber;
567
+ if (typeof raw === "string") return Date.parse(raw) || 0;
568
+ return 0;
569
+ }
570
+ function normalizeNoloSubjectKind(kind) {
571
+ return kind === "tableRow" ? "table-row" : kind;
572
+ }
573
+ function normalizeNoloSubjectRef(value) {
574
+ if (!isRecord(value)) return null;
575
+ const kindRaw = asOptionalTrimmedString(value.kind);
576
+ const kind = kindRaw ? normalizeNoloSubjectKind(kindRaw) : "";
577
+ const id = asOptionalTrimmedString(value.id) ?? "";
578
+ if (!kind || !id) return null;
579
+ const role = asOptionalTrimmedString(value.role) ?? "";
580
+ return {
581
+ kind,
582
+ id,
583
+ ...role ? { role } : {}
584
+ };
585
+ }
586
+ function buildNoloSubjectRefQueryTarget(args) {
587
+ const rowDbKey = noloStringArg(args.rowDbKey ?? args.row ?? args.taskRowDbKey);
588
+ const subjectKind = noloStringArg(args.subjectKind ?? args.kind) ?? (rowDbKey ? "table-row" : null);
589
+ const subjectId = noloStringArg(args.subjectId ?? args.id) ?? rowDbKey;
590
+ const subjectRole = noloStringArg(args.subjectRole ?? args.role) ?? (rowDbKey ? "task" : null);
591
+ if (!subjectKind || !subjectId) return null;
592
+ return {
593
+ kind: normalizeNoloSubjectKind(subjectKind),
594
+ id: subjectId,
595
+ ...subjectRole ? { role: subjectRole } : {}
596
+ };
597
+ }
598
+ function extractNoloDialogSubjectRefs(dialog) {
599
+ if (!isRecord(dialog) || !Array.isArray(dialog.subjectRefs)) return [];
600
+ return dialog.subjectRefs.map(normalizeNoloSubjectRef).filter((ref) => Boolean(ref));
601
+ }
602
+ function noloDialogMatchesSubjectRef(dialog, target) {
603
+ const normalizedTarget = normalizeNoloSubjectRef(target);
604
+ if (!normalizedTarget) return false;
605
+ return extractNoloDialogSubjectRefs(dialog).some(
606
+ (ref) => ref.kind === normalizedTarget.kind && ref.id === normalizedTarget.id
607
+ );
608
+ }
609
+ function noloArtifactCount(value) {
610
+ if (Array.isArray(value)) return value.length;
611
+ if (isRecord(value)) return Object.keys(value).length > 0 ? 1 : 0;
612
+ return value ? 1 : 0;
613
+ }
614
+ function summarizeNoloDialogSubjectRefEvidence(dialog, target) {
615
+ const dialogKey = asOptionalTrimmedString(dialog?.dbKey) ?? "";
616
+ const checkpoint = asRecordOrEmpty(dialog?.runtimeCheckpoint);
617
+ const matchedSubjectRefs = extractNoloDialogSubjectRefs(dialog).filter(
618
+ (ref) => ref.kind === normalizeNoloSubjectKind(target.kind) && ref.id === target.id
619
+ );
620
+ const lastToolNames = asNonEmptyStringArray(checkpoint.lastToolNames);
621
+ const artifactCount = noloArtifactCount(dialog?.artifacts);
622
+ return {
623
+ dialogId: asOptionalTrimmedString(dialog?.dialogId) ?? asOptionalTrimmedString(dialog?.id) ?? (dialogKey ? getNoloDialogIdFromKey(dialogKey) : null),
624
+ dialogKey: dialogKey || null,
625
+ title: asOptionalTrimmedString(dialog?.title) ?? null,
626
+ status: asOptionalTrimmedString(dialog?.status) ?? null,
627
+ checkpointStatus: asOptionalTrimmedString(checkpoint.status) ?? null,
628
+ updatedAt: typeof dialog?.updatedAt === "string" || typeof dialog?.updatedAt === "number" ? dialog.updatedAt : null,
629
+ hasArtifacts: artifactCount > 0,
630
+ artifactCount,
631
+ subjectRefs: matchedSubjectRefs,
632
+ lastToolNames
633
+ };
634
+ }
635
+ function normalizeNoloExcludeDialogIds(value) {
636
+ const rawValues = Array.isArray(value) ? value : [value];
637
+ const ids = /* @__PURE__ */ new Set();
638
+ for (const rawValue of rawValues) {
639
+ if (typeof rawValue !== "string") continue;
640
+ const trimmed = rawValue.trim();
641
+ if (!trimmed) continue;
642
+ ids.add(trimmed);
643
+ if (trimmed.startsWith("dialog-")) {
644
+ ids.add(getNoloDialogIdFromKey(trimmed));
645
+ }
646
+ }
647
+ return [...ids];
648
+ }
649
+ function getNoloDialogIdentityValues(dialog) {
650
+ if (!isRecord(dialog)) return [];
651
+ const values = /* @__PURE__ */ new Set();
652
+ for (const rawValue of [dialog.dialogId, dialog.id, dialog.dbKey]) {
653
+ if (typeof rawValue !== "string") continue;
654
+ const trimmed = rawValue.trim();
655
+ if (!trimmed) continue;
656
+ values.add(trimmed);
657
+ if (trimmed.startsWith("dialog-")) {
658
+ values.add(getNoloDialogIdFromKey(trimmed));
659
+ }
660
+ }
661
+ return [...values];
662
+ }
663
+ function filterNoloDialogsByExcludedIds(dialogs, excludeDialogIds) {
664
+ const excluded = new Set(normalizeNoloExcludeDialogIds(excludeDialogIds));
665
+ if (excluded.size === 0) return dialogs;
666
+ return dialogs.filter(
667
+ (dialog) => getNoloDialogIdentityValues(dialog).every((value) => !excluded.has(value))
668
+ );
669
+ }
670
+ function filterNoloDialogSubjectRefEvidence(args) {
671
+ const matched = [];
672
+ for (const dialog of filterNoloDialogsByExcludedIds(args.dialogs, args.excludeDialogIds)) {
673
+ if (noloDialogMatchesSubjectRef(dialog, args.target)) {
674
+ matched.push(dialog);
675
+ }
676
+ }
677
+ matched.sort((left, right) => getNoloComparableUpdatedAt(right) - getNoloComparableUpdatedAt(left));
678
+ const evidence = [];
679
+ for (const dialog of matched) {
680
+ const entry = summarizeNoloDialogSubjectRefEvidence(dialog, args.target);
681
+ if (args.status && entry.status !== args.status) continue;
682
+ if (args.checkpointStatus && entry.checkpointStatus !== args.checkpointStatus) continue;
683
+ if (args.hasArtifacts != null && entry.hasArtifacts !== args.hasArtifacts) continue;
684
+ evidence.push(entry);
685
+ }
686
+ return evidence.slice(0, args.limit);
687
+ }
688
+ function verifyNoloDialogSubjectRefQuery(dialogs, target, options = {}) {
689
+ const checkedDialogs = filterNoloDialogsByExcludedIds(dialogs, options.excludeDialogIds);
690
+ const unmatchedDialogs = [];
691
+ for (const dialog of checkedDialogs) {
692
+ if (noloDialogMatchesSubjectRef(dialog, target)) continue;
693
+ unmatchedDialogs.push({
694
+ dialogId: asOptionalTrimmedString(dialog?.dialogId) ?? asOptionalTrimmedString(dialog?.id) ?? (typeof dialog?.dbKey === "string" ? getNoloDialogIdFromKey(dialog.dbKey) : null),
695
+ dialogKey: asOptionalTrimmedString(dialog?.dbKey) ?? null,
696
+ subjectRefs: extractNoloDialogSubjectRefs(dialog)
697
+ });
698
+ }
699
+ const reason = unmatchedDialogs.length > 0 ? "unmatched_results" : "ok";
700
+ return {
701
+ ok: reason === "ok",
702
+ reason,
703
+ target,
704
+ returnedCount: checkedDialogs.length,
705
+ matchedCount: checkedDialogs.length - unmatchedDialogs.length,
706
+ unmatchedCount: unmatchedDialogs.length,
707
+ unmatchedDialogs
708
+ };
709
+ }
710
+ function buildNoloTableQueryRequest(args, currentUserId) {
711
+ const tableInput = noloStringArg(args.table ?? args.metaKey);
712
+ if (!tableInput) return null;
713
+ const tableMetaParts = tableInput.startsWith("meta-") ? tableInput.split("-") : [];
714
+ const tenantId = args.tenantId ?? (tableMetaParts.length >= 3 ? tableMetaParts[1] : currentUserId);
715
+ const tableId = args.tableId ?? (tableMetaParts.length >= 3 ? tableMetaParts.slice(2).join("-") : tableInput);
716
+ const filters = {
717
+ ...asRecordOrEmpty(args.filters)
718
+ };
719
+ const row = noloStringArg(args.row ?? args.rowId);
720
+ if (row) {
721
+ if (row.startsWith("row-")) filters.dbKey = row;
722
+ else filters.rowId = row;
723
+ }
724
+ return {
725
+ tenantId,
726
+ tableId,
727
+ filters,
728
+ columns: args.columns,
729
+ limit: args.limit ?? (row ? 1 : 20),
730
+ offset: args.offset,
731
+ includeBaseFields: args.includeBaseFields,
732
+ sortBy: args.sortBy ?? "updatedAt",
733
+ sortOrder: args.sortOrder === "asc" ? "asc" : "desc"
734
+ };
735
+ }
736
+ function buildNoloWorkspaceCommandArgs(call) {
737
+ const args = parseNoloWorkspaceToolArguments(call.arguments);
738
+ switch (call.name) {
739
+ case "listDialogs": {
740
+ const cliArgs = ["dialog", "list"];
741
+ const limit = noloPositiveIntegerString(args.limit);
742
+ const space = noloStringArg(args.space);
743
+ if (limit) cliArgs.push("--limit", limit);
744
+ if (space) cliArgs.push("--space", space);
745
+ return cliArgs;
746
+ }
747
+ case "readDialog": {
748
+ const dialog = noloStringArg(args.dialog ?? args.dialogId ?? args.id);
749
+ if (!dialog) throw new Error("readDialog requires dialog.");
750
+ const cliArgs = ["dialog", "read", dialog];
751
+ const limit = noloPositiveIntegerString(args.limit);
752
+ if (limit) cliArgs.push(limit);
753
+ return cliArgs;
754
+ }
755
+ case "queryDialogsBySubjectRef": {
756
+ const target = buildNoloSubjectRefQueryTarget(args);
757
+ if (!target) throw new Error("queryDialogsBySubjectRef requires rowDbKey or subjectKind plus subjectId.");
758
+ const cliArgs = ["dialog", "query"];
759
+ const rowDbKey = noloStringArg(args.rowDbKey ?? args.row ?? args.taskRowDbKey);
760
+ if (rowDbKey && target.kind === "table-row" && target.id === rowDbKey) {
761
+ cliArgs.push("--row-dbkey", rowDbKey);
762
+ } else {
763
+ cliArgs.push("--subject-kind", target.kind, "--subject-id", target.id);
764
+ if (target.role) cliArgs.push("--subject-role", target.role);
765
+ }
766
+ const limit = noloPositiveIntegerString(args.limit);
767
+ if (limit) cliArgs.push("--limit", limit);
768
+ const excludeDialogId = noloStringArg(args.excludeDialogId ?? args.excludeDialog);
769
+ if (excludeDialogId) cliArgs.push("--exclude-dialog", excludeDialogId);
770
+ cliArgs.push("--json");
771
+ return cliArgs;
772
+ }
773
+ case "listAgents": {
774
+ const cliArgs = ["agent", "list"];
775
+ const space = noloStringArg(args.space);
776
+ if (space) cliArgs.push("--space", space);
777
+ if (args.publicOnly === true) cliArgs.push("--public-only");
778
+ return cliArgs;
779
+ }
780
+ case "readAgent": {
781
+ const agent = noloStringArg(args.agent ?? args.agentKey ?? args.id);
782
+ if (!agent) throw new Error("readAgent requires agent.");
783
+ return ["agent", "read", agent];
784
+ }
785
+ case "listSpaces":
786
+ return ["space", "list"];
787
+ case "readSpace": {
788
+ const space = noloStringArg(args.space ?? args.spaceId ?? args.id);
789
+ if (!space) throw new Error("readSpace requires space.");
790
+ const cliArgs = ["space", "read", space];
791
+ const contentKey = noloStringArg(args.contentKey);
792
+ if (contentKey) cliArgs.push("--content-key", contentKey);
793
+ if (args.brief === true) cliArgs.push("--brief");
794
+ return cliArgs;
795
+ }
796
+ case "readDoc": {
797
+ const doc = noloStringArg(args.doc ?? args.docKey ?? args.pageKey ?? args.key);
798
+ if (!doc) throw new Error("readDoc requires doc.");
799
+ return ["doc", "read", doc];
800
+ }
801
+ case "readSkillDoc": {
802
+ const doc = noloStringArg(args.doc ?? args.docKey ?? args.pageKey ?? args.key);
803
+ if (!doc) throw new Error("readSkillDoc requires doc.");
804
+ return ["skill-doc", "read", doc];
805
+ }
806
+ case "loadSkill":
807
+ throw new Error("loadSkill is a local-fs tool and has no CLI mapping; wire buildLoadSkillExecutor instead.");
808
+ case "listTables": {
809
+ const cliArgs = ["table", "list"];
810
+ const limit = noloPositiveIntegerString(args.limit);
811
+ const space = noloStringArg(args.space ?? args.spaceId);
812
+ const titleQuery = noloStringArg(args.titleQuery);
813
+ const purpose = noloStringArg(args.purpose);
814
+ if (limit) cliArgs.push("--limit", limit);
815
+ if (space) cliArgs.push("--space", space);
816
+ if (titleQuery) cliArgs.push("--title-query", titleQuery);
817
+ if (purpose) cliArgs.push("--purpose", purpose);
818
+ return cliArgs;
819
+ }
820
+ case "queryTableRows": {
821
+ const table = noloStringArg(args.table ?? args.tableId ?? args.metaKey);
822
+ if (!table) throw new Error("queryTableRows requires table.");
823
+ const cliArgs = ["table", "query", "--table", table];
824
+ const limit = noloPositiveIntegerString(args.limit);
825
+ const row = noloStringArg(args.row ?? args.rowId);
826
+ const output = noloStringArg(args.output);
827
+ if (limit) cliArgs.push("--limit", limit);
828
+ if (row) cliArgs.push("--row", row);
829
+ if (output) cliArgs.push("--output", output);
830
+ return cliArgs;
831
+ }
832
+ case "cliWhoami":
833
+ return ["whoami"];
834
+ case "cliDoctor":
835
+ return ["doctor"];
836
+ default:
837
+ throw new Error(`Unsupported Nolo workspace tool: ${call.name}`);
838
+ }
839
+ }
840
+ async function readNoloProcessStream(readable) {
841
+ if (!readable) return "";
842
+ return new Response(readable).text();
843
+ }
844
+ async function runNoloWorkspaceCliTool(call, args) {
845
+ const cliArgs = buildNoloWorkspaceCommandArgs(call);
846
+ const bunSpawn = globalThis.Bun?.spawn;
847
+ const spawn2 = args.spawn ?? (typeof bunSpawn === "function" ? bunSpawn : nodeSpawnFallback);
848
+ const execPath = args.processExecPath ?? process.execPath;
849
+ const entrypoint = args.cliEntrypoint;
850
+ const cmd = entrypoint && entrypoint !== execPath ? [execPath, entrypoint, ...cliArgs] : [execPath, ...cliArgs];
851
+ const proc = spawn2({
852
+ cmd,
853
+ stdout: "pipe",
854
+ stderr: "pipe",
855
+ env: args.env
856
+ });
857
+ const [stdout, stderr, exitCode] = await Promise.all([
858
+ readNoloProcessStream(proc.stdout),
859
+ readNoloProcessStream(proc.stderr),
860
+ proc.exited
861
+ ]);
862
+ const content = `${stdout}${stderr}`;
863
+ if (exitCode !== 0) {
864
+ throw new Error(content.trim() || `nolo ${cliArgs.join(" ")} exited ${exitCode}`);
865
+ }
866
+ return {
867
+ content,
868
+ metadata: {
869
+ [args.metadataKind ?? "noloWorkspaceTool"]: true,
870
+ command: ["nolo", ...cliArgs].join(" "),
871
+ exitCode
872
+ }
873
+ };
874
+ }
875
+ function buildNoloWorkspaceCliToolExecutors(args) {
876
+ const executors = {};
877
+ for (const toolName of NOLO_WORKSPACE_TOOL_NAMES) {
878
+ if (toolName === "loadSkill") continue;
879
+ executors[toolName] = (call) => runNoloWorkspaceCliTool(call, args);
880
+ }
881
+ return executors;
882
+ }
883
+ function buildLoadSkillExecutor(args) {
884
+ return async (call) => {
885
+ const parsed = parseNoloWorkspaceToolArguments(call.arguments);
886
+ const name = noloStringArg(parsed.name ?? parsed.skillName ?? parsed.skill);
887
+ if (!name) {
888
+ return {
889
+ content: await formatUnknownSkillMessage(args.cwd, "(no name provided)"),
890
+ metadata: { loadSkill: true, resolved: false }
891
+ };
892
+ }
893
+ const { resolveSkillByName } = await import("./skillDiscovery-UGSQGX2U.js");
894
+ const resolved = resolveSkillByName(args.cwd, name);
895
+ if (!resolved) {
896
+ return {
897
+ content: await formatUnknownSkillMessage(args.cwd, name),
898
+ metadata: { loadSkill: true, resolved: false, name, requestedName: name }
899
+ };
900
+ }
901
+ try {
902
+ const { readFileSync } = await import("node:fs");
903
+ const body = readFileSync(resolved, "utf8");
904
+ return {
905
+ content: `Skill "${name}" loaded inline. Follow its instructions.
906
+
907
+ ${body}`,
908
+ metadata: { loadSkill: true, resolved: true, name, requestedName: name, path: resolved }
909
+ };
910
+ } catch (err) {
911
+ const message = err instanceof Error ? err.message : String(err);
912
+ return {
913
+ content: `Skill "${name}" could not be read: ${message}`,
914
+ metadata: { loadSkill: true, resolved: true, name, requestedName: name, path: resolved, readError: message }
915
+ };
916
+ }
917
+ };
918
+ }
919
+ async function formatUnknownSkillMessage(cwd, requestedName) {
920
+ const { discoverSkills } = await import("./skillDiscovery-UGSQGX2U.js");
921
+ let available = [];
922
+ try {
923
+ available = discoverSkills(cwd).map((s) => s.name);
924
+ } catch {
925
+ }
926
+ const header = `Skill "${requestedName}" not found in this workspace's skill directories (.agents/skills/<name>/SKILL.md, docs/skills/<name>.md).`;
927
+ if (available.length === 0) return `${header}
928
+
929
+ No skills were discovered in this workspace.`;
930
+ return `${header}
931
+
932
+ Available skills: ${available.join(", ")}`;
933
+ }
934
+ var nodeSpawnFallback = (options) => {
935
+ return spawnToWebStreams({ cmd: options.cmd, env: options.env });
936
+ };
937
+
938
+ export {
939
+ canonicalizeToolName,
940
+ canonicalizeToolNames,
941
+ prioritizeToolNames,
942
+ resolveRuntimeToolSurfaceForAgent,
943
+ redactAgentRecordForWorkspaceTool,
944
+ resolveExecutableOnPath,
945
+ createGlob,
946
+ NOLO_WORKSPACE_TOOL_NAMES,
947
+ filterNoloWorkspaceToolNames,
948
+ buildNoloWorkspaceOpenAiTools,
949
+ parseNoloWorkspaceToolArguments,
950
+ clampNoloPositiveInteger,
951
+ getNoloDialogIdFromKey,
952
+ resolveNoloDialogInput,
953
+ normalizeNoloSpaceInput,
954
+ getNoloComparableUpdatedAt,
955
+ buildNoloSubjectRefQueryTarget,
956
+ normalizeNoloExcludeDialogIds,
957
+ filterNoloDialogSubjectRefEvidence,
958
+ verifyNoloDialogSubjectRefQuery,
959
+ buildNoloTableQueryRequest,
960
+ buildNoloWorkspaceCliToolExecutors,
961
+ buildLoadSkillExecutor
962
+ };