nolo-cli 0.1.33 → 0.1.35

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 (84) hide show
  1. package/README.md +15 -5
  2. package/agent-runtime/agentRecordConfig.ts +8 -0
  3. package/agent-runtime/hostAdapter.ts +9 -1
  4. package/agent-runtime/index.ts +10 -0
  5. package/agent-runtime/localLoop.ts +49 -2
  6. package/agent-runtime/localToolPolicy.ts +71 -22
  7. package/agent-runtime/localWorkspaceTools.ts +5 -2
  8. package/agent-runtime/openAiCompatibleProvider.ts +7 -3
  9. package/agent-runtime/openAiCompatibleProviderConfig.ts +15 -26
  10. package/agent-runtime/platformChatProvider.ts +48 -71
  11. package/agent-runtime/providerResolution.ts +242 -0
  12. package/agent-runtime/runtimeToolPolicy.ts +33 -0
  13. package/agent-runtime/shellCommandPolicy.ts +120 -0
  14. package/agentCommandSupport.ts +4 -0
  15. package/agentInternalCommandEntries.ts +2 -0
  16. package/agentListCommands.ts +74 -12
  17. package/agentListHelpers.ts +56 -1
  18. package/agentPullCommand.ts +6 -11
  19. package/agentRecordCommands.ts +87 -2
  20. package/agentRecordHelpers.ts +132 -9
  21. package/agentRuntimeLocal.ts +3 -0
  22. package/ai/tools/toolNameAliases.ts +70 -0
  23. package/cli/agentCommandSupport.ts +4 -0
  24. package/cli/agentInternalCommandEntries.ts +2 -0
  25. package/cli/agentListCommands.ts +74 -12
  26. package/cli/agentListHelpers.ts +56 -1
  27. package/cli/agentPullCommand.ts +6 -11
  28. package/cli/agentRecordCommands.ts +87 -2
  29. package/cli/agentRecordHelpers.ts +132 -9
  30. package/cli/agentRuntimeLocal.ts +3 -0
  31. package/cli/cliCommandDispatch.ts +2 -2
  32. package/cli/cliEnvHelpers.ts +80 -12
  33. package/cli/cliSpaceHelpers.ts +39 -0
  34. package/cli/client/agentRun.ts +1 -0
  35. package/cli/client/localRuntimeAdapter.ts +44 -7
  36. package/cli/commandRegistry.ts +2 -2
  37. package/cli/connectorWebSocketTarget.ts +10 -3
  38. package/cli/dialogCommands.ts +446 -0
  39. package/cli/dialogInternalCommandEntries.ts +13 -0
  40. package/cli/globalRecordOperations.ts +258 -0
  41. package/cli/internalCommandEntries.ts +2 -0
  42. package/cli/localRuntimeAuthority.ts +182 -0
  43. package/cli/localRuntimeDb.ts +2 -4
  44. package/cli/machineCommands.ts +1 -1
  45. package/cli/machineWsRunDispatch.ts +29 -12
  46. package/cli/machineWsSession.ts +2 -0
  47. package/cli/offlineMarxistsAgentCommand.ts +1 -1
  48. package/cli/runtimeDoctorCommands.ts +65 -9
  49. package/cli/tableCommands.ts +1 -1
  50. package/cli/taskRunCommand.ts +1 -1
  51. package/cliCommandDispatch.ts +2 -2
  52. package/cliEnvHelpers.ts +80 -12
  53. package/cliSpaceHelpers.ts +39 -0
  54. package/client/agentRun.ts +1 -0
  55. package/client/localProviderResolver.test.ts +26 -2
  56. package/client/localRuntimeAdapter.test.ts +287 -3
  57. package/client/localRuntimeAdapter.ts +44 -7
  58. package/commandRegistry.ts +2 -2
  59. package/connectorWebSocketTarget.ts +10 -3
  60. package/database/server/authorityStoreTypes.ts +31 -0
  61. package/database/server/cliAuthorityBrokerClient.ts +227 -0
  62. package/database/server/cliAuthorityBrokerServer.ts +283 -0
  63. package/database/server/cliAuthorityBrokerTypes.ts +43 -0
  64. package/database/server/cliAuthorityStoreDriver.ts +98 -0
  65. package/database/server/legacyServerDb.ts +58 -0
  66. package/database/server/levelAuthorityStore.ts +95 -0
  67. package/database/tombstones.ts +52 -0
  68. package/database/userDataMerge.ts +95 -0
  69. package/dialogCommands.ts +446 -0
  70. package/dialogInternalCommandEntries.ts +13 -0
  71. package/globalRecordOperations.ts +258 -0
  72. package/internalCommandEntries.ts +2 -0
  73. package/localRuntimeAuthority.ts +182 -0
  74. package/localRuntimeDb.ts +2 -4
  75. package/machineCommands.ts +1 -1
  76. package/machineWsRunDispatch.ts +29 -12
  77. package/machineWsSession.ts +2 -0
  78. package/offlineMarxistsAgentCommand.ts +1 -1
  79. package/package.json +24 -4
  80. package/runtimeDoctorCommands.ts +65 -9
  81. package/tableCommands.ts +1 -1
  82. package/taskRunCommand.ts +1 -1
  83. package/database/server/db.ts +0 -118
  84. package/database/server/ensureDbOpen.ts +0 -12
@@ -1,4 +1,10 @@
1
1
  import { resolveAgentRuntimeDecision } from "../agent-runtime/runtimeDecision";
2
+ import {
3
+ resolveCliAuthorityBrokerEndpoint,
4
+ resolveCliAuthorityBrokerHealthPath,
5
+ resolveCliAuthorityBrokerMetadataPath,
6
+ resolveCliAuthorityStoreDriver,
7
+ } from "../database/server/cliAuthorityStoreDriver";
2
8
  import {
3
9
  type AgentCommandDeps,
4
10
  type LocalRuntimeProbeResult,
@@ -39,23 +45,57 @@ function detectProviderLabel(env: EnvLike) {
39
45
  async function defaultLocalRuntimeProbe(env: EnvLike): Promise<LocalRuntimeProbeResult> {
40
46
  const { resolveCliLocalRuntimeDbPath } = await import("./localRuntimeDb");
41
47
  const dbPath = resolveCliLocalRuntimeDbPath({ env });
48
+ const authorityDriver = resolveCliAuthorityStoreDriver({ env });
49
+ const authorityEndpoint = resolveCliAuthorityBrokerEndpoint({ transport: "tcp", env });
50
+ const authorityMetadataPath = resolveCliAuthorityBrokerMetadataPath({ transport: "tcp", env });
51
+ const authorityHealthPath = resolveCliAuthorityBrokerHealthPath({ transport: "tcp", env });
42
52
  const agentKey = readLocalAgentKey(env);
43
53
  try {
44
54
  const { getDefaultCliLocalRuntimeDb } = await import("./localRuntimeDb");
45
- const db = await getDefaultCliLocalRuntimeDb();
55
+ const db = await getDefaultCliLocalRuntimeDb({ env });
46
56
  if (!agentKey) {
47
- return { ok: true, dbPath, agentFound: false };
57
+ return {
58
+ ok: true,
59
+ dbPath,
60
+ authorityDriver,
61
+ authorityEndpoint,
62
+ authorityMetadataPath,
63
+ authorityHealthPath,
64
+ agentFound: false,
65
+ };
48
66
  }
49
67
  try {
50
- await db.get(agentKey);
51
- return { ok: true, dbPath, agentFound: true, agentKey };
68
+ const record = await db.get(agentKey);
69
+ return {
70
+ ok: true,
71
+ dbPath,
72
+ authorityDriver,
73
+ authorityEndpoint,
74
+ authorityMetadataPath,
75
+ authorityHealthPath,
76
+ agentFound: record != null,
77
+ agentKey,
78
+ };
52
79
  } catch {
53
- return { ok: true, dbPath, agentFound: false, agentKey };
80
+ return {
81
+ ok: true,
82
+ dbPath,
83
+ authorityDriver,
84
+ authorityEndpoint,
85
+ authorityMetadataPath,
86
+ authorityHealthPath,
87
+ agentFound: false,
88
+ agentKey,
89
+ };
54
90
  }
55
91
  } catch (error) {
56
92
  return {
57
93
  ok: false,
58
94
  dbPath,
95
+ authorityDriver,
96
+ authorityEndpoint,
97
+ authorityMetadataPath,
98
+ authorityHealthPath,
59
99
  agentFound: false,
60
100
  ...(agentKey ? { agentKey } : {}),
61
101
  error: error instanceof Error ? error.message : String(error),
@@ -64,13 +104,13 @@ async function defaultLocalRuntimeProbe(env: EnvLike): Promise<LocalRuntimeProbe
64
104
  }
65
105
 
66
106
  export async function runDoctorRuntimeCommand(
67
- _args: string[],
107
+ args: string[],
68
108
  deps: AgentCommandDeps = {}
69
109
  ) {
70
110
  const env = deps.env ?? process.env;
71
111
  const output = deps.output ?? process.stdout;
72
- const authToken = resolveAuthToken(env);
73
- const serverUrl = resolveServerUrl(env);
112
+ const authToken = resolveAuthToken(args, env);
113
+ const serverUrl = resolveServerUrl(args, env);
74
114
  const localProbe = await (deps.localRuntimeProbe ?? defaultLocalRuntimeProbe)(env);
75
115
  const hasLocalAgentConfig = detectLocalAgentConfig(env) && localProbe.ok && localProbe.agentFound;
76
116
  const hasLocalProvider = detectLocalProvider(env);
@@ -88,13 +128,29 @@ export async function runDoctorRuntimeCommand(
88
128
  hasLocalPersistence: true,
89
129
  missingLocalCapabilities,
90
130
  requiresServer: false,
91
- serverFallbackAvailable: Boolean(authToken || env.NOLO_SERVER || env.BASE_URL),
131
+ serverFallbackAvailable: Boolean(
132
+ authToken ||
133
+ args.includes("--server") ||
134
+ args.includes("--server-url") ||
135
+ env.NOLO_SERVER ||
136
+ env.BASE_URL
137
+ ),
92
138
  });
93
139
 
94
140
  output.write(`Runtime: ${decision.mode}\n`);
95
141
  output.write(`Reason: ${decision.reason}\n`);
96
142
  output.write(`LevelDB: ${localProbe.ok ? "ok" : "failed"}\n`);
97
143
  output.write(`DB path: ${localProbe.dbPath}\n`);
144
+ output.write(`Authority driver: ${localProbe.authorityDriver ?? "unknown"}\n`);
145
+ if (localProbe.authorityEndpoint) {
146
+ output.write(`Authority endpoint: ${localProbe.authorityEndpoint}\n`);
147
+ }
148
+ if (localProbe.authorityMetadataPath) {
149
+ output.write(`Authority metadata: ${localProbe.authorityMetadataPath}\n`);
150
+ }
151
+ if (localProbe.authorityHealthPath) {
152
+ output.write(`Authority health: ${localProbe.authorityHealthPath}\n`);
153
+ }
98
154
  if (!localProbe.ok && localProbe.error) {
99
155
  output.write(`DB error: ${localProbe.error}\n`);
100
156
  }
@@ -80,7 +80,7 @@ function resolveServerUrl(args: string[], env: EnvLike): string {
80
80
 
81
81
  function resolveAuthToken(args: string[], env: EnvLike): string {
82
82
  return (
83
- readOption(args, "--api-key") ||
83
+ readOption(args, "--machine-key") ||
84
84
  readOption(args, "--token") ||
85
85
  env.AUTH_TOKEN ||
86
86
  env.AUTH ||
@@ -82,7 +82,7 @@ function resolveServerUrl(args: string[], env: EnvLike) {
82
82
 
83
83
  function resolveAuthToken(args: string[], env: EnvLike) {
84
84
  return (
85
- readOption(args, "--api-key") ||
85
+ readOption(args, "--machine-key") ||
86
86
  readOption(args, "--token") ||
87
87
  env.NOLO_TASK_RUN_TOKEN ||
88
88
  env.NOLO_MACHINE_API_KEY ||
@@ -31,7 +31,7 @@ function readOption(args: string[], flag: string) {
31
31
 
32
32
  function buildDaemonEnv(args: string[], runtimeEnv: NodeJS.ProcessEnv) {
33
33
  const serverUrl = readOption(args, "--server-url") || readOption(args, "--server");
34
- const apiKey = readOption(args, "--api-key") || readOption(args, "--token");
34
+ const apiKey = readOption(args, "--machine-key") || readOption(args, "--token");
35
35
  return {
36
36
  ...runtimeEnv,
37
37
  ...(serverUrl ? { NOLO_SERVER: serverUrl } : {}),
@@ -40,7 +40,7 @@ function buildDaemonEnv(args: string[], runtimeEnv: NodeJS.ProcessEnv) {
40
40
  }
41
41
 
42
42
  export function looksLikeDaemonShortcut(args: string[]) {
43
- return args.includes("--server-url") || args.includes("--api-key");
43
+ return args.includes("--server-url") || args.includes("--machine-key");
44
44
  }
45
45
 
46
46
  export function createCliRuntimeContext(args: {
package/cliEnvHelpers.ts CHANGED
@@ -3,19 +3,17 @@ import { NOLO_CLUSTER_SERVERS } from "./database/config";
3
3
 
4
4
  export type EnvLike = Record<string, string | undefined>;
5
5
 
6
- export function resolveServerUrl(env: EnvLike) {
6
+ export function resolveServerUrlFromEnv(env: EnvLike) {
7
7
  return (env.NOLO_SERVER || env.BASE_URL || DEFAULT_NOLO_SERVER_URL).replace(/\/+$/, "");
8
8
  }
9
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
- ];
10
+ type ResolverInput = string[] | EnvLike;
11
+
12
+ function isCliArgs(value: ResolverInput): value is string[] {
13
+ return Array.isArray(value);
14
+ }
15
+
16
+ function buildServerCandidates(values: Array<string | null | undefined>) {
19
17
  return [...new Set(
20
18
  values
21
19
  .filter((value): value is string => typeof value === "string" && value.trim().length > 0)
@@ -23,8 +21,78 @@ export function resolveServerCandidates(env: EnvLike, preferred?: string | null)
23
21
  )];
24
22
  }
25
23
 
26
- export function resolveAuthToken(env: EnvLike) {
27
- return env.AUTH_TOKEN || env.AUTH || "";
24
+ export function resolveServerUrl(env: EnvLike): string;
25
+ export function resolveServerUrl(args: string[], env: EnvLike): string;
26
+ export function resolveServerUrl(input: ResolverInput, env?: EnvLike) {
27
+ if (isCliArgs(input)) {
28
+ const explicit =
29
+ readOption(input, "--server-url") ||
30
+ readOption(input, "--server");
31
+ return explicit?.replace(/\/+$/, "") || resolveServerUrlFromEnv(env ?? {});
32
+ }
33
+ return resolveServerUrlFromEnv(input);
34
+ }
35
+
36
+ export function resolveServerCandidates(env: EnvLike, preferred?: string | null): string[];
37
+ export function resolveServerCandidates(
38
+ args: string[],
39
+ env: EnvLike,
40
+ preferred?: string | null,
41
+ ): string[];
42
+ export function resolveServerCandidates(
43
+ input: ResolverInput,
44
+ envOrPreferred?: EnvLike | string | null,
45
+ preferred?: string | null,
46
+ ) {
47
+ if (isCliArgs(input)) {
48
+ const env = (envOrPreferred ?? {}) as EnvLike;
49
+ const explicitServer = resolveServerUrl(input, env);
50
+ return buildServerCandidates([
51
+ explicitServer,
52
+ preferred?.trim(),
53
+ env.NOLO_SERVER,
54
+ env.BASE_URL,
55
+ env.NOLO_SERVER_URL,
56
+ DEFAULT_NOLO_SERVER_URL,
57
+ ...NOLO_CLUSTER_SERVERS,
58
+ ]);
59
+ }
60
+
61
+ const env = input;
62
+ return buildServerCandidates([
63
+ typeof envOrPreferred === "string" ? envOrPreferred.trim() : undefined,
64
+ env.NOLO_SERVER,
65
+ env.BASE_URL,
66
+ env.NOLO_SERVER_URL,
67
+ DEFAULT_NOLO_SERVER_URL,
68
+ ...NOLO_CLUSTER_SERVERS,
69
+ ]);
70
+ }
71
+
72
+ export function resolveAuthTokenFromEnv(env: EnvLike, extraEnvKeys: string[] = []) {
73
+ for (const key of ["AUTH_TOKEN", "AUTH", ...extraEnvKeys]) {
74
+ const value = env[key];
75
+ if (typeof value === "string" && value.trim()) return value;
76
+ }
77
+ return "";
78
+ }
79
+
80
+ export function resolveAuthToken(env: EnvLike, extraEnvKeys?: string[]): string;
81
+ export function resolveAuthToken(args: string[], env: EnvLike, extraEnvKeys?: string[]): string;
82
+ export function resolveAuthToken(
83
+ input: ResolverInput,
84
+ envOrExtraEnvKeys?: EnvLike | string[],
85
+ extraEnvKeys: string[] = [],
86
+ ) {
87
+ if (isCliArgs(input)) {
88
+ const env = (envOrExtraEnvKeys ?? {}) as EnvLike;
89
+ return (
90
+ readOption(input, "--token") ||
91
+ readOption(input, "--machine-key") ||
92
+ resolveAuthTokenFromEnv(env, extraEnvKeys)
93
+ );
94
+ }
95
+ return resolveAuthTokenFromEnv(input, (envOrExtraEnvKeys as string[] | undefined) ?? []);
28
96
  }
29
97
 
30
98
  export function parseUserIdFromAuthToken(token: string) {
@@ -0,0 +1,39 @@
1
+ export function normalizeSpaceIdInput(rawInput: string) {
2
+ const raw = rawInput.trim();
3
+ if (!raw) return "";
4
+
5
+ if (raw.startsWith("http://") || raw.startsWith("https://")) {
6
+ const url = new URL(raw);
7
+ const match = url.pathname.match(/^\/space\/([^/?#]+)/);
8
+ if (match?.[1]) return decodeURIComponent(match[1]);
9
+ }
10
+
11
+ return raw.startsWith("space-") ? raw.slice("space-".length) : raw;
12
+ }
13
+
14
+ export function buildSpaceLookup(rawInput: string) {
15
+ const spaceId = normalizeSpaceIdInput(rawInput);
16
+ return {
17
+ spaceId,
18
+ spaceKey: spaceId.startsWith("space-") ? spaceId : `space-${spaceId}`,
19
+ };
20
+ }
21
+
22
+ export function getSpaceContentKeys(spaceRecord: any): Set<string> {
23
+ const keys = new Set<string>();
24
+ const contents = spaceRecord?.contents;
25
+ if (!contents || typeof contents !== "object") return keys;
26
+
27
+ for (const [entryKey, value] of Object.entries(contents)) {
28
+ if (typeof entryKey === "string" && entryKey.trim()) {
29
+ keys.add(entryKey.trim());
30
+ }
31
+ if (value && typeof value === "object") {
32
+ const contentKey = (value as any).contentKey;
33
+ if (typeof contentKey === "string" && contentKey.trim()) {
34
+ keys.add(contentKey.trim());
35
+ }
36
+ }
37
+ }
38
+ return keys;
39
+ }
@@ -778,6 +778,7 @@ async function runLocalAgentTurnForCli(
778
778
  background: options.background,
779
779
  noStream: options.noStream,
780
780
  maxToolRounds: options.maxToolRounds,
781
+ ...(typeof options.timeoutMs === "number" ? { timeoutMs: options.timeoutMs } : {}),
781
782
  ...(traceLocalTools || collectToolEvidence
782
783
  ? {
783
784
  onToolEvent: (event) => {
@@ -11,15 +11,18 @@ describe("CLI local provider resolver", () => {
11
11
  provider: "custom",
12
12
  apiSource: "custom",
13
13
  customProviderUrl: "https://provider.example/v1/chat/completions",
14
+ apiKey: "sk-agent-custom",
15
+ apiKeyHeader: "api-key",
14
16
  },
15
17
  env: {
16
- OPENAI_API_KEY: "sk-env",
18
+ OPENAI_API_KEY: "sk-env-should-not-win",
17
19
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
18
20
  },
19
21
  })).toEqual({
20
22
  model: "qwen-coder",
21
23
  endpoint: "https://provider.example/v1/chat/completions",
22
- apiKey: "sk-env",
24
+ apiKey: "sk-agent-custom",
25
+ apiKeyHeader: "api-key",
23
26
  provider: "custom",
24
27
  requestOptions: {},
25
28
  });
@@ -53,6 +56,27 @@ describe("CLI local provider resolver", () => {
53
56
  });
54
57
  });
55
58
 
59
+ test("defaults Xiaomi custom endpoints to api-key auth header", () => {
60
+ expect(resolveCliOpenAiProviderConfig({
61
+ agentConfig: {
62
+ key: "agent-user-1-mimo",
63
+ provider: "custom",
64
+ apiSource: "custom",
65
+ model: "mimo-v2.5-pro",
66
+ customProviderUrl: "https://token-plan-cn.xiaomimimo.com/v1",
67
+ apiKey: "mimo-monthly-key",
68
+ },
69
+ env: {},
70
+ })).toEqual({
71
+ model: "mimo-v2.5-pro",
72
+ endpoint: "https://token-plan-cn.xiaomimimo.com/v1/chat/completions",
73
+ apiKey: "mimo-monthly-key",
74
+ apiKeyHeader: "api-key",
75
+ provider: "custom",
76
+ requestOptions: {},
77
+ });
78
+ });
79
+
56
80
  test("carries explicit agent inference options for request body construction", () => {
57
81
  expect(resolveCliOpenAiProviderConfig({
58
82
  agentConfig: {