nolo-cli 0.1.22 → 0.1.26

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 (128) hide show
  1. package/README.md +25 -3
  2. package/agent-runtime/agentRecordConfig.ts +4 -0
  3. package/agent-runtime/hostAdapter.ts +2 -0
  4. package/agent-runtime/hybridRecordStore.ts +30 -9
  5. package/agent-runtime/index.ts +7 -0
  6. package/agent-runtime/localLoop.ts +14 -4
  7. package/agent-runtime/localToolPolicy.ts +22 -10
  8. package/agent-runtime/localWorkspaceTools.ts +140 -374
  9. package/agent-runtime/platformChatProvider.ts +3 -0
  10. package/agent-runtime/runtimeToolPolicy.ts +133 -0
  11. package/agent-runtime/types.ts +47 -0
  12. package/agentAliases.ts +1 -1
  13. package/agentCommandSupport.ts +77 -0
  14. package/agentInternalCommandEntries.ts +34 -0
  15. package/agentListCommands.ts +123 -0
  16. package/agentListHelpers.ts +187 -0
  17. package/agentMachineCommands.ts +402 -0
  18. package/agentRecordCommands.ts +141 -0
  19. package/agentRecordHelpers.ts +395 -0
  20. package/agentRunCommand.ts +75 -3
  21. package/agentRuntimeCommands.ts +7 -773
  22. package/ai/agent/_executeModel.ts +29 -3
  23. package/ai/agent/buildSystemPrompt.ts +17 -0
  24. package/ai/agent/cliChatClient.ts +38 -4
  25. package/ai/agent/cliExecutor.ts +304 -25
  26. package/ai/agent/createAgentSchema.ts +2 -2
  27. package/ai/agent/guidedCreation/assistant.ts +82 -0
  28. package/ai/agent/guidedCreation/capabilities.ts +84 -0
  29. package/ai/agent/guidedCreation/draft.ts +62 -0
  30. package/ai/agent/guidedCreation/types.ts +38 -0
  31. package/ai/agent/machineRunPermissions.ts +21 -3
  32. package/ai/agent/runtimeGuidance.ts +1 -1
  33. package/ai/agent/server/fetchPublicAgents.ts +6 -1
  34. package/ai/agent/streamAgentChatTurn.ts +593 -36
  35. package/ai/agent/web/useGuidedAgentCreation.ts +217 -0
  36. package/ai/ai.locale.ts +14 -2
  37. package/ai/chat/fetchUtils.native.ts +2 -0
  38. package/ai/chat/fetchUtils.ts +2 -0
  39. package/ai/chat/sendOpenAICompletionsRequest.ts +82 -1
  40. package/ai/chat/sendOpenAIResponseRequest.ts +65 -0
  41. package/ai/llm/getPricing.ts +14 -0
  42. package/ai/llm/kimi.ts +4 -1
  43. package/ai/llm/modelAvatar.ts +1 -0
  44. package/ai/llm/providers.ts +4 -1
  45. package/ai/llm/reasoningModels.ts +1 -0
  46. package/ai/taskRun/taskRunProtocol.ts +25 -10
  47. package/ai/token/modelUsageQuery.ts +17 -0
  48. package/ai/tools/agent/agentTools.ts +38 -0
  49. package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
  50. package/ai/tools/agent/startAgentDialogTool.ts +53 -0
  51. package/ai/tools/checkEnvTool.ts +52 -20
  52. package/ai/tools/convertMarxistsBookTool.ts +103 -0
  53. package/ai/tools/{execBashTool.ts → execShellTool.ts} +44 -161
  54. package/ai/tools/index.ts +24 -14
  55. package/ai/tools/marxistsOfflineBook.ts +253 -0
  56. package/ai/tools/modelUsageTools.ts +9 -2
  57. package/ai/tools/readTool.ts +31 -0
  58. package/ai/tools/toolApiClient.ts +35 -1
  59. package/ai/tools/toolNameAliases.ts +13 -0
  60. package/cliCommandAdapters.ts +28 -0
  61. package/cliCommandDispatch.ts +66 -0
  62. package/cliCommandFactories.ts +34 -0
  63. package/cliCommandTypes.ts +49 -0
  64. package/cliEnvHelpers.ts +44 -0
  65. package/client/agentRun.test.ts +330 -24
  66. package/client/agentRun.ts +117 -35
  67. package/client/hybridRecordStore.test.ts +42 -0
  68. package/client/hybridRecordStore.ts +11 -0
  69. package/client/localRuntimeAdapter.test.ts +191 -21
  70. package/client/localRuntimeAdapter.ts +99 -10
  71. package/client/localRuntimeDryRun.test.ts +5 -2
  72. package/client/taskRunPrompt.ts +1 -0
  73. package/commandRegistry.ts +11 -61
  74. package/connector-experimental/capabilities.ts +1 -0
  75. package/database/actions/common.ts +4 -3
  76. package/database/config.ts +19 -0
  77. package/database/server/coreDataProxy.ts +43 -26
  78. package/index.ts +54 -191
  79. package/internalCommandEntries.ts +12 -0
  80. package/machineCommands.ts +688 -64
  81. package/offlineMarxistsAgentCommand.ts +314 -0
  82. package/package.json +22 -2
  83. package/render/canvas/canvasEditContext.ts +127 -0
  84. package/render/canvas/canvasRuntime.ts +57 -0
  85. package/render/canvas/canvasSnapshotParser.ts +76 -0
  86. package/render/canvas/canvasTree.ts +308 -0
  87. package/render/canvas/types.ts +46 -0
  88. package/render/layout/deleteBehavior.ts +52 -0
  89. package/render/layout/mainLayoutSidebar.ts +17 -0
  90. package/render/layout/mainLayoutViewMode.ts +56 -0
  91. package/render/layout/topbarUtils.ts +87 -0
  92. package/render/layout/useDevReloadPending.ts +30 -0
  93. package/render/page/createPageAction.ts +183 -0
  94. package/render/page/docSlice.ts +468 -0
  95. package/render/page/server/createPage.ts +174 -0
  96. package/render/page/server/handleCreatePage.ts +91 -0
  97. package/render/page/server/index.ts +4 -0
  98. package/render/page/types.ts +17 -0
  99. package/render/page/useKeyboardSave.ts +48 -0
  100. package/render/styles/zIndex.ts +12 -0
  101. package/render/surf/WeatherIconStyles.ts +17 -0
  102. package/render/surf/color.ts +9 -0
  103. package/render/surf/config.ts +46 -0
  104. package/render/surf/screens/style.ts +1 -0
  105. package/render/surf/styles/ToggleButtonStyles.ts +8 -0
  106. package/render/surf/utils/groupedWeatherData.ts +32 -0
  107. package/render/surf/weatherUtils.ts +50 -0
  108. package/render/table/activityColumns.ts +6 -0
  109. package/render/table/createTableAction.ts +270 -0
  110. package/render/table/deleteTableAction.ts +129 -0
  111. package/render/table/fetchAndCacheTableRows.ts +174 -0
  112. package/render/table/tableSlice.ts +1106 -0
  113. package/render/table/tableView.ts +289 -0
  114. package/render/table/toolValueUtils.ts +363 -0
  115. package/render/table/types.ts +252 -0
  116. package/render/table/useCreateTable.ts +72 -0
  117. package/render/table/useTable.ts +61 -0
  118. package/render/table/utils/tableSerialization.ts +50 -0
  119. package/render/web/elements/artifactPreviewCode.ts +43 -0
  120. package/render/web/elements/artifactRuntimePreload.ts +52 -0
  121. package/render/web/elements/codeBlockAutoPreview.ts +10 -0
  122. package/render/web/elements/mermaidPreview.ts +21 -0
  123. package/render/web/ui/useInlineEdit.ts +135 -0
  124. package/runtimeDoctorCommands.ts +118 -0
  125. package/scriptCommandEntries.ts +71 -0
  126. package/systemInternalCommandEntries.ts +71 -0
  127. package/tableCommands.ts +42 -5
  128. package/workflowInternalCommandEntries.ts +11 -0
@@ -14,6 +14,7 @@
14
14
 
15
15
  import type { RootState } from "app/store";
16
16
  import { selectCurrentServer } from "app/settings/settingSlice";
17
+ import { getIsDesktopApp } from "app/utils/env";
17
18
  import { selectCurrentToken } from "auth/authSlice";
18
19
  import { selectCurrentDialogKey } from "chat/dialog/dialogSlice";
19
20
  import { extractCustomId } from "core/prefix";
@@ -39,6 +40,34 @@ export const resolveToolBaseUrl = (currentServer?: string | null): string => {
39
40
  return currentServer.replace(/\/+$/, "");
40
41
  };
41
42
 
43
+ const DESKTOP_LOCAL_TOOL_PATHS = new Set([
44
+ "/api/exec-shell",
45
+ "/api/check-env",
46
+ "/api/read-file",
47
+ "/api/write-file",
48
+ "/api/apply-edit",
49
+ "/api/apply-line-edits",
50
+ "/api/code-search",
51
+ "/api/search-repo",
52
+ ]);
53
+
54
+ const getWindowOrigin = (): string | null => {
55
+ const _window = (globalThis as any).window;
56
+ const origin = _window?.location?.origin;
57
+ return typeof origin === "string" && origin ? origin.replace(/\/+$/, "") : null;
58
+ };
59
+
60
+ export const resolveToolApiBaseUrl = (
61
+ currentServer?: string | null,
62
+ path?: string
63
+ ): string => {
64
+ if (path && DESKTOP_LOCAL_TOOL_PATHS.has(path) && getIsDesktopApp()) {
65
+ const localOrigin = getWindowOrigin();
66
+ if (localOrigin) return localOrigin;
67
+ }
68
+ return resolveToolBaseUrl(currentServer);
69
+ };
70
+
42
71
  export const getRequestConfig = (thunkApi: any): RequestConfig => {
43
72
  const state = thunkApi.getState() as RootState;
44
73
  const currentServer = selectCurrentServer(state);
@@ -118,6 +147,9 @@ export const buildToolRequestHeaders = (
118
147
  if (agentKey && typeof agentKey === "string" && agentKey.trim()) {
119
148
  headers["X-Nolo-Agent-Key"] = agentKey.trim();
120
149
  }
150
+ if (typeof window !== "undefined" && (window as any).__NOLO_DESKTOP__) {
151
+ headers["X-Nolo-Desktop-Tool"] = "1";
152
+ }
121
153
  return headers;
122
154
  };
123
155
 
@@ -152,7 +184,9 @@ export async function callToolApi<T = any>(
152
184
  ): Promise<T> {
153
185
  const { currentServer } = getRequestConfig(thunkApi);
154
186
 
155
- const url = `${currentServer}${path}`;
187
+ const baseUrl = resolveToolApiBaseUrl(currentServer, path);
188
+ if (!baseUrl) throw new Error("无法获取工具服务器地址。");
189
+ const url = `${baseUrl}${path}`;
156
190
  const headers = buildToolRequestHeaders(thunkApi, options);
157
191
 
158
192
  const response = await fetch(url, {
@@ -15,6 +15,19 @@ const LEGACY_TOOL_NAME_ALIASES: Record<string, string> = {
15
15
  read_doc: "readDoc",
16
16
  createdoc: "createDoc",
17
17
  updateDocTool: "updateDoc",
18
+ readLocal: "readLocalFile",
19
+ read_local: "readLocalFile",
20
+ readLocalTool: "readLocalFile",
21
+ listLocal: "listLocalFiles",
22
+ list_local: "listLocalFiles",
23
+ terminalCommand: "execShell",
24
+ terminal_command: "execShell",
25
+ runCommand: "execShell",
26
+ run_command: "execShell",
27
+ runInBash: "execShell",
28
+ run_in_bash: "execShell",
29
+ executeCommand: "execShell",
30
+ execute_command: "execShell",
18
31
  };
19
32
 
20
33
  const normalizeToolName = (name: string): string =>
@@ -0,0 +1,28 @@
1
+ import type { CliCommandHandler, CliRuntimeContext } from "./cliCommandTypes";
2
+
3
+ export function withCliEnv<TDeps extends { env: NodeJS.ProcessEnv }>(
4
+ command: (args: string[], deps: TDeps) => Promise<number>
5
+ ): CliCommandHandler {
6
+ return (args: string[], ctx: CliRuntimeContext) =>
7
+ command(args, { env: ctx.env } as TDeps);
8
+ }
9
+
10
+ export function withCliEnvAndScriptDir<TDeps extends { env: NodeJS.ProcessEnv; scriptDir: string }>(
11
+ command: (args: string[], deps: TDeps) => Promise<number>
12
+ ): CliCommandHandler {
13
+ return (args: string[], ctx: CliRuntimeContext) =>
14
+ command(args, {
15
+ env: ctx.env,
16
+ scriptDir: ctx.scriptDir,
17
+ } as TDeps);
18
+ }
19
+
20
+ export function withCliEntrypointEnv<TDeps extends { env: NodeJS.ProcessEnv; cliEntrypointPath: string }>(
21
+ command: (args: string[], deps: TDeps) => Promise<number>
22
+ ): CliCommandHandler {
23
+ return (args: string[], ctx: CliRuntimeContext) =>
24
+ command(args, {
25
+ env: ctx.env,
26
+ cliEntrypointPath: ctx.entrypointPath,
27
+ } as TDeps);
28
+ }
@@ -0,0 +1,66 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import type { CliPackageInfo, CliRuntimeContext, CommandEntry } from "./cliCommandTypes";
3
+
4
+ export async function runResolvedCommand(
5
+ command: CommandEntry,
6
+ originalArgs: string[],
7
+ ctx: CliRuntimeContext,
8
+ deps: {
9
+ runScript: (script: string, forwardedArgs: string[], env: NodeJS.ProcessEnv) => Promise<number>;
10
+ }
11
+ ) {
12
+ if (command.kind === "internal") {
13
+ if (!command.handler) {
14
+ throw new Error(`Internal command ${command.path.join(" ")} is missing a handler.`);
15
+ }
16
+ return command.handler(originalArgs.slice(command.path.length), ctx);
17
+ }
18
+
19
+ if (!command.script) {
20
+ throw new Error(`Script command ${command.path.join(" ")} is missing a script.`);
21
+ }
22
+
23
+ const forwardedArgs = [...(command.fixedArgs ?? []), ...originalArgs.slice(command.path.length)];
24
+ return deps.runScript(command.script, forwardedArgs, ctx.env);
25
+ }
26
+
27
+ function readOption(args: string[], flag: string) {
28
+ const index = args.indexOf(flag);
29
+ return index >= 0 ? args[index + 1] : undefined;
30
+ }
31
+
32
+ function buildDaemonEnv(args: string[], runtimeEnv: NodeJS.ProcessEnv) {
33
+ const serverUrl = readOption(args, "--server-url") || readOption(args, "--server");
34
+ const apiKey = readOption(args, "--api-key") || readOption(args, "--token");
35
+ return {
36
+ ...runtimeEnv,
37
+ ...(serverUrl ? { NOLO_SERVER: serverUrl } : {}),
38
+ ...(apiKey ? { AUTH_TOKEN: apiKey } : {}),
39
+ };
40
+ }
41
+
42
+ export function looksLikeDaemonShortcut(args: string[]) {
43
+ return args.includes("--server-url") || args.includes("--api-key");
44
+ }
45
+
46
+ export function createCliRuntimeContext(args: {
47
+ env: NodeJS.ProcessEnv;
48
+ scriptDir: string;
49
+ entrypointPath?: string;
50
+ packageInfo: CliPackageInfo;
51
+ }): CliRuntimeContext {
52
+ return {
53
+ env: args.env,
54
+ scriptDir: args.scriptDir,
55
+ entrypointPath: args.entrypointPath ?? fileURLToPath(import.meta.url),
56
+ packageInfo: args.packageInfo,
57
+ };
58
+ }
59
+
60
+ export function withDaemonShortcutArgs(args: string[], runtimeEnv: NodeJS.ProcessEnv) {
61
+ if (!looksLikeDaemonShortcut(args)) return { commandArgs: args, envOverride: null as NodeJS.ProcessEnv | null };
62
+ return {
63
+ commandArgs: ["daemon", ...args],
64
+ envOverride: buildDaemonEnv(args, runtimeEnv),
65
+ };
66
+ }
@@ -0,0 +1,34 @@
1
+ import {
2
+ withCliEntrypointEnv,
3
+ withCliEnv,
4
+ withCliEnvAndScriptDir,
5
+ } from "./cliCommandAdapters";
6
+ import {
7
+ createInternalCommand,
8
+ type CliCommandHandler,
9
+ type CommandEntry,
10
+ } from "./cliCommandTypes";
11
+
12
+ export function createEnvCommand<TDeps extends { env: NodeJS.ProcessEnv }>(
13
+ path: string[],
14
+ description: string,
15
+ command: (args: string[], deps: TDeps) => Promise<number>
16
+ ): CommandEntry {
17
+ return createInternalCommand(path, description, withCliEnv(command) as CliCommandHandler);
18
+ }
19
+
20
+ export function createEnvScriptDirCommand<TDeps extends { env: NodeJS.ProcessEnv; scriptDir: string }>(
21
+ path: string[],
22
+ description: string,
23
+ command: (args: string[], deps: TDeps) => Promise<number>
24
+ ): CommandEntry {
25
+ return createInternalCommand(path, description, withCliEnvAndScriptDir(command) as CliCommandHandler);
26
+ }
27
+
28
+ export function createEntrypointEnvCommand<TDeps extends { env: NodeJS.ProcessEnv; cliEntrypointPath: string }>(
29
+ path: string[],
30
+ description: string,
31
+ command: (args: string[], deps: TDeps) => Promise<number>
32
+ ): CommandEntry {
33
+ return createInternalCommand(path, description, withCliEntrypointEnv(command) as CliCommandHandler);
34
+ }
@@ -0,0 +1,49 @@
1
+ import type { readPackageInfo } from "./updateCommands";
2
+
3
+ export type CliPackageInfo = ReturnType<typeof readPackageInfo>;
4
+
5
+ export type CliRuntimeContext = {
6
+ env: NodeJS.ProcessEnv;
7
+ scriptDir: string;
8
+ entrypointPath: string;
9
+ packageInfo: CliPackageInfo;
10
+ };
11
+
12
+ export type CliCommandHandler = (args: string[], ctx: CliRuntimeContext) => Promise<number>;
13
+
14
+ export type CommandEntry = {
15
+ path: string[];
16
+ description: string;
17
+ kind: "internal" | "script";
18
+ script?: string;
19
+ fixedArgs?: string[];
20
+ handler?: CliCommandHandler;
21
+ };
22
+
23
+ export function createScriptCommand(
24
+ path: string[],
25
+ script: string,
26
+ description: string,
27
+ fixedArgs?: string[]
28
+ ): CommandEntry {
29
+ return {
30
+ path,
31
+ kind: "script",
32
+ script,
33
+ description,
34
+ ...(fixedArgs ? { fixedArgs } : {}),
35
+ };
36
+ }
37
+
38
+ export function createInternalCommand(
39
+ path: string[],
40
+ description: string,
41
+ handler: CliCommandHandler
42
+ ): CommandEntry {
43
+ return {
44
+ path,
45
+ kind: "internal",
46
+ description,
47
+ handler,
48
+ };
49
+ }
@@ -0,0 +1,44 @@
1
+ import { DEFAULT_NOLO_SERVER_URL } from "./defaultServer";
2
+ import { NOLO_CLUSTER_SERVERS } from "./database/config";
3
+
4
+ export type EnvLike = Record<string, string | undefined>;
5
+
6
+ export function resolveServerUrl(env: EnvLike) {
7
+ return (env.NOLO_SERVER || env.BASE_URL || DEFAULT_NOLO_SERVER_URL).replace(/\/+$/, "");
8
+ }
9
+
10
+ export function resolveServerCandidates(env: EnvLike, preferred?: string | null) {
11
+ const values = [
12
+ preferred?.trim(),
13
+ env.NOLO_SERVER,
14
+ env.BASE_URL,
15
+ env.NOLO_SERVER_URL,
16
+ DEFAULT_NOLO_SERVER_URL,
17
+ ...NOLO_CLUSTER_SERVERS,
18
+ ];
19
+ return [...new Set(
20
+ values
21
+ .filter((value): value is string => typeof value === "string" && value.trim().length > 0)
22
+ .map((value) => value.replace(/\/+$/, ""))
23
+ )];
24
+ }
25
+
26
+ export function resolveAuthToken(env: EnvLike) {
27
+ return env.AUTH_TOKEN || env.AUTH || "";
28
+ }
29
+
30
+ export function parseUserIdFromAuthToken(token: string) {
31
+ const payload = token.trim().split(".")[0];
32
+ if (!payload) return "";
33
+ try {
34
+ const parsed = JSON.parse(Buffer.from(payload, "base64").toString("utf8"));
35
+ return typeof parsed?.userId === "string" ? parsed.userId : "";
36
+ } catch {
37
+ return "";
38
+ }
39
+ }
40
+
41
+ export function readOption(args: string[], flag: string) {
42
+ const index = args.indexOf(flag);
43
+ return index >= 0 ? args[index + 1] : undefined;
44
+ }