nolo-cli 0.1.34 → 0.1.36
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.
- package/README.md +11 -1
- package/agent-runtime/index.ts +2 -0
- package/agent-runtime/localToolPolicy.ts +1 -1
- package/agent-runtime/localWorkspaceTools.ts +5 -2
- package/agent-runtime/platformChatProvider.ts +17 -9
- package/agent-runtime/providerResolution.ts +71 -13
- package/agentCommandSupport.ts +4 -0
- package/agentListCommands.ts +73 -11
- package/agentListHelpers.ts +56 -1
- package/agentRecordHelpers.ts +45 -5
- package/cli/agentCommandSupport.ts +4 -0
- package/cli/agentListCommands.ts +73 -11
- package/cli/agentListHelpers.ts +56 -1
- package/cli/agentRecordHelpers.ts +45 -5
- package/cli/cliSpaceHelpers.ts +39 -0
- package/cli/client/localRuntimeAdapter.ts +86 -2
- package/cli/connectorWebSocketTarget.ts +10 -3
- package/cli/dialogCommands.ts +446 -0
- package/cli/dialogInternalCommandEntries.ts +13 -0
- package/cli/globalRecordOperations.ts +258 -0
- package/cli/internalCommandEntries.ts +2 -0
- package/cli/localRuntimeAuthority.ts +182 -0
- package/cli/localRuntimeDb.ts +2 -4
- package/cli/machineWsRunDispatch.ts +42 -3
- package/cli/machineWsSession.ts +2 -0
- package/cli/runtimeDoctorCommands.ts +55 -5
- package/cliSpaceHelpers.ts +39 -0
- package/client/localRuntimeAdapter.ts +86 -2
- package/connectorWebSocketTarget.ts +10 -3
- package/database/server/cliAuthorityBrokerClient.ts +227 -0
- package/database/server/cliAuthorityBrokerServer.ts +283 -0
- package/database/server/cliAuthorityBrokerTypes.ts +43 -0
- package/database/server/cliAuthorityStoreDriver.ts +98 -0
- package/database/server/levelAuthorityStore.ts +46 -26
- package/database/tombstones.ts +52 -0
- package/database/userDataMerge.ts +95 -0
- package/dialogCommands.ts +446 -0
- package/dialogInternalCommandEntries.ts +13 -0
- package/globalRecordOperations.ts +258 -0
- package/internalCommandEntries.ts +2 -0
- package/localRuntimeAuthority.ts +182 -0
- package/localRuntimeDb.ts +2 -4
- package/machineWsRunDispatch.ts +42 -3
- package/machineWsSession.ts +2 -0
- package/package.json +18 -6
- package/runtimeDoctorCommands.ts +55 -5
- package/database/server/db.ts +0 -99
- package/database/server/ensureDbOpen.ts +0 -12
- package/database/server/memoryAuthorityStore.ts +0 -133
- package/database/server/serverStoreFactory.ts +0 -118
package/README.md
CHANGED
|
@@ -171,8 +171,11 @@ nolo agent read <agent>
|
|
|
171
171
|
nolo agent update <agent> --model gpt-5.4 --cli-provider codex --api-source cli
|
|
172
172
|
nolo agent run <agent> "检查最近失败任务"
|
|
173
173
|
nolo agent run frontend-implementer --msg "修一个小的通知弹窗 CSS 问题"
|
|
174
|
-
nolo
|
|
174
|
+
nolo agent list --space <space>
|
|
175
|
+
nolo dialog list
|
|
176
|
+
nolo dialog list --space <space>
|
|
175
177
|
nolo dialog read <dialog>
|
|
178
|
+
nolo dialog delete <dialog> --yes
|
|
176
179
|
nolo doc list --agent <agent>
|
|
177
180
|
nolo table query --table meta-b2e06f801f-NOLOTASKBOARD --limit 20
|
|
178
181
|
nolo table query --table meta-b2e06f801f-NOLOTASKBOARD --columns '["title","status","owner","priority","codeStatus"]' --no-base-fields --output items
|
|
@@ -180,6 +183,13 @@ nolo table update-row --table meta-b2e06f801f-NOLOTASKBOARD --row 01ROWID --chan
|
|
|
180
183
|
nolo table add-column --table meta-b2e06f801f-NOLOTASKBOARD --schema-write-ok --name "blockedBy" --label "Blocked By"
|
|
181
184
|
```
|
|
182
185
|
|
|
186
|
+
`agent list`, `dialog list`, and record delete commands use global server
|
|
187
|
+
candidates for the current CLI profile: the selected `--server` / `NOLO_SERVER`
|
|
188
|
+
plus known Nolo cluster peers. List commands merge tombstones so a newer delete
|
|
189
|
+
on one server hides older live records from another. Dialog, doc, skill-doc,
|
|
190
|
+
space, and agent public-record deletes send the delete to all target servers;
|
|
191
|
+
each server applies the normal tombstone/cascade behavior for that record type.
|
|
192
|
+
|
|
183
193
|
`nolo table add-column` mutates table schema metadata, so it requires
|
|
184
194
|
`--schema-write-ok` and should be run serially per table. Row-level table writes
|
|
185
195
|
do not require this flag.
|
package/agent-runtime/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, relative, resolve, sep } from "node:path";
|
|
|
4
4
|
import type {
|
|
5
5
|
AgentRuntimeToolCallInput,
|
|
6
6
|
AgentRuntimeToolResult,
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./hostAdapter";
|
|
8
8
|
|
|
9
9
|
type LocalWorkspaceToolArgs = {
|
|
10
10
|
workspaceRoot: string;
|
|
@@ -646,7 +646,10 @@ function readVisualStateCaptureArgs(args: WorkspaceFileArgs) {
|
|
|
646
646
|
};
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
async function readWorkspacePackageScripts(workspaceRoot: string) {
|
|
649
|
+
async function readWorkspacePackageScripts(workspaceRoot: string): Promise<{
|
|
650
|
+
scripts: string[];
|
|
651
|
+
error?: string;
|
|
652
|
+
}> {
|
|
650
653
|
try {
|
|
651
654
|
const raw = await readFile(resolve(workspaceRoot, "package.json"), "utf8");
|
|
652
655
|
const parsed = JSON.parse(raw);
|
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
buildProviderExecutionPlan,
|
|
8
8
|
canUsePlatformChatProvider as canUsePlatformChatProviderFromEnv,
|
|
9
9
|
hasDirectOpenAiCompatibleProvider as hasDirectOpenAiCompatibleProviderFromEnv,
|
|
10
|
+
resolveAgentRuntimeLocation,
|
|
10
11
|
resolvePlatformAuthToken,
|
|
11
12
|
resolvePlatformServerUrl,
|
|
12
|
-
|
|
13
|
+
resolveProviderTransportDecision,
|
|
13
14
|
} from "./providerResolution";
|
|
14
15
|
|
|
15
16
|
type EnvLike = Record<string, string | undefined>;
|
|
@@ -206,16 +207,23 @@ export function hasDirectOpenAiCompatibleProvider(env: EnvLike) {
|
|
|
206
207
|
return hasDirectOpenAiCompatibleProviderFromEnv(env);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
function agentRequiresPlatformChatProvider(agentConfig?: AgentRuntimeAgentConfig) {
|
|
210
|
-
if (agentConfig?.apiSource === "platform") return true;
|
|
211
|
-
if (agentConfig?.apiSource === "custom" || agentConfig?.customProviderUrl?.trim()) return false;
|
|
212
|
-
return agentConfig?.useServerProxy === true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
210
|
export function shouldUsePlatformChatProvider(
|
|
216
211
|
env: EnvLike,
|
|
217
212
|
agentConfig?: AgentRuntimeAgentConfig
|
|
218
213
|
) {
|
|
219
|
-
if (
|
|
220
|
-
|
|
214
|
+
if (!agentConfig) {
|
|
215
|
+
return resolveProviderTransportDecision({
|
|
216
|
+
agentConfig: { key: "default-platform" },
|
|
217
|
+
env,
|
|
218
|
+
runtimeLocation: "local-host",
|
|
219
|
+
}).transport === "proxy";
|
|
220
|
+
}
|
|
221
|
+
return resolveProviderTransportDecision({
|
|
222
|
+
agentConfig,
|
|
223
|
+
env,
|
|
224
|
+
runtimeLocation: resolveAgentRuntimeLocation({
|
|
225
|
+
agentConfig,
|
|
226
|
+
runtimeKind: "local",
|
|
227
|
+
}),
|
|
228
|
+
}).transport === "proxy";
|
|
221
229
|
}
|
|
@@ -16,6 +16,21 @@ const PROVIDER_ENDPOINTS: Record<string, string> = {
|
|
|
16
16
|
|
|
17
17
|
export type AgentProviderMode = "cli" | "platform" | "custom";
|
|
18
18
|
export type ProviderExecutionTransport = "direct" | "proxy";
|
|
19
|
+
export type AgentRuntimeLocation = "server" | "bound-machine" | "local-host";
|
|
20
|
+
|
|
21
|
+
export type ProviderTransportDecision = {
|
|
22
|
+
mode: AgentProviderMode;
|
|
23
|
+
transport: ProviderExecutionTransport;
|
|
24
|
+
reason:
|
|
25
|
+
| "cli-provider"
|
|
26
|
+
| "custom-provider"
|
|
27
|
+
| "custom-server-proxy"
|
|
28
|
+
| "platform-agent"
|
|
29
|
+
| "forced-platform-env"
|
|
30
|
+
| "forced-direct-env"
|
|
31
|
+
| "direct-provider-env"
|
|
32
|
+
| "platform-proxy-fallback";
|
|
33
|
+
};
|
|
19
34
|
|
|
20
35
|
type ProviderExecutionPlanBase = {
|
|
21
36
|
mode: AgentProviderMode;
|
|
@@ -122,16 +137,50 @@ export function resolveAgentProviderMode(agentConfig: AgentRuntimeAgentConfig):
|
|
|
122
137
|
return "platform";
|
|
123
138
|
}
|
|
124
139
|
|
|
125
|
-
export function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
|
|
140
|
+
export function resolveAgentRuntimeLocation(args: {
|
|
141
|
+
agentConfig: AgentRuntimeAgentConfig;
|
|
142
|
+
runtimeKind: "local" | "desktop" | "server";
|
|
143
|
+
}): AgentRuntimeLocation {
|
|
144
|
+
const runtimeBinding = args.agentConfig.runtimeBinding;
|
|
145
|
+
const machineId = typeof runtimeBinding?.machineId === "string"
|
|
146
|
+
? runtimeBinding.machineId.trim()
|
|
147
|
+
: "";
|
|
148
|
+
if (machineId) return "bound-machine";
|
|
149
|
+
if (args.runtimeKind === "server") return "server";
|
|
150
|
+
return "local-host";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function resolveProviderTransportDecision(args: {
|
|
154
|
+
agentConfig: AgentRuntimeAgentConfig;
|
|
155
|
+
env: EnvLike;
|
|
156
|
+
runtimeLocation: AgentRuntimeLocation;
|
|
157
|
+
}): ProviderTransportDecision {
|
|
158
|
+
const mode = resolveAgentProviderMode(args.agentConfig);
|
|
159
|
+
if (mode === "cli") {
|
|
160
|
+
return { mode, transport: "direct", reason: "cli-provider" };
|
|
161
|
+
}
|
|
162
|
+
if (mode === "custom") {
|
|
163
|
+
if (args.runtimeLocation === "server" && args.agentConfig.useServerProxy === true) {
|
|
164
|
+
return { mode, transport: "proxy", reason: "custom-server-proxy" };
|
|
165
|
+
}
|
|
166
|
+
return { mode, transport: "direct", reason: "custom-provider" };
|
|
167
|
+
}
|
|
168
|
+
if (args.agentConfig.apiSource === "platform" || args.agentConfig.useServerProxy === true) {
|
|
169
|
+
return { mode, transport: "proxy", reason: "platform-agent" };
|
|
170
|
+
}
|
|
171
|
+
if (args.env.NOLO_LOCAL_LLM === "platform") {
|
|
172
|
+
return { mode, transport: "proxy", reason: "forced-platform-env" };
|
|
173
|
+
}
|
|
174
|
+
if (args.env.NOLO_LOCAL_LLM === "direct") {
|
|
175
|
+
return { mode, transport: "direct", reason: "forced-direct-env" };
|
|
176
|
+
}
|
|
177
|
+
if (hasDirectOpenAiCompatibleProvider(args.env)) {
|
|
178
|
+
return { mode, transport: "direct", reason: "direct-provider-env" };
|
|
179
|
+
}
|
|
180
|
+
if (canUsePlatformChatProvider(args.env)) {
|
|
181
|
+
return { mode, transport: "proxy", reason: "platform-proxy-fallback" };
|
|
182
|
+
}
|
|
183
|
+
return { mode, transport: "direct", reason: "direct-provider-env" };
|
|
135
184
|
}
|
|
136
185
|
|
|
137
186
|
export function resolveProviderAuthHeaderName(args: {
|
|
@@ -163,6 +212,15 @@ export function buildProviderExecutionPlan(args: {
|
|
|
163
212
|
}): ProviderExecutionPlan {
|
|
164
213
|
const { agentConfig, env } = args;
|
|
165
214
|
const mode = resolveAgentProviderMode(agentConfig);
|
|
215
|
+
const runtimeLocation = resolveAgentRuntimeLocation({
|
|
216
|
+
agentConfig,
|
|
217
|
+
runtimeKind: args.runtimeKind,
|
|
218
|
+
});
|
|
219
|
+
const transportDecision = resolveProviderTransportDecision({
|
|
220
|
+
agentConfig,
|
|
221
|
+
env,
|
|
222
|
+
runtimeLocation,
|
|
223
|
+
});
|
|
166
224
|
const model = agentConfig.model || "gpt-4.1-mini";
|
|
167
225
|
const requestOptions = pickAgentRuntimeInferenceOptions(agentConfig);
|
|
168
226
|
|
|
@@ -184,7 +242,7 @@ export function buildProviderExecutionPlan(args: {
|
|
|
184
242
|
endpoint,
|
|
185
243
|
apiKeyHeader: agentConfig.apiKeyHeader,
|
|
186
244
|
});
|
|
187
|
-
if (
|
|
245
|
+
if (transportDecision.transport === "proxy") {
|
|
188
246
|
return {
|
|
189
247
|
mode,
|
|
190
248
|
transport: "proxy",
|
|
@@ -213,10 +271,10 @@ export function buildProviderExecutionPlan(args: {
|
|
|
213
271
|
}
|
|
214
272
|
|
|
215
273
|
const provider = agentConfig.provider || agentConfig.apiSource || "openai";
|
|
216
|
-
const endpoint =
|
|
274
|
+
const endpoint = transportDecision.transport === "proxy"
|
|
217
275
|
? resolvePlatformProviderEndpoint(agentConfig)
|
|
218
276
|
: resolveChatCompletionsEndpoint(resolveOpenAiCompatibleBaseUrl(env));
|
|
219
|
-
if (
|
|
277
|
+
if (transportDecision.transport === "proxy") {
|
|
220
278
|
return {
|
|
221
279
|
mode,
|
|
222
280
|
transport: "proxy",
|
package/agentCommandSupport.ts
CHANGED
|
@@ -20,6 +20,10 @@ export type LocalCliExecutor = (
|
|
|
20
20
|
export type LocalRuntimeProbeResult = {
|
|
21
21
|
ok: boolean;
|
|
22
22
|
dbPath: string;
|
|
23
|
+
authorityDriver?: string;
|
|
24
|
+
authorityEndpoint?: string;
|
|
25
|
+
authorityMetadataPath?: string;
|
|
26
|
+
authorityHealthPath?: string;
|
|
23
27
|
agentFound: boolean;
|
|
24
28
|
agentKey?: string;
|
|
25
29
|
error?: string;
|
package/agentListCommands.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getReadableCliDb, type AgentCommandDeps } from "./agentCommandSupport";
|
|
2
2
|
import {
|
|
3
|
+
decorateAgentsWithPublicStatusAcrossServers,
|
|
3
4
|
listLocalCachedAgents,
|
|
5
|
+
listRemoteAgentsAcrossServers,
|
|
4
6
|
listRemoteAgents,
|
|
5
7
|
parseAgentListArgs,
|
|
6
8
|
type ListedAgent,
|
|
@@ -9,11 +11,15 @@ import {
|
|
|
9
11
|
queryUserRecords,
|
|
10
12
|
readDbRecord,
|
|
11
13
|
} from "./agentRecordHelpers";
|
|
14
|
+
import { buildSpaceLookup, getSpaceContentKeys } from "./cliSpaceHelpers";
|
|
12
15
|
import {
|
|
13
16
|
parseUserIdFromAuthToken,
|
|
17
|
+
readOption,
|
|
14
18
|
resolveAuthToken,
|
|
19
|
+
resolveServerCandidates,
|
|
15
20
|
resolveServerUrl,
|
|
16
21
|
} from "./cliEnvHelpers";
|
|
22
|
+
import { readLiveDbRecordAfterTombstoneMerge } from "./globalRecordOperations";
|
|
17
23
|
|
|
18
24
|
export async function runAgentListCommand(
|
|
19
25
|
args: string[],
|
|
@@ -22,6 +28,7 @@ export async function runAgentListCommand(
|
|
|
22
28
|
const env = deps.env ?? process.env;
|
|
23
29
|
const output = deps.output ?? process.stdout;
|
|
24
30
|
const { wantJson, publicOnly, idsOnly, includeLegacy } = parseAgentListArgs(args);
|
|
31
|
+
const spaceInput = readOption(args, "--space") ?? readOption(args, "--space-id");
|
|
25
32
|
|
|
26
33
|
const authToken = resolveAuthToken(args, env);
|
|
27
34
|
if (!authToken) {
|
|
@@ -35,34 +42,79 @@ export async function runAgentListCommand(
|
|
|
35
42
|
return 1;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
const db = deps.db ?? await getReadableCliDb(output);
|
|
39
45
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
40
46
|
const fallbackFetchImpl = deps.fallbackFetchImpl;
|
|
47
|
+
const serverUrl = resolveServerUrl(args, env);
|
|
48
|
+
const serverUrls = resolveServerCandidates(args, env, serverUrl);
|
|
41
49
|
|
|
42
50
|
try {
|
|
43
51
|
let agents: ListedAgent[];
|
|
44
|
-
let source: "local-cache" | "remote-cache";
|
|
52
|
+
let source: "local-cache" | "remote-cache" | "global-cache";
|
|
53
|
+
let serverFailures: Array<{ serverUrl: string; error: string }> = [];
|
|
45
54
|
try {
|
|
46
|
-
|
|
47
|
-
source = "local-cache";
|
|
48
|
-
} catch {
|
|
49
|
-
const serverUrl = resolveServerUrl(args, env);
|
|
50
|
-
agents = await listRemoteAgents({
|
|
55
|
+
const remoteResult = await listRemoteAgentsAcrossServers({
|
|
51
56
|
authToken,
|
|
52
57
|
fallbackFetchImpl,
|
|
53
58
|
fetchImpl,
|
|
54
59
|
includeLegacy,
|
|
55
|
-
|
|
60
|
+
serverUrls,
|
|
56
61
|
userId,
|
|
57
|
-
queryUserRecords,
|
|
58
|
-
readDbRecord,
|
|
59
62
|
});
|
|
60
|
-
|
|
63
|
+
agents = remoteResult.agents;
|
|
64
|
+
serverFailures = remoteResult.failures;
|
|
65
|
+
source = "global-cache";
|
|
66
|
+
} catch {
|
|
67
|
+
try {
|
|
68
|
+
const db = deps.db ?? await getReadableCliDb(output);
|
|
69
|
+
agents = await listLocalCachedAgents({ db, userId });
|
|
70
|
+
source = "local-cache";
|
|
71
|
+
} catch {
|
|
72
|
+
agents = await listRemoteAgents({
|
|
73
|
+
authToken,
|
|
74
|
+
fallbackFetchImpl,
|
|
75
|
+
fetchImpl,
|
|
76
|
+
includeLegacy,
|
|
77
|
+
serverUrl,
|
|
78
|
+
userId,
|
|
79
|
+
queryUserRecords,
|
|
80
|
+
readDbRecord,
|
|
81
|
+
});
|
|
82
|
+
source = "remote-cache";
|
|
83
|
+
}
|
|
61
84
|
}
|
|
62
85
|
|
|
63
86
|
if (!includeLegacy) {
|
|
64
87
|
agents = agents.filter((agent) => !agent.privateKey.startsWith("cybot-"));
|
|
65
88
|
}
|
|
89
|
+
let resolvedSpaceId: string | null = null;
|
|
90
|
+
if (spaceInput) {
|
|
91
|
+
const { spaceId, spaceKey } = buildSpaceLookup(spaceInput);
|
|
92
|
+
resolvedSpaceId = spaceId;
|
|
93
|
+
const spaceRead = await readLiveDbRecordAfterTombstoneMerge({
|
|
94
|
+
authToken,
|
|
95
|
+
dbKey: spaceKey,
|
|
96
|
+
fallbackFetchImpl,
|
|
97
|
+
fetchImpl,
|
|
98
|
+
serverUrls,
|
|
99
|
+
});
|
|
100
|
+
serverFailures = [...serverFailures, ...spaceRead.failures];
|
|
101
|
+
const spaceRecord = spaceRead.record;
|
|
102
|
+
const spaceContentKeys = getSpaceContentKeys(spaceRecord);
|
|
103
|
+
agents = agents.filter((agent) =>
|
|
104
|
+
spaceContentKeys.has(agent.privateKey) ||
|
|
105
|
+
spaceContentKeys.has(agent.publicKey) ||
|
|
106
|
+
spaceContentKeys.has(agent.id)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (source === "global-cache") {
|
|
110
|
+
await decorateAgentsWithPublicStatusAcrossServers({
|
|
111
|
+
agents,
|
|
112
|
+
authToken,
|
|
113
|
+
fallbackFetchImpl,
|
|
114
|
+
fetchImpl,
|
|
115
|
+
serverUrls,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
66
118
|
if (publicOnly) {
|
|
67
119
|
agents = agents.filter((agent) => agent.publicRecordExists);
|
|
68
120
|
}
|
|
@@ -75,6 +127,9 @@ export async function runAgentListCommand(
|
|
|
75
127
|
if (wantJson) {
|
|
76
128
|
output.write(JSON.stringify({
|
|
77
129
|
userId,
|
|
130
|
+
...(resolvedSpaceId ? { spaceId: resolvedSpaceId } : {}),
|
|
131
|
+
targetServers: serverUrls,
|
|
132
|
+
...(serverFailures.length ? { serverFailures } : {}),
|
|
78
133
|
total: agents.length,
|
|
79
134
|
publicCount: agents.filter((agent) => agent.publicRecordExists).length,
|
|
80
135
|
source,
|
|
@@ -85,6 +140,13 @@ export async function runAgentListCommand(
|
|
|
85
140
|
}
|
|
86
141
|
|
|
87
142
|
output.write(`userId: ${userId}\n`);
|
|
143
|
+
if (resolvedSpaceId) {
|
|
144
|
+
output.write(`spaceId: ${resolvedSpaceId}\n`);
|
|
145
|
+
}
|
|
146
|
+
output.write(`targetServers: ${serverUrls.join(", ")}\n`);
|
|
147
|
+
if (serverFailures.length) {
|
|
148
|
+
output.write(`serverFailures: ${serverFailures.length}\n`);
|
|
149
|
+
}
|
|
88
150
|
output.write(`total agents: ${agents.length}\n`);
|
|
89
151
|
output.write(`public agents: ${agents.filter((agent) => agent.publicRecordExists).length}\n`);
|
|
90
152
|
output.write(`source: ${source}\n`);
|
package/agentListHelpers.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { CliKvDb } from "./client/hybridRecordStore";
|
|
2
|
+
import {
|
|
3
|
+
listUserRecordsFromServers,
|
|
4
|
+
readLiveDbRecordAfterTombstoneMerge,
|
|
5
|
+
} from "./globalRecordOperations";
|
|
2
6
|
|
|
3
7
|
export type ListedAgent = {
|
|
4
8
|
id: string;
|
|
@@ -93,7 +97,7 @@ export async function listLocalCachedAgents(args: {
|
|
|
93
97
|
}) {
|
|
94
98
|
const privateRecords = new Map<string, any>();
|
|
95
99
|
const publicKeys = new Set<string>();
|
|
96
|
-
for await (const [key, value] of args.db.iterator()) {
|
|
100
|
+
for await (const [key, value] of args.db.iterator({ gte: "", lte: "\uffff" })) {
|
|
97
101
|
if (typeof key !== "string" || !value || typeof value !== "object") continue;
|
|
98
102
|
if (key.startsWith(`agent-${args.userId}-`) || key.startsWith(`cybot-${args.userId}-`)) {
|
|
99
103
|
privateRecords.set(key, { ...(value as Record<string, unknown>), dbKey: key });
|
|
@@ -185,3 +189,54 @@ export async function listRemoteAgents(args: {
|
|
|
185
189
|
);
|
|
186
190
|
return agents;
|
|
187
191
|
}
|
|
192
|
+
|
|
193
|
+
export async function listRemoteAgentsAcrossServers(args: {
|
|
194
|
+
authToken: string;
|
|
195
|
+
fallbackFetchImpl?: typeof fetch;
|
|
196
|
+
fetchImpl: typeof fetch;
|
|
197
|
+
includeLegacy: boolean;
|
|
198
|
+
serverUrls: string[];
|
|
199
|
+
userId: string;
|
|
200
|
+
}) {
|
|
201
|
+
const remoteResult = await listUserRecordsFromServers({
|
|
202
|
+
authToken: args.authToken,
|
|
203
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
204
|
+
fetchImpl: args.fetchImpl,
|
|
205
|
+
label: "agent query",
|
|
206
|
+
serverUrls: args.serverUrls,
|
|
207
|
+
type: args.includeLegacy ? ["agent", "cybot"] : "agent",
|
|
208
|
+
userId: args.userId,
|
|
209
|
+
});
|
|
210
|
+
const agents = sortListedAgents(
|
|
211
|
+
remoteResult.records
|
|
212
|
+
.map((record) => normalizeListedAgent(record))
|
|
213
|
+
.filter((agent): agent is ListedAgent => agent != null)
|
|
214
|
+
);
|
|
215
|
+
return { agents, failures: remoteResult.failures };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function decorateAgentsWithPublicStatusAcrossServers(args: {
|
|
219
|
+
agents: ListedAgent[];
|
|
220
|
+
authToken: string;
|
|
221
|
+
fallbackFetchImpl?: typeof fetch;
|
|
222
|
+
fetchImpl: typeof fetch;
|
|
223
|
+
serverUrls: string[];
|
|
224
|
+
}) {
|
|
225
|
+
await Promise.all(
|
|
226
|
+
args.agents.map(async (agent) => {
|
|
227
|
+
try {
|
|
228
|
+
const result = await readLiveDbRecordAfterTombstoneMerge({
|
|
229
|
+
authToken: args.authToken,
|
|
230
|
+
dbKey: agent.publicKey,
|
|
231
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
232
|
+
fetchImpl: args.fetchImpl,
|
|
233
|
+
serverUrls: args.serverUrls,
|
|
234
|
+
});
|
|
235
|
+
agent.publicRecordExists = result.record?.isPublic === true;
|
|
236
|
+
} catch {
|
|
237
|
+
agent.publicRecordExists = false;
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
return args.agents;
|
|
242
|
+
}
|
package/agentRecordHelpers.ts
CHANGED
|
@@ -125,10 +125,12 @@ export async function readDbRecord(args: {
|
|
|
125
125
|
authToken: string;
|
|
126
126
|
fallbackFetchImpl?: typeof fetch;
|
|
127
127
|
fetchImpl: typeof fetch;
|
|
128
|
+
includeDeleted?: boolean;
|
|
128
129
|
serverUrl: string;
|
|
129
130
|
}) {
|
|
131
|
+
const query = args.includeDeleted ? "?includeDeleted=true" : "";
|
|
130
132
|
const res = await fetchWithTransportFallback(
|
|
131
|
-
`${args.serverUrl}/api/v1/db/read/${encodeURIComponent(args.dbKey)}`,
|
|
133
|
+
`${args.serverUrl}/api/v1/db/read/${encodeURIComponent(args.dbKey)}${query}`,
|
|
132
134
|
{
|
|
133
135
|
method: "GET",
|
|
134
136
|
headers: { Authorization: `Bearer ${args.authToken}` },
|
|
@@ -146,19 +148,29 @@ export async function queryUserRecords(args: {
|
|
|
146
148
|
authToken: string;
|
|
147
149
|
fallbackFetchImpl?: typeof fetch;
|
|
148
150
|
fetchImpl: typeof fetch;
|
|
151
|
+
limit?: number;
|
|
149
152
|
serverUrl: string;
|
|
153
|
+
summary?: boolean;
|
|
154
|
+
includeDeleted?: boolean;
|
|
150
155
|
userId: string;
|
|
151
|
-
type:
|
|
152
|
-
}) {
|
|
156
|
+
type: string | string[];
|
|
157
|
+
}): Promise<any[]> {
|
|
158
|
+
const query = typeof args.limit === "number" && args.limit > 0
|
|
159
|
+
? `?limit=${Math.floor(args.limit)}`
|
|
160
|
+
: "";
|
|
153
161
|
const res = await fetchWithTransportFallback(
|
|
154
|
-
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(args.userId)}`,
|
|
162
|
+
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(args.userId)}${query}`,
|
|
155
163
|
{
|
|
156
164
|
method: "POST",
|
|
157
165
|
headers: {
|
|
158
166
|
Authorization: `Bearer ${args.authToken}`,
|
|
159
167
|
"Content-Type": "application/json",
|
|
160
168
|
},
|
|
161
|
-
body: JSON.stringify({
|
|
169
|
+
body: JSON.stringify({
|
|
170
|
+
type: args.type,
|
|
171
|
+
...(args.includeDeleted ? { includeDeleted: true } : {}),
|
|
172
|
+
...(args.summary ? { summary: true } : {}),
|
|
173
|
+
}),
|
|
162
174
|
},
|
|
163
175
|
args
|
|
164
176
|
);
|
|
@@ -173,6 +185,34 @@ export async function queryUserRecords(args: {
|
|
|
173
185
|
: [];
|
|
174
186
|
}
|
|
175
187
|
|
|
188
|
+
export async function deleteDbRecord(args: {
|
|
189
|
+
dbKey: string;
|
|
190
|
+
deleteOptions?: { type?: "single" | "table" | "messages" };
|
|
191
|
+
authToken: string;
|
|
192
|
+
fallbackFetchImpl?: typeof fetch;
|
|
193
|
+
fetchImpl: typeof fetch;
|
|
194
|
+
serverUrl: string;
|
|
195
|
+
}) {
|
|
196
|
+
const type = args.deleteOptions?.type;
|
|
197
|
+
const query =
|
|
198
|
+
type && type !== "single"
|
|
199
|
+
? `?type=${encodeURIComponent(type)}`
|
|
200
|
+
: "";
|
|
201
|
+
const res = await fetchWithTransportFallback(
|
|
202
|
+
`${args.serverUrl}/api/v1/db/delete/${encodeURIComponent(args.dbKey)}${query}`,
|
|
203
|
+
{
|
|
204
|
+
method: "DELETE",
|
|
205
|
+
headers: { Authorization: `Bearer ${args.authToken}` },
|
|
206
|
+
},
|
|
207
|
+
args
|
|
208
|
+
);
|
|
209
|
+
const data = await res.json().catch(() => ({}));
|
|
210
|
+
if (!res.ok) {
|
|
211
|
+
throw new Error(`delete failed: HTTP ${res.status} ${JSON.stringify(data)}`);
|
|
212
|
+
}
|
|
213
|
+
return data;
|
|
214
|
+
}
|
|
215
|
+
|
|
176
216
|
export async function writeAgentRecord(args: {
|
|
177
217
|
agentKey: string;
|
|
178
218
|
authToken: string;
|
|
@@ -20,6 +20,10 @@ export type LocalCliExecutor = (
|
|
|
20
20
|
export type LocalRuntimeProbeResult = {
|
|
21
21
|
ok: boolean;
|
|
22
22
|
dbPath: string;
|
|
23
|
+
authorityDriver?: string;
|
|
24
|
+
authorityEndpoint?: string;
|
|
25
|
+
authorityMetadataPath?: string;
|
|
26
|
+
authorityHealthPath?: string;
|
|
23
27
|
agentFound: boolean;
|
|
24
28
|
agentKey?: string;
|
|
25
29
|
error?: string;
|