nolo-cli 0.1.32 → 0.1.33

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 (230) hide show
  1. package/README.md +0 -6
  2. package/agent-runtime/agentRecordConfig.ts +2 -0
  3. package/agent-runtime/hostAdapter.ts +1 -0
  4. package/agent-runtime/index.ts +0 -21
  5. package/agent-runtime/localToolPolicy.ts +6 -13
  6. package/agent-runtime/localWorkspaceTools.ts +30 -333
  7. package/agent-runtime/platformChatProvider.ts +1 -4
  8. package/agent-runtime/runtimeToolPolicy.ts +47 -32
  9. package/agentAliases.ts +14 -83
  10. package/agentCommandSupport.ts +3 -6
  11. package/agentInternalCommandEntries.ts +2 -13
  12. package/agentListCommands.ts +19 -28
  13. package/agentMachineCommands.ts +40 -336
  14. package/agentPullCommand.ts +36 -56
  15. package/agentRecordCommands.ts +3 -5
  16. package/agentRecordHelpers.ts +22 -189
  17. package/agentRunCommand.ts +438 -107
  18. package/agentRuntimeLocal.ts +0 -10
  19. package/ai/agent/cliExecutor.ts +19 -323
  20. package/authCommands.ts +2 -36
  21. package/cli/agentAliases.ts +14 -83
  22. package/cli/agentCommandSupport.ts +3 -6
  23. package/cli/agentInternalCommandEntries.ts +2 -13
  24. package/cli/agentListCommands.ts +19 -28
  25. package/cli/agentMachineCommands.ts +40 -336
  26. package/cli/agentPullCommand.ts +36 -56
  27. package/cli/agentRecordCommands.ts +3 -5
  28. package/cli/agentRecordHelpers.ts +22 -189
  29. package/cli/agentRunCommand.ts +438 -107
  30. package/cli/agentRuntimeLocal.ts +0 -10
  31. package/cli/authCommands.ts +2 -36
  32. package/cli/cliEnvHelpers.ts +21 -162
  33. package/cli/client/agentRun.ts +853 -57
  34. package/cli/client/localRuntimeAdapter.ts +22 -159
  35. package/cli/client/streamingOutput.ts +3 -1
  36. package/cli/client/taskRunPrompt.ts +24 -7
  37. package/cli/commandRegistry.ts +2 -3
  38. package/cli/connectorRunArtifact.ts +10 -34
  39. package/cli/connectorWebSocketTarget.ts +6 -10
  40. package/cli/internalCommandEntries.ts +0 -8
  41. package/cli/localRuntimeDb.ts +2 -39
  42. package/cli/machineCommands.ts +189 -190
  43. package/cli/machineDaemonCommands.ts +165 -9
  44. package/cli/machineHeartbeatCommands.ts +2 -1
  45. package/cli/machineStatusCommands.ts +13 -5
  46. package/cli/machineWatchCommands.ts +1 -1
  47. package/cli/machineWsRunDispatch.ts +14 -48
  48. package/cli/machineWsSession.ts +0 -2
  49. package/cli/offlineMarxistsAgentCommand.ts +314 -0
  50. package/cli/runtimeDoctorCommands.ts +69 -18
  51. package/cli/scriptCommandEntries.ts +45 -5
  52. package/cli/tableCommands.ts +133 -33
  53. package/cli/taskRunCommand.ts +211 -16
  54. package/cli/tui/session.ts +372 -43
  55. package/cli/workflowInternalCommandEntries.ts +0 -20
  56. package/cliEnvHelpers.ts +21 -162
  57. package/client/agentConfigResolver.test.ts +2 -0
  58. package/client/agentRun.test.ts +12 -208
  59. package/client/agentRun.ts +853 -57
  60. package/client/localRuntimeAdapter.test.ts +9 -168
  61. package/client/localRuntimeAdapter.ts +22 -159
  62. package/client/localToolPolicy.test.ts +4 -28
  63. package/client/streamingOutput.ts +3 -1
  64. package/client/taskRunPrompt.ts +24 -7
  65. package/commandRegistry.ts +2 -3
  66. package/connectorRunArtifact.ts +10 -34
  67. package/connectorWebSocketTarget.ts +6 -10
  68. package/database/server/db.ts +34 -15
  69. package/internalCommandEntries.ts +0 -8
  70. package/localRuntimeDb.ts +2 -39
  71. package/machineCommands.ts +189 -190
  72. package/machineDaemonCommands.ts +165 -9
  73. package/machineHeartbeatCommands.ts +2 -1
  74. package/machineStatusCommands.ts +13 -5
  75. package/machineWatchCommands.ts +1 -1
  76. package/machineWsRunDispatch.ts +14 -48
  77. package/machineWsSession.ts +0 -2
  78. package/offlineMarxistsAgentCommand.ts +314 -0
  79. package/package.json +49 -193
  80. package/runtimeDoctorCommands.ts +69 -18
  81. package/scriptCommandEntries.ts +45 -5
  82. package/tableCommands.ts +133 -33
  83. package/taskRunCommand.ts +211 -16
  84. package/tui/session.ts +372 -43
  85. package/workflowInternalCommandEntries.ts +0 -20
  86. package/agent-runtime/dialogStatus.ts +0 -139
  87. package/agent-runtime/hostRuntimeConfig.ts +0 -86
  88. package/agentCreateCustomCommands.ts +0 -278
  89. package/agentDialogsCommands.ts +0 -227
  90. package/agentDoctorCommands.ts +0 -203
  91. package/agentRunLocalWorkspace.ts +0 -182
  92. package/agentRunParsing.ts +0 -298
  93. package/agentSuperviseCommands.ts +0 -8
  94. package/agentUnpublishCommands.ts +0 -113
  95. package/ai/agent/agentRunDialogLineage.ts +0 -56
  96. package/ai/policy/types.ts +0 -64
  97. package/ai/skills/skillSummaryMarker.ts +0 -26
  98. package/app/types.ts +0 -358
  99. package/build.ts +0 -16
  100. package/buildPublish.ts +0 -138
  101. package/buildPublishArtifactAssembly.ts +0 -724
  102. package/buildPublishImportAnalysis.ts +0 -242
  103. package/chat/messages/fetchMessages.ts +0 -84
  104. package/chat/messages/types.ts +0 -185
  105. package/cli/agentCreateCustomCommands.ts +0 -278
  106. package/cli/agentDialogsCommands.ts +0 -227
  107. package/cli/agentDoctorCommands.ts +0 -203
  108. package/cli/agentRunLocalWorkspace.ts +0 -182
  109. package/cli/agentRunParsing.ts +0 -298
  110. package/cli/agentSuperviseCommands.ts +0 -8
  111. package/cli/agentUnpublishCommands.ts +0 -113
  112. package/cli/buildPublish.ts +0 -138
  113. package/cli/buildPublishArtifactAssembly.ts +0 -724
  114. package/cli/buildPublishImportAnalysis.ts +0 -242
  115. package/cli/cliIoTypes.ts +0 -3
  116. package/cli/cliRuntimeDoctorReport.ts +0 -193
  117. package/cli/client/agentRunInput.ts +0 -10
  118. package/cli/client/agentRunLocalExecution.ts +0 -124
  119. package/cli/client/agentRunLocalExecutor.ts +0 -179
  120. package/cli/client/agentRunRuntimeSelection.ts +0 -145
  121. package/cli/client/agentRunServerTransport.ts +0 -397
  122. package/cli/client/agentRunTaskRunRecorder.ts +0 -176
  123. package/cli/customCodingAgentFlow.ts +0 -208
  124. package/cli/customCodingAgentRecord.ts +0 -179
  125. package/cli/dialogDataAccess.ts +0 -186
  126. package/cli/dialogInternalCommandEntries.ts +0 -11
  127. package/cli/dialogReadCommands.ts +0 -180
  128. package/cli/dialogReadHelpers.ts +0 -226
  129. package/cli/dialogStatusCommands.ts +0 -123
  130. package/cli/docInternalCommandEntries.ts +0 -20
  131. package/cli/hybridReadHelpers.ts +0 -109
  132. package/cli/machineCommandPrompts.ts +0 -79
  133. package/cli/machineCommandResolution.ts +0 -43
  134. package/cli/noloReadBridgePrompt.ts +0 -16
  135. package/cli/pageCreateCommands.ts +0 -219
  136. package/cli/pageDeleteCommands.ts +0 -167
  137. package/cli/pageReadCommands.ts +0 -151
  138. package/cli/pageUpdateCommands.ts +0 -249
  139. package/cli/pageWriteHelpers.ts +0 -209
  140. package/cli/publishPackage.ts +0 -36
  141. package/cli/runtimeInternalCommandEntries.ts +0 -15
  142. package/cli/runtimePassthroughCommands.ts +0 -22
  143. package/cli/scriptPassthroughHelpers.ts +0 -28
  144. package/cli/secretScanHelpers.ts +0 -31
  145. package/cli/spaceAttachCommands.ts +0 -134
  146. package/cli/spaceCategoryCommands.ts +0 -263
  147. package/cli/spaceCommands.ts +0 -295
  148. package/cli/spaceDeleteCommands.ts +0 -312
  149. package/cli/spaceInternalCommandEntries.ts +0 -21
  150. package/cli/spaceMutationHelpers.ts +0 -135
  151. package/cli/spaceReadCommands.ts +0 -323
  152. package/cli/tableDataOutput.ts +0 -41
  153. package/cli/tableDataSafety.ts +0 -26
  154. package/cli/tableMetaCommands.ts +0 -307
  155. package/cli/tableMutationCommands.ts +0 -266
  156. package/cli/tableQueryParsing.ts +0 -90
  157. package/cli/tableQueryRequest.ts +0 -53
  158. package/cli/taskRunActions.ts +0 -122
  159. package/cli/taskRunParsing.ts +0 -86
  160. package/cli/taskRunPromptShared.ts +0 -55
  161. package/cli/tui/tuiCatalog.ts +0 -22
  162. package/cli/tui/tuiCommandInterpreter.ts +0 -253
  163. package/cli/tui/tuiPresentation.ts +0 -146
  164. package/cliIoTypes.ts +0 -3
  165. package/cliRuntimeDoctorReport.ts +0 -193
  166. package/client/agentRunInput.ts +0 -10
  167. package/client/agentRunLocalExecution.test.ts +0 -123
  168. package/client/agentRunLocalExecution.ts +0 -124
  169. package/client/agentRunLocalExecutor.ts +0 -179
  170. package/client/agentRunRuntimeSelection.test.ts +0 -159
  171. package/client/agentRunRuntimeSelection.ts +0 -145
  172. package/client/agentRunServerTransport.ts +0 -397
  173. package/client/agentRunTaskRunRecorder.ts +0 -176
  174. package/connector-experimental/daemonLauncher.ts +0 -223
  175. package/create/space/spaceKeys.ts +0 -65
  176. package/create/types.ts +0 -21
  177. package/customCodingAgentFlow.ts +0 -208
  178. package/customCodingAgentRecord.ts +0 -179
  179. package/database/keys.ts +0 -765
  180. package/database/server/authorityStoreTypes.ts +0 -31
  181. package/database/server/legacyServerDb.ts +0 -58
  182. package/database/server/levelAuthorityStore.ts +0 -75
  183. package/database/server/memoryAuthorityStore.ts +0 -133
  184. package/database/server/serverStoreFactory.ts +0 -124
  185. package/database/tombstones.ts +0 -52
  186. package/database/utils/ulid.ts +0 -1
  187. package/dialogDataAccess.ts +0 -186
  188. package/dialogInternalCommandEntries.ts +0 -11
  189. package/dialogReadCommands.ts +0 -180
  190. package/dialogReadHelpers.ts +0 -226
  191. package/dialogStatusCommands.ts +0 -123
  192. package/docInternalCommandEntries.ts +0 -20
  193. package/hybridReadHelpers.ts +0 -109
  194. package/machineCommandPrompts.ts +0 -79
  195. package/machineCommandResolution.ts +0 -43
  196. package/noloReadBridgePrompt.ts +0 -16
  197. package/pageCreateCommands.ts +0 -219
  198. package/pageDeleteCommands.ts +0 -167
  199. package/pageReadCommands.ts +0 -151
  200. package/pageUpdateCommands.ts +0 -249
  201. package/pageWriteHelpers.ts +0 -209
  202. package/publishPackage.ts +0 -36
  203. package/runtimeInternalCommandEntries.ts +0 -15
  204. package/runtimePassthroughCommands.ts +0 -22
  205. package/scriptPassthroughHelpers.ts +0 -28
  206. package/secretScanHelpers.ts +0 -31
  207. package/share/helpers.ts +0 -302
  208. package/share/keys.ts +0 -243
  209. package/share/types.ts +0 -100
  210. package/spaceAttachCommands.ts +0 -134
  211. package/spaceCategoryCommands.ts +0 -263
  212. package/spaceCommands.ts +0 -295
  213. package/spaceDeleteCommands.ts +0 -312
  214. package/spaceInternalCommandEntries.ts +0 -21
  215. package/spaceMutationHelpers.ts +0 -135
  216. package/spaceReadCommands.ts +0 -323
  217. package/tableDataOutput.ts +0 -41
  218. package/tableDataSafety.ts +0 -26
  219. package/tableMetaCommands.ts +0 -307
  220. package/tableMutationCommands.ts +0 -266
  221. package/tableQueryParsing.ts +0 -90
  222. package/tableQueryRequest.ts +0 -53
  223. package/taskRunActions.ts +0 -122
  224. package/taskRunParsing.ts +0 -86
  225. package/taskRunPromptShared.ts +0 -55
  226. package/tui/tuiCatalog.ts +0 -22
  227. package/tui/tuiCommandInterpreter.test.ts +0 -169
  228. package/tui/tuiCommandInterpreter.ts +0 -253
  229. package/tui/tuiPresentation.test.ts +0 -154
  230. package/tui/tuiPresentation.ts +0 -146
@@ -3,7 +3,6 @@ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
 
6
- import { createHostRuntimeConfig } from "../agent-runtime";
7
6
  import { runLocalAgentTurn } from "../agent-runtime/localLoop";
8
7
  import { createCliLocalRuntimeAdapter } from "./localRuntimeAdapter";
9
8
 
@@ -23,9 +22,7 @@ describe("CLI local runtime adapter", () => {
23
22
  "searchFiles",
24
23
  ];
25
24
  const SHELL_LOCAL_CODING_TOOL_NAMES = [
26
- "readFile",
27
- "writeFile",
28
- "editFile",
25
+ ...DEFAULT_LOCAL_CODING_TOOL_NAMES,
29
26
  "execShell",
30
27
  ];
31
28
 
@@ -33,14 +30,6 @@ describe("CLI local runtime adapter", () => {
33
30
  return request?.body?.tools?.map((tool: any) => tool.function.name) ?? [];
34
31
  }
35
32
 
36
- function createCliHostRuntimeConfig(allowShell = false, workspaceBinding: "explicit-cwd" | "default-cwd" = "explicit-cwd") {
37
- return createHostRuntimeConfig({
38
- surface: "cli-local",
39
- workspaceBinding,
40
- allowShell,
41
- });
42
- }
43
-
44
33
  test("loads agent/history from LevelDB and saves dialog/message records back to LevelDB", async () => {
45
34
  const requests: Array<{ url: string; body: any; auth: string | null }> = [];
46
35
  const store = new Map<string, any>([
@@ -289,57 +278,6 @@ describe("CLI local runtime adapter", () => {
289
278
  });
290
279
  });
291
280
 
292
- test("runs apiSource=cli agents through the local CLI executor even when direct provider env is present", async () => {
293
- const executions: Array<{ provider: string; prompt: string; options: any }> = [];
294
- const adapter = createCliLocalRuntimeAdapter({
295
- env: {
296
- OPENAI_API_KEY: "sk-local",
297
- NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
298
- },
299
- cwd: import.meta.dir,
300
- db: {
301
- get: async () => ({
302
- dbKey: "agent-local-frontend",
303
- id: "frontend",
304
- apiSource: "cli",
305
- cliProvider: "agy",
306
- prompt: "Fix UI",
307
- model: "",
308
- }),
309
- put: async () => {},
310
- batch: async () => {},
311
- iterator: () => (async function* () {})(),
312
- },
313
- fetchImpl: async () => {
314
- throw new Error("OpenAI-compatible fetch should not run for local CLI agents");
315
- },
316
- executeCli: async (provider, prompt, options) => {
317
- executions.push({ provider, prompt, options });
318
- return { text: "cli local ok", raw: "cli local ok", elapsed: 10 };
319
- },
320
- });
321
-
322
- const result = await runLocalAgentTurn({
323
- adapter,
324
- agentRef: "frontend",
325
- input: "make it cleaner",
326
- });
327
-
328
- expect(result).toMatchObject({
329
- content: "cli local ok",
330
- model: "agy",
331
- });
332
- expect(executions).toEqual([{
333
- provider: "agy",
334
- prompt: "make it cleaner",
335
- options: expect.objectContaining({
336
- cwd: import.meta.dir,
337
- yolo: true,
338
- systemPrompt: "Fix UI",
339
- }),
340
- }]);
341
- });
342
-
343
281
  test("uses agent customProviderUrl for local OpenAI-compatible requests", async () => {
344
282
  const requests: Array<{ url: string; auth: string | null; body: any }> = [];
345
283
  const store = new Map<string, any>([
@@ -746,10 +684,6 @@ describe("CLI local runtime adapter", () => {
746
684
  id: "shell",
747
685
  prompt: "Use shell.",
748
686
  model: "gpt-4.1-mini",
749
- runtimeToolPolicy: {
750
- version: 1,
751
- runtimeTools: ["execShell"],
752
- },
753
687
  }],
754
688
  ]);
755
689
  const adapter = createCliLocalRuntimeAdapter({
@@ -1054,28 +988,17 @@ describe("CLI local runtime adapter", () => {
1054
988
  });
1055
989
  });
1056
990
 
1057
- test("rejects execShell when the host disables shell even if the agent requested it", async () => {
991
+ test("rejects tools unless the local tool policy allows and registers them", async () => {
1058
992
  const adapter = createCliLocalRuntimeAdapter({
1059
- env: { NOLO_LOCAL_USER_ID: "user-1" },
1060
- hostRuntimeConfig: createCliHostRuntimeConfig(),
1061
- db: {
1062
- get: async () => ({
1063
- dbKey: "agent-user-1-shell",
1064
- toolNames: ["execShell"],
1065
- }),
1066
- put: async () => {},
1067
- batch: async () => {},
1068
- iterator: () => (async function* () {})(),
1069
- },
993
+ env: {},
1070
994
  fetchImpl: async () => Response.json({}),
1071
995
  });
1072
996
 
1073
- await adapter.loadAgentConfig("shell");
1074
997
  await expect(adapter.executeTool({
1075
998
  id: "call-1",
1076
999
  name: "execShell",
1077
1000
  arguments: "{}",
1078
- })).rejects.toThrow("execShell is not requested by this agent runtime.");
1001
+ })).rejects.toThrow("execShell requires NOLO_LOCAL_SHELL_MODE");
1079
1002
  });
1080
1003
 
1081
1004
  test("executes explicitly allowed registered local tools declared by the agent", async () => {
@@ -1117,22 +1040,19 @@ describe("CLI local runtime adapter", () => {
1117
1040
  expect(result.content).toContain("README.md");
1118
1041
  });
1119
1042
 
1120
- test("defaults the CLI local host runtime to shell-on when runtimeToolPolicy requests execShell", async () => {
1043
+ test("advertises execShell to OpenAI-compatible providers when shell mode is enabled", async () => {
1121
1044
  const requests: Array<{ body: any }> = [];
1122
1045
  const adapter = createCliLocalRuntimeAdapter({
1123
1046
  env: {
1124
1047
  OPENAI_API_KEY: "sk-local",
1125
1048
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1049
+ NOLO_LOCAL_SHELL_MODE: "worktree",
1126
1050
  },
1127
1051
  db: {
1128
1052
  get: async () => ({
1129
1053
  dbKey: "agent-local-shell",
1130
1054
  prompt: "Use shell.",
1131
1055
  model: "gpt-4.1-mini",
1132
- runtimeToolPolicy: {
1133
- version: 1,
1134
- runtimeTools: ["execShell"],
1135
- },
1136
1056
  }),
1137
1057
  put: async () => {},
1138
1058
  batch: async () => {},
@@ -1155,81 +1075,6 @@ describe("CLI local runtime adapter", () => {
1155
1075
  expect(toolNamesFromRequest(requests[0])).toEqual(SHELL_LOCAL_CODING_TOOL_NAMES);
1156
1076
  });
1157
1077
 
1158
- test("keeps advertised fallback workspace tools executable when shell is explicitly disabled", async () => {
1159
- const workspaceRoot = mkdtempSync(join(tmpdir(), "nolo-cli-runtime-shell-off-"));
1160
- try {
1161
- const adapter = createCliLocalRuntimeAdapter({
1162
- env: {},
1163
- hostRuntimeConfig: createCliHostRuntimeConfig(false),
1164
- db: {
1165
- get: async () => ({
1166
- dbKey: "agent-local-shell-off",
1167
- runtimeToolPolicy: {
1168
- version: 1,
1169
- runtimeTools: ["execShell"],
1170
- },
1171
- }),
1172
- put: async () => {},
1173
- batch: async () => {},
1174
- iterator: () => (async function* () {})(),
1175
- },
1176
- cwd: workspaceRoot,
1177
- fetchImpl: async () => Response.json({}),
1178
- });
1179
-
1180
- await adapter.loadAgentConfig("shell-off");
1181
- const result = await adapter.executeTool({
1182
- id: "call-list-files",
1183
- name: "listFiles",
1184
- arguments: JSON.stringify({ path: "." }),
1185
- });
1186
-
1187
- expect(result.metadata).toMatchObject({ path: ".", count: 0 });
1188
- expect(result.content).toBe("");
1189
- } finally {
1190
- rmSync(workspaceRoot, { recursive: true, force: true });
1191
- }
1192
- });
1193
-
1194
- test("does not advertise execShell when only a legacy runtimeToolPolicy.shell block is present", async () => {
1195
- const requests: Array<{ body: any }> = [];
1196
- const adapter = createCliLocalRuntimeAdapter({
1197
- env: {
1198
- OPENAI_API_KEY: "sk-local",
1199
- NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1200
- },
1201
- hostRuntimeConfig: createCliHostRuntimeConfig(true),
1202
- db: {
1203
- get: async () => ({
1204
- dbKey: "agent-local-legacy-shell",
1205
- prompt: "Do not get shell from legacy policy.",
1206
- model: "gpt-4.1-mini",
1207
- runtimeToolPolicy: {
1208
- version: 1,
1209
- shell: { enabled: true, mode: "worktree" },
1210
- },
1211
- }),
1212
- put: async () => {},
1213
- batch: async () => {},
1214
- iterator: () => (async function* () {})(),
1215
- },
1216
- fetchImpl: async (_url, init) => {
1217
- requests.push({ body: JSON.parse(String(init?.body)) });
1218
- return Response.json({
1219
- choices: [{ message: { content: "done" } }],
1220
- });
1221
- },
1222
- });
1223
-
1224
- await runLocalAgentTurn({
1225
- adapter,
1226
- agentRef: "legacy-shell",
1227
- input: "pwd",
1228
- });
1229
-
1230
- expect(toolNamesFromRequest(requests[0])).not.toContain("execShell");
1231
- });
1232
-
1233
1078
  test("allows default semantic workspace tools without legacy agent tool declarations", async () => {
1234
1079
  const workspaceRoot = mkdtempSync(join(tmpdir(), "nolo-cli-runtime-"));
1235
1080
  try {
@@ -1391,17 +1236,13 @@ describe("CLI local runtime adapter", () => {
1391
1236
  }
1392
1237
  });
1393
1238
 
1394
- test("runs execShell locally when the host grants shell capability", async () => {
1239
+ test("runs execShell locally in explicit worktree shell mode", async () => {
1395
1240
  const adapter = createCliLocalRuntimeAdapter({
1396
- env: {},
1397
- hostRuntimeConfig: createCliHostRuntimeConfig(true),
1241
+ env: { NOLO_LOCAL_SHELL_MODE: "worktree" },
1398
1242
  db: {
1399
1243
  get: async () => ({
1400
1244
  dbKey: "agent-local-shell",
1401
- runtimeToolPolicy: {
1402
- version: 1,
1403
- runtimeTools: ["execShell"],
1404
- },
1245
+ toolNames: ["execShell"],
1405
1246
  }),
1406
1247
  put: async () => {},
1407
1248
  batch: async () => {},
@@ -7,7 +7,6 @@ import { request as httpRequest } from "node:http";
7
7
  import { request as httpsRequest } from "node:https";
8
8
  import {
9
9
  buildLocalWorkspacePolicyToolNames,
10
- resolveLocalWorkspaceShellToolExposure,
11
10
  buildLocalWorkspaceToolset,
12
11
  buildLocalWorkspaceOpenAiTools,
13
12
  buildOpenAiCompatibleChatCompletionRequest,
@@ -16,11 +15,8 @@ import {
16
15
  parseOpenAiCompatibleChatCompletionResponse,
17
16
  parsePlatformChatCompletionData,
18
17
  parsePlatformChatCompletionResponse,
19
- resolveHostRuntimeConfigFromEnv,
20
18
  resolvePlatformChatProviderConfig,
21
- resolveRequestedRuntimeToolNames,
22
19
  shouldUsePlatformChatProvider,
23
- type HostRuntimeConfig,
24
20
  } from "../agentRuntimeLocal";
25
21
  import type { AgentRuntimeChatMessage } from "../agent-runtime";
26
22
  import { getDefaultCliLocalRuntimeDb } from "../localRuntimeDb";
@@ -52,29 +48,6 @@ import {
52
48
  type EnvLike = Record<string, string | undefined>;
53
49
  type FetchInput = Parameters<typeof fetch>[0];
54
50
  type FetchInit = Parameters<typeof fetch>[1];
55
- type CliLocalRuntimeCliExecution = {
56
- text: string;
57
- raw?: string;
58
- elapsed?: number;
59
- warnings?: string[];
60
- };
61
- type CliLocalRuntimeCliExecutor = (
62
- provider: string,
63
- prompt: string,
64
- options: {
65
- model?: string;
66
- timeout?: number;
67
- cwd?: string;
68
- yolo?: boolean;
69
- env?: EnvLike;
70
- systemPrompt?: string;
71
- reasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max";
72
- temperature?: number;
73
- topP?: number;
74
- frequencyPenalty?: number;
75
- maxTokens?: number;
76
- }
77
- ) => Promise<CliLocalRuntimeCliExecution>;
78
51
  const TRANSIENT_FETCH_MAX_ATTEMPTS = 8;
79
52
  const TRANSIENT_FETCH_RETRY_BASE_DELAY_MS = 250;
80
53
 
@@ -82,17 +55,16 @@ export type CliLocalRuntimeDb = CliKvDb;
82
55
 
83
56
  export type CliLocalRuntimeAdapterDeps = {
84
57
  env: EnvLike;
85
- hostRuntimeConfig?: HostRuntimeConfig;
86
58
  db?: CliLocalRuntimeDb;
87
59
  store?: HybridRecordStore;
88
60
  now?: () => number;
89
61
  createId?: () => string;
90
62
  fetchImpl?: typeof fetch;
91
63
  cwd?: string;
64
+ useCwdAsTaskWorkspaceBase?: boolean;
92
65
  output?: { write(chunk: string): unknown };
93
66
  prepareTaskWorktree?: typeof prepareTaskWorktree;
94
67
  localToolExecutors?: Record<string, (call: any) => Promise<{ content: string; metadata?: Record<string, unknown> }>>;
95
- executeCli?: CliLocalRuntimeCliExecutor;
96
68
  sleep?: (ms: number) => Promise<void>;
97
69
  loopbackRequest?: (input: FetchInput, init?: FetchInit) => Promise<Response>;
98
70
  };
@@ -101,15 +73,6 @@ async function defaultLocalRuntimeDb(): Promise<CliLocalRuntimeDb> {
101
73
  return getDefaultCliLocalRuntimeDb();
102
74
  }
103
75
 
104
- async function defaultExecuteCli(
105
- provider: string,
106
- prompt: string,
107
- options: Parameters<CliLocalRuntimeCliExecutor>[2]
108
- ) {
109
- const { executeCli } = await import("../ai/agent/cliExecutor");
110
- return executeCli(provider as any, prompt, options);
111
- }
112
-
113
76
  function createFallbackId() {
114
77
  return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`.toUpperCase();
115
78
  }
@@ -118,6 +81,10 @@ function resolveLocalUserId(env: EnvLike) {
118
81
  return env.NOLO_LOCAL_USER_ID || env.NOLO_USER_ID || "local";
119
82
  }
120
83
 
84
+ function shellModeEnabled(env: EnvLike) {
85
+ return ["worktree", "dangerous", "1", "true"].includes(env.NOLO_LOCAL_SHELL_MODE || "");
86
+ }
87
+
121
88
  function parseLocalToolBudgets(env: EnvLike) {
122
89
  const raw = env.NOLO_LOCAL_TOOL_BUDGETS?.trim();
123
90
  if (!raw) return {};
@@ -234,52 +201,32 @@ async function fetchWithTransientRetry(
234
201
  throw lastError;
235
202
  }
236
203
 
237
- function buildOpenAiTools(args: {
238
- requestedToolNames?: string[];
239
- platformToolNames?: string[];
240
- hostRuntimeConfig: HostRuntimeConfig;
241
- }) {
242
- const toolset = buildLocalWorkspaceToolsetForHost(args);
204
+ function buildOpenAiTools(args: { toolNames?: string[]; env: EnvLike }) {
205
+ const toolset = buildLocalWorkspaceToolsetForEnv(args);
243
206
  return [
244
207
  ...buildLocalWorkspaceOpenAiTools({
245
208
  toolNames: toolset.toolNames,
246
209
  exposeShellTools: toolset.exposeShellTools,
247
210
  }),
248
- ...buildServerPlatformOpenAiTools({ toolNames: args.platformToolNames }),
211
+ ...buildServerPlatformOpenAiTools({ toolNames: args.toolNames }),
249
212
  ];
250
213
  }
251
214
 
252
- function buildLocalWorkspaceToolsetForHost(args: {
253
- requestedToolNames?: string[];
254
- hostRuntimeConfig: HostRuntimeConfig;
255
- }) {
256
- const requestedToolNames = args.requestedToolNames ?? [];
257
- const exposeShellTools = resolveLocalWorkspaceShellToolExposure({
258
- declaredToolNames: requestedToolNames,
259
- hostRuntimeConfig: args.hostRuntimeConfig,
260
- });
215
+ function buildLocalWorkspaceToolsetForEnv(args: { toolNames?: string[]; env: EnvLike }) {
261
216
  const toolset = buildLocalWorkspaceToolset({
262
- declaredToolNames: requestedToolNames,
263
- exposeShellTools,
217
+ declaredToolNames: args.toolNames,
218
+ exposeShellTools: shellModeEnabled(args.env),
264
219
  });
265
220
  return toolset;
266
221
  }
267
222
 
268
- function buildLocalPolicyToolNames(args: {
269
- requestedToolNames?: string[];
270
- platformToolNames?: string[];
271
- hostRuntimeConfig: HostRuntimeConfig;
272
- }) {
273
- const exposeShellTools = resolveLocalWorkspaceShellToolExposure({
274
- declaredToolNames: args.requestedToolNames,
275
- hostRuntimeConfig: args.hostRuntimeConfig,
276
- });
223
+ function buildLocalPolicyToolNames(args: { toolNames?: string[]; env: EnvLike }) {
277
224
  return [
278
225
  ...buildLocalWorkspacePolicyToolNames({
279
- declaredToolNames: args.requestedToolNames,
280
- exposeShellTools,
226
+ declaredToolNames: args.toolNames,
227
+ exposeShellTools: shellModeEnabled(args.env),
281
228
  }),
282
- ...((args.platformToolNames ?? []).includes("taskRun") ? ["taskRun"] : []),
229
+ ...((args.toolNames ?? []).includes("taskRun") ? ["taskRun"] : []),
283
230
  ];
284
231
  }
285
232
 
@@ -365,33 +312,6 @@ function readLocalWorkspaceMode(agentConfig: AgentRuntimeAgentConfig | null) {
365
312
  return value === "task-worktree" ? "task-worktree" : "current";
366
313
  }
367
314
 
368
- function extractRuntimeMessageText(content: AgentRuntimeChatMessage["content"]) {
369
- if (typeof content === "string") return content;
370
- if (!Array.isArray(content)) return "";
371
- return content
372
- .filter((part): part is Extract<typeof part, { type: "text" }> => part?.type === "text")
373
- .map((part) => part.text ?? "")
374
- .join("");
375
- }
376
-
377
- function buildCliTaskPromptFromMessages(messages: AgentRuntimeChatMessage[]) {
378
- const history = messages
379
- .filter((message) => message.role === "user" || message.role === "assistant")
380
- .map((message) => {
381
- const text = extractRuntimeMessageText(message.content).trim();
382
- if (!text) return null;
383
- return `[${message.role === "user" ? "用户" : "助手"}]\n${text}`;
384
- })
385
- .filter((message): message is string => Boolean(message))
386
- .slice(-6);
387
-
388
- if (history.length === 0) return "";
389
- if (history.length === 1 && history[0]?.startsWith("[用户]\n")) {
390
- return history[0].slice("[用户]\n".length);
391
- }
392
- return `请基于以下最近对话继续完成当前任务。\n\n${history.join("\n\n")}`;
393
- }
394
-
395
315
  async function resolveStore(deps: CliLocalRuntimeAdapterDeps) {
396
316
  if (deps.store) return deps.store;
397
317
  return createCliHybridRecordStore({
@@ -462,18 +382,12 @@ export function createCliLocalRuntimeAdapter(
462
382
  const createId = deps.createId ?? createFallbackId;
463
383
  const fetchImpl = deps.fetchImpl ?? fetch;
464
384
  const loopbackRequest = deps.loopbackRequest ?? (deps.fetchImpl ? undefined : defaultLoopbackRequest);
465
- const executeCli = deps.executeCli ?? defaultExecuteCli;
466
385
  const userId = resolveLocalUserId(deps.env);
467
- const hostRuntimeConfig = deps.hostRuntimeConfig ?? resolveHostRuntimeConfigFromEnv({
468
- env: deps.env,
469
- surface: "cli-local",
470
- workspaceBinding: "explicit-cwd",
471
- });
472
386
  const localToolBudgets = parseLocalToolBudgets(deps.env);
473
387
  const localToolUsage = new Map<string, number>();
474
388
  let activeAgentToolNames: string[] = [];
475
389
  let workspaceSession: WorkspaceSession = createWorkspaceSession(
476
- hostRuntimeConfig.workspaceBinding === "default-cwd"
390
+ deps.useCwdAsTaskWorkspaceBase
477
391
  ? { defaultCwd: deps.cwd }
478
392
  : { cwd: deps.cwd }
479
393
  );
@@ -514,13 +428,9 @@ export function createCliLocalRuntimeAdapter(
514
428
  store: await resolveStore(deps),
515
429
  userId,
516
430
  });
517
- const requestedToolNames = agentConfig
518
- ? resolveRequestedRuntimeToolNames({ agentConfig })
519
- : [];
520
431
  activeAgentToolNames = buildLocalPolicyToolNames({
521
- requestedToolNames,
522
- platformToolNames: agentConfig?.toolNames,
523
- hostRuntimeConfig,
432
+ toolNames: agentConfig?.toolNames,
433
+ env: deps.env,
524
434
  });
525
435
  await activateAgentWorkspaceSession({ agentRef, agentConfig });
526
436
  return agentConfig;
@@ -538,48 +448,6 @@ export function createCliLocalRuntimeAdapter(
538
448
  cwd: workspaceSession.workspaceRoot,
539
449
  }),
540
450
  resolveProvider: async (agentConfig) => {
541
- if (agentConfig.apiSource === "cli") {
542
- const cliProvider = String(agentConfig.cliProvider || "copilot").trim() || "copilot";
543
- return {
544
- model: agentConfig.model || cliProvider,
545
- complete: async (messages) => {
546
- const [firstMessage, ...remainingMessages] = messages;
547
- const systemPrompt = firstMessage?.role === "system"
548
- ? extractRuntimeMessageText(firstMessage.content).trim()
549
- : "";
550
- const taskPrompt = buildCliTaskPromptFromMessages(
551
- firstMessage?.role === "system" ? remainingMessages : messages
552
- );
553
- const result = await executeCli(cliProvider, taskPrompt, {
554
- ...(agentConfig.model ? { model: agentConfig.model } : {}),
555
- cwd: workspaceSession.workspaceRoot,
556
- yolo: true,
557
- env: deps.env,
558
- ...(systemPrompt ? { systemPrompt } : {}),
559
- ...(typeof agentConfig.reasoning_effort === "string"
560
- ? { reasoningEffort: agentConfig.reasoning_effort as "low" | "medium" | "high" | "xhigh" | "max" }
561
- : {}),
562
- ...(typeof agentConfig.temperature === "number"
563
- ? { temperature: agentConfig.temperature }
564
- : {}),
565
- ...(typeof agentConfig.top_p === "number" ? { topP: agentConfig.top_p } : {}),
566
- ...(typeof agentConfig.frequency_penalty === "number"
567
- ? { frequencyPenalty: agentConfig.frequency_penalty }
568
- : {}),
569
- ...(typeof agentConfig.max_tokens === "number"
570
- ? { maxTokens: agentConfig.max_tokens }
571
- : {}),
572
- });
573
- return {
574
- content: result.text,
575
- model: agentConfig.model || cliProvider,
576
- provider: cliProvider,
577
- trace: messages,
578
- };
579
- },
580
- };
581
- }
582
-
583
451
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
584
452
  const providerConfig = resolvePlatformChatProviderConfig({
585
453
  agentConfig,
@@ -588,11 +456,9 @@ export function createCliLocalRuntimeAdapter(
588
456
  return {
589
457
  model: providerConfig.model,
590
458
  complete: async (messages) => {
591
- const requestedToolNames = resolveRequestedRuntimeToolNames({ agentConfig });
592
459
  const tools = buildOpenAiTools({
593
- requestedToolNames,
594
- platformToolNames: agentConfig.toolNames,
595
- hostRuntimeConfig,
460
+ toolNames: agentConfig.toolNames,
461
+ env: deps.env,
596
462
  });
597
463
  const request = buildPlatformChatCompletionRequest({
598
464
  providerConfig,
@@ -623,11 +489,9 @@ export function createCliLocalRuntimeAdapter(
623
489
  return {
624
490
  model: providerConfig.model,
625
491
  complete: async (messages) => {
626
- const requestedToolNames = resolveRequestedRuntimeToolNames({ agentConfig });
627
492
  const tools = buildOpenAiTools({
628
- requestedToolNames,
629
- platformToolNames: agentConfig.toolNames,
630
- hostRuntimeConfig,
493
+ toolNames: agentConfig.toolNames,
494
+ env: deps.env,
631
495
  });
632
496
  const request = buildOpenAiCompatibleChatCompletionRequest({
633
497
  providerConfig,
@@ -658,7 +522,6 @@ export function createCliLocalRuntimeAdapter(
658
522
  });
659
523
  const result = await executeLocalToolWithPolicy({
660
524
  env: deps.env,
661
- hostRuntimeConfig,
662
525
  agentToolNames: activeAgentToolNames,
663
526
  call,
664
527
  executors: localToolExecutors,
@@ -1,47 +1,24 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import { executeLocalToolWithPolicy, resolveLocalToolPolicy } from "./localToolPolicy";
4
- import { createHostRuntimeConfig } from "../agent-runtime";
5
-
6
- function createCliHostRuntimeConfig(allowShell = false) {
7
- return createHostRuntimeConfig({
8
- surface: "cli-local",
9
- workspaceBinding: "explicit-cwd",
10
- allowShell,
11
- });
12
- }
13
4
 
14
5
  describe("CLI local tool policy", () => {
15
- test("allows execShell when the host grants shell capability", () => {
6
+ test("allows execShell in explicit worktree shell mode", () => {
16
7
  expect(resolveLocalToolPolicy({
17
- env: {},
18
- hostRuntimeConfig: createCliHostRuntimeConfig(true),
19
- agentToolNames: ["execShell"],
8
+ env: { NOLO_LOCAL_SHELL_MODE: "worktree" },
9
+ agentToolNames: [],
20
10
  toolName: "execShell",
21
11
  })).toEqual({ allowed: true, toolName: "execShell" });
22
12
  });
23
13
 
24
- test("blocks execShell unless the host grants shell capability", () => {
14
+ test("blocks execShell unless explicit shell mode is enabled", () => {
25
15
  expect(resolveLocalToolPolicy({
26
16
  env: { NOLO_LOCAL_ALLOWED_TOOLS: "execShell" },
27
- hostRuntimeConfig: createCliHostRuntimeConfig(),
28
17
  agentToolNames: ["execShell"],
29
18
  toolName: "execShell",
30
19
  })).toMatchObject({ allowed: false });
31
20
  });
32
21
 
33
- test("blocks execShell when shell was not requested by the runtime", () => {
34
- expect(resolveLocalToolPolicy({
35
- env: {},
36
- hostRuntimeConfig: createCliHostRuntimeConfig(true),
37
- agentToolNames: [],
38
- toolName: "execShell",
39
- })).toMatchObject({
40
- allowed: false,
41
- reason: "execShell is not requested by this agent runtime.",
42
- });
43
- });
44
-
45
22
  test("requires both env allowlist and agent declaration", () => {
46
23
  expect(resolveLocalToolPolicy({
47
24
  env: { NOLO_LOCAL_ALLOWED_TOOLS: "readFile" },
@@ -59,7 +36,6 @@ describe("CLI local tool policy", () => {
59
36
  test("executes only registered tools after policy allows them", async () => {
60
37
  const result = await executeLocalToolWithPolicy({
61
38
  env: { NOLO_LOCAL_ALLOWED_TOOLS: "readFile" },
62
- hostRuntimeConfig: createCliHostRuntimeConfig(),
63
39
  agentToolNames: ["readFile"],
64
40
  call: { id: "call-1", name: "readFile", arguments: "{\"path\":\"README.md\"}" },
65
41
  executors: {
@@ -1,4 +1,6 @@
1
- import type { OutputLike } from "../cliIoTypes";
1
+ type OutputLike = {
2
+ write(chunk: string): unknown;
3
+ };
2
4
 
3
5
  export function splitStreamingText(content: string): string[] {
4
6
  const Segmenter = Intl.Segmenter;
@@ -1,10 +1,27 @@
1
- import {
2
- prependTaskRunPromptForRuntime,
3
- type TaskRunPromptContext,
4
- } from "../taskRunPromptShared";
5
-
6
- export type { TaskRunPromptContext };
1
+ export type TaskRunPromptContext = {
2
+ rowDbKey: string;
3
+ taskRunId?: string;
4
+ workItemId?: string;
5
+ artifactIds?: string[];
6
+ };
7
7
 
8
8
  export function prependTaskRunPrompt(message: string, context?: TaskRunPromptContext): string {
9
- return prependTaskRunPromptForRuntime(message, context, "cli");
9
+ if (!context?.rowDbKey) return message;
10
+ const artifactIds = context.artifactIds?.filter(Boolean) ?? [];
11
+ return [
12
+ "AI-native task-run context:",
13
+ "- This system is AI-native. The current task board is only the present observation and validation use case; different users, companies, and workflows may use different task owners later.",
14
+ "- Treat the task row meta as the durable execution context. Do not infer branch, runner, handoff, review, or blocker state from chat history alone.",
15
+ `- rowDbKey: ${context.rowDbKey}`,
16
+ ...(context.taskRunId ? [`- taskRunId: ${context.taskRunId}`] : []),
17
+ ...(context.workItemId ? [`- workItemId: ${context.workItemId}`] : []),
18
+ ...(artifactIds.length ? [`- artifactIds: ${artifactIds.join(",")}`] : []),
19
+ "- Handoff rule: start from the durable task context, then inspect existing refs such as workItems.dialogIds, workItems.outcome, review.dialogId, activityRefs, agentRuns.dialogId/resultSummary, and artifactRefs. Use dialog read/search for exact evidence.",
20
+ "- When you create, update, hand off, block, or review work, update the task context with `bun run task:run -- ...`.",
21
+ "- If this turn already includes a server TaskRun preflight snapshot, use that snapshot directly for read-only reporting or planning.",
22
+ "- Keep long reasoning and logs in the dialog; record only resumable references in task row meta.",
23
+ "",
24
+ "User task:",
25
+ message,
26
+ ].join("\n");
10
27
  }