nolo-cli 0.1.30 → 0.1.31

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 (308) hide show
  1. package/agent-runtime/agentRecordConfig.ts +0 -2
  2. package/agent-runtime/hostAdapter.ts +0 -1
  3. package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
  4. package/agent-runtime/hostRuntimeConfig.ts +86 -0
  5. package/agent-runtime/index.ts +13 -0
  6. package/agent-runtime/localToolPolicy.ts +13 -6
  7. package/agent-runtime/localWorkspaceTools.ts +333 -30
  8. package/agent-runtime/platformChatProvider.ts +4 -1
  9. package/agent-runtime/runtimeToolPolicy.ts +32 -47
  10. package/agent-runtime/shellCommandPolicy.ts +117 -0
  11. package/agent-runtime/toolGate.ts +38 -0
  12. package/agentRecordCommands.ts +1 -1
  13. package/agentRecordHelpers.ts +35 -20
  14. package/agentRunParsing.ts +18 -5
  15. package/agentRuntimeLocal.ts +10 -0
  16. package/ai/agent/agentRunDialogLineage.ts +56 -0
  17. package/ai/agent/agentSlice.ts +45 -10
  18. package/ai/agent/avatarUtils.ts +1 -1
  19. package/ai/agent/buildSystemPrompt.ts +1 -2
  20. package/ai/agent/cliExecutor.ts +330 -19
  21. package/ai/agent/createAgentSchema.ts +22 -0
  22. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  23. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  24. package/ai/agent/publicAgentCatalog.ts +359 -0
  25. package/ai/agent/publicAgentIdentity.ts +76 -0
  26. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  27. package/ai/agent/serverOrigin.ts +7 -0
  28. package/ai/agent/streamAgentChatTurn.ts +23 -21
  29. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  30. package/ai/agent/types.ts +2 -0
  31. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  32. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  33. package/ai/ai.locale.ts +8 -0
  34. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  35. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  36. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  37. package/ai/chat/updateTotalUsage.ts +7 -0
  38. package/ai/llm/deepinfra.ts +30 -15
  39. package/ai/llm/mistral.ts +3 -4
  40. package/ai/llm/providers.ts +2 -0
  41. package/ai/llm/types.ts +15 -0
  42. package/ai/memory/capture.ts +3 -3
  43. package/ai/memory/consolidate.ts +2 -2
  44. package/ai/memory/delete.ts +4 -3
  45. package/ai/memory/query.ts +3 -3
  46. package/ai/memory/remember.ts +2 -2
  47. package/ai/memory/store.ts +3 -3
  48. package/ai/memory/storeShared.ts +3 -2
  49. package/ai/policy/commercialMultiplier.ts +16 -0
  50. package/ai/token/billingAdminAuditEvent.ts +68 -0
  51. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  52. package/ai/token/billingAnomaly.ts +90 -0
  53. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  54. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  55. package/ai/token/billingAnomalyWriter.ts +41 -0
  56. package/ai/token/calculatePrice.ts +3 -2
  57. package/ai/token/deepinfraReconciliation.ts +153 -0
  58. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  59. package/ai/token/externalToolCost.ts +54 -41
  60. package/ai/token/missingUsageEstimate.ts +12 -3
  61. package/ai/token/normalizeUsage.ts +45 -5
  62. package/ai/token/openaiReconciliation.ts +188 -0
  63. package/ai/token/providerBillableEvent.ts +84 -0
  64. package/ai/token/providerBillableEventWriter.ts +36 -0
  65. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  66. package/ai/token/providerBillingDrilldown.ts +361 -0
  67. package/ai/token/providerBillingHealthReport.ts +366 -0
  68. package/ai/token/providerCall.ts +144 -0
  69. package/ai/token/providerCallSweeper.ts +168 -0
  70. package/ai/token/providerCallWriter.ts +33 -0
  71. package/ai/token/providerCredential.ts +89 -0
  72. package/ai/token/providerCredentialAnomaly.ts +154 -0
  73. package/ai/token/providerCredentialLifecycle.ts +59 -0
  74. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  75. package/ai/token/providerCredentialRegistry.ts +83 -0
  76. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  77. package/ai/token/providerCredentialRegistryList.ts +124 -0
  78. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  79. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  80. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  81. package/ai/token/providerCredentialRuntime.ts +56 -0
  82. package/ai/token/providerDispatchIntent.ts +67 -0
  83. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  84. package/ai/token/providerGateway.ts +260 -0
  85. package/ai/token/providerReconciliation.ts +148 -0
  86. package/ai/token/providerReconciliationLocal.ts +97 -0
  87. package/ai/token/providerReconciliationRunner.ts +165 -0
  88. package/ai/token/providerReconciliationWriter.ts +41 -0
  89. package/ai/token/ratingResult.ts +202 -0
  90. package/ai/token/ratingResultWriter.ts +33 -0
  91. package/ai/token/serverDialogProjection.ts +5 -3
  92. package/ai/token/serverTokenWriter.ts +11 -3
  93. package/ai/token/types.ts +10 -0
  94. package/ai/tools/agent/callAgentTool.ts +3 -4
  95. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  96. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  97. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  98. package/ai/tools/readXPostTool.ts +1 -5
  99. package/app/admin/adminPages.ts +9 -0
  100. package/app/i18n/i18n.config.ts +5 -0
  101. package/app/i18n/translations/pricing.locale.ts +397 -0
  102. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  103. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  104. package/app/utils/imageUtils.ts +64 -34
  105. package/auth/adminPermissions.ts +18 -0
  106. package/auth/authSlice.ts +26 -12
  107. package/auth/hooks/useFetchUsers.ts +3 -0
  108. package/auth/routes.ts +46 -0
  109. package/auth/server/accessActivity.ts +4 -3
  110. package/auth/server/adminPermissions.ts +43 -0
  111. package/auth/server/adminUsageReport.ts +375 -0
  112. package/auth/server/billingAnomalies.ts +235 -0
  113. package/auth/server/billingUsageReport.ts +41 -2
  114. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  115. package/auth/server/deduct.ts +14 -7
  116. package/auth/server/delete.ts +10 -2
  117. package/auth/server/disable.ts +4 -3
  118. package/auth/server/emailAutomation.ts +7 -5
  119. package/auth/server/emailDbConfig.ts +4 -2
  120. package/auth/server/emailDelivery.ts +24 -20
  121. package/auth/server/emailDeliveryGuards.ts +10 -7
  122. package/auth/server/emailPreferences.ts +6 -4
  123. package/auth/server/emailReport.ts +6 -4
  124. package/auth/server/emailRuntimeConfig.ts +3 -3
  125. package/auth/server/emailScenarioNotifications.ts +9 -8
  126. package/auth/server/enable.ts +4 -3
  127. package/auth/server/getRechargeHistory.ts +3 -2
  128. package/auth/server/getUser.ts +3 -2
  129. package/auth/server/gptProAccess.ts +44 -0
  130. package/auth/server/inviteReward.ts +10 -7
  131. package/auth/server/listusers.ts +6 -4
  132. package/auth/server/login.ts +2 -2
  133. package/auth/server/productEntitlements.ts +7 -4
  134. package/auth/server/productPurchase.ts +10 -2
  135. package/auth/server/providerBillingDrilldown.ts +47 -0
  136. package/auth/server/providerBillingHealth.ts +71 -0
  137. package/auth/server/providerCredentials.ts +136 -0
  138. package/auth/server/recharge.ts +14 -8
  139. package/auth/server/revokeSessions.ts +4 -3
  140. package/auth/server/route.ts +77 -0
  141. package/auth/server/sendEmail.ts +5 -4
  142. package/auth/server/signup.ts +10 -3
  143. package/auth/server/token.ts +53 -55
  144. package/auth/server/tokenUsageBilling.ts +18 -7
  145. package/auth/server/usageManagementAccess.ts +43 -0
  146. package/auth/server/usageReport.ts +59 -0
  147. package/auth/types.ts +12 -0
  148. package/auth/utils.ts +24 -22
  149. package/authCommands.ts +36 -2
  150. package/buildPublish.ts +3 -1
  151. package/buildPublishArtifactAssembly.ts +62 -1
  152. package/buildPublishImportAnalysis.ts +21 -16
  153. package/chat/dialog/dialogLaunchScope.ts +32 -0
  154. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  155. package/chat/dialog/useCreateDialog.ts +1 -1
  156. package/chat/hooks/useChatInput.ts +41 -10
  157. package/chat/messages/messageSlice.ts +5 -1
  158. package/chat/messages/pendingAttachmentParts.ts +28 -2
  159. package/chat/messages/sendFirstMessage.ts +76 -79
  160. package/chat/messages/types.ts +9 -0
  161. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  162. package/chat/messages/web/useStreamingReveal.ts +91 -0
  163. package/chat/web/messageInputAgentUi.ts +94 -6
  164. package/cliEnvHelpers.ts +8 -0
  165. package/cliRuntimeDoctorReport.ts +193 -0
  166. package/client/agentConfigResolver.test.ts +0 -2
  167. package/client/agentRun.test.ts +171 -10
  168. package/client/agentRun.ts +44 -637
  169. package/client/agentRunInput.ts +10 -0
  170. package/client/agentRunLocalExecutor.ts +179 -0
  171. package/client/agentRunServerTransport.ts +394 -0
  172. package/client/agentRunTaskRunRecorder.ts +176 -0
  173. package/client/localRuntimeAdapter.test.ts +236 -9
  174. package/client/localRuntimeAdapter.ts +221 -23
  175. package/client/localToolPolicy.test.ts +28 -4
  176. package/connector-experimental/daemonLauncher.ts +38 -4
  177. package/connectorRunArtifact.ts +34 -10
  178. package/connectorWebSocketTarget.ts +9 -5
  179. package/core/builtinAgents.ts +155 -11
  180. package/create/space/contentLabels.ts +1 -1
  181. package/create/space/contentTypeMeta.ts +3 -2
  182. package/create/space/sidebarVisibleTypes.ts +27 -0
  183. package/create/space/space.locale.ts +76 -4
  184. package/database/actions/agentReadResolution.ts +2 -8
  185. package/database/actions/read.ts +11 -9
  186. package/database/actions/readAndWait.ts +10 -5
  187. package/database/server/agentDelegation.ts +3 -2
  188. package/database/server/authorityStoreConformance.ts +209 -0
  189. package/database/server/authorityStoreTypes.ts +31 -0
  190. package/database/server/coreDataProxy.ts +1 -1
  191. package/database/server/dataHandlers.ts +13 -5
  192. package/database/server/db.ts +15 -34
  193. package/database/server/delete.ts +88 -71
  194. package/database/server/emailRepository.ts +11 -9
  195. package/database/server/fileService.ts +2 -1
  196. package/database/server/legacyServerDb.ts +58 -0
  197. package/database/server/levelAuthorityStore.ts +75 -0
  198. package/database/server/memoryAuthorityStore.ts +133 -0
  199. package/database/server/patch.ts +13 -12
  200. package/database/server/query.ts +3 -2
  201. package/database/server/read.ts +33 -30
  202. package/database/server/resourceAccess.ts +7 -5
  203. package/database/server/serverStoreFactory.ts +124 -0
  204. package/database/server/spaceMemberAuthority.ts +3 -2
  205. package/database/server/storeBatchCompat.ts +37 -0
  206. package/database/server/testAuthorityStore.ts +76 -0
  207. package/database/server/write.ts +29 -27
  208. package/integrations/anthropic/anthropicModels.ts +12 -12
  209. package/integrations/deepseek/models.ts +67 -67
  210. package/integrations/google/models.ts +111 -53
  211. package/integrations/openai/models.ts +22 -22
  212. package/integrations/xai/models.ts +1 -1
  213. package/localRuntimeDb.ts +39 -2
  214. package/machineCommandPrompts.ts +2 -0
  215. package/machineCommands.ts +193 -63
  216. package/machineWsRunDispatch.ts +80 -15
  217. package/machineWsSession.ts +39 -2
  218. package/noloReadBridgePrompt.ts +16 -0
  219. package/package.json +99 -6
  220. package/render/layout/mainLayoutViewMode.ts +25 -0
  221. package/render/page/server/createPage.ts +3 -1
  222. package/render/page/server/handleCreatePage.ts +2 -11
  223. package/runtimeDoctorCommands.ts +15 -66
  224. package/server/api/methods.ts +34 -12
  225. package/server/api/tableHandlers.ts +6 -3
  226. package/server/authenticateToken.ts +47 -2
  227. package/server/billingLedgerRoutes.ts +15 -0
  228. package/server/buildManifest.ts +54 -0
  229. package/server/coreReadiness.ts +34 -25
  230. package/server/coreRuntime.ts +15 -10
  231. package/server/handlers/activityStatsHandler.ts +5 -2
  232. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  233. package/server/handlers/agentRun/agentLookup.ts +1 -7
  234. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  235. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  236. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  237. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  238. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  239. package/server/handlers/agentRun/index.ts +864 -404
  240. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  241. package/server/handlers/agentRun/loop.ts +920 -508
  242. package/server/handlers/agentRun/machineConnector.ts +56 -8
  243. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  244. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  245. package/server/handlers/agentRun/requestContext.ts +12 -8
  246. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  247. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  248. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  249. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  250. package/server/handlers/agentRun/saveDialog.ts +97 -87
  251. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  252. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  253. package/server/handlers/agentRun/types.ts +2 -1
  254. package/server/handlers/appDeployStatusStore.ts +17 -10
  255. package/server/handlers/appDomainHandler.ts +21 -15
  256. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  257. package/server/handlers/appSandboxHandler.ts +29 -8
  258. package/server/handlers/appSpaceAccess.ts +15 -8
  259. package/server/handlers/chatHandler.ts +22 -2
  260. package/server/handlers/chatUpstreamRetry.ts +225 -2
  261. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  262. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  263. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  264. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  265. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  266. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  267. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  268. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  269. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  270. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  271. package/server/handlers/favoriteHandlers.ts +8 -2
  272. package/server/handlers/getDialogBillingHandler.ts +4 -3
  273. package/server/handlers/getTransactionsHandler.ts +5 -2
  274. package/server/handlers/machines/machineBinding.ts +1 -0
  275. package/server/handlers/machines/machineHandlers.ts +0 -14
  276. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  277. package/server/handlers/notificationEmitter.ts +5 -3
  278. package/server/handlers/notificationsHandler.ts +5 -2
  279. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  280. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  281. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  282. package/server/handlers/tableAccess.ts +6 -2
  283. package/server/handlers/tableToolHandlers.ts +28 -14
  284. package/server/handlers/userSecretsHandler.ts +17 -6
  285. package/server/handlers/versionHandler.ts +9 -4
  286. package/server/handlers/versionStore.ts +18 -10
  287. package/server/html/ssrPreload.ts +5 -3
  288. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  289. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  290. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  291. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  292. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  293. package/server/runtimeRole.ts +15 -0
  294. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  295. package/server/scheduler/schedulerService.ts +2 -2
  296. package/server/taskRunBridgeRoutes.ts +8 -5
  297. package/share/server/fetchCommunityShares.ts +1 -1
  298. package/share/server/helpers.ts +19 -17
  299. package/share/server/importShare.ts +9 -13
  300. package/share/server/listCommunityShares.ts +4 -4
  301. package/share/server/purchaseDoc.ts +8 -16
  302. package/share/server/readCommunityShareCover.ts +3 -2
  303. package/share/server/readSharedTable.ts +14 -13
  304. package/share/server/tableReplication.ts +42 -39
  305. package/spaceAttachCommands.ts +135 -0
  306. package/spaceInternalCommandEntries.ts +2 -0
  307. package/ai/agent/runtimeServerBase.ts +0 -37
  308. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -0,0 +1,176 @@
1
+ import { join } from "node:path";
2
+
3
+ import type { EnvLike } from "../cliEnvHelpers";
4
+ import type { OutputLike } from "../cliIoTypes";
5
+ import {
6
+ classifyTaskRunReviewStatus,
7
+ type TaskRunToolEvidence,
8
+ } from "./agentRunLocalExecution";
9
+ import type { TaskRunPromptContext } from "./taskRunPrompt";
10
+
11
+ type TaskRunAgentRole = "pm" | "frontend" | "fullstack" | "reviewer" | "codex";
12
+ type TaskRunStatus = "running" | "completed" | "failed";
13
+
14
+ type TaskRunRecorderOptionShape = {
15
+ agentName: string;
16
+ agentKey: string;
17
+ serverUrl: string;
18
+ scriptDir: string;
19
+ env: EnvLike;
20
+ output: OutputLike;
21
+ taskRunContext?: TaskRunPromptContext;
22
+ taskRunRecorder?: unknown;
23
+ };
24
+
25
+ export type TaskRunRecorderArgs<
26
+ TOptions extends TaskRunRecorderOptionShape = TaskRunRecorderOptionShape,
27
+ > = {
28
+ options: TOptions;
29
+ status: TaskRunStatus;
30
+ dialogId?: string;
31
+ resultSummary?: string;
32
+ errorCode?: string;
33
+ toolEvidence?: TaskRunToolEvidence;
34
+ };
35
+
36
+ export type TaskRunRecorder<
37
+ TOptions extends TaskRunRecorderOptionShape = TaskRunRecorderOptionShape,
38
+ > = (args: TaskRunRecorderArgs<TOptions>) => Promise<void>;
39
+
40
+ export function inferTaskRunAgentRole(agentRef: string): TaskRunAgentRole {
41
+ const normalized = agentRef.toLowerCase();
42
+ if (normalized.includes("project-manager") || normalized.includes("manager")) return "pm";
43
+ if (normalized.includes("frontend")) return "frontend";
44
+ if (normalized.includes("fullstack")) return "fullstack";
45
+ if (normalized.includes("review")) return "reviewer";
46
+ return "codex";
47
+ }
48
+
49
+ export async function runTaskRunCli<TOptions extends TaskRunRecorderOptionShape>(args: {
50
+ options: TOptions;
51
+ cliArgs: string[];
52
+ }) {
53
+ const scriptPath = join(args.options.scriptDir, "taskRun.ts");
54
+ const proc = Bun.spawn({
55
+ cmd: [process.execPath, scriptPath, ...args.cliArgs],
56
+ stdout: "pipe",
57
+ stderr: "pipe",
58
+ env: {
59
+ ...process.env,
60
+ ...args.options.env,
61
+ BASE_URL: args.options.serverUrl,
62
+ },
63
+ });
64
+ const [stdout, stderr, exitCode] = await Promise.all([
65
+ new Response(proc.stdout).text(),
66
+ new Response(proc.stderr).text(),
67
+ proc.exited,
68
+ ]);
69
+ if (exitCode !== 0) {
70
+ throw new Error((stderr || stdout || `taskRun.ts exited ${exitCode}`).trim());
71
+ }
72
+ }
73
+
74
+ export async function defaultTaskRunRecorder<TOptions extends TaskRunRecorderOptionShape>(
75
+ args: TaskRunRecorderArgs<TOptions>
76
+ ) {
77
+ const context = args.options.taskRunContext;
78
+ if (!context?.rowDbKey) return;
79
+ const role = inferTaskRunAgentRole(args.options.agentName || args.options.agentKey);
80
+ if (role === "reviewer" && args.status !== "running") {
81
+ await runTaskRunCli({
82
+ options: args.options,
83
+ cliArgs: [
84
+ "request-review",
85
+ "--row-dbkey",
86
+ context.rowDbKey,
87
+ "--base-url",
88
+ args.options.serverUrl,
89
+ "--reviewer-agent-key",
90
+ args.options.agentKey,
91
+ ...(context.artifactIds?.length ? ["--artifact-ids", context.artifactIds.join(",")] : []),
92
+ ...(args.dialogId ? ["--dialog-id", args.dialogId] : []),
93
+ ],
94
+ });
95
+ }
96
+ await runTaskRunCli({
97
+ options: args.options,
98
+ cliArgs: [
99
+ "record-agent-run",
100
+ "--row-dbkey",
101
+ context.rowDbKey,
102
+ "--base-url",
103
+ args.options.serverUrl,
104
+ "--agent-key",
105
+ args.options.agentKey,
106
+ "--role",
107
+ role,
108
+ "--run-status",
109
+ args.status,
110
+ ...(context.workItemId ? ["--work-item-id", context.workItemId] : []),
111
+ ...(args.dialogId ? ["--dialog-id", args.dialogId] : []),
112
+ ...(args.resultSummary ? ["--result-summary", args.resultSummary.slice(0, 240)] : []),
113
+ ...(args.errorCode ? ["--error-code", args.errorCode] : []),
114
+ ...(args.toolEvidence?.toolsUsed?.length
115
+ ? ["--tools-used", args.toolEvidence.toolsUsed.join(",")]
116
+ : []),
117
+ ...(args.toolEvidence?.summary
118
+ ? ["--tool-trace-summary", JSON.stringify(args.toolEvidence.summary)]
119
+ : []),
120
+ ],
121
+ });
122
+ if (context.workItemId && args.dialogId) {
123
+ await runTaskRunCli({
124
+ options: args.options,
125
+ cliArgs: [
126
+ "update-work-item",
127
+ "--row-dbkey",
128
+ context.rowDbKey,
129
+ "--base-url",
130
+ args.options.serverUrl,
131
+ "--id",
132
+ context.workItemId,
133
+ "--dialog-ids",
134
+ args.dialogId,
135
+ ],
136
+ });
137
+ }
138
+ if (role === "reviewer" && args.status !== "running") {
139
+ const reviewStatus =
140
+ args.status === "failed" ? "blocked" : classifyTaskRunReviewStatus(args.resultSummary);
141
+ if (reviewStatus) {
142
+ await runTaskRunCli({
143
+ options: args.options,
144
+ cliArgs: [
145
+ "review-result",
146
+ "--row-dbkey",
147
+ context.rowDbKey,
148
+ "--base-url",
149
+ args.options.serverUrl,
150
+ "--review-status",
151
+ reviewStatus,
152
+ "--reviewer-agent-key",
153
+ args.options.agentKey,
154
+ ...(context.artifactIds?.length ? ["--artifact-ids", context.artifactIds.join(",")] : []),
155
+ ...(args.dialogId ? ["--dialog-id", args.dialogId] : []),
156
+ ],
157
+ });
158
+ }
159
+ }
160
+ }
161
+
162
+ export async function recordTaskRunOutcome<TOptions extends TaskRunRecorderOptionShape>(
163
+ args: TaskRunRecorderArgs<TOptions>
164
+ ) {
165
+ if (!args.options.taskRunContext?.rowDbKey) return;
166
+ try {
167
+ const recorder =
168
+ (args.options.taskRunRecorder as TaskRunRecorder<TOptions> | undefined) ??
169
+ ((nextArgs: TaskRunRecorderArgs<TOptions>) => defaultTaskRunRecorder(nextArgs));
170
+ await recorder(args);
171
+ } catch (error) {
172
+ args.options.output.write(
173
+ `[nolo] task-run writeback failed: ${error instanceof Error ? error.message : String(error)}\n`
174
+ );
175
+ }
176
+ }
@@ -3,6 +3,7 @@ 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";
6
7
  import { runLocalAgentTurn } from "../agent-runtime/localLoop";
7
8
  import { createCliLocalRuntimeAdapter } from "./localRuntimeAdapter";
8
9
 
@@ -22,7 +23,9 @@ describe("CLI local runtime adapter", () => {
22
23
  "searchFiles",
23
24
  ];
24
25
  const SHELL_LOCAL_CODING_TOOL_NAMES = [
25
- ...DEFAULT_LOCAL_CODING_TOOL_NAMES,
26
+ "readFile",
27
+ "writeFile",
28
+ "editFile",
26
29
  "execShell",
27
30
  ];
28
31
 
@@ -30,6 +33,14 @@ describe("CLI local runtime adapter", () => {
30
33
  return request?.body?.tools?.map((tool: any) => tool.function.name) ?? [];
31
34
  }
32
35
 
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
+
33
44
  test("loads agent/history from LevelDB and saves dialog/message records back to LevelDB", async () => {
34
45
  const requests: Array<{ url: string; body: any; auth: string | null }> = [];
35
46
  const store = new Map<string, any>([
@@ -278,6 +289,57 @@ describe("CLI local runtime adapter", () => {
278
289
  });
279
290
  });
280
291
 
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
+
281
343
  test("uses agent customProviderUrl for local OpenAI-compatible requests", async () => {
282
344
  const requests: Array<{ url: string; auth: string | null; body: any }> = [];
283
345
  const store = new Map<string, any>([
@@ -353,6 +415,74 @@ describe("CLI local runtime adapter", () => {
353
415
  expect(toolNamesFromRequest(requests[0])).toEqual(DEFAULT_LOCAL_CODING_TOOL_NAMES);
354
416
  });
355
417
 
418
+ test("uses loopback transport for localhost custom providers when the default fetch path cannot connect", async () => {
419
+ const store = new Map<string, any>([
420
+ ["agent-user-1-localhost", {
421
+ dbKey: "agent-user-1-localhost",
422
+ id: "localhost",
423
+ prompt: "Use localhost provider.",
424
+ model: "Qwen3.6-27B-MTP-Q3_K_M.gguf",
425
+ provider: "custom-openai-compatible",
426
+ apiSource: "custom",
427
+ customProviderUrl: "http://127.0.0.1:8080/v1/chat/completions",
428
+ }],
429
+ ]);
430
+ const loopbackRequests: Array<{ url: string; body: any }> = [];
431
+ const adapter = createCliLocalRuntimeAdapter({
432
+ env: {
433
+ NOLO_LOCAL_USER_ID: "user-1",
434
+ },
435
+ db: {
436
+ get: async (key) => {
437
+ if (!store.has(key)) throw new Error(`not found: ${key}`);
438
+ return store.get(key);
439
+ },
440
+ put: async (key, value) => {
441
+ store.set(key, value);
442
+ },
443
+ batch: async (ops) => {
444
+ for (const op of ops) {
445
+ if (op.type === "put") store.set(op.key, op.value);
446
+ }
447
+ },
448
+ iterator: () => (async function* () {})(),
449
+ },
450
+ fetchImpl: async () => {
451
+ throw new TypeError("Unable to connect. Is the computer able to access the url?");
452
+ },
453
+ loopbackRequest: async (url, init) => {
454
+ loopbackRequests.push({
455
+ url: String(url),
456
+ body: JSON.parse(String(init?.body)),
457
+ });
458
+ return Response.json({
459
+ choices: [{ message: { content: "loopback ok" } }],
460
+ });
461
+ },
462
+ });
463
+
464
+ const result = await runLocalAgentTurn({
465
+ adapter,
466
+ agentRef: "localhost",
467
+ input: "hello",
468
+ });
469
+
470
+ expect(result.content).toBe("loopback ok");
471
+ expect(loopbackRequests).toHaveLength(1);
472
+ expect(loopbackRequests[0]).toMatchObject({
473
+ url: "http://127.0.0.1:8080/v1/chat/completions",
474
+ body: {
475
+ model: "Qwen3.6-27B-MTP-Q3_K_M.gguf",
476
+ messages: [
477
+ { role: "system", content: "Use localhost provider." },
478
+ { role: "user", content: "hello" },
479
+ ],
480
+ stream: false,
481
+ },
482
+ });
483
+ expect(toolNamesFromRequest(loopbackRequests[0])).toEqual(DEFAULT_LOCAL_CODING_TOOL_NAMES);
484
+ });
485
+
356
486
  test("uses the Nolo chat proxy when local provider keys are absent", async () => {
357
487
  const requests: Array<{ url: string; auth: string | null; body: any }> = [];
358
488
  const store = new Map<string, any>([
@@ -616,6 +746,10 @@ describe("CLI local runtime adapter", () => {
616
746
  id: "shell",
617
747
  prompt: "Use shell.",
618
748
  model: "gpt-4.1-mini",
749
+ runtimeToolPolicy: {
750
+ version: 1,
751
+ runtimeTools: ["execShell"],
752
+ },
619
753
  }],
620
754
  ]);
621
755
  const adapter = createCliLocalRuntimeAdapter({
@@ -920,17 +1054,28 @@ describe("CLI local runtime adapter", () => {
920
1054
  });
921
1055
  });
922
1056
 
923
- test("rejects tools unless the local tool policy allows and registers them", async () => {
1057
+ test("rejects execShell when the host disables shell even if the agent requested it", async () => {
924
1058
  const adapter = createCliLocalRuntimeAdapter({
925
- env: {},
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
+ },
926
1070
  fetchImpl: async () => Response.json({}),
927
1071
  });
928
1072
 
1073
+ await adapter.loadAgentConfig("shell");
929
1074
  await expect(adapter.executeTool({
930
1075
  id: "call-1",
931
1076
  name: "execShell",
932
1077
  arguments: "{}",
933
- })).rejects.toThrow("execShell requires NOLO_LOCAL_SHELL_MODE");
1078
+ })).rejects.toThrow("execShell is not requested by this agent runtime.");
934
1079
  });
935
1080
 
936
1081
  test("executes explicitly allowed registered local tools declared by the agent", async () => {
@@ -972,19 +1117,22 @@ describe("CLI local runtime adapter", () => {
972
1117
  expect(result.content).toContain("README.md");
973
1118
  });
974
1119
 
975
- test("advertises execShell to OpenAI-compatible providers when shell mode is enabled", async () => {
1120
+ test("defaults the CLI local host runtime to shell-on when runtimeToolPolicy requests execShell", async () => {
976
1121
  const requests: Array<{ body: any }> = [];
977
1122
  const adapter = createCliLocalRuntimeAdapter({
978
1123
  env: {
979
1124
  OPENAI_API_KEY: "sk-local",
980
1125
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
981
- NOLO_LOCAL_SHELL_MODE: "worktree",
982
1126
  },
983
1127
  db: {
984
1128
  get: async () => ({
985
1129
  dbKey: "agent-local-shell",
986
1130
  prompt: "Use shell.",
987
1131
  model: "gpt-4.1-mini",
1132
+ runtimeToolPolicy: {
1133
+ version: 1,
1134
+ runtimeTools: ["execShell"],
1135
+ },
988
1136
  }),
989
1137
  put: async () => {},
990
1138
  batch: async () => {},
@@ -1007,6 +1155,81 @@ describe("CLI local runtime adapter", () => {
1007
1155
  expect(toolNamesFromRequest(requests[0])).toEqual(SHELL_LOCAL_CODING_TOOL_NAMES);
1008
1156
  });
1009
1157
 
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
+
1010
1233
  test("allows default semantic workspace tools without legacy agent tool declarations", async () => {
1011
1234
  const workspaceRoot = mkdtempSync(join(tmpdir(), "nolo-cli-runtime-"));
1012
1235
  try {
@@ -1168,13 +1391,17 @@ describe("CLI local runtime adapter", () => {
1168
1391
  }
1169
1392
  });
1170
1393
 
1171
- test("runs execShell locally in explicit worktree shell mode", async () => {
1394
+ test("runs execShell locally when the host grants shell capability", async () => {
1172
1395
  const adapter = createCliLocalRuntimeAdapter({
1173
- env: { NOLO_LOCAL_SHELL_MODE: "worktree" },
1396
+ env: {},
1397
+ hostRuntimeConfig: createCliHostRuntimeConfig(true),
1174
1398
  db: {
1175
1399
  get: async () => ({
1176
1400
  dbKey: "agent-local-shell",
1177
- toolNames: ["execShell"],
1401
+ runtimeToolPolicy: {
1402
+ version: 1,
1403
+ runtimeTools: ["execShell"],
1404
+ },
1178
1405
  }),
1179
1406
  put: async () => {},
1180
1407
  batch: async () => {},