@withone/cli 2.4.0 → 2.6.0
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 +13 -11
- package/dist/{chunk-6FA7KUNQ.js → chunk-4KX5ZERS.js} +797 -116
- package/dist/{chunk-7FPQOAQ4.js → chunk-O3HDWHHS.js} +5 -3
- package/dist/{chunk-XKUTG7JD.js → chunk-PUQKTRYC.js} +5 -3
- package/dist/chunk-Q6PWTATS.js +79 -0
- package/dist/{chunk-NOFJ4NYD.js → chunk-VMFWA43Q.js} +5 -77
- package/dist/{flow-runner-SFECNAO2.js → flow-runner-FME4AVVN.js} +2 -1
- package/dist/index.js +830 -1350
- package/dist/{migrate-3LSEIPRF.js → migrate-KWEEEQ3E.js} +3 -2
- package/dist/{schema-FICQRMZ7.js → schema-YJ7JTGFL.js} +5 -3
- package/dist/{sql-AKQSXRV2.js → sql-NDMMFQP6.js} +3 -2
- package/package.json +1 -1
- package/skills/one/SKILL.md +3 -1
package/dist/index.js
CHANGED
|
@@ -7,12 +7,21 @@ import {
|
|
|
7
7
|
TimeoutError,
|
|
8
8
|
clearAll,
|
|
9
9
|
clearEntry,
|
|
10
|
+
cliVersion,
|
|
11
|
+
collectInstallContext,
|
|
12
|
+
describeInstallContext,
|
|
13
|
+
drainQueue,
|
|
10
14
|
flowRequiresBash,
|
|
15
|
+
flush,
|
|
16
|
+
flushUsageRollups,
|
|
11
17
|
formatAge,
|
|
12
18
|
generateFlowGuide,
|
|
13
19
|
getAge,
|
|
20
|
+
getAgentStatuses,
|
|
14
21
|
getNestedStepsKeys,
|
|
15
22
|
getStepTypeDescriptor,
|
|
23
|
+
installContextToParams,
|
|
24
|
+
installMcpConfig,
|
|
16
25
|
isActionAllowed,
|
|
17
26
|
isFresh,
|
|
18
27
|
isMethodAllowed,
|
|
@@ -21,17 +30,19 @@ import {
|
|
|
21
30
|
listFlows,
|
|
22
31
|
loadFlowWithMeta,
|
|
23
32
|
makeCacheEntry,
|
|
33
|
+
maybeShowTelemetryNotice,
|
|
24
34
|
readCache,
|
|
35
|
+
recordCommand,
|
|
25
36
|
resolveActionDetails,
|
|
26
37
|
resolveFlowPath,
|
|
27
38
|
saveFlow,
|
|
28
39
|
validateActionInput,
|
|
29
40
|
walkSteps,
|
|
30
41
|
writeCache
|
|
31
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-4KX5ZERS.js";
|
|
32
43
|
import {
|
|
33
44
|
memSqlCommand
|
|
34
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-O3HDWHHS.js";
|
|
35
46
|
import {
|
|
36
47
|
collectIdentityKeys,
|
|
37
48
|
countRecords,
|
|
@@ -62,20 +73,12 @@ import {
|
|
|
62
73
|
writeDraftProfile,
|
|
63
74
|
writePageToMemory,
|
|
64
75
|
writeProfile
|
|
65
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-PUQKTRYC.js";
|
|
66
77
|
import {
|
|
67
78
|
getByDotPath
|
|
68
79
|
} from "./chunk-44CV5IMX.js";
|
|
69
80
|
import {
|
|
70
|
-
cancel,
|
|
71
|
-
createSpinner,
|
|
72
|
-
error,
|
|
73
|
-
intro,
|
|
74
|
-
isAgentMode,
|
|
75
|
-
json,
|
|
76
|
-
note,
|
|
77
81
|
okJson,
|
|
78
|
-
outro,
|
|
79
82
|
parseCsv,
|
|
80
83
|
parseJsonArg,
|
|
81
84
|
parsePositiveInt,
|
|
@@ -83,10 +86,20 @@ import {
|
|
|
83
86
|
printRecord,
|
|
84
87
|
requireMemoryInit,
|
|
85
88
|
semanticSearchUpgradeHint,
|
|
86
|
-
semanticSearchUpgradeLine
|
|
89
|
+
semanticSearchUpgradeLine
|
|
90
|
+
} from "./chunk-VMFWA43Q.js";
|
|
91
|
+
import {
|
|
92
|
+
cancel,
|
|
93
|
+
createSpinner,
|
|
94
|
+
error,
|
|
95
|
+
intro,
|
|
96
|
+
isAgentMode,
|
|
97
|
+
json,
|
|
98
|
+
note,
|
|
99
|
+
outro,
|
|
87
100
|
setAgentMode,
|
|
88
101
|
silenceWarningsInAgentMode
|
|
89
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-Q6PWTATS.js";
|
|
90
103
|
import {
|
|
91
104
|
SCHEMA_VERSION,
|
|
92
105
|
addRecord,
|
|
@@ -108,16 +121,12 @@ import {
|
|
|
108
121
|
updateMemoryConfig
|
|
109
122
|
} from "./chunk-3HRC3IPE.js";
|
|
110
123
|
import {
|
|
111
|
-
appendAnalyticsQueue,
|
|
112
|
-
appendUsageLog,
|
|
113
|
-
claimUsageLog,
|
|
114
124
|
configExists,
|
|
115
125
|
ensureWhoAmI,
|
|
116
126
|
getAccessControl,
|
|
117
127
|
getAccessControlFromAllSources,
|
|
118
128
|
getApiBase,
|
|
119
129
|
getApiKey,
|
|
120
|
-
getDeviceId,
|
|
121
130
|
getEnvFromApiKey,
|
|
122
131
|
getGlobalConfigPath,
|
|
123
132
|
getOpenAiApiKey,
|
|
@@ -126,665 +135,32 @@ import {
|
|
|
126
135
|
getWhoAmI,
|
|
127
136
|
globalConfigExists,
|
|
128
137
|
homeDir,
|
|
129
|
-
markTelemetryNoticeShown,
|
|
130
138
|
projectConfigExists,
|
|
131
|
-
readAnalyticsQueue,
|
|
132
139
|
readConfig,
|
|
133
140
|
readGlobalConfig,
|
|
134
141
|
readProjectConfig,
|
|
135
|
-
readUsageState,
|
|
136
142
|
resolveConfig,
|
|
137
143
|
saveCredentials,
|
|
138
|
-
telemetryNoticeShown,
|
|
139
144
|
updateAccessControl,
|
|
140
145
|
updateApiBase,
|
|
141
146
|
updateWhoAmI,
|
|
142
|
-
|
|
143
|
-
writeConfig,
|
|
144
|
-
writeUsageLog,
|
|
145
|
-
writeUsageState
|
|
147
|
+
writeConfig
|
|
146
148
|
} from "./chunk-HTXZZQ6U.js";
|
|
147
149
|
|
|
148
150
|
// src/cli.ts
|
|
149
|
-
import { createRequire
|
|
150
|
-
import
|
|
151
|
+
import { createRequire } from "module";
|
|
152
|
+
import path12 from "path";
|
|
151
153
|
import { Command } from "commander";
|
|
152
154
|
|
|
153
155
|
// src/commands/init.ts
|
|
154
156
|
import * as p3 from "@clack/prompts";
|
|
155
|
-
import
|
|
156
|
-
import fs4 from "fs";
|
|
157
|
-
import path5 from "path";
|
|
158
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
159
|
-
|
|
160
|
-
// src/lib/agents.ts
|
|
161
|
-
import fs from "fs";
|
|
162
|
-
import path from "path";
|
|
163
|
-
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
164
|
-
function expandPath(p9) {
|
|
165
|
-
if (p9.startsWith("~/")) {
|
|
166
|
-
return path.join(homeDir(), p9.slice(2));
|
|
167
|
-
}
|
|
168
|
-
return p9;
|
|
169
|
-
}
|
|
170
|
-
function getClaudeDesktopConfigPath() {
|
|
171
|
-
switch (process.platform) {
|
|
172
|
-
case "darwin":
|
|
173
|
-
return "~/Library/Application Support/Claude/claude_desktop_config.json";
|
|
174
|
-
case "win32":
|
|
175
|
-
return path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
176
|
-
default:
|
|
177
|
-
return "~/.config/Claude/claude_desktop_config.json";
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function getClaudeDesktopDetectDir() {
|
|
181
|
-
switch (process.platform) {
|
|
182
|
-
case "darwin":
|
|
183
|
-
return "~/Library/Application Support/Claude";
|
|
184
|
-
case "win32":
|
|
185
|
-
return path.join(process.env.APPDATA || "", "Claude");
|
|
186
|
-
default:
|
|
187
|
-
return "~/.config/Claude";
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function getWindsurfConfigPath() {
|
|
191
|
-
if (process.platform === "win32") {
|
|
192
|
-
return path.join(homeDir(), ".codeium", "windsurf", "mcp_config.json");
|
|
193
|
-
}
|
|
194
|
-
return "~/.codeium/windsurf/mcp_config.json";
|
|
195
|
-
}
|
|
196
|
-
function getWindsurfDetectDir() {
|
|
197
|
-
if (process.platform === "win32") {
|
|
198
|
-
return path.join(homeDir(), ".codeium", "windsurf");
|
|
199
|
-
}
|
|
200
|
-
return "~/.codeium/windsurf";
|
|
201
|
-
}
|
|
202
|
-
function getCursorConfigPath() {
|
|
203
|
-
if (process.platform === "win32") {
|
|
204
|
-
return path.join(homeDir(), ".cursor", "mcp.json");
|
|
205
|
-
}
|
|
206
|
-
return "~/.cursor/mcp.json";
|
|
207
|
-
}
|
|
208
|
-
function getAgents() {
|
|
209
|
-
return [
|
|
210
|
-
{
|
|
211
|
-
id: "claude-code",
|
|
212
|
-
name: "Claude Code",
|
|
213
|
-
configPath: "~/.claude.json",
|
|
214
|
-
configKey: "mcpServers",
|
|
215
|
-
detectDir: "~/.claude",
|
|
216
|
-
projectConfigPath: ".mcp.json"
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
id: "claude-desktop",
|
|
220
|
-
name: "Claude Desktop",
|
|
221
|
-
configPath: getClaudeDesktopConfigPath(),
|
|
222
|
-
configKey: "mcpServers",
|
|
223
|
-
detectDir: getClaudeDesktopDetectDir()
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
id: "cursor",
|
|
227
|
-
name: "Cursor",
|
|
228
|
-
configPath: getCursorConfigPath(),
|
|
229
|
-
configKey: "mcpServers",
|
|
230
|
-
detectDir: "~/.cursor",
|
|
231
|
-
projectConfigPath: ".cursor/mcp.json"
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
id: "windsurf",
|
|
235
|
-
name: "Windsurf",
|
|
236
|
-
configPath: getWindsurfConfigPath(),
|
|
237
|
-
configKey: "mcpServers",
|
|
238
|
-
detectDir: getWindsurfDetectDir()
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
id: "codex",
|
|
242
|
-
name: "Codex",
|
|
243
|
-
configPath: "~/.codex/config.toml",
|
|
244
|
-
configKey: "mcp_servers",
|
|
245
|
-
detectDir: "~/.codex",
|
|
246
|
-
projectConfigPath: ".codex/config.toml",
|
|
247
|
-
configFormat: "toml"
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
id: "kiro",
|
|
251
|
-
name: "Kiro",
|
|
252
|
-
configPath: "~/.kiro/settings/mcp.json",
|
|
253
|
-
configKey: "mcpServers",
|
|
254
|
-
detectDir: "~/.kiro",
|
|
255
|
-
projectConfigPath: ".kiro/settings/mcp.json"
|
|
256
|
-
}
|
|
257
|
-
];
|
|
258
|
-
}
|
|
259
|
-
function detectInstalledAgents() {
|
|
260
|
-
return getAgents().filter((agent) => {
|
|
261
|
-
const detectDir = expandPath(agent.detectDir);
|
|
262
|
-
return fs.existsSync(detectDir);
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
function getAgentConfigPath(agent, scope = "global") {
|
|
266
|
-
if (scope === "project" && agent.projectConfigPath) {
|
|
267
|
-
return path.join(process.cwd(), agent.projectConfigPath);
|
|
268
|
-
}
|
|
269
|
-
return expandPath(agent.configPath);
|
|
270
|
-
}
|
|
271
|
-
function readAgentConfig(agent, scope = "global") {
|
|
272
|
-
const configPath = getAgentConfigPath(agent, scope);
|
|
273
|
-
if (!fs.existsSync(configPath)) {
|
|
274
|
-
return {};
|
|
275
|
-
}
|
|
276
|
-
try {
|
|
277
|
-
const content = fs.readFileSync(configPath, "utf-8");
|
|
278
|
-
if (agent.configFormat === "toml") {
|
|
279
|
-
return parseToml(content);
|
|
280
|
-
}
|
|
281
|
-
return JSON.parse(content);
|
|
282
|
-
} catch {
|
|
283
|
-
return {};
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
function writeAgentConfig(agent, config2, scope = "global") {
|
|
287
|
-
const configPath = getAgentConfigPath(agent, scope);
|
|
288
|
-
const configDir = path.dirname(configPath);
|
|
289
|
-
if (!fs.existsSync(configDir)) {
|
|
290
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
291
|
-
}
|
|
292
|
-
if (agent.configFormat === "toml") {
|
|
293
|
-
fs.writeFileSync(configPath, stringifyToml(config2));
|
|
294
|
-
} else {
|
|
295
|
-
fs.writeFileSync(configPath, JSON.stringify(config2, null, 2));
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
function getMcpServerConfig(apiKey, accessControl) {
|
|
299
|
-
const env = {
|
|
300
|
-
ONE_SECRET: apiKey
|
|
301
|
-
};
|
|
302
|
-
if (accessControl) {
|
|
303
|
-
if (accessControl.permissions && accessControl.permissions !== "admin") {
|
|
304
|
-
env.ONE_PERMISSIONS = accessControl.permissions;
|
|
305
|
-
}
|
|
306
|
-
if (accessControl.connectionKeys && !(accessControl.connectionKeys.length === 1 && accessControl.connectionKeys[0] === "*")) {
|
|
307
|
-
env.ONE_CONNECTION_KEYS = accessControl.connectionKeys.join(",");
|
|
308
|
-
}
|
|
309
|
-
if (accessControl.actionIds && !(accessControl.actionIds.length === 1 && accessControl.actionIds[0] === "*")) {
|
|
310
|
-
env.ONE_ACTION_IDS = accessControl.actionIds.join(",");
|
|
311
|
-
}
|
|
312
|
-
if (accessControl.knowledgeAgent) {
|
|
313
|
-
env.ONE_KNOWLEDGE_AGENT = "true";
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return {
|
|
317
|
-
command: "npx",
|
|
318
|
-
args: ["-y", "@withone/mcp"],
|
|
319
|
-
env
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
function installMcpConfig(agent, apiKey, scope = "global", accessControl) {
|
|
323
|
-
const config2 = readAgentConfig(agent, scope);
|
|
324
|
-
const configKey = agent.configKey;
|
|
325
|
-
const mcpServers = config2[configKey] || {};
|
|
326
|
-
mcpServers["one"] = getMcpServerConfig(apiKey, accessControl);
|
|
327
|
-
config2[configKey] = mcpServers;
|
|
328
|
-
writeAgentConfig(agent, config2, scope);
|
|
329
|
-
}
|
|
330
|
-
function isMcpInstalled(agent, scope = "global") {
|
|
331
|
-
const config2 = readAgentConfig(agent, scope);
|
|
332
|
-
const configKey = agent.configKey;
|
|
333
|
-
const mcpServers = config2[configKey];
|
|
334
|
-
return mcpServers?.["one"] !== void 0;
|
|
335
|
-
}
|
|
336
|
-
function getAgentStatuses() {
|
|
337
|
-
return getAgents().map((agent) => {
|
|
338
|
-
const detected = fs.existsSync(expandPath(agent.detectDir));
|
|
339
|
-
const globalMcp = detected && isMcpInstalled(agent, "global");
|
|
340
|
-
const projectMcp = agent.projectConfigPath ? isMcpInstalled(agent, "project") : null;
|
|
341
|
-
return { agent, detected, globalMcp, projectMcp };
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// src/lib/browser.ts
|
|
346
|
-
import open from "open";
|
|
347
|
-
|
|
348
|
-
// src/lib/install-context.ts
|
|
157
|
+
import pc3 from "picocolors";
|
|
349
158
|
import fs2 from "fs";
|
|
350
|
-
import os from "os";
|
|
351
|
-
import path3 from "path";
|
|
352
|
-
|
|
353
|
-
// src/lib/analytics.ts
|
|
354
|
-
import { createRequire as createRequire2 } from "module";
|
|
355
|
-
import { randomUUID, createHash } from "crypto";
|
|
356
|
-
import pc from "picocolors";
|
|
357
|
-
|
|
358
|
-
// src/lib/version.ts
|
|
359
|
-
import { createRequire } from "module";
|
|
360
|
-
import { existsSync } from "fs";
|
|
361
159
|
import path2 from "path";
|
|
362
|
-
import { fileURLToPath } from "url";
|
|
363
|
-
var require2 = createRequire(import.meta.url);
|
|
364
|
-
var cached = null;
|
|
365
|
-
function cliVersion() {
|
|
366
|
-
if (cached !== null) return cached;
|
|
367
|
-
const dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
368
|
-
for (let i = 1; i <= 4; i++) {
|
|
369
|
-
const candidate = path2.resolve(dir, ...Array(i).fill(".."), "package.json");
|
|
370
|
-
if (!existsSync(candidate)) continue;
|
|
371
|
-
try {
|
|
372
|
-
const version2 = require2(candidate).version;
|
|
373
|
-
if (version2) {
|
|
374
|
-
cached = version2;
|
|
375
|
-
return cached;
|
|
376
|
-
}
|
|
377
|
-
} catch {
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
cached = "unknown";
|
|
381
|
-
return cached;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// src/lib/analytics.ts
|
|
385
|
-
var require3 = createRequire2(import.meta.url);
|
|
386
|
-
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
387
|
-
var DEFAULT_POSTHOG_KEY = "phc_a9ok4w0uxiZcVoSWOISIlin85lHMXQD3vWPaYnuRlRV";
|
|
388
|
-
var SEND_MAX_ATTEMPTS = 3;
|
|
389
|
-
var QUEUE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
390
|
-
var EXIT_GRACE_MS = 300;
|
|
391
|
-
var inFlight = /* @__PURE__ */ new Set();
|
|
392
|
-
var pending = /* @__PURE__ */ new Set();
|
|
393
|
-
var dispatched = /* @__PURE__ */ new Set();
|
|
394
|
-
var delivered = /* @__PURE__ */ new Set();
|
|
395
|
-
var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
396
|
-
function uuidFromInsertId(insertId) {
|
|
397
|
-
if (UUID_SHAPE.test(insertId)) return insertId.toLowerCase();
|
|
398
|
-
const h = createHash("sha1").update(`one-cli-event:${insertId}`).digest("hex");
|
|
399
|
-
const variant = (parseInt(h[16], 16) & 3 | 8).toString(16);
|
|
400
|
-
return `${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
401
|
-
}
|
|
402
|
-
function posthogHost() {
|
|
403
|
-
return process.env.ONE_POSTHOG_HOST || DEFAULT_POSTHOG_HOST;
|
|
404
|
-
}
|
|
405
|
-
function posthogKey() {
|
|
406
|
-
return process.env.ONE_POSTHOG_KEY || DEFAULT_POSTHOG_KEY;
|
|
407
|
-
}
|
|
408
|
-
function envName() {
|
|
409
|
-
const key = getApiKey();
|
|
410
|
-
return key ? getEnvFromApiKey(key) : "live";
|
|
411
|
-
}
|
|
412
|
-
function isOn(value) {
|
|
413
|
-
return value === "1" || value === "true";
|
|
414
|
-
}
|
|
415
|
-
function debugLog(message) {
|
|
416
|
-
if (isOn(process.env.ONE_ANALYTICS_DEBUG)) {
|
|
417
|
-
process.stderr.write(`[analytics] ${message}
|
|
418
|
-
`);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function isTelemetryDisabled() {
|
|
422
|
-
if (isOn(process.env.ONE_NO_TELEMETRY) || isOn(process.env.ONE_DISABLE_TELEMETRY)) return true;
|
|
423
|
-
if (isOn(process.env.DO_NOT_TRACK)) return true;
|
|
424
|
-
if (isOn(process.env.CI)) return true;
|
|
425
|
-
if (readConfig()?.telemetry === "off") return true;
|
|
426
|
-
return false;
|
|
427
|
-
}
|
|
428
|
-
function distinctId() {
|
|
429
|
-
return getWhoAmI()?.user?.id ?? getDeviceId();
|
|
430
|
-
}
|
|
431
|
-
function isAuthenticated() {
|
|
432
|
-
return !!getWhoAmI()?.user || !!getApiKey();
|
|
433
|
-
}
|
|
434
|
-
function baseProperties() {
|
|
435
|
-
return {
|
|
436
|
-
$lib: "one-cli",
|
|
437
|
-
cli_version: cliVersion(),
|
|
438
|
-
agent_mode: isAgentMode(),
|
|
439
|
-
env: envName(),
|
|
440
|
-
os: process.platform,
|
|
441
|
-
arch: process.arch,
|
|
442
|
-
node_version: process.versions.node,
|
|
443
|
-
authenticated: isAuthenticated()
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
function personSet() {
|
|
447
|
-
const whoami = getWhoAmI();
|
|
448
|
-
if (!whoami?.user) return void 0;
|
|
449
|
-
const set = {};
|
|
450
|
-
if (whoami.user.email) set.email = whoami.user.email;
|
|
451
|
-
if (whoami.user.name) set.name = whoami.user.name;
|
|
452
|
-
if (whoami.organization?.id) set.organization_id = whoami.organization.id;
|
|
453
|
-
return Object.keys(set).length ? set : void 0;
|
|
454
|
-
}
|
|
455
|
-
function send(item) {
|
|
456
|
-
const insertId = item.properties.$insert_id;
|
|
457
|
-
if (insertId) dispatched.add(insertId);
|
|
458
|
-
const controller = new AbortController();
|
|
459
|
-
inFlight.add(controller);
|
|
460
|
-
const run = (async () => {
|
|
461
|
-
try {
|
|
462
|
-
const res = await fetch(`${posthogHost()}/i/v0/e/`, {
|
|
463
|
-
method: "POST",
|
|
464
|
-
headers: { "Content-Type": "application/json" },
|
|
465
|
-
body: JSON.stringify({
|
|
466
|
-
api_key: posthogKey(),
|
|
467
|
-
event: item.event,
|
|
468
|
-
distinct_id: item.distinct_id,
|
|
469
|
-
// PostHog's dedupe key — a re-sent copy is dropped on ingest.
|
|
470
|
-
uuid: item.uuid ?? (insertId ? uuidFromInsertId(insertId) : void 0),
|
|
471
|
-
properties: item.properties,
|
|
472
|
-
timestamp: item.timestamp
|
|
473
|
-
}),
|
|
474
|
-
signal: controller.signal
|
|
475
|
-
});
|
|
476
|
-
if (res.ok && insertId) delivered.add(insertId);
|
|
477
|
-
debugLog(`"${item.event}" -> HTTP ${res.status}${res.ok ? "" : " (retry next run)"}`);
|
|
478
|
-
} catch (err) {
|
|
479
|
-
debugLog(`"${item.event}" not sent: ${err instanceof Error ? err.message : String(err)} (retry next run)`);
|
|
480
|
-
} finally {
|
|
481
|
-
inFlight.delete(controller);
|
|
482
|
-
}
|
|
483
|
-
})();
|
|
484
|
-
pending.add(run);
|
|
485
|
-
void run.finally(() => pending.delete(run));
|
|
486
|
-
}
|
|
487
|
-
function capture(event, properties = {}, opts = {}) {
|
|
488
|
-
if (isTelemetryDisabled()) {
|
|
489
|
-
debugLog(`disabled \u2014 skipping "${event}"`);
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
const did = opts.distinctId ?? distinctId();
|
|
493
|
-
const props = { ...baseProperties(), ...properties };
|
|
494
|
-
if (props.$insert_id === void 0) props.$insert_id = randomUUID();
|
|
495
|
-
const insertId = props.$insert_id;
|
|
496
|
-
if (opts.personProfile === false) {
|
|
497
|
-
props.$process_person_profile = false;
|
|
498
|
-
} else if (did === distinctId()) {
|
|
499
|
-
const set = personSet();
|
|
500
|
-
if (set) props.$set = set;
|
|
501
|
-
}
|
|
502
|
-
const item = {
|
|
503
|
-
event,
|
|
504
|
-
distinct_id: did,
|
|
505
|
-
properties: props,
|
|
506
|
-
timestamp: opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
507
|
-
uuid: uuidFromInsertId(insertId)
|
|
508
|
-
};
|
|
509
|
-
appendAnalyticsQueue(JSON.stringify(item));
|
|
510
|
-
}
|
|
511
|
-
var ROLLUP_WINDOW_MS = 5 * 60 * 1e3;
|
|
512
|
-
var ROLLUP_MAX_BATCH = 500;
|
|
513
|
-
function utcDay(ts) {
|
|
514
|
-
return new Date(ts).toISOString().slice(0, 10);
|
|
515
|
-
}
|
|
516
|
-
var PRE_AUTH_COMMANDS = /* @__PURE__ */ new Set([
|
|
517
|
-
"init",
|
|
518
|
-
"login",
|
|
519
|
-
"logout",
|
|
520
|
-
"guide",
|
|
521
|
-
"platforms",
|
|
522
|
-
"onboard",
|
|
523
|
-
"config",
|
|
524
|
-
"update",
|
|
525
|
-
"help"
|
|
526
|
-
]);
|
|
527
|
-
function shouldRecord(commandPath2) {
|
|
528
|
-
if (isAuthenticated()) return true;
|
|
529
|
-
return PRE_AUTH_COMMANDS.has(commandPath2.split(" ")[0]);
|
|
530
|
-
}
|
|
531
|
-
function recordCommand(command) {
|
|
532
|
-
if (isTelemetryDisabled()) {
|
|
533
|
-
writeUsageLog([]);
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
const cmdPath = commandPath(command);
|
|
537
|
-
if (!shouldRecord(cmdPath)) return;
|
|
538
|
-
const did = distinctId();
|
|
539
|
-
const entry = { ts: Date.now(), command: cmdPath, agent: isAgentMode(), did };
|
|
540
|
-
appendUsageLog(JSON.stringify(entry));
|
|
541
|
-
const today = utcDay(entry.ts);
|
|
542
|
-
const state = readUsageState();
|
|
543
|
-
const firstTouch = state.lastDay !== today || state.distinctId !== did;
|
|
544
|
-
flushUsageRollups({ force: firstTouch });
|
|
545
|
-
if (firstTouch) writeUsageState({ lastDay: today, distinctId: did });
|
|
546
|
-
}
|
|
547
|
-
function flushUsageRollups(opts = {}) {
|
|
548
|
-
if (isTelemetryDisabled()) {
|
|
549
|
-
writeUsageLog([]);
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
const lines = claimUsageLog();
|
|
553
|
-
if (!lines || lines.length === 0) return;
|
|
554
|
-
const entries = [];
|
|
555
|
-
for (const line of lines) {
|
|
556
|
-
try {
|
|
557
|
-
const e = JSON.parse(line);
|
|
558
|
-
if (e && typeof e.ts === "number" && typeof e.command === "string" && typeof e.did === "string") {
|
|
559
|
-
entries.push(e);
|
|
560
|
-
}
|
|
561
|
-
} catch {
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (entries.length === 0) return;
|
|
565
|
-
const currentDid = entries[entries.length - 1].did;
|
|
566
|
-
const now = Date.now();
|
|
567
|
-
const groups = /* @__PURE__ */ new Map();
|
|
568
|
-
for (const e of entries) {
|
|
569
|
-
const g = groups.get(e.did);
|
|
570
|
-
if (g) g.push(e);
|
|
571
|
-
else groups.set(e.did, [e]);
|
|
572
|
-
}
|
|
573
|
-
const kept = [];
|
|
574
|
-
for (const [did, group] of groups) {
|
|
575
|
-
const due = opts.force === true || did !== currentDid || // a superseded login's batch — flush it now
|
|
576
|
-
group.length >= ROLLUP_MAX_BATCH || now - group[0].ts >= ROLLUP_WINDOW_MS;
|
|
577
|
-
if (due) emitRollup(did, group);
|
|
578
|
-
else kept.push(...group);
|
|
579
|
-
}
|
|
580
|
-
for (const e of kept) appendUsageLog(JSON.stringify(e));
|
|
581
|
-
}
|
|
582
|
-
function emitRollup(did, group) {
|
|
583
|
-
const byCommand = {};
|
|
584
|
-
let agentCount = 0;
|
|
585
|
-
for (const e of group) {
|
|
586
|
-
byCommand[e.command] = (byCommand[e.command] ?? 0) + 1;
|
|
587
|
-
if (e.agent) agentCount += 1;
|
|
588
|
-
}
|
|
589
|
-
const insertId = createHash("sha1").update(`${did}|${group.map((e) => `${e.ts}:${e.command}:${e.agent ? 1 : 0}`).join("|")}`).digest("hex");
|
|
590
|
-
capture(
|
|
591
|
-
"CLI Usage Rollup",
|
|
592
|
-
{
|
|
593
|
-
command_count: group.length,
|
|
594
|
-
by_command: byCommand,
|
|
595
|
-
agent_count: agentCount,
|
|
596
|
-
human_count: group.length - agentCount,
|
|
597
|
-
window_start: new Date(group[0].ts).toISOString(),
|
|
598
|
-
window_end: new Date(group[group.length - 1].ts).toISOString(),
|
|
599
|
-
$insert_id: insertId
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
distinctId: did,
|
|
603
|
-
timestamp: new Date(group[group.length - 1].ts).toISOString(),
|
|
604
|
-
// Rollups bill at the anonymous rate; the person already exists.
|
|
605
|
-
personProfile: false
|
|
606
|
-
}
|
|
607
|
-
);
|
|
608
|
-
debugLog(`rollup \u2014 ${group.length} command(s) for ${did}`);
|
|
609
|
-
}
|
|
610
|
-
function commandPath(command) {
|
|
611
|
-
const parts = [];
|
|
612
|
-
let current = command;
|
|
613
|
-
while (current && current.name() && current.name() !== "one") {
|
|
614
|
-
parts.unshift(current.name());
|
|
615
|
-
current = current.parent;
|
|
616
|
-
}
|
|
617
|
-
return parts.join(" ") || command.name();
|
|
618
|
-
}
|
|
619
|
-
function drainQueue() {
|
|
620
|
-
if (isTelemetryDisabled()) {
|
|
621
|
-
writeAnalyticsQueue([]);
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
const now = Date.now();
|
|
625
|
-
const kept = [];
|
|
626
|
-
let changed = false;
|
|
627
|
-
for (const line of readAnalyticsQueue()) {
|
|
628
|
-
let item;
|
|
629
|
-
try {
|
|
630
|
-
item = JSON.parse(line);
|
|
631
|
-
} catch {
|
|
632
|
-
changed = true;
|
|
633
|
-
continue;
|
|
634
|
-
}
|
|
635
|
-
const insertId = item?.properties?.$insert_id;
|
|
636
|
-
if (!insertId) {
|
|
637
|
-
changed = true;
|
|
638
|
-
continue;
|
|
639
|
-
}
|
|
640
|
-
const age = now - Date.parse(item.timestamp);
|
|
641
|
-
const attempts = item.attempts ?? 0;
|
|
642
|
-
if (!(age < QUEUE_MAX_AGE_MS) || attempts >= SEND_MAX_ATTEMPTS) {
|
|
643
|
-
debugLog(`"${item.event}" dropped (${attempts} attempts, ${Math.round(age / 6e4)} min old)`);
|
|
644
|
-
changed = true;
|
|
645
|
-
continue;
|
|
646
|
-
}
|
|
647
|
-
if (dispatched.has(insertId)) {
|
|
648
|
-
kept.push(line);
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
item.attempts = attempts + 1;
|
|
652
|
-
if (!item.uuid) item.uuid = uuidFromInsertId(insertId);
|
|
653
|
-
kept.push(JSON.stringify(item));
|
|
654
|
-
changed = true;
|
|
655
|
-
send(item);
|
|
656
|
-
}
|
|
657
|
-
if (changed) writeAnalyticsQueue(kept);
|
|
658
|
-
}
|
|
659
|
-
async function flush() {
|
|
660
|
-
if (pending.size > 0) {
|
|
661
|
-
await Promise.race([
|
|
662
|
-
Promise.allSettled([...pending]),
|
|
663
|
-
new Promise((resolve) => setTimeout(resolve, EXIT_GRACE_MS))
|
|
664
|
-
]);
|
|
665
|
-
}
|
|
666
|
-
for (const controller of inFlight) controller.abort();
|
|
667
|
-
const remaining = readAnalyticsQueue().filter((line) => {
|
|
668
|
-
try {
|
|
669
|
-
const item = JSON.parse(line);
|
|
670
|
-
const id = item.properties?.$insert_id;
|
|
671
|
-
if (!id || delivered.has(id)) return false;
|
|
672
|
-
return (item.attempts ?? 0) < SEND_MAX_ATTEMPTS;
|
|
673
|
-
} catch {
|
|
674
|
-
return false;
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
writeAnalyticsQueue(remaining);
|
|
678
|
-
dispatched.clear();
|
|
679
|
-
delivered.clear();
|
|
680
|
-
}
|
|
681
|
-
function maybeShowTelemetryNotice() {
|
|
682
|
-
if (isTelemetryDisabled() || isAgentMode()) return;
|
|
683
|
-
if (telemetryNoticeShown()) return;
|
|
684
|
-
markTelemetryNoticeShown();
|
|
685
|
-
process.stderr.write(
|
|
686
|
-
pc.dim(
|
|
687
|
-
"One CLI collects usage analytics (which commands run, linked to your One account) to improve the product.\nNo arguments, inputs, or secrets are ever collected. Opt out anytime with ONE_NO_TELEMETRY=1.\n"
|
|
688
|
-
)
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// src/lib/install-context.ts
|
|
693
|
-
var EXTRA_HARNESS_DIRS = [
|
|
694
|
-
{ id: "gemini-cli", dir: ".gemini" },
|
|
695
|
-
{ id: "openclaw", dir: ".openclaw" },
|
|
696
|
-
{ id: "hermes", dir: ".hermes" },
|
|
697
|
-
{ id: "devin", dir: ".devin" }
|
|
698
|
-
];
|
|
699
|
-
var LAUNCHER_ENV = [
|
|
700
|
-
{ id: "claude-code", vars: ["CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT"] },
|
|
701
|
-
{ id: "codex", vars: ["CODEX_SANDBOX", "CODEX_CI", "CODEX_THREAD_ID"] },
|
|
702
|
-
{ id: "gemini-cli", vars: ["GEMINI_CLI"] },
|
|
703
|
-
// CURSOR_TRACE_ID is deliberately absent: Cursor exports it into every
|
|
704
|
-
// integrated-terminal shell, so it marks the editor, not an agent.
|
|
705
|
-
{ id: "cursor", vars: ["CURSOR_AGENT"] },
|
|
706
|
-
{ id: "windsurf", vars: ["WINDSURF_AGENT"] },
|
|
707
|
-
{ id: "kiro", vars: ["KIRO_AGENT"] },
|
|
708
|
-
{ id: "openclaw", vars: ["OPENCLAW_AGENT", "OPENCLAW_SESSION"] },
|
|
709
|
-
{ id: "hermes", vars: ["HERMES_AGENT", "HERMES_SESSION"] },
|
|
710
|
-
{ id: "devin", vars: ["DEVIN_SESSION_ID"] }
|
|
711
|
-
];
|
|
712
|
-
function detectLauncher(env = process.env) {
|
|
713
|
-
for (const entry of LAUNCHER_ENV) {
|
|
714
|
-
if (entry.vars.some((v) => env[v] !== void 0 && env[v] !== "")) return entry.id;
|
|
715
|
-
}
|
|
716
|
-
return void 0;
|
|
717
|
-
}
|
|
718
|
-
function detectInstalledHarnesses() {
|
|
719
|
-
const ids = new Set(detectInstalledAgents().map((a) => a.id));
|
|
720
|
-
for (const { id, dir } of EXTRA_HARNESS_DIRS) {
|
|
721
|
-
if (fs2.existsSync(path3.join(homeDir(), dir))) ids.add(id);
|
|
722
|
-
}
|
|
723
|
-
return [...ids].sort();
|
|
724
|
-
}
|
|
725
|
-
function tryRead(read) {
|
|
726
|
-
try {
|
|
727
|
-
const value = read();
|
|
728
|
-
return value === null || value === "" ? void 0 : value;
|
|
729
|
-
} catch {
|
|
730
|
-
return void 0;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
function collectInstallContext(opts) {
|
|
734
|
-
const env = opts.env ?? process.env;
|
|
735
|
-
const ctx = {
|
|
736
|
-
scope: opts.scope,
|
|
737
|
-
harnesses: tryRead(() => detectInstalledHarnesses()) ?? []
|
|
738
|
-
};
|
|
739
|
-
if (opts.scope === "project") {
|
|
740
|
-
ctx.path = opts.projectRoot ?? tryRead(() => getProjectRoot());
|
|
741
|
-
}
|
|
742
|
-
ctx.host = tryRead(() => os.hostname());
|
|
743
|
-
ctx.os = process.platform;
|
|
744
|
-
ctx.osVersion = tryRead(() => os.release());
|
|
745
|
-
ctx.arch = process.arch;
|
|
746
|
-
ctx.user = tryRead(() => os.userInfo().username);
|
|
747
|
-
if (!isTelemetryDisabled()) ctx.device = tryRead(() => getDeviceId());
|
|
748
|
-
const cli = tryRead(() => cliVersion());
|
|
749
|
-
ctx.cli = cli === "unknown" ? void 0 : cli;
|
|
750
|
-
ctx.launcher = detectLauncher(env);
|
|
751
|
-
return ctx;
|
|
752
|
-
}
|
|
753
|
-
function installContextToParams(ctx) {
|
|
754
|
-
const params = new URLSearchParams();
|
|
755
|
-
const set = (key, value) => {
|
|
756
|
-
if (value !== void 0 && value !== "") params.set(key, value);
|
|
757
|
-
};
|
|
758
|
-
set("scope", ctx.scope);
|
|
759
|
-
set("path", ctx.path);
|
|
760
|
-
set("host", ctx.host);
|
|
761
|
-
set("os", ctx.os);
|
|
762
|
-
set("osv", ctx.osVersion);
|
|
763
|
-
set("arch", ctx.arch);
|
|
764
|
-
set("user", ctx.user);
|
|
765
|
-
set("device", ctx.device);
|
|
766
|
-
set("cli", ctx.cli);
|
|
767
|
-
if (ctx.harnesses.length > 0) params.set("harnesses", ctx.harnesses.join(","));
|
|
768
|
-
set("launcher", ctx.launcher);
|
|
769
|
-
return params;
|
|
770
|
-
}
|
|
771
|
-
function describeInstallContext(ctx) {
|
|
772
|
-
const lines = [`scope: ${ctx.scope}`];
|
|
773
|
-
if (ctx.path) lines.push(`path: ${ctx.path}`);
|
|
774
|
-
if (ctx.host || ctx.os) {
|
|
775
|
-
const osPart = [ctx.os, ctx.osVersion].filter(Boolean).join(" ");
|
|
776
|
-
const detail = [osPart, ctx.arch].filter(Boolean).join(", ");
|
|
777
|
-
lines.push(`machine: ${ctx.host ?? "unknown"}${detail ? ` (${detail})` : ""}`);
|
|
778
|
-
}
|
|
779
|
-
if (ctx.user) lines.push(`user: ${ctx.user}`);
|
|
780
|
-
if (ctx.device) lines.push(`device: ${ctx.device}`);
|
|
781
|
-
if (ctx.harnesses.length > 0) lines.push(`harnesses: ${ctx.harnesses.join(", ")}`);
|
|
782
|
-
if (ctx.launcher) lines.push(`launched by: ${ctx.launcher}`);
|
|
783
|
-
if (ctx.cli) lines.push(`cli: ${ctx.cli}`);
|
|
784
|
-
return lines.join("\n");
|
|
785
|
-
}
|
|
160
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
786
161
|
|
|
787
162
|
// src/lib/browser.ts
|
|
163
|
+
import open from "open";
|
|
788
164
|
var DEFAULT_APP_URL = "https://app.withone.ai";
|
|
789
165
|
function oneAppUrl() {
|
|
790
166
|
const override = process.env.ONE_APP_URL?.trim();
|
|
@@ -818,25 +194,25 @@ function getCliAuthUrl(port, state, context) {
|
|
|
818
194
|
|
|
819
195
|
// src/commands/config.ts
|
|
820
196
|
import * as p from "@clack/prompts";
|
|
821
|
-
import
|
|
197
|
+
import pc from "picocolors";
|
|
822
198
|
async function configCommand() {
|
|
823
199
|
if (isAgentMode()) {
|
|
824
200
|
error("This command requires interactive input. Run without --agent.");
|
|
825
201
|
}
|
|
826
202
|
const config2 = readConfig();
|
|
827
203
|
if (!config2) {
|
|
828
|
-
p.log.error(`No One config found. Run ${
|
|
204
|
+
p.log.error(`No One config found. Run ${pc.cyan("one init")} first.`);
|
|
829
205
|
return;
|
|
830
206
|
}
|
|
831
|
-
p.intro(
|
|
207
|
+
p.intro(pc.bgCyan(pc.black(" One Access Control ")));
|
|
832
208
|
const current = getAccessControl();
|
|
833
209
|
console.log();
|
|
834
|
-
console.log(` ${
|
|
835
|
-
console.log(` ${
|
|
836
|
-
console.log(` ${
|
|
837
|
-
console.log(` ${
|
|
838
|
-
console.log(` ${
|
|
839
|
-
console.log(` ${
|
|
210
|
+
console.log(` ${pc.bold("Current Access Control")}`);
|
|
211
|
+
console.log(` ${pc.dim("\u2500".repeat(42))}`);
|
|
212
|
+
console.log(` ${pc.dim("Permissions:")} ${current.permissions ?? "admin"}`);
|
|
213
|
+
console.log(` ${pc.dim("Connections:")} ${formatList(current.connectionKeys)}`);
|
|
214
|
+
console.log(` ${pc.dim("Action IDs:")} ${formatList(current.actionIds)}`);
|
|
215
|
+
console.log(` ${pc.dim("Knowledge only:")} ${current.knowledgeAgent ? "yes" : "no"}`);
|
|
840
216
|
console.log();
|
|
841
217
|
const permissions = await p.select({
|
|
842
218
|
message: "Permission level",
|
|
@@ -871,7 +247,7 @@ async function configCommand() {
|
|
|
871
247
|
return;
|
|
872
248
|
}
|
|
873
249
|
if (connectionKeys.length === 0) {
|
|
874
|
-
p.log.info(`No connections found. Defaulting to all. Use ${
|
|
250
|
+
p.log.info(`No connections found. Defaulting to all. Use ${pc.cyan("one add")} to connect platforms.`);
|
|
875
251
|
connectionKeys = void 0;
|
|
876
252
|
}
|
|
877
253
|
}
|
|
@@ -948,7 +324,7 @@ async function configCommand() {
|
|
|
948
324
|
}
|
|
949
325
|
const normalized = customUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
950
326
|
const apiKey = await p.text({
|
|
951
|
-
message: `Enter your API key for ${
|
|
327
|
+
message: `Enter your API key for ${pc.cyan(normalized)}:`,
|
|
952
328
|
placeholder: "sk_live_...",
|
|
953
329
|
validate: (value) => {
|
|
954
330
|
if (!value) return "API key is required";
|
|
@@ -971,12 +347,12 @@ async function configCommand() {
|
|
|
971
347
|
} catch (err) {
|
|
972
348
|
spinner.stop("Connection failed");
|
|
973
349
|
const msg = err instanceof Error ? err.message : String(err);
|
|
974
|
-
p.log.error(`Could not reach ${
|
|
350
|
+
p.log.error(`Could not reach ${pc.cyan(normalized)}: ${msg}`);
|
|
975
351
|
return;
|
|
976
352
|
}
|
|
977
353
|
if (!isValid) {
|
|
978
354
|
spinner.stop("Invalid API key");
|
|
979
|
-
p.log.error(`Invalid API key for ${
|
|
355
|
+
p.log.error(`Invalid API key for ${pc.cyan(normalized)}.`);
|
|
980
356
|
return;
|
|
981
357
|
}
|
|
982
358
|
spinner.stop("API key validated");
|
|
@@ -984,7 +360,7 @@ async function configCommand() {
|
|
|
984
360
|
newApiKey = apiKey;
|
|
985
361
|
} else if (isCustomBase) {
|
|
986
362
|
const apiKey = await p.text({
|
|
987
|
-
message: `Enter your API key for ${
|
|
363
|
+
message: `Enter your API key for ${pc.cyan("https://api.withone.ai")}:`,
|
|
988
364
|
placeholder: "sk_live_...",
|
|
989
365
|
validate: (value) => {
|
|
990
366
|
if (!value) return "API key is required";
|
|
@@ -1007,7 +383,7 @@ async function configCommand() {
|
|
|
1007
383
|
} catch (err) {
|
|
1008
384
|
spinner.stop("Connection failed");
|
|
1009
385
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1010
|
-
p.log.error(`Could not reach ${
|
|
386
|
+
p.log.error(`Could not reach ${pc.cyan("https://api.withone.ai")}: ${msg}`);
|
|
1011
387
|
return;
|
|
1012
388
|
}
|
|
1013
389
|
if (!isValid) {
|
|
@@ -1098,15 +474,15 @@ function formatList(list) {
|
|
|
1098
474
|
import open3 from "open";
|
|
1099
475
|
|
|
1100
476
|
// src/lib/skill-sync.ts
|
|
1101
|
-
import
|
|
1102
|
-
import
|
|
1103
|
-
import { fileURLToPath
|
|
477
|
+
import fs from "fs";
|
|
478
|
+
import path from "path";
|
|
479
|
+
import { fileURLToPath } from "url";
|
|
1104
480
|
|
|
1105
481
|
// src/commands/update.ts
|
|
1106
482
|
import { spawn } from "child_process";
|
|
1107
|
-
import { existsSync
|
|
483
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, openSync, closeSync } from "fs";
|
|
1108
484
|
import { delimiter, dirname, join } from "path";
|
|
1109
|
-
import
|
|
485
|
+
import pc2 from "picocolors";
|
|
1110
486
|
var currentVersion = cliVersion();
|
|
1111
487
|
var ONE_DIR = () => join(homeDir(), ".one");
|
|
1112
488
|
var CACHE_PATH = () => join(ONE_DIR(), "update-check.json");
|
|
@@ -1165,7 +541,7 @@ function resolveNpmBin(nodeExecPath = process.execPath) {
|
|
|
1165
541
|
const name = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
1166
542
|
try {
|
|
1167
543
|
const sibling = join(dirname(nodeExecPath), name);
|
|
1168
|
-
if (
|
|
544
|
+
if (existsSync(sibling)) return sibling;
|
|
1169
545
|
} catch {
|
|
1170
546
|
}
|
|
1171
547
|
return name;
|
|
@@ -1282,10 +658,10 @@ function maybeWarnAboutFailedUpdates(targetVersion) {
|
|
|
1282
658
|
if (!shouldWarnAboutFailedUpdates(state)) return;
|
|
1283
659
|
writeAutoUpdateState({ ...state, lastNoticeAt: Date.now() });
|
|
1284
660
|
process.stderr.write(
|
|
1285
|
-
|
|
661
|
+
pc2.yellow(
|
|
1286
662
|
`One CLI could not auto-update (v${currentVersion} \u2192 v${targetVersion}) after ${state.failures} attempts.
|
|
1287
663
|
`
|
|
1288
|
-
) +
|
|
664
|
+
) + pc2.dim(
|
|
1289
665
|
`Update manually with: npm install -g @withone/cli@latest
|
|
1290
666
|
Details: ${LOG_PATH()}. Silence this with ONE_NO_AUTO_UPDATE=1.
|
|
1291
667
|
`
|
|
@@ -1382,42 +758,42 @@ function autoUpdate(targetVersion, publishedAt) {
|
|
|
1382
758
|
var CANONICAL_SKILL_DIR = ".agents/skills";
|
|
1383
759
|
var VERSION_MARKER = ".one-cli-version";
|
|
1384
760
|
function getPackagedSkillDir() {
|
|
1385
|
-
const here =
|
|
1386
|
-
return
|
|
761
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
762
|
+
return path.resolve(here, "..", "skills", "one");
|
|
1387
763
|
}
|
|
1388
764
|
function getCanonicalSkillPath() {
|
|
1389
|
-
return
|
|
765
|
+
return path.join(homeDir(), CANONICAL_SKILL_DIR, "one");
|
|
1390
766
|
}
|
|
1391
767
|
function getVersionMarkerPath() {
|
|
1392
|
-
return
|
|
768
|
+
return path.join(getCanonicalSkillPath(), VERSION_MARKER);
|
|
1393
769
|
}
|
|
1394
770
|
function isSkillInstalled() {
|
|
1395
|
-
return
|
|
771
|
+
return fs.existsSync(path.join(getCanonicalSkillPath(), "SKILL.md"));
|
|
1396
772
|
}
|
|
1397
773
|
function readInstalledSkillVersion() {
|
|
1398
774
|
try {
|
|
1399
|
-
return
|
|
775
|
+
return fs.readFileSync(getVersionMarkerPath(), "utf-8").trim() || null;
|
|
1400
776
|
} catch {
|
|
1401
777
|
return null;
|
|
1402
778
|
}
|
|
1403
779
|
}
|
|
1404
780
|
function writeInstalledSkillVersion(version2) {
|
|
1405
781
|
try {
|
|
1406
|
-
|
|
1407
|
-
|
|
782
|
+
fs.mkdirSync(getCanonicalSkillPath(), { recursive: true });
|
|
783
|
+
fs.writeFileSync(getVersionMarkerPath(), `${version2}
|
|
1408
784
|
`);
|
|
1409
785
|
} catch {
|
|
1410
786
|
}
|
|
1411
787
|
}
|
|
1412
788
|
function copyDirSync(src, dest) {
|
|
1413
|
-
|
|
1414
|
-
for (const entry of
|
|
1415
|
-
const srcPath =
|
|
1416
|
-
const destPath =
|
|
789
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
790
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
791
|
+
const srcPath = path.join(src, entry.name);
|
|
792
|
+
const destPath = path.join(dest, entry.name);
|
|
1417
793
|
if (entry.isDirectory()) {
|
|
1418
794
|
copyDirSync(srcPath, destPath);
|
|
1419
795
|
} else {
|
|
1420
|
-
|
|
796
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1421
797
|
}
|
|
1422
798
|
}
|
|
1423
799
|
}
|
|
@@ -1440,7 +816,7 @@ function forceSyncSkills() {
|
|
|
1440
816
|
}
|
|
1441
817
|
function performSync(current, reason) {
|
|
1442
818
|
const source = getPackagedSkillDir();
|
|
1443
|
-
if (!
|
|
819
|
+
if (!fs.existsSync(path.join(source, "SKILL.md"))) {
|
|
1444
820
|
return { synced: false, reason: "source-missing" };
|
|
1445
821
|
}
|
|
1446
822
|
const canonical = getCanonicalSkillPath();
|
|
@@ -1686,25 +1062,25 @@ async function loginCommand() {
|
|
|
1686
1062
|
let targetScope = "global";
|
|
1687
1063
|
const existingKey = getApiKey();
|
|
1688
1064
|
if (existingKey) {
|
|
1689
|
-
const
|
|
1065
|
+
const pc17 = (await import("picocolors")).default;
|
|
1690
1066
|
const resolved = resolveConfig();
|
|
1691
1067
|
const whoami2 = resolved.config?.whoami;
|
|
1692
1068
|
const env2 = getEnvFromApiKey(existingKey);
|
|
1693
|
-
const envLabel2 = env2 === "test" ?
|
|
1694
|
-
const currentScope = resolved.scope === "project" ?
|
|
1069
|
+
const envLabel2 = env2 === "test" ? pc17.yellow("test") : pc17.green("live");
|
|
1070
|
+
const currentScope = resolved.scope === "project" ? pc17.cyan("local config") : pc17.magenta("global config");
|
|
1695
1071
|
const lines = ["You are already logged in.", ""];
|
|
1696
1072
|
if (whoami2) {
|
|
1697
1073
|
const contextParts2 = [];
|
|
1698
1074
|
if (whoami2.organization) contextParts2.push(whoami2.organization.name);
|
|
1699
1075
|
if (whoami2.project) contextParts2.push(whoami2.project.name);
|
|
1700
1076
|
const scopeDisplay2 = contextParts2.length > 0 ? contextParts2.join(" / ") : "Personal";
|
|
1701
|
-
lines.push(`${
|
|
1702
|
-
lines.push(`${whoami2.user.name} ${
|
|
1703
|
-
if (whoami2.organization) lines.push(`${
|
|
1704
|
-
if (whoami2.project) lines.push(`${
|
|
1077
|
+
lines.push(`${pc17.bold(scopeDisplay2)} ${pc17.dim("\xB7")} ${envLabel2}`);
|
|
1078
|
+
lines.push(`${whoami2.user.name} ${pc17.dim(`(${whoami2.user.email})`)}`);
|
|
1079
|
+
if (whoami2.organization) lines.push(`${pc17.dim("Org:")} ${whoami2.organization.name}`);
|
|
1080
|
+
if (whoami2.project) lines.push(`${pc17.dim("Project:")} ${whoami2.project.name}`);
|
|
1705
1081
|
}
|
|
1706
1082
|
lines.push("");
|
|
1707
|
-
lines.push(`${
|
|
1083
|
+
lines.push(`${pc17.dim("Stored in")} ${currentScope}`);
|
|
1708
1084
|
p2.note(lines.join("\n"));
|
|
1709
1085
|
const scopeChoice = await p2.select({
|
|
1710
1086
|
message: "Where would you like to log in?",
|
|
@@ -1723,42 +1099,42 @@ async function loginCommand() {
|
|
|
1723
1099
|
if (!result) return;
|
|
1724
1100
|
const { apiKey, whoami, keyName, grant, knowledgeOnly } = result;
|
|
1725
1101
|
saveCredentials(apiKey, targetScope, { keyName, whoami, knowledgeOnly });
|
|
1726
|
-
const
|
|
1102
|
+
const pc16 = (await import("picocolors")).default;
|
|
1727
1103
|
const env = getEnvFromApiKey(apiKey);
|
|
1728
1104
|
const contextParts = [];
|
|
1729
1105
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
1730
1106
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
1731
1107
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1732
|
-
const envLabel = env === "test" ?
|
|
1733
|
-
const configLabel = targetScope === "project" ?
|
|
1108
|
+
const envLabel = env === "test" ? pc16.yellow("test") : pc16.green("live");
|
|
1109
|
+
const configLabel = targetScope === "project" ? pc16.cyan("local config") : pc16.magenta("global config");
|
|
1734
1110
|
const infoLines = [
|
|
1735
|
-
`${
|
|
1736
|
-
`${whoami.user.name} ${
|
|
1111
|
+
`${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`,
|
|
1112
|
+
`${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`
|
|
1737
1113
|
];
|
|
1738
|
-
if (keyName) infoLines.push(`${
|
|
1739
|
-
infoLines.push(...grantNoteLines(grant,
|
|
1740
|
-
if (whoami.organization) infoLines.push(`${
|
|
1741
|
-
if (whoami.project) infoLines.push(`${
|
|
1114
|
+
if (keyName) infoLines.push(`${pc16.dim("Key:")} ${keyName}`);
|
|
1115
|
+
infoLines.push(...grantNoteLines(grant, pc16.dim("Access:")));
|
|
1116
|
+
if (whoami.organization) infoLines.push(`${pc16.dim("Org:")} ${whoami.organization.name}`);
|
|
1117
|
+
if (whoami.project) infoLines.push(`${pc16.dim("Project:")} ${whoami.project.name}`);
|
|
1742
1118
|
infoLines.push("");
|
|
1743
|
-
infoLines.push(`${
|
|
1119
|
+
infoLines.push(`${pc16.dim("Stored in")} ${configLabel}`);
|
|
1744
1120
|
p2.note(infoLines.join("\n"), "Logged in");
|
|
1745
1121
|
console.log();
|
|
1746
|
-
console.log(` ${
|
|
1747
|
-
console.log(` ${
|
|
1122
|
+
console.log(` ${pc16.dim("Next steps:")}`);
|
|
1123
|
+
console.log(` ${pc16.cyan("one add <platform>")} ${pc16.dim("\u2014")} Connect a platform (e.g. gmail, slack, stripe)`);
|
|
1748
1124
|
console.log();
|
|
1749
|
-
console.log(
|
|
1125
|
+
console.log(pc16.bold(" Copy-paste this to your AI agent:"));
|
|
1750
1126
|
console.log();
|
|
1751
|
-
console.log(
|
|
1752
|
-
console.log(
|
|
1753
|
-
console.log(
|
|
1754
|
-
console.log(
|
|
1755
|
-
console.log(
|
|
1756
|
-
console.log(
|
|
1757
|
-
console.log(
|
|
1758
|
-
console.log(
|
|
1759
|
-
console.log(
|
|
1760
|
-
console.log(
|
|
1761
|
-
console.log(
|
|
1127
|
+
console.log(pc16.cyan(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1128
|
+
console.log(pc16.cyan(" \u2502"));
|
|
1129
|
+
console.log(pc16.cyan(" \u2502 The One CLI (`one`) is now installed on this machine. It"));
|
|
1130
|
+
console.log(pc16.cyan(" \u2502 lets you interact with 750+ third-party platforms (Gmail,"));
|
|
1131
|
+
console.log(pc16.cyan(" \u2502 Slack, Shopify, HubSpot, Stripe, GitHub, etc.) through"));
|
|
1132
|
+
console.log(pc16.cyan(" \u2502 their APIs. Whenever you need to interact with any"));
|
|
1133
|
+
console.log(pc16.cyan(" \u2502 third-party platform or external service, use the `one`"));
|
|
1134
|
+
console.log(pc16.cyan(" \u2502 skill. Please save this to your project instructions or"));
|
|
1135
|
+
console.log(pc16.cyan(" \u2502 memory so you remember it in future conversations."));
|
|
1136
|
+
console.log(pc16.cyan(" \u2502"));
|
|
1137
|
+
console.log(pc16.cyan(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1762
1138
|
console.log();
|
|
1763
1139
|
p2.outro("Happy building!");
|
|
1764
1140
|
}
|
|
@@ -1862,20 +1238,20 @@ async function nonInteractiveInit(options) {
|
|
|
1862
1238
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
1863
1239
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
1864
1240
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1865
|
-
const envLabel = env === "test" ?
|
|
1241
|
+
const envLabel = env === "test" ? pc3.yellow("test") : pc3.green("live");
|
|
1866
1242
|
console.log();
|
|
1867
|
-
console.log(` ${
|
|
1868
|
-
console.log(` ${
|
|
1869
|
-
console.log(` ${
|
|
1870
|
-
console.log(` ${
|
|
1871
|
-
if (keyName) console.log(` ${
|
|
1872
|
-
if (grant) console.log(` ${
|
|
1873
|
-
console.log(` ${
|
|
1243
|
+
console.log(` ${pc3.bold("Setup complete")} ${scopeLabel(scope)}`);
|
|
1244
|
+
console.log(` ${pc3.dim("\u2500".repeat(42))}`);
|
|
1245
|
+
console.log(` ${pc3.dim("Account:")} ${scopeDisplay} ${pc3.dim("\xB7")} ${envLabel}`);
|
|
1246
|
+
console.log(` ${pc3.dim("User:")} ${whoami.user.name} ${pc3.dim(`(${whoami.user.email})`)}`);
|
|
1247
|
+
if (keyName) console.log(` ${pc3.dim("Key:")} ${keyName}`);
|
|
1248
|
+
if (grant) console.log(` ${pc3.dim("Access:")} ${grant}`);
|
|
1249
|
+
console.log(` ${pc3.dim("Config:")} ${tildify(configPath)}`);
|
|
1874
1250
|
if (installed.length > 0) {
|
|
1875
|
-
console.log(` ${
|
|
1251
|
+
console.log(` ${pc3.dim("Skill:")} ${pc3.green("installed")} ${pc3.dim("\xB7 " + installed.join(", "))}`);
|
|
1876
1252
|
}
|
|
1877
1253
|
console.log();
|
|
1878
|
-
console.log(` ${
|
|
1254
|
+
console.log(` ${pc3.dim("Connect a platform later with")} ${pc3.cyan("one add <platform>")}`);
|
|
1879
1255
|
printOnboardingPrompt();
|
|
1880
1256
|
}
|
|
1881
1257
|
async function chooseConfigScope(options) {
|
|
@@ -1885,13 +1261,13 @@ async function chooseConfigScope(options) {
|
|
|
1885
1261
|
const hasGlobal = globalConfigExists();
|
|
1886
1262
|
const hasProject = projectConfigExists();
|
|
1887
1263
|
const projectRoot = resolved.projectRoot;
|
|
1888
|
-
const projectName =
|
|
1264
|
+
const projectName = path2.basename(projectRoot);
|
|
1889
1265
|
const homeGlobal = tildify(getGlobalConfigPath());
|
|
1890
1266
|
const homeProject = tildify(getProjectConfigPath(projectRoot));
|
|
1891
1267
|
if (hasProject) {
|
|
1892
1268
|
console.log();
|
|
1893
|
-
console.log(` ${
|
|
1894
|
-
console.log(` ${
|
|
1269
|
+
console.log(` ${pc3.dim("Project:")} ${projectName} ${pc3.dim(projectRoot)}`);
|
|
1270
|
+
console.log(` ${pc3.bold("Active config:")} ${pc3.cyan("project")} ${pc3.dim("\xB7 " + homeProject)}`);
|
|
1895
1271
|
console.log();
|
|
1896
1272
|
if (hasGlobal) {
|
|
1897
1273
|
const which2 = await p3.select({
|
|
@@ -1908,11 +1284,11 @@ async function chooseConfigScope(options) {
|
|
|
1908
1284
|
return "project";
|
|
1909
1285
|
}
|
|
1910
1286
|
console.log();
|
|
1911
|
-
console.log(` ${
|
|
1912
|
-
console.log(` ${
|
|
1913
|
-
console.log(` ${
|
|
1914
|
-
console.log(` ${
|
|
1915
|
-
console.log(` ${
|
|
1287
|
+
console.log(` ${pc3.bold("Initializing One")}`);
|
|
1288
|
+
console.log(` ${pc3.dim("\u2500".repeat(42))}`);
|
|
1289
|
+
console.log(` ${pc3.dim("Project:")} ${projectName} ${pc3.dim(projectRoot)}`);
|
|
1290
|
+
console.log(` ${pc3.dim("Global:")} ${hasGlobal ? pc3.green("\u2713 configured") : pc3.yellow("\u2014 not set up")} ${pc3.dim(homeGlobal)}`);
|
|
1291
|
+
console.log(` ${pc3.dim("Project:")} ${pc3.yellow("\u2014 not set up")} ${pc3.dim(homeProject)}`);
|
|
1916
1292
|
console.log();
|
|
1917
1293
|
const defaultScope = hasGlobal ? "project" : "global";
|
|
1918
1294
|
const hint = hasGlobal ? "Your global config stays as-is. This folder gets its own setup." : "No global config yet \u2014 this becomes your default for every folder.";
|
|
@@ -1941,7 +1317,7 @@ function tildify(filePath) {
|
|
|
1941
1317
|
return filePath.startsWith(home) ? "~" + filePath.slice(home.length) : filePath;
|
|
1942
1318
|
}
|
|
1943
1319
|
function scopeLabel(scope) {
|
|
1944
|
-
return scope === "project" ?
|
|
1320
|
+
return scope === "project" ? pc3.cyan("[project]") : pc3.magenta("[global]");
|
|
1945
1321
|
}
|
|
1946
1322
|
function scopedMessage(scope, message) {
|
|
1947
1323
|
return `${scopeLabel(scope)} ${message}`;
|
|
@@ -1952,20 +1328,20 @@ async function handleExistingConfig(apiKey, scope, options) {
|
|
|
1952
1328
|
const skillInstalled = isSkillInstalled2();
|
|
1953
1329
|
const activeConfigPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
|
|
1954
1330
|
console.log();
|
|
1955
|
-
console.log(` ${
|
|
1956
|
-
console.log(` ${
|
|
1957
|
-
console.log(` ${
|
|
1958
|
-
console.log(` ${
|
|
1959
|
-
console.log(` ${
|
|
1331
|
+
console.log(` ${pc3.bold("Current Setup")} ${scopeLabel(scope)}`);
|
|
1332
|
+
console.log(` ${pc3.dim("\u2500".repeat(42))}`);
|
|
1333
|
+
console.log(` ${pc3.dim("API Key:")} ${masked}`);
|
|
1334
|
+
console.log(` ${pc3.dim("Skill:")} ${skillInstalled ? pc3.green("installed") : pc3.yellow("not installed")}`);
|
|
1335
|
+
console.log(` ${pc3.dim("Config:")} ${tildify(activeConfigPath)}`);
|
|
1960
1336
|
const ac = getAccessControl();
|
|
1961
1337
|
if (Object.keys(ac).length > 0) {
|
|
1962
1338
|
console.log();
|
|
1963
|
-
console.log(` ${
|
|
1964
|
-
console.log(` ${
|
|
1965
|
-
if (ac.permissions) console.log(` ${
|
|
1966
|
-
if (ac.connectionKeys) console.log(` ${
|
|
1967
|
-
if (ac.actionIds) console.log(` ${
|
|
1968
|
-
if (ac.knowledgeAgent) console.log(` ${
|
|
1339
|
+
console.log(` ${pc3.bold("Access Control")}`);
|
|
1340
|
+
console.log(` ${pc3.dim("\u2500".repeat(42))}`);
|
|
1341
|
+
if (ac.permissions) console.log(` ${pc3.dim("Permissions:")} ${ac.permissions}`);
|
|
1342
|
+
if (ac.connectionKeys) console.log(` ${pc3.dim("Connections:")} ${ac.connectionKeys.join(", ")}`);
|
|
1343
|
+
if (ac.actionIds) console.log(` ${pc3.dim("Action IDs:")} ${ac.actionIds.join(", ")}`);
|
|
1344
|
+
if (ac.knowledgeAgent) console.log(` ${pc3.dim("Knowledge only:")} yes`);
|
|
1969
1345
|
}
|
|
1970
1346
|
console.log();
|
|
1971
1347
|
const actionOptions = [];
|
|
@@ -2081,7 +1457,7 @@ async function handleUpdateKey(statuses, scope) {
|
|
|
2081
1457
|
whoamiResult = result.whoami;
|
|
2082
1458
|
} else {
|
|
2083
1459
|
p3.note(`Get your API key at:
|
|
2084
|
-
${
|
|
1460
|
+
${pc3.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
2085
1461
|
const openBrowser = await p3.confirm({
|
|
2086
1462
|
message: scopedMessage(scope, "Open browser to get API key?"),
|
|
2087
1463
|
initialValue: true
|
|
@@ -2126,13 +1502,13 @@ ${pc4.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
2126
1502
|
if (whoamiResult.organization) contextParts.push(whoamiResult.organization.name);
|
|
2127
1503
|
if (whoamiResult.project) contextParts.push(whoamiResult.project.name);
|
|
2128
1504
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
2129
|
-
const envLabel = env === "test" ?
|
|
1505
|
+
const envLabel = env === "test" ? pc3.yellow("test") : pc3.green("live");
|
|
2130
1506
|
p3.note(
|
|
2131
1507
|
[
|
|
2132
|
-
`${scopeDisplay} ${
|
|
2133
|
-
`${whoamiResult.user.name} ${
|
|
2134
|
-
...keyName ? [`${
|
|
2135
|
-
...grantNoteLines(grant,
|
|
1508
|
+
`${scopeDisplay} ${pc3.dim("\xB7")} ${envLabel}`,
|
|
1509
|
+
`${whoamiResult.user.name} ${pc3.dim(`(${whoamiResult.user.email})`)}`,
|
|
1510
|
+
...keyName ? [`${pc3.dim("Key:")} ${keyName}`] : [],
|
|
1511
|
+
...grantNoteLines(grant, pc3.dim("Access:"))
|
|
2136
1512
|
].join("\n"),
|
|
2137
1513
|
"Account"
|
|
2138
1514
|
);
|
|
@@ -2168,30 +1544,30 @@ var SKILL_AGENTS = [
|
|
|
2168
1544
|
];
|
|
2169
1545
|
var CANONICAL_SKILL_DIR2 = ".agents/skills";
|
|
2170
1546
|
function getSkillSourceDir() {
|
|
2171
|
-
const __dirname2 =
|
|
2172
|
-
return
|
|
1547
|
+
const __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
|
|
1548
|
+
return path2.resolve(__dirname2, "..", "skills", "one");
|
|
2173
1549
|
}
|
|
2174
1550
|
function getCanonicalSkillPath2() {
|
|
2175
|
-
return
|
|
1551
|
+
return path2.join(homeDir(), CANONICAL_SKILL_DIR2, "one");
|
|
2176
1552
|
}
|
|
2177
1553
|
function getAgentSkillPath(agent) {
|
|
2178
|
-
return
|
|
1554
|
+
return path2.join(homeDir(), agent.skillDir, "one");
|
|
2179
1555
|
}
|
|
2180
1556
|
function isSkillInstalled2() {
|
|
2181
|
-
return
|
|
1557
|
+
return fs2.existsSync(path2.join(getCanonicalSkillPath2(), "SKILL.md"));
|
|
2182
1558
|
}
|
|
2183
1559
|
function isSkillInstalledForAgent(agent) {
|
|
2184
|
-
return
|
|
1560
|
+
return fs2.existsSync(path2.join(getAgentSkillPath(agent), "SKILL.md"));
|
|
2185
1561
|
}
|
|
2186
1562
|
function copyDirSync2(src, dest) {
|
|
2187
|
-
|
|
2188
|
-
for (const entry of
|
|
2189
|
-
const srcPath =
|
|
2190
|
-
const destPath =
|
|
1563
|
+
fs2.mkdirSync(dest, { recursive: true });
|
|
1564
|
+
for (const entry of fs2.readdirSync(src, { withFileTypes: true })) {
|
|
1565
|
+
const srcPath = path2.join(src, entry.name);
|
|
1566
|
+
const destPath = path2.join(dest, entry.name);
|
|
2191
1567
|
if (entry.isDirectory()) {
|
|
2192
1568
|
copyDirSync2(srcPath, destPath);
|
|
2193
1569
|
} else {
|
|
2194
|
-
|
|
1570
|
+
fs2.copyFileSync(srcPath, destPath);
|
|
2195
1571
|
}
|
|
2196
1572
|
}
|
|
2197
1573
|
}
|
|
@@ -2200,12 +1576,12 @@ function installSkillForAgents(agentIds) {
|
|
|
2200
1576
|
const canonical = getCanonicalSkillPath2();
|
|
2201
1577
|
const installed = [];
|
|
2202
1578
|
const failed = [];
|
|
2203
|
-
if (!
|
|
1579
|
+
if (!fs2.existsSync(path2.join(source, "SKILL.md"))) {
|
|
2204
1580
|
return { installed: [], failed: ["skill source not found"] };
|
|
2205
1581
|
}
|
|
2206
1582
|
try {
|
|
2207
|
-
if (
|
|
2208
|
-
|
|
1583
|
+
if (fs2.existsSync(canonical)) {
|
|
1584
|
+
fs2.rmSync(canonical, { recursive: true });
|
|
2209
1585
|
}
|
|
2210
1586
|
copyDirSync2(source, canonical);
|
|
2211
1587
|
writeInstalledSkillVersion(getCurrentVersion());
|
|
@@ -2222,15 +1598,15 @@ function installSkillForAgents(agentIds) {
|
|
|
2222
1598
|
continue;
|
|
2223
1599
|
}
|
|
2224
1600
|
try {
|
|
2225
|
-
const agentSkillsDir =
|
|
2226
|
-
|
|
1601
|
+
const agentSkillsDir = path2.dirname(agentPath);
|
|
1602
|
+
fs2.mkdirSync(agentSkillsDir, { recursive: true });
|
|
2227
1603
|
try {
|
|
2228
|
-
|
|
2229
|
-
|
|
1604
|
+
fs2.lstatSync(agentPath);
|
|
1605
|
+
fs2.rmSync(agentPath, { recursive: true });
|
|
2230
1606
|
} catch {
|
|
2231
1607
|
}
|
|
2232
|
-
const relative =
|
|
2233
|
-
|
|
1608
|
+
const relative = path2.relative(agentSkillsDir, canonical);
|
|
1609
|
+
fs2.symlinkSync(relative, agentPath);
|
|
2234
1610
|
installed.push(agent.name);
|
|
2235
1611
|
seen.set(agentPath, true);
|
|
2236
1612
|
} catch {
|
|
@@ -2245,7 +1621,7 @@ async function promptOpenAiKey(scope) {
|
|
|
2245
1621
|
const entered = await p3.password({
|
|
2246
1622
|
message: scopedMessage(
|
|
2247
1623
|
scope,
|
|
2248
|
-
`OpenAI API key ${
|
|
1624
|
+
`OpenAI API key ${pc3.dim("(optional \u2014 enables semantic search in `one mem`)")}`
|
|
2249
1625
|
),
|
|
2250
1626
|
mask: "\u2022",
|
|
2251
1627
|
// Validator accepts empty → treated as "skip".
|
|
@@ -2300,7 +1676,7 @@ async function promptSkillInstall() {
|
|
|
2300
1676
|
...primaryAgents.map((a) => ({
|
|
2301
1677
|
value: a.id,
|
|
2302
1678
|
label: a.name,
|
|
2303
|
-
hint: isSkillInstalledForAgent(a) ?
|
|
1679
|
+
hint: isSkillInstalledForAgent(a) ? pc3.green("installed") : void 0
|
|
2304
1680
|
})),
|
|
2305
1681
|
{
|
|
2306
1682
|
value: "_other",
|
|
@@ -2324,7 +1700,7 @@ async function promptSkillInstall() {
|
|
|
2324
1700
|
options: otherAgents.map((a) => ({
|
|
2325
1701
|
value: a.id,
|
|
2326
1702
|
label: a.name,
|
|
2327
|
-
hint: isSkillInstalledForAgent(a) ?
|
|
1703
|
+
hint: isSkillInstalledForAgent(a) ? pc3.green("installed") : void 0
|
|
2328
1704
|
}))
|
|
2329
1705
|
});
|
|
2330
1706
|
if (!p3.isCancel(otherChoice)) {
|
|
@@ -2340,7 +1716,7 @@ async function promptSkillInstall() {
|
|
|
2340
1716
|
const { installed, failed } = installSkillForAgents(selectedIds);
|
|
2341
1717
|
spinner.stop(installed.length > 0 ? "Skill installed" : "Installation failed");
|
|
2342
1718
|
for (const name of installed) {
|
|
2343
|
-
p3.log.success(`${name}: ${
|
|
1719
|
+
p3.log.success(`${name}: ${pc3.green("\u2713")} skill installed`);
|
|
2344
1720
|
}
|
|
2345
1721
|
for (const name of failed) {
|
|
2346
1722
|
p3.log.warn(`${name}: failed to install`);
|
|
@@ -2349,19 +1725,19 @@ async function promptSkillInstall() {
|
|
|
2349
1725
|
}
|
|
2350
1726
|
function printOnboardingPrompt() {
|
|
2351
1727
|
console.log();
|
|
2352
|
-
console.log(
|
|
1728
|
+
console.log(pc3.bold(" Copy-paste this to your AI agent:"));
|
|
2353
1729
|
console.log();
|
|
2354
|
-
console.log(
|
|
2355
|
-
console.log(
|
|
2356
|
-
console.log(
|
|
2357
|
-
console.log(
|
|
2358
|
-
console.log(
|
|
2359
|
-
console.log(
|
|
2360
|
-
console.log(
|
|
2361
|
-
console.log(
|
|
2362
|
-
console.log(
|
|
2363
|
-
console.log(
|
|
2364
|
-
console.log(
|
|
1730
|
+
console.log(pc3.cyan(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1731
|
+
console.log(pc3.cyan(" \u2502"));
|
|
1732
|
+
console.log(pc3.cyan(" \u2502 The One CLI (`one`) is now installed on this machine. It"));
|
|
1733
|
+
console.log(pc3.cyan(" \u2502 lets you interact with 750+ third-party platforms (Gmail,"));
|
|
1734
|
+
console.log(pc3.cyan(" \u2502 Slack, Shopify, HubSpot, Stripe, GitHub, etc.) through"));
|
|
1735
|
+
console.log(pc3.cyan(" \u2502 their APIs. Whenever you need to interact with any"));
|
|
1736
|
+
console.log(pc3.cyan(" \u2502 third-party platform or external service, use the `one`"));
|
|
1737
|
+
console.log(pc3.cyan(" \u2502 skill. Please save this to your project instructions or"));
|
|
1738
|
+
console.log(pc3.cyan(" \u2502 memory so you remember it in future conversations."));
|
|
1739
|
+
console.log(pc3.cyan(" \u2502"));
|
|
1740
|
+
console.log(pc3.cyan(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
2365
1741
|
console.log();
|
|
2366
1742
|
}
|
|
2367
1743
|
async function freshSetup(scope, options) {
|
|
@@ -2389,13 +1765,13 @@ async function freshSetup(scope, options) {
|
|
|
2389
1765
|
if (result.whoami.organization) contextParts.push(result.whoami.organization.name);
|
|
2390
1766
|
if (result.whoami.project) contextParts.push(result.whoami.project.name);
|
|
2391
1767
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
2392
|
-
const envLabel = env2 === "test" ?
|
|
1768
|
+
const envLabel = env2 === "test" ? pc3.yellow("test") : pc3.green("live");
|
|
2393
1769
|
p3.note(
|
|
2394
1770
|
[
|
|
2395
|
-
`${scopeDisplay} ${
|
|
2396
|
-
`${result.whoami.user.name} ${
|
|
2397
|
-
...result.keyName ? [`${
|
|
2398
|
-
...grantNoteLines(result.grant,
|
|
1771
|
+
`${scopeDisplay} ${pc3.dim("\xB7")} ${envLabel}`,
|
|
1772
|
+
`${result.whoami.user.name} ${pc3.dim(`(${result.whoami.user.email})`)}`,
|
|
1773
|
+
...result.keyName ? [`${pc3.dim("Key:")} ${result.keyName}`] : [],
|
|
1774
|
+
...grantNoteLines(result.grant, pc3.dim("Access:"))
|
|
2399
1775
|
].join("\n"),
|
|
2400
1776
|
"Account"
|
|
2401
1777
|
);
|
|
@@ -2406,7 +1782,7 @@ async function freshSetup(scope, options) {
|
|
|
2406
1782
|
});
|
|
2407
1783
|
} else {
|
|
2408
1784
|
p3.note(`Get your API key at:
|
|
2409
|
-
${
|
|
1785
|
+
${pc3.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
2410
1786
|
const openBrowser = await p3.confirm({
|
|
2411
1787
|
message: scopedMessage(scope, "Open browser to get API key?"),
|
|
2412
1788
|
initialValue: true
|
|
@@ -2449,10 +1825,10 @@ ${pc4.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
2449
1825
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
2450
1826
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
2451
1827
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
2452
|
-
const envLabel = env2 === "test" ?
|
|
1828
|
+
const envLabel = env2 === "test" ? pc3.yellow("test") : pc3.green("live");
|
|
2453
1829
|
p3.note(
|
|
2454
|
-
`${scopeDisplay} ${
|
|
2455
|
-
${whoami.user.name} ${
|
|
1830
|
+
`${scopeDisplay} ${pc3.dim("\xB7")} ${envLabel}
|
|
1831
|
+
${whoami.user.name} ${pc3.dim(`(${whoami.user.email})`)}`,
|
|
2456
1832
|
"Account"
|
|
2457
1833
|
);
|
|
2458
1834
|
saveCredentials(apiKey, scope, { whoami });
|
|
@@ -2468,11 +1844,11 @@ ${whoami.user.name} ${pc4.dim(`(${whoami.user.email})`)}`,
|
|
|
2468
1844
|
};
|
|
2469
1845
|
await promptConnectIntegrations(apiKey, connParams);
|
|
2470
1846
|
const savedPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
|
|
2471
|
-
const resolutionHint = scope === "project" ? `When you run ${
|
|
1847
|
+
const resolutionHint = scope === "project" ? `When you run ${pc3.cyan("one")} from ${pc3.bold(path2.basename(getProjectRoot()))}, it uses this project config.
|
|
2472
1848
|
From anywhere else, it falls back to your global config.` : `This config applies to every folder unless a project config is set.`;
|
|
2473
1849
|
p3.note(
|
|
2474
1850
|
`${scopeLabel(scope)} Config saved to:
|
|
2475
|
-
${
|
|
1851
|
+
${pc3.dim(tildify(savedPath))}
|
|
2476
1852
|
|
|
2477
1853
|
${resolutionHint}`,
|
|
2478
1854
|
"Setup Complete"
|
|
@@ -2481,9 +1857,9 @@ ${resolutionHint}`,
|
|
|
2481
1857
|
p3.outro("Done! Paste the prompt above to your AI agent.");
|
|
2482
1858
|
}
|
|
2483
1859
|
function lime(text5) {
|
|
2484
|
-
if (!
|
|
1860
|
+
if (!pc3.isColorSupported) return text5;
|
|
2485
1861
|
const truecolor = process.env.COLORTERM === "truecolor" || process.env.COLORTERM === "24bit";
|
|
2486
|
-
return truecolor ? `\x1B[38;2;204;255;0m${text5}\x1B[39m` :
|
|
1862
|
+
return truecolor ? `\x1B[38;2;204;255;0m${text5}\x1B[39m` : pc3.green(text5);
|
|
2487
1863
|
}
|
|
2488
1864
|
function printBanner() {
|
|
2489
1865
|
console.log();
|
|
@@ -2498,7 +1874,7 @@ function printBanner() {
|
|
|
2498
1874
|
console.log(lime(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
2499
1875
|
console.log(lime(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
2500
1876
|
console.log();
|
|
2501
|
-
console.log(
|
|
1877
|
+
console.log(pc3.dim(" I N F R A S T R U C T U R E F O R A G E N T S"));
|
|
2502
1878
|
console.log();
|
|
2503
1879
|
}
|
|
2504
1880
|
var TOP_INTEGRATIONS = [
|
|
@@ -2544,13 +1920,13 @@ async function promptConnectIntegrations(apiKey, connParams) {
|
|
|
2544
1920
|
} catch {
|
|
2545
1921
|
p3.note(connectionsUrl, "Open in browser");
|
|
2546
1922
|
}
|
|
2547
|
-
p3.log.info(`Connect from the dashboard, or use ${
|
|
1923
|
+
p3.log.info(`Connect from the dashboard, or use ${pc3.cyan("one add <platform>")}`);
|
|
2548
1924
|
break;
|
|
2549
1925
|
}
|
|
2550
1926
|
const platform = choice;
|
|
2551
1927
|
const integration = TOP_INTEGRATIONS.find((i) => i.value === platform);
|
|
2552
1928
|
const label = integration?.label ?? platform;
|
|
2553
|
-
p3.log.info(`Opening browser to connect ${
|
|
1929
|
+
p3.log.info(`Opening browser to connect ${pc3.cyan(label)}...`);
|
|
2554
1930
|
try {
|
|
2555
1931
|
await openConnectionPage(platform, connParams);
|
|
2556
1932
|
} catch {
|
|
@@ -2563,13 +1939,13 @@ async function promptConnectIntegrations(apiKey, connParams) {
|
|
|
2563
1939
|
try {
|
|
2564
1940
|
await api.waitForConnection(platform, 5 * 60 * 1e3, 5e3);
|
|
2565
1941
|
spinner.stop(`${label} connected!`);
|
|
2566
|
-
p3.log.success(`${
|
|
1942
|
+
p3.log.success(`${pc3.green("\u2713")} ${label} is now available to your AI agents`);
|
|
2567
1943
|
connected.push(platform);
|
|
2568
1944
|
first = false;
|
|
2569
1945
|
} catch (error2) {
|
|
2570
1946
|
spinner.stop("Connection timed out");
|
|
2571
1947
|
if (error2 instanceof TimeoutError) {
|
|
2572
|
-
p3.log.warn(`No worries. Connect later with: ${
|
|
1948
|
+
p3.log.warn(`No worries. Connect later with: ${pc3.cyan(`one add ${platform}`)}`);
|
|
2573
1949
|
}
|
|
2574
1950
|
first = false;
|
|
2575
1951
|
}
|
|
@@ -2586,7 +1962,7 @@ function maskApiKey(key) {
|
|
|
2586
1962
|
|
|
2587
1963
|
// src/commands/connection.ts
|
|
2588
1964
|
import * as p4 from "@clack/prompts";
|
|
2589
|
-
import
|
|
1965
|
+
import pc5 from "picocolors";
|
|
2590
1966
|
|
|
2591
1967
|
// src/lib/access.ts
|
|
2592
1968
|
async function resolveAllowedActions(api, actionIds) {
|
|
@@ -2610,21 +1986,91 @@ async function resolveAllowedActions(api, actionIds) {
|
|
|
2610
1986
|
);
|
|
2611
1987
|
return resolved.filter((a) => a !== null);
|
|
2612
1988
|
}
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
1989
|
+
var UNRESTRICTED = { reachable: true, methods: null, actionIds: null };
|
|
1990
|
+
var UNREACHABLE = { reachable: false, methods: [], actionIds: [] };
|
|
1991
|
+
function serverEnvelope(doc, connectionKey) {
|
|
1992
|
+
if (!doc) return UNRESTRICTED;
|
|
1993
|
+
if (doc.rules === null) return { reachable: true, methods: doc.methods, actionIds: null };
|
|
1994
|
+
const rule = doc.rules.find((r) => r.connectionKey === connectionKey);
|
|
1995
|
+
if (!rule) return UNREACHABLE;
|
|
1996
|
+
return {
|
|
1997
|
+
reachable: true,
|
|
1998
|
+
methods: rule.methods ?? doc.methods,
|
|
1999
|
+
actionIds: rule.actionIds ?? null
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
function localEnvelope(permissions, actionIds, connectionKeys, connectionKey) {
|
|
2003
|
+
if (!connectionKeys.includes("*") && !connectionKeys.includes(connectionKey)) return UNREACHABLE;
|
|
2004
|
+
return {
|
|
2005
|
+
reachable: true,
|
|
2006
|
+
methods: PERMISSION_METHODS[permissions],
|
|
2007
|
+
actionIds: actionIds.includes("*") ? null : actionIds
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
function intersectList(a, b) {
|
|
2011
|
+
if (a === null) return b;
|
|
2012
|
+
if (b === null) return a;
|
|
2013
|
+
const upper = new Set(b.map((x) => x.toUpperCase()));
|
|
2014
|
+
return a.filter((x) => upper.has(x.toUpperCase()));
|
|
2015
|
+
}
|
|
2016
|
+
function intersectEnvelopes(a, b) {
|
|
2017
|
+
if (!a.reachable || !b.reachable) return UNREACHABLE;
|
|
2018
|
+
return {
|
|
2019
|
+
reachable: true,
|
|
2020
|
+
methods: intersectList(a.methods, b.methods),
|
|
2021
|
+
actionIds: a.actionIds === null ? b.actionIds : b.actionIds === null ? a.actionIds : a.actionIds.filter((id) => b.actionIds.includes(id))
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
function envelopeToAccess(envelope, resolved, localMethods = null) {
|
|
2025
|
+
if (!envelope.reachable || envelope.methods !== null && envelope.methods.length === 0) {
|
|
2026
|
+
return { access: { policy: "actions", actions: [] }, unresolved: [] };
|
|
2617
2027
|
}
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2028
|
+
if (envelope.actionIds !== null) {
|
|
2029
|
+
const actions2 = envelope.actionIds.flatMap((id) => {
|
|
2030
|
+
const hit = resolved.find((a) => a.actionId === id);
|
|
2031
|
+
if (!hit) return [];
|
|
2032
|
+
if (localMethods && !localMethods.includes(hit.method.toUpperCase())) return [];
|
|
2033
|
+
return [{ actionId: hit.actionId, title: hit.title, method: hit.method }];
|
|
2034
|
+
});
|
|
2035
|
+
return {
|
|
2036
|
+
access: { policy: "actions", actions: actions2 },
|
|
2037
|
+
unresolved: envelope.actionIds.filter((id) => !resolved.some((a) => a.actionId === id))
|
|
2038
|
+
};
|
|
2621
2039
|
}
|
|
2622
|
-
|
|
2040
|
+
if (envelope.methods !== null) {
|
|
2041
|
+
return { access: { policy: "methods", methods: envelope.methods.map((m) => m.toUpperCase()) }, unresolved: [] };
|
|
2042
|
+
}
|
|
2043
|
+
return { access: { policy: "full" }, unresolved: [] };
|
|
2623
2044
|
}
|
|
2624
|
-
|
|
2045
|
+
var READ_WRITE = ["GET", "PATCH", "POST", "PUT"];
|
|
2046
|
+
function accessLevel(access) {
|
|
2625
2047
|
switch (access.policy) {
|
|
2626
2048
|
case "full":
|
|
2627
2049
|
return "full";
|
|
2050
|
+
case "methods": {
|
|
2051
|
+
const set = [...new Set(access.methods.map((m) => m.toUpperCase()))].sort();
|
|
2052
|
+
if (set.length === 0) return "none";
|
|
2053
|
+
if (set.length === 1 && set[0] === "GET") return "read-only";
|
|
2054
|
+
if (set.join(",") === READ_WRITE.join(",")) return "read-write";
|
|
2055
|
+
return "custom";
|
|
2056
|
+
}
|
|
2057
|
+
case "actions":
|
|
2058
|
+
return access.actions.length === 0 ? "none" : "custom";
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
var LEVEL_LABELS = {
|
|
2062
|
+
full: "Full access",
|
|
2063
|
+
"read-write": "Read & write",
|
|
2064
|
+
"read-only": "Read only",
|
|
2065
|
+
custom: "Custom",
|
|
2066
|
+
none: "No access"
|
|
2067
|
+
};
|
|
2068
|
+
function formatAccess(access, maxActions = 2) {
|
|
2069
|
+
const level = accessLevel(access);
|
|
2070
|
+
if (level !== "custom") return LEVEL_LABELS[level];
|
|
2071
|
+
switch (access.policy) {
|
|
2072
|
+
case "full":
|
|
2073
|
+
return LEVEL_LABELS.full;
|
|
2628
2074
|
case "methods":
|
|
2629
2075
|
return access.methods.join(", ");
|
|
2630
2076
|
case "actions": {
|
|
@@ -2672,7 +2118,7 @@ function countMatchingChars(a, b) {
|
|
|
2672
2118
|
}
|
|
2673
2119
|
|
|
2674
2120
|
// src/lib/table.ts
|
|
2675
|
-
import
|
|
2121
|
+
import pc4 from "picocolors";
|
|
2676
2122
|
function printTable(columns, rows) {
|
|
2677
2123
|
if (rows.length === 0) return;
|
|
2678
2124
|
const gap = " ";
|
|
@@ -2684,10 +2130,10 @@ function printTable(columns, rows) {
|
|
|
2684
2130
|
});
|
|
2685
2131
|
const header = columns.map((col, i) => {
|
|
2686
2132
|
const padded = col.align === "right" ? col.label.padStart(widths[i]) : col.label.padEnd(widths[i]);
|
|
2687
|
-
return
|
|
2133
|
+
return pc4.dim(padded);
|
|
2688
2134
|
}).join(gap);
|
|
2689
2135
|
console.log(`${indent}${header}`);
|
|
2690
|
-
const separator = columns.map((_, i) =>
|
|
2136
|
+
const separator = columns.map((_, i) => pc4.dim("\u2500".repeat(widths[i]))).join(gap);
|
|
2691
2137
|
console.log(`${indent}${separator}`);
|
|
2692
2138
|
for (const row of rows) {
|
|
2693
2139
|
const line = columns.map((col, i) => {
|
|
@@ -2712,7 +2158,7 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2712
2158
|
if (isAgentMode()) {
|
|
2713
2159
|
error("This command requires interactive input. Run without --agent.");
|
|
2714
2160
|
}
|
|
2715
|
-
p4.intro(
|
|
2161
|
+
p4.intro(pc5.bgCyan(pc5.black(" One ")));
|
|
2716
2162
|
const apiKey = getApiKey();
|
|
2717
2163
|
if (!apiKey) {
|
|
2718
2164
|
p4.cancel("Not configured. Run `one init` first.");
|
|
@@ -2747,7 +2193,7 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2747
2193
|
]
|
|
2748
2194
|
});
|
|
2749
2195
|
if (p4.isCancel(suggestion) || suggestion === "__other__") {
|
|
2750
|
-
p4.note(`Run ${
|
|
2196
|
+
p4.note(`Run ${pc5.cyan("one platforms")} to see all available platforms.`);
|
|
2751
2197
|
p4.cancel("Connection cancelled.");
|
|
2752
2198
|
process.exit(0);
|
|
2753
2199
|
}
|
|
@@ -2755,7 +2201,7 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2755
2201
|
} else {
|
|
2756
2202
|
p4.cancel(`Unknown platform: ${platformArg}
|
|
2757
2203
|
|
|
2758
|
-
Run ${
|
|
2204
|
+
Run ${pc5.cyan("one platforms")} to see available platforms.`);
|
|
2759
2205
|
process.exit(1);
|
|
2760
2206
|
}
|
|
2761
2207
|
}
|
|
@@ -2778,7 +2224,7 @@ Run ${pc6.cyan("one platforms")} to see available platforms.`);
|
|
|
2778
2224
|
} else {
|
|
2779
2225
|
p4.cancel(`Unknown platform: ${platformInput}
|
|
2780
2226
|
|
|
2781
|
-
Run ${
|
|
2227
|
+
Run ${pc5.cyan("one platforms")} to see available platforms.`);
|
|
2782
2228
|
process.exit(1);
|
|
2783
2229
|
}
|
|
2784
2230
|
}
|
|
@@ -2789,8 +2235,8 @@ Run ${pc6.cyan("one platforms")} to see available platforms.`);
|
|
|
2789
2235
|
...whoami?.project && { projectId: whoami.project.id }
|
|
2790
2236
|
};
|
|
2791
2237
|
const url = getConnectionUrl(platform, connParams);
|
|
2792
|
-
p4.log.info(`Opening browser to connect ${
|
|
2793
|
-
p4.note(
|
|
2238
|
+
p4.log.info(`Opening browser to connect ${pc5.cyan(platform)}...`);
|
|
2239
|
+
p4.note(pc5.dim(url), "URL");
|
|
2794
2240
|
try {
|
|
2795
2241
|
await openConnectionPage(platform, connParams);
|
|
2796
2242
|
} catch {
|
|
@@ -2818,7 +2264,7 @@ The connection is usable; set the tag later in the dashboard or retry.`
|
|
|
2818
2264
|
);
|
|
2819
2265
|
}
|
|
2820
2266
|
}
|
|
2821
|
-
p4.log.success(`${
|
|
2267
|
+
p4.log.success(`${pc5.green("\u2713")} ${connection2.platform} is now available to your AI agents.${tag ? ` (tag: ${tag})` : ""}`);
|
|
2822
2268
|
p4.outro("Connection complete!");
|
|
2823
2269
|
} catch (error2) {
|
|
2824
2270
|
pollSpinner.stop("Connection timed out");
|
|
@@ -2829,7 +2275,7 @@ The connection is usable; set the tag later in the dashboard or retry.`
|
|
|
2829
2275
|
- Browser popup was blocked
|
|
2830
2276
|
- Wrong account selected
|
|
2831
2277
|
|
|
2832
|
-
Try again with: ${
|
|
2278
|
+
Try again with: ${pc5.cyan(`one connection add ${platform}`)}`,
|
|
2833
2279
|
"Timed Out"
|
|
2834
2280
|
);
|
|
2835
2281
|
} else {
|
|
@@ -2847,18 +2293,30 @@ async function connectionListCommand(options) {
|
|
|
2847
2293
|
const spinner = createSpinner();
|
|
2848
2294
|
spinner.start("Loading connections...");
|
|
2849
2295
|
try {
|
|
2850
|
-
const allConnections = await
|
|
2296
|
+
const [allConnections, serverAccess] = await Promise.all([
|
|
2297
|
+
api.listConnections(),
|
|
2298
|
+
api.getOwnAccess().then(
|
|
2299
|
+
(doc) => ({ ok: true, doc }),
|
|
2300
|
+
() => ({ ok: false, doc: null })
|
|
2301
|
+
)
|
|
2302
|
+
]);
|
|
2851
2303
|
const ac = getAccessControlFromAllSources();
|
|
2852
2304
|
const permissions = ac.permissions || "admin";
|
|
2853
2305
|
const allowedKeys = ac.connectionKeys || ["*"];
|
|
2854
2306
|
const actionIds = ac.actionIds || ["*"];
|
|
2855
2307
|
const knowledgeOnly = ac.knowledgeAgent || false;
|
|
2856
|
-
const
|
|
2857
|
-
const
|
|
2858
|
-
const
|
|
2859
|
-
const
|
|
2860
|
-
const
|
|
2861
|
-
const
|
|
2308
|
+
const envelopeFor = (key) => intersectEnvelopes(serverEnvelope(serverAccess.doc, key), localEnvelope(permissions, actionIds, allowedKeys, key));
|
|
2309
|
+
const accessFiltered = allConnections.filter((conn) => envelopeFor(conn.key).reachable);
|
|
2310
|
+
const namedActionIds = new Set(actionIds.includes("*") ? [] : actionIds);
|
|
2311
|
+
for (const rule of serverAccess.doc?.rules ?? []) for (const id of rule.actionIds ?? []) namedActionIds.add(id);
|
|
2312
|
+
const resolvedActions = await resolveAllowedActions(api, [...namedActionIds]);
|
|
2313
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
2314
|
+
const accessFor = (conn) => {
|
|
2315
|
+
const { access, unresolved: missing } = envelopeToAccess(envelopeFor(conn.key), resolvedActions, PERMISSION_METHODS[permissions]);
|
|
2316
|
+
missing.forEach((id) => unresolved.add(id));
|
|
2317
|
+
return access;
|
|
2318
|
+
};
|
|
2319
|
+
const hintText = accessHint(permissions, actionIds, knowledgeOnly, serverAccess.ok ? serverAccess.doc : void 0);
|
|
2862
2320
|
const searchQuery = options?.search?.toLowerCase();
|
|
2863
2321
|
const filtered = searchQuery ? accessFiltered.filter((conn) => conn.platform.toLowerCase().includes(searchQuery)) : accessFiltered;
|
|
2864
2322
|
const limitArg = options?.limit ? parseInt(options.limit, 10) : void 0;
|
|
@@ -2875,10 +2333,11 @@ async function connectionListCommand(options) {
|
|
|
2875
2333
|
key: conn.key,
|
|
2876
2334
|
...conn.name && { name: conn.name },
|
|
2877
2335
|
...conn.tags?.length && { tags: conn.tags },
|
|
2878
|
-
access: accessFor(conn
|
|
2336
|
+
access: withLevel(accessFor(conn))
|
|
2879
2337
|
})),
|
|
2338
|
+
accessSource: serverAccess.ok ? "server" : "local",
|
|
2880
2339
|
...knowledgeOnly && { knowledgeOnly: true },
|
|
2881
|
-
...
|
|
2340
|
+
...unresolved.size > 0 && { unresolvedActionIds: [...unresolved] },
|
|
2882
2341
|
...hintText && { accessHint: hintText },
|
|
2883
2342
|
...limited.length < filtered.length && {
|
|
2884
2343
|
hint: `Showing ${limited.length} of ${filtered.length} connections. Use --search <query> to filter by platform or --limit <n> to see more.`
|
|
@@ -2893,14 +2352,21 @@ async function connectionListCommand(options) {
|
|
|
2893
2352
|
p4.note(
|
|
2894
2353
|
`No connections matching "${searchQuery}".
|
|
2895
2354
|
|
|
2896
|
-
Try: ${
|
|
2355
|
+
Try: ${pc5.cyan("one connection list")} to see all connections.`,
|
|
2897
2356
|
"No Results"
|
|
2898
2357
|
);
|
|
2358
|
+
} else if (serverAccess.doc?.rules && allConnections.length === 0) {
|
|
2359
|
+
p4.note(
|
|
2360
|
+
`This key reaches no connections: it can search actions and read their docs, but runs none.
|
|
2361
|
+
|
|
2362
|
+
Change it in the dashboard under API keys.`,
|
|
2363
|
+
"No Connections"
|
|
2364
|
+
);
|
|
2899
2365
|
} else {
|
|
2900
2366
|
p4.note(
|
|
2901
2367
|
`No connections yet.
|
|
2902
2368
|
|
|
2903
|
-
Add one with: ${
|
|
2369
|
+
Add one with: ${pc5.cyan("one connection add gmail")}`,
|
|
2904
2370
|
"No Connections"
|
|
2905
2371
|
);
|
|
2906
2372
|
}
|
|
@@ -2913,32 +2379,32 @@ Add one with: ${pc6.cyan("one connection add gmail")}`,
|
|
|
2913
2379
|
state: conn.state,
|
|
2914
2380
|
key: conn.key,
|
|
2915
2381
|
tags: conn.tags?.length ? conn.tags.join(", ") : "",
|
|
2916
|
-
access: formatAccess(accessFor(conn
|
|
2382
|
+
access: formatAccess(accessFor(conn))
|
|
2917
2383
|
}));
|
|
2918
2384
|
const hasTags = rows.some((r) => r.tags);
|
|
2919
|
-
const hasScopedAccess = rows.some((r) => r.access !== "full");
|
|
2920
2385
|
printTable(
|
|
2921
2386
|
[
|
|
2922
2387
|
{ key: "status", label: "" },
|
|
2923
2388
|
{ key: "platform", label: "Platform" },
|
|
2924
2389
|
{ key: "state", label: "Status" },
|
|
2925
|
-
{ key: "key", label: "Connection Key", color:
|
|
2926
|
-
...hasTags ? [{ key: "tags", label: "Tags", color:
|
|
2927
|
-
|
|
2390
|
+
{ key: "key", label: "Connection Key", color: pc5.dim },
|
|
2391
|
+
...hasTags ? [{ key: "tags", label: "Tags", color: pc5.dim }] : [],
|
|
2392
|
+
{ key: "access", label: serverAccess.ok ? "Access" : "Access (CLI settings only)", color: pc5.yellow }
|
|
2928
2393
|
],
|
|
2929
2394
|
rows
|
|
2930
2395
|
);
|
|
2931
2396
|
console.log();
|
|
2932
|
-
if (hintText) {
|
|
2933
|
-
const lines = [hintText];
|
|
2934
|
-
if (
|
|
2935
|
-
lines.push(
|
|
2936
|
-
`Could not resolve ${unresolvedActionIds.length} allowlisted action id(s): ${unresolvedActionIds.join(", ")}`
|
|
2937
|
-
);
|
|
2397
|
+
if (hintText || unresolved.size > 0) {
|
|
2398
|
+
const lines = hintText ? [hintText] : [];
|
|
2399
|
+
if (unresolved.size > 0) {
|
|
2400
|
+
lines.push(`Could not resolve ${unresolved.size} allowed action id(s): ${[...unresolved].join(", ")}`);
|
|
2938
2401
|
}
|
|
2939
|
-
p4.note(
|
|
2402
|
+
p4.note(
|
|
2403
|
+
`${wrapText(lines.join("\n"))}
|
|
2940
2404
|
|
|
2941
|
-
|
|
2405
|
+
This key's access: dashboard \u2192 API keys. This CLI's own limits: ${pc5.cyan("one config")}`,
|
|
2406
|
+
"Access"
|
|
2407
|
+
);
|
|
2942
2408
|
}
|
|
2943
2409
|
if (displayed.length < filtered.length) {
|
|
2944
2410
|
p4.note(
|
|
@@ -2946,7 +2412,7 @@ Change it with: ${pc6.cyan("one config")}`, "Access");
|
|
|
2946
2412
|
"Limited"
|
|
2947
2413
|
);
|
|
2948
2414
|
} else {
|
|
2949
|
-
p4.note(`Add more with: ${
|
|
2415
|
+
p4.note(`Add more with: ${pc5.cyan("one connection add <platform>")}`, "Tip");
|
|
2950
2416
|
}
|
|
2951
2417
|
} catch (error2) {
|
|
2952
2418
|
spinner.stop("Failed to load connections");
|
|
@@ -2982,7 +2448,7 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
2982
2448
|
spinner.stop(`Found ${connection2.platform} (${connection2.state})`);
|
|
2983
2449
|
if (!isAgentMode() && !options?.force) {
|
|
2984
2450
|
console.log();
|
|
2985
|
-
console.log(` ${getStatusIndicator(connection2.state)} ${connection2.platform} ${
|
|
2451
|
+
console.log(` ${getStatusIndicator(connection2.state)} ${connection2.platform} ${pc5.dim(connection2.key)}`);
|
|
2986
2452
|
console.log();
|
|
2987
2453
|
const confirmed = await p4.confirm({
|
|
2988
2454
|
message: "Are you sure you want to delete this connection?",
|
|
@@ -3006,27 +2472,41 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
3006
2472
|
});
|
|
3007
2473
|
return;
|
|
3008
2474
|
}
|
|
3009
|
-
p4.log.success(`${
|
|
2475
|
+
p4.log.success(`${pc5.green("\u2713")} ${connection2.platform} connection removed.`);
|
|
3010
2476
|
} catch (error2) {
|
|
3011
2477
|
deleteSpinner.stop("Failed to delete connection");
|
|
3012
2478
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
3013
2479
|
}
|
|
3014
2480
|
}
|
|
3015
|
-
function accessHint(permissions, actionIds, knowledgeOnly) {
|
|
2481
|
+
function accessHint(permissions, actionIds, knowledgeOnly, server) {
|
|
3016
2482
|
const parts = [];
|
|
2483
|
+
if (server === void 0) {
|
|
2484
|
+
parts.push(
|
|
2485
|
+
"One did not report this key's access, so each `access` shows only this CLI's own settings; One may allow less. Check the key in the dashboard under API keys."
|
|
2486
|
+
);
|
|
2487
|
+
} else if (server?.rules && server.rules.length === 0) {
|
|
2488
|
+
parts.push("This key reaches no connections: it can read docs and search actions, but no action will execute.");
|
|
2489
|
+
} else if (server?.rules?.some((r) => r.actionIds)) {
|
|
2490
|
+
parts.push(
|
|
2491
|
+
"Some connections are action-scoped: their `access.actions` are the only actions you may run there \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
3017
2494
|
if (!actionIds.includes("*")) {
|
|
3018
2495
|
parts.push(
|
|
3019
|
-
"Action-scoped: each connection's `access.actions` are the only actions you may run \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
2496
|
+
"Action-scoped (local settings): each connection's `access.actions` are the only actions you may run \u2014 use them directly: `actions load <actionId>` reads their docs, no find needed."
|
|
3020
2497
|
);
|
|
3021
2498
|
} else if (permissions !== "admin") {
|
|
3022
2499
|
const methods = PERMISSION_METHODS[permissions]?.join(", ") ?? "";
|
|
3023
|
-
parts.push(`Permission level "${permissions}": only ${methods} actions will execute.`);
|
|
2500
|
+
parts.push(`Permission level "${permissions}" (local settings): only ${methods} actions will execute.`);
|
|
3024
2501
|
}
|
|
3025
2502
|
if (knowledgeOnly) {
|
|
3026
2503
|
parts.push("Knowledge-only mode: `actions execute` is disabled \u2014 read knowledge and write code instead.");
|
|
3027
2504
|
}
|
|
3028
2505
|
return parts.length > 0 ? parts.join(" ") : null;
|
|
3029
2506
|
}
|
|
2507
|
+
function withLevel(access) {
|
|
2508
|
+
return { ...access, level: accessLevel(access) };
|
|
2509
|
+
}
|
|
3030
2510
|
function wrapText(text5, width = 72) {
|
|
3031
2511
|
return text5.split("\n").map((paragraph) => {
|
|
3032
2512
|
const lines = [];
|
|
@@ -3046,19 +2526,19 @@ function wrapText(text5, width = 72) {
|
|
|
3046
2526
|
function getStatusIndicator(state) {
|
|
3047
2527
|
switch (state) {
|
|
3048
2528
|
case "operational":
|
|
3049
|
-
return
|
|
2529
|
+
return pc5.green("\u25CF");
|
|
3050
2530
|
case "degraded":
|
|
3051
|
-
return
|
|
2531
|
+
return pc5.yellow("\u25CF");
|
|
3052
2532
|
case "failed":
|
|
3053
|
-
return
|
|
2533
|
+
return pc5.red("\u25CF");
|
|
3054
2534
|
default:
|
|
3055
|
-
return
|
|
2535
|
+
return pc5.dim("\u25CB");
|
|
3056
2536
|
}
|
|
3057
2537
|
}
|
|
3058
2538
|
|
|
3059
2539
|
// src/commands/platforms.ts
|
|
3060
2540
|
import * as p5 from "@clack/prompts";
|
|
3061
|
-
import
|
|
2541
|
+
import pc6 from "picocolors";
|
|
3062
2542
|
async function platformsCommand(options) {
|
|
3063
2543
|
const apiKey = getApiKey();
|
|
3064
2544
|
if (!apiKey) {
|
|
@@ -3124,7 +2604,7 @@ async function platformsCommand(options) {
|
|
|
3124
2604
|
);
|
|
3125
2605
|
}
|
|
3126
2606
|
console.log();
|
|
3127
|
-
p5.note(`Connect with: ${
|
|
2607
|
+
p5.note(`Connect with: ${pc6.cyan("one connection add <platform>")}`, "Tip");
|
|
3128
2608
|
} catch (error2) {
|
|
3129
2609
|
spinner.stop("Failed to load platforms");
|
|
3130
2610
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
@@ -3132,7 +2612,7 @@ async function platformsCommand(options) {
|
|
|
3132
2612
|
}
|
|
3133
2613
|
|
|
3134
2614
|
// src/commands/actions.ts
|
|
3135
|
-
import
|
|
2615
|
+
import pc7 from "picocolors";
|
|
3136
2616
|
|
|
3137
2617
|
// src/lib/knowledge-sections.ts
|
|
3138
2618
|
var DEFAULT_WHOLE_DOC_THRESHOLD = 8e3;
|
|
@@ -3789,7 +3269,7 @@ var CUSTOM_ACTION_NOTE = '\n\nThis is a custom action: ALSO include "connectionK
|
|
|
3789
3269
|
function codeGuideAction(action, knowledge, platform, tags, apiBase) {
|
|
3790
3270
|
const base = apiBase.replace(/\/$/, "");
|
|
3791
3271
|
const method = action.method.toUpperCase();
|
|
3792
|
-
const
|
|
3272
|
+
const path13 = action.path.startsWith("/") ? action.path : `/${action.path}`;
|
|
3793
3273
|
const connEnv = `ONE_${platformEnvSegment(platform)}_CONNECTION_KEY`;
|
|
3794
3274
|
const customNote = tags.includes("custom") ? CUSTOM_ACTION_NOTE : "";
|
|
3795
3275
|
return `### ${actionHeading(action)}
|
|
@@ -3798,7 +3278,7 @@ function codeGuideAction(action, knowledge, platform, tags, apiBase) {
|
|
|
3798
3278
|
${knowledge ?? NO_KNOWLEDGE}
|
|
3799
3279
|
|
|
3800
3280
|
## Calling this action from code
|
|
3801
|
-
URL: ${base}/passthrough${
|
|
3281
|
+
URL: ${base}/passthrough${path13}
|
|
3802
3282
|
Method: ${method}
|
|
3803
3283
|
Headers:
|
|
3804
3284
|
- x-one-secret: the value of the ONE_SECRET env var
|
|
@@ -3809,7 +3289,7 @@ Headers:
|
|
|
3809
3289
|
Environment variables: ONE_SECRET (their One API key) and ${connEnv} (the key of their ${platform} connection), both from the One dashboard.
|
|
3810
3290
|
|
|
3811
3291
|
\`\`\`typescript
|
|
3812
|
-
const response = await fetch("${base}/passthrough${
|
|
3292
|
+
const response = await fetch("${base}/passthrough${path13}", {
|
|
3813
3293
|
method: "${method}",
|
|
3814
3294
|
headers: {
|
|
3815
3295
|
"x-one-secret": process.env.ONE_SECRET,
|
|
@@ -3940,7 +3420,7 @@ function failure(error2) {
|
|
|
3940
3420
|
return error2 instanceof Error ? error2.message : "Unknown error";
|
|
3941
3421
|
}
|
|
3942
3422
|
async function actionsFindCommand(pairs, options) {
|
|
3943
|
-
intro(
|
|
3423
|
+
intro(pc7.bgCyan(pc7.black(" One ")));
|
|
3944
3424
|
if (options.type !== void 0 && options.type !== "execute" && options.type !== "knowledge") {
|
|
3945
3425
|
error("--type must be execute or knowledge.");
|
|
3946
3426
|
}
|
|
@@ -3998,7 +3478,7 @@ async function actionsLoadCommand(actionIds, options) {
|
|
|
3998
3478
|
);
|
|
3999
3479
|
return;
|
|
4000
3480
|
}
|
|
4001
|
-
intro(
|
|
3481
|
+
intro(pc7.bgCyan(pc7.black(" One ")));
|
|
4002
3482
|
const { apiKey, permissions, connectionKeys, actionIds: allowed, knowledgeAgent } = getConfig();
|
|
4003
3483
|
const api = new OneApi(apiKey, getApiBase());
|
|
4004
3484
|
const settings = { knowledgeAgent, permissions, actionIds: allowed, connectionKeys, apiBase: getApiBase() };
|
|
@@ -4020,7 +3500,7 @@ async function actionsLoadCommand(actionIds, options) {
|
|
|
4020
3500
|
}
|
|
4021
3501
|
}
|
|
4022
3502
|
async function actionsExecuteCommand(platform, actionId, connectionKey, options) {
|
|
4023
|
-
intro(
|
|
3503
|
+
intro(pc7.bgCyan(pc7.black(" One ")));
|
|
4024
3504
|
const { apiKey, permissions, actionIds, connectionKeys, knowledgeAgent } = getConfig();
|
|
4025
3505
|
if (knowledgeAgent) {
|
|
4026
3506
|
error(
|
|
@@ -4045,7 +3525,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
4045
3525
|
);
|
|
4046
3526
|
}
|
|
4047
3527
|
spinner.stop(
|
|
4048
|
-
`Action: ${actionDetails.title} [${actionDetails.method}]` + (preflightCacheHit ?
|
|
3528
|
+
`Action: ${actionDetails.title} [${actionDetails.method}]` + (preflightCacheHit ? pc7.dim(" (cached)") : "")
|
|
4049
3529
|
);
|
|
4050
3530
|
const data = options.data ? parseJsonArg2(options.data, "--data") : void 0;
|
|
4051
3531
|
const pathVariables = options.pathVars ? parseJsonArg2(options.pathVars, "--path-vars") : void 0;
|
|
@@ -4065,9 +3545,9 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
4065
3545
|
}
|
|
4066
3546
|
console.log();
|
|
4067
3547
|
for (const m of validation.missing) {
|
|
4068
|
-
console.log(
|
|
3548
|
+
console.log(pc7.red(` ${m.flag} is missing "${m.param}"`));
|
|
4069
3549
|
if (m.description) {
|
|
4070
|
-
console.log(
|
|
3550
|
+
console.log(pc7.dim(` ${m.description}`));
|
|
4071
3551
|
}
|
|
4072
3552
|
}
|
|
4073
3553
|
console.log();
|
|
@@ -4092,7 +3572,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
4092
3572
|
}
|
|
4093
3573
|
console.log();
|
|
4094
3574
|
if (mockResponse) {
|
|
4095
|
-
console.log(
|
|
3575
|
+
console.log(pc7.bold("Mock Response:"));
|
|
4096
3576
|
console.log(JSON.stringify(mockResponse, null, 2));
|
|
4097
3577
|
} else {
|
|
4098
3578
|
note("No example output available for this action", "Mock");
|
|
@@ -4133,26 +3613,26 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
4133
3613
|
return;
|
|
4134
3614
|
}
|
|
4135
3615
|
console.log();
|
|
4136
|
-
console.log(
|
|
3616
|
+
console.log(pc7.dim("Request:"));
|
|
4137
3617
|
console.log(
|
|
4138
|
-
|
|
3618
|
+
pc7.dim(
|
|
4139
3619
|
` ${result.requestConfig.method} ${result.requestConfig.url}`
|
|
4140
3620
|
)
|
|
4141
3621
|
);
|
|
4142
3622
|
if (options.dryRun) {
|
|
4143
3623
|
if (result.requestConfig.data) {
|
|
4144
3624
|
console.log();
|
|
4145
|
-
console.log(
|
|
4146
|
-
console.log(
|
|
3625
|
+
console.log(pc7.dim("Body:"));
|
|
3626
|
+
console.log(pc7.dim(JSON.stringify(result.requestConfig.data, null, 2)));
|
|
4147
3627
|
}
|
|
4148
3628
|
console.log();
|
|
4149
3629
|
note("Dry run \u2014 request was not sent", "Dry Run");
|
|
4150
3630
|
} else {
|
|
4151
3631
|
console.log();
|
|
4152
|
-
console.log(
|
|
3632
|
+
console.log(pc7.bold("Response:"));
|
|
4153
3633
|
const rd = result.responseData;
|
|
4154
3634
|
if (rd && typeof rd === "object" && typeof rd.text === "string" && "contentType" in rd) {
|
|
4155
|
-
if (rd.contentType) console.log(
|
|
3635
|
+
if (rd.contentType) console.log(pc7.dim(`(${rd.contentType})`));
|
|
4156
3636
|
console.log(rd.text);
|
|
4157
3637
|
} else {
|
|
4158
3638
|
console.log(JSON.stringify(result.responseData, null, 2));
|
|
@@ -4356,7 +3836,7 @@ async function actionsExecuteParallelCommand() {
|
|
|
4356
3836
|
}
|
|
4357
3837
|
console.log();
|
|
4358
3838
|
for (const e of errors) {
|
|
4359
|
-
console.log(` ${
|
|
3839
|
+
console.log(` ${pc7.red("\u2717")} Segment ${e.segment} (${e.label}):`);
|
|
4360
3840
|
for (const msg of e.messages) {
|
|
4361
3841
|
console.log(` ${msg}`);
|
|
4362
3842
|
}
|
|
@@ -4451,17 +3931,17 @@ async function actionsExecuteParallelCommand() {
|
|
|
4451
3931
|
console.log();
|
|
4452
3932
|
for (const r of results) {
|
|
4453
3933
|
const label = `${r.platform}/${r.actionId}`;
|
|
4454
|
-
const time =
|
|
3934
|
+
const time = pc7.dim(`(${(r.durationMs / 1e3).toFixed(2)}s)`);
|
|
4455
3935
|
if (r.mock) {
|
|
4456
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
4457
|
-
if (r.response) console.log(` ${
|
|
3936
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc7.cyan("\u25C7 mock")} ${time}`);
|
|
3937
|
+
if (r.response) console.log(` ${pc7.dim(JSON.stringify(r.response, null, 2).split("\n").join("\n "))}`);
|
|
4458
3938
|
} else if (r.dryRun) {
|
|
4459
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3939
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc7.yellow("\u2298 dry-run")} ${time}`);
|
|
4460
3940
|
} else if (r.status === "success") {
|
|
4461
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
4462
|
-
if (r.response) console.log(` ${
|
|
3941
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc7.green("\u2713")} ${time}`);
|
|
3942
|
+
if (r.response) console.log(` ${pc7.dim(JSON.stringify(r.response, null, 2).split("\n").join("\n "))}`);
|
|
4463
3943
|
} else {
|
|
4464
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3944
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc7.red("\u2717")} ${time} \u2014 ${r.error}`);
|
|
4465
3945
|
}
|
|
4466
3946
|
}
|
|
4467
3947
|
console.log();
|
|
@@ -4475,11 +3955,11 @@ async function actionsExecuteParallelCommand() {
|
|
|
4475
3955
|
}
|
|
4476
3956
|
|
|
4477
3957
|
// src/commands/flow.ts
|
|
4478
|
-
import
|
|
3958
|
+
import pc8 from "picocolors";
|
|
4479
3959
|
|
|
4480
3960
|
// src/lib/flow-validator.ts
|
|
4481
|
-
import
|
|
4482
|
-
import
|
|
3961
|
+
import fs3 from "fs";
|
|
3962
|
+
import path3 from "path";
|
|
4483
3963
|
import { spawnSync } from "child_process";
|
|
4484
3964
|
function validateFlowSchema(flow2) {
|
|
4485
3965
|
const errors = [];
|
|
@@ -4554,32 +4034,32 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
4554
4034
|
const validTypes = FLOW_SCHEMA.stepTypes.map((st) => st.type);
|
|
4555
4035
|
for (let i = 0; i < steps.length; i++) {
|
|
4556
4036
|
const step = steps[i];
|
|
4557
|
-
const
|
|
4037
|
+
const path13 = `${pathPrefix}[${i}]`;
|
|
4558
4038
|
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
4559
|
-
errors.push({ path:
|
|
4039
|
+
errors.push({ path: path13, message: "Step must be an object" });
|
|
4560
4040
|
continue;
|
|
4561
4041
|
}
|
|
4562
4042
|
const s = step;
|
|
4563
4043
|
if (!s.id || typeof s.id !== "string") {
|
|
4564
|
-
errors.push({ path: `${
|
|
4044
|
+
errors.push({ path: `${path13}.id`, message: 'Step must have a string "id"' });
|
|
4565
4045
|
}
|
|
4566
4046
|
if (!s.name || typeof s.name !== "string") {
|
|
4567
|
-
errors.push({ path: `${
|
|
4047
|
+
errors.push({ path: `${path13}.name`, message: 'Step must have a string "name"' });
|
|
4568
4048
|
}
|
|
4569
4049
|
if (!s.type || !validTypes.includes(s.type)) {
|
|
4570
|
-
errors.push({ path: `${
|
|
4050
|
+
errors.push({ path: `${path13}.type`, message: `Step type must be one of: ${validTypes.join(", ")}` });
|
|
4571
4051
|
continue;
|
|
4572
4052
|
}
|
|
4573
4053
|
if (s.requires !== void 0) {
|
|
4574
4054
|
if (!Array.isArray(s.requires)) {
|
|
4575
|
-
errors.push({ path: `${
|
|
4055
|
+
errors.push({ path: `${path13}.requires`, message: '"requires" must be an array of selector strings (e.g. ["$.steps.foo.output.bar"])' });
|
|
4576
4056
|
} else {
|
|
4577
4057
|
for (let r = 0; r < s.requires.length; r++) {
|
|
4578
4058
|
const sel = s.requires[r];
|
|
4579
4059
|
if (typeof sel !== "string") {
|
|
4580
|
-
errors.push({ path: `${
|
|
4060
|
+
errors.push({ path: `${path13}.requires[${r}]`, message: '"requires" entry must be a selector string' });
|
|
4581
4061
|
} else if (!sel.startsWith("$.")) {
|
|
4582
|
-
errors.push({ path: `${
|
|
4062
|
+
errors.push({ path: `${path13}.requires[${r}]`, message: `"requires" entry "${sel}" must be a selector starting with "$." (e.g. "$.steps.foo.output.bar")` });
|
|
4583
4063
|
}
|
|
4584
4064
|
}
|
|
4585
4065
|
}
|
|
@@ -4587,7 +4067,7 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
4587
4067
|
if (s.onError && typeof s.onError === "object") {
|
|
4588
4068
|
const oe = s.onError;
|
|
4589
4069
|
if (!FLOW_SCHEMA.errorStrategies.includes(oe.strategy)) {
|
|
4590
|
-
errors.push({ path: `${
|
|
4070
|
+
errors.push({ path: `${path13}.onError.strategy`, message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
|
|
4591
4071
|
}
|
|
4592
4072
|
}
|
|
4593
4073
|
const descriptor = getStepTypeDescriptor(s.type);
|
|
@@ -4597,14 +4077,14 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
4597
4077
|
if (!configObj || typeof configObj !== "object") {
|
|
4598
4078
|
const hint = detectFlatConfigHint(s, descriptor);
|
|
4599
4079
|
errors.push({
|
|
4600
|
-
path: `${
|
|
4080
|
+
path: `${path13}.${configKey}`,
|
|
4601
4081
|
message: `${capitalize(descriptor.type)} step must have a "${configKey}" config object${hint}`
|
|
4602
4082
|
});
|
|
4603
4083
|
continue;
|
|
4604
4084
|
}
|
|
4605
4085
|
const config2 = configObj;
|
|
4606
4086
|
for (const [fieldName, fd] of Object.entries(descriptor.fields)) {
|
|
4607
|
-
const fieldPath = `${
|
|
4087
|
+
const fieldPath = `${path13}.${configKey}.${fieldName}`;
|
|
4608
4088
|
const value = config2[fieldName];
|
|
4609
4089
|
if (fd.required && (value === void 0 || value === null || value === "")) {
|
|
4610
4090
|
errors.push({ path: fieldPath, message: `${capitalize(descriptor.type)} must have ${fd.type === "string" ? "a string" : fd.type === "array" ? "a" : "a"} "${fieldName}"` });
|
|
@@ -4637,30 +4117,30 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
4637
4117
|
}
|
|
4638
4118
|
}
|
|
4639
4119
|
if (descriptor.type === "action") {
|
|
4640
|
-
validateConnectionForm(config2, `${
|
|
4120
|
+
validateConnectionForm(config2, `${path13}.${configKey}`, errors);
|
|
4641
4121
|
}
|
|
4642
4122
|
if (descriptor.type === "code") {
|
|
4643
4123
|
const hasSource = typeof config2.source === "string" && config2.source.length > 0;
|
|
4644
4124
|
const hasModule = typeof config2.module === "string" && config2.module.length > 0;
|
|
4645
4125
|
if (!hasSource && !hasModule) {
|
|
4646
|
-
errors.push({ path: `${
|
|
4126
|
+
errors.push({ path: `${path13}.${configKey}`, message: 'Code step must define either "source" (inline JS) or "module" (path to .mjs file)' });
|
|
4647
4127
|
} else if (hasSource && hasModule) {
|
|
4648
|
-
errors.push({ path: `${
|
|
4128
|
+
errors.push({ path: `${path13}.${configKey}`, message: 'Code step cannot define both "source" and "module" \u2014 pick one' });
|
|
4649
4129
|
}
|
|
4650
4130
|
if (hasModule) {
|
|
4651
4131
|
const m = config2.module;
|
|
4652
4132
|
if (m.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(m)) {
|
|
4653
|
-
errors.push({ path: `${
|
|
4133
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: "Code module path must be relative to the flow folder (no absolute paths)" });
|
|
4654
4134
|
} else if (m.split(/[\\/]/).includes("..")) {
|
|
4655
|
-
errors.push({ path: `${
|
|
4135
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: 'Code module path must not escape the flow folder ("..")' });
|
|
4656
4136
|
} else if (!m.endsWith(".mjs")) {
|
|
4657
|
-
errors.push({ path: `${
|
|
4137
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: "Code module must be a .mjs file" });
|
|
4658
4138
|
}
|
|
4659
4139
|
}
|
|
4660
4140
|
if (hasSource) {
|
|
4661
4141
|
const syntaxError = checkCodeSourceSyntax(config2.source);
|
|
4662
4142
|
if (syntaxError) {
|
|
4663
|
-
errors.push({ path: `${
|
|
4143
|
+
errors.push({ path: `${path13}.${configKey}.source`, message: `Syntax error in code step: ${syntaxError}` });
|
|
4664
4144
|
}
|
|
4665
4145
|
}
|
|
4666
4146
|
}
|
|
@@ -4732,16 +4212,16 @@ function validateStepIds(flow2) {
|
|
|
4732
4212
|
function collectIds(steps, pathPrefix) {
|
|
4733
4213
|
for (let i = 0; i < steps.length; i++) {
|
|
4734
4214
|
const step = steps[i];
|
|
4735
|
-
const
|
|
4215
|
+
const path13 = `${pathPrefix}[${i}]`;
|
|
4736
4216
|
if (seen.has(step.id)) {
|
|
4737
|
-
errors.push({ path: `${
|
|
4217
|
+
errors.push({ path: `${path13}.id`, message: `Duplicate step ID: "${step.id}"` });
|
|
4738
4218
|
} else {
|
|
4739
4219
|
seen.add(step.id);
|
|
4740
4220
|
}
|
|
4741
4221
|
for (const { configKey, fieldName } of nestedKeys) {
|
|
4742
4222
|
const config2 = step[configKey];
|
|
4743
4223
|
if (config2 && Array.isArray(config2[fieldName])) {
|
|
4744
|
-
collectIds(config2[fieldName], `${
|
|
4224
|
+
collectIds(config2[fieldName], `${path13}.${configKey}.${fieldName}`);
|
|
4745
4225
|
}
|
|
4746
4226
|
}
|
|
4747
4227
|
}
|
|
@@ -4789,7 +4269,7 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
4789
4269
|
}
|
|
4790
4270
|
return selectors;
|
|
4791
4271
|
}
|
|
4792
|
-
function checkSelectors(selectors,
|
|
4272
|
+
function checkSelectors(selectors, path13, precedingStepIds) {
|
|
4793
4273
|
for (const selector of selectors) {
|
|
4794
4274
|
const parts = selector.split(".");
|
|
4795
4275
|
if (parts.length < 3) continue;
|
|
@@ -4797,15 +4277,15 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
4797
4277
|
if (root === "input") {
|
|
4798
4278
|
const inputName = parts[2];
|
|
4799
4279
|
if (!inputNames.has(inputName)) {
|
|
4800
|
-
errors.push({ path:
|
|
4280
|
+
errors.push({ path: path13, message: `Selector "${selector}" references undefined input "${inputName}"` });
|
|
4801
4281
|
}
|
|
4802
4282
|
} else if (root === "steps") {
|
|
4803
4283
|
const stepId = parts[2].replace(/[\[\]]/g, "").split(/[\[\]]/)[0];
|
|
4804
4284
|
if (!allStepIds.has(stepId)) {
|
|
4805
|
-
errors.push({ path:
|
|
4285
|
+
errors.push({ path: path13, message: `Selector "${selector}" references undefined step "${stepId}"` });
|
|
4806
4286
|
} else if (precedingStepIds && !precedingStepIds.has(stepId)) {
|
|
4807
4287
|
errors.push({
|
|
4808
|
-
path:
|
|
4288
|
+
path: path13,
|
|
4809
4289
|
message: `Selector "${selector}" references step "${stepId}" which is declared after the current step. Steps execute in declaration order, so this will always resolve to undefined at runtime \u2014 move the dependency earlier in the steps array.`
|
|
4810
4290
|
});
|
|
4811
4291
|
}
|
|
@@ -4813,20 +4293,20 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
4813
4293
|
}
|
|
4814
4294
|
}
|
|
4815
4295
|
const EXPRESSION_FIELDS = /* @__PURE__ */ new Set(["condition.expression", "while.condition"]);
|
|
4816
|
-
function checkOperatorsInSelectorField(value,
|
|
4296
|
+
function checkOperatorsInSelectorField(value, path13) {
|
|
4817
4297
|
if (typeof value === "string" && value.startsWith("$.")) {
|
|
4818
4298
|
if (value.includes("||")) {
|
|
4819
|
-
errors.push({ path:
|
|
4299
|
+
errors.push({ path: path13, message: `Selector "${value}" contains unsupported operator "||". Selectors in data fields use dot-path resolution, not JS evaluation. Use the "default" field on the input definition instead, or use a "code" step for complex expressions.` });
|
|
4820
4300
|
} else if (value.includes("&&")) {
|
|
4821
|
-
errors.push({ path:
|
|
4301
|
+
errors.push({ path: path13, message: `Selector "${value}" contains unsupported operator "&&". Selectors in data fields use dot-path resolution, not JS evaluation. Use a "condition" step or "code" step for complex expressions.` });
|
|
4822
4302
|
}
|
|
4823
4303
|
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
4824
4304
|
for (const [k, v] of Object.entries(value)) {
|
|
4825
|
-
checkOperatorsInSelectorField(v, `${
|
|
4305
|
+
checkOperatorsInSelectorField(v, `${path13}.${k}`);
|
|
4826
4306
|
}
|
|
4827
4307
|
} else if (Array.isArray(value)) {
|
|
4828
4308
|
for (let i = 0; i < value.length; i++) {
|
|
4829
|
-
checkOperatorsInSelectorField(value[i], `${
|
|
4309
|
+
checkOperatorsInSelectorField(value[i], `${path13}[${i}]`);
|
|
4830
4310
|
}
|
|
4831
4311
|
}
|
|
4832
4312
|
}
|
|
@@ -4870,10 +4350,10 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
4870
4350
|
}
|
|
4871
4351
|
const modulePath = step.type === "code" ? c.module : void 0;
|
|
4872
4352
|
if (rootDir && typeof modulePath === "string" && modulePath.length > 0) {
|
|
4873
|
-
const abs =
|
|
4874
|
-
if (
|
|
4353
|
+
const abs = path3.resolve(rootDir, modulePath);
|
|
4354
|
+
if (fs3.existsSync(abs)) {
|
|
4875
4355
|
try {
|
|
4876
|
-
const moduleText =
|
|
4356
|
+
const moduleText = fs3.readFileSync(abs, "utf-8");
|
|
4877
4357
|
checkSelectors(extractSelectors(moduleText), `${pathPrefix}.${descriptor.configKey}.module`, preceding2);
|
|
4878
4358
|
} catch {
|
|
4879
4359
|
}
|
|
@@ -4911,10 +4391,10 @@ var VALID_OUTPUT_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "number", "bo
|
|
|
4911
4391
|
function isOutputSchemaObject(v) {
|
|
4912
4392
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
4913
4393
|
}
|
|
4914
|
-
function walkOutputSchema(schema,
|
|
4394
|
+
function walkOutputSchema(schema, path13) {
|
|
4915
4395
|
let current = schema;
|
|
4916
|
-
for (let i = 0; i <
|
|
4917
|
-
const seg =
|
|
4396
|
+
for (let i = 0; i < path13.length; i++) {
|
|
4397
|
+
const seg = path13[i];
|
|
4918
4398
|
if (typeof current === "string") {
|
|
4919
4399
|
return current === "unknown" || current === "object" || current === "array" ? "opaque" : "opaque";
|
|
4920
4400
|
}
|
|
@@ -5066,8 +4546,8 @@ function validateCodeModules(flow2, rootDir) {
|
|
|
5066
4546
|
const stepPath = `${pathPrefix}[${i}]`;
|
|
5067
4547
|
if (step.type === "code" && step.code?.module) {
|
|
5068
4548
|
const m = step.code.module;
|
|
5069
|
-
const abs =
|
|
5070
|
-
if (!
|
|
4549
|
+
const abs = path3.resolve(rootDir, m);
|
|
4550
|
+
if (!fs3.existsSync(abs)) {
|
|
5071
4551
|
errors.push({
|
|
5072
4552
|
path: `${stepPath}.code.module`,
|
|
5073
4553
|
message: `Code module "${m}" not found at ${abs}`
|
|
@@ -5198,11 +4678,11 @@ function validateFileReadSchemas(flow2) {
|
|
|
5198
4678
|
}
|
|
5199
4679
|
|
|
5200
4680
|
// src/commands/flow.ts
|
|
5201
|
-
import
|
|
5202
|
-
import
|
|
4681
|
+
import fs4 from "fs";
|
|
4682
|
+
import path4 from "path";
|
|
5203
4683
|
async function writeFlowResultFile(filePath, meta, steps) {
|
|
5204
|
-
const abs =
|
|
5205
|
-
const ws =
|
|
4684
|
+
const abs = path4.resolve(filePath);
|
|
4685
|
+
const ws = fs4.createWriteStream(abs);
|
|
5206
4686
|
const done = new Promise((resolve, reject) => {
|
|
5207
4687
|
ws.on("finish", () => resolve());
|
|
5208
4688
|
ws.on("error", reject);
|
|
@@ -5233,25 +4713,25 @@ function previewValue(value, max = 120) {
|
|
|
5233
4713
|
}
|
|
5234
4714
|
function renderDryRef(ref2) {
|
|
5235
4715
|
if (ref2.status === "resolved") {
|
|
5236
|
-
return `${
|
|
4716
|
+
return `${pc8.green("\u2713")} ${ref2.selector} ${pc8.dim("\u2192")} ${previewValue(ref2.value)}`;
|
|
5237
4717
|
}
|
|
5238
4718
|
if (ref2.status === "deferred") {
|
|
5239
|
-
return `${
|
|
4719
|
+
return `${pc8.dim("\u25CB")} ${ref2.selector} ${pc8.dim("\u2192 pending (produced by a later step)")}`;
|
|
5240
4720
|
}
|
|
5241
|
-
return `${
|
|
4721
|
+
return `${pc8.yellow("!")} ${ref2.selector} ${pc8.yellow("\u2192 unresolved \u2014 check the input/env name")}`;
|
|
5242
4722
|
}
|
|
5243
4723
|
function renderDryResolution(steps) {
|
|
5244
4724
|
const isExpr = (t) => t === "transform" || t === "condition" || t === "while";
|
|
5245
4725
|
for (const s of steps) {
|
|
5246
|
-
const label = s.name ? `${s.stepId} ${
|
|
5247
|
-
console.log(` ${
|
|
4726
|
+
const label = s.name ? `${s.stepId} ${pc8.dim(`"${s.name}"`)}` : s.stepId;
|
|
4727
|
+
console.log(` ${pc8.cyan("\u25B8")} ${label} ${pc8.dim(`(${s.type})`)}`);
|
|
5248
4728
|
if (s.error !== void 0) {
|
|
5249
|
-
console.log(` ${
|
|
4729
|
+
console.log(` ${pc8.red("error")} ${s.error}`);
|
|
5250
4730
|
} else if (isExpr(s.type) && s.deferred) {
|
|
5251
4731
|
const deps = s.references.map((r) => r.selector).join(", ");
|
|
5252
|
-
console.log(` ${
|
|
4732
|
+
console.log(` ${pc8.dim("\u25CB pending \u2014 depends on")} ${deps} ${pc8.dim("(produced by a later step)")}`);
|
|
5253
4733
|
} else if (isExpr(s.type)) {
|
|
5254
|
-
console.log(` ${
|
|
4734
|
+
console.log(` ${pc8.dim("=")} ${previewValue(s.resolved)}`);
|
|
5255
4735
|
}
|
|
5256
4736
|
if (!(isExpr(s.type) && s.deferred)) {
|
|
5257
4737
|
for (const ref2 of s.references) {
|
|
@@ -5259,7 +4739,7 @@ function renderDryResolution(steps) {
|
|
|
5259
4739
|
}
|
|
5260
4740
|
}
|
|
5261
4741
|
if (!isExpr(s.type) && s.references.length === 0 && s.error === void 0) {
|
|
5262
|
-
console.log(` ${
|
|
4742
|
+
console.log(` ${pc8.dim("(no interpolations)")}`);
|
|
5263
4743
|
}
|
|
5264
4744
|
}
|
|
5265
4745
|
}
|
|
@@ -5313,14 +4793,14 @@ async function autoResolveConnectionInputs(flow2, inputs, api) {
|
|
|
5313
4793
|
return resolved;
|
|
5314
4794
|
}
|
|
5315
4795
|
async function flowCreateCommand(key, options) {
|
|
5316
|
-
intro(
|
|
4796
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5317
4797
|
let flow2;
|
|
5318
4798
|
if (options.definition) {
|
|
5319
4799
|
let raw = options.definition;
|
|
5320
4800
|
if (raw.startsWith("@")) {
|
|
5321
4801
|
const filePath = raw.slice(1);
|
|
5322
4802
|
try {
|
|
5323
|
-
raw =
|
|
4803
|
+
raw = fs4.readFileSync(filePath, "utf-8");
|
|
5324
4804
|
} catch (err) {
|
|
5325
4805
|
error(`Cannot read file "${filePath}": ${err.message}`);
|
|
5326
4806
|
}
|
|
@@ -5369,11 +4849,11 @@ ${errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
5369
4849
|
return;
|
|
5370
4850
|
}
|
|
5371
4851
|
note(`Workflow "${flow2.name}" saved to ${flowPath}`, "Created");
|
|
5372
|
-
outro(`Validate: ${
|
|
5373
|
-
Execute: ${
|
|
4852
|
+
outro(`Validate: ${pc8.cyan(`one flow validate ${flow2.key}`)}
|
|
4853
|
+
Execute: ${pc8.cyan(`one flow execute ${flow2.key}`)}`);
|
|
5374
4854
|
}
|
|
5375
4855
|
async function flowExecuteCommand(keyOrPath, options) {
|
|
5376
|
-
intro(
|
|
4856
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5377
4857
|
const { apiKey, permissions, actionIds } = getConfig2();
|
|
5378
4858
|
const api = new OneApi(apiKey, getApiBase());
|
|
5379
4859
|
const spinner = createSpinner();
|
|
@@ -5406,7 +4886,7 @@ ${preflightErrors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
5406
4886
|
if (isAgentMode()) {
|
|
5407
4887
|
json({ event: "flow:deprecation", flowKey: flow2.key, warning: msg });
|
|
5408
4888
|
} else {
|
|
5409
|
-
console.error(
|
|
4889
|
+
console.error(pc8.yellow(`\u26A0 ${msg}`));
|
|
5410
4890
|
}
|
|
5411
4891
|
}
|
|
5412
4892
|
if (!options.allowBash && flowRequiresBash(flow2)) {
|
|
@@ -5440,7 +4920,7 @@ ${preflightErrors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
5440
4920
|
runner.requestPause();
|
|
5441
4921
|
if (!isAgentMode()) {
|
|
5442
4922
|
console.log(`
|
|
5443
|
-
${
|
|
4923
|
+
${pc8.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
5444
4924
|
}
|
|
5445
4925
|
};
|
|
5446
4926
|
process.on("SIGINT", sigintHandler);
|
|
@@ -5460,12 +4940,12 @@ ${pc9.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
|
5460
4940
|
} else if (options.verbose) {
|
|
5461
4941
|
const ts = (/* @__PURE__ */ new Date()).toISOString().split("T")[1].slice(0, 8);
|
|
5462
4942
|
if (event.event === "step:start") {
|
|
5463
|
-
console.log(` ${
|
|
4943
|
+
console.log(` ${pc8.dim(ts)} ${pc8.cyan("\u25B6")} ${event.stepName} ${pc8.dim(`(${event.type})`)}`);
|
|
5464
4944
|
} else if (event.event === "step:complete") {
|
|
5465
|
-
const status2 = event.status === "success" ?
|
|
5466
|
-
console.log(` ${
|
|
4945
|
+
const status2 = event.status === "success" ? pc8.green("\u2713") : event.status === "skipped" ? pc8.dim("\u25CB") : pc8.red("\u2717");
|
|
4946
|
+
console.log(` ${pc8.dim(ts)} ${status2} ${event.stepId} ${pc8.dim(`${event.durationMs}ms`)}`);
|
|
5467
4947
|
} else if (event.event === "step:error") {
|
|
5468
|
-
console.log(` ${
|
|
4948
|
+
console.log(` ${pc8.dim(ts)} ${pc8.red("\u2717")} ${event.stepId}: ${event.error}`);
|
|
5469
4949
|
}
|
|
5470
4950
|
}
|
|
5471
4951
|
};
|
|
@@ -5514,8 +4994,8 @@ ${pc9.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
|
5514
4994
|
console.log();
|
|
5515
4995
|
const missing = dryRunSteps.reduce((n, s) => n + s.references.filter((r) => r.status === "missing").length, 0);
|
|
5516
4996
|
note(
|
|
5517
|
-
`Dry run \u2014 no steps executed. Resolved ${dryRunSteps.length} step(s)` + (missing > 0 ? `; ${
|
|
5518
|
-
${
|
|
4997
|
+
`Dry run \u2014 no steps executed. Resolved ${dryRunSteps.length} step(s)` + (missing > 0 ? `; ${pc8.yellow(`${missing} unresolved input/env reference(s)`)}` : "") + `.
|
|
4998
|
+
${pc8.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<stepId> to resolve them against real output.")}`,
|
|
5519
4999
|
"Dry Run"
|
|
5520
5000
|
);
|
|
5521
5001
|
return;
|
|
@@ -5525,17 +5005,17 @@ ${pc9.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<st
|
|
|
5525
5005
|
const failed = stepEntries.filter(([, r]) => r.status === "failed").length;
|
|
5526
5006
|
const skipped = stepEntries.filter(([, r]) => r.status === "skipped").length;
|
|
5527
5007
|
console.log();
|
|
5528
|
-
console.log(` ${
|
|
5529
|
-
console.log(` ${
|
|
5530
|
-
console.log(` ${
|
|
5008
|
+
console.log(` ${pc8.green("\u2713")} ${succeeded} succeeded ${failed > 0 ? pc8.red(`\u2717 ${failed} failed`) : ""} ${skipped > 0 ? pc8.dim(`\u25CB ${skipped} skipped`) : ""}`);
|
|
5009
|
+
console.log(` ${pc8.dim(`Run ID: ${runId}`)}`);
|
|
5010
|
+
console.log(` ${pc8.dim(`Log: ${logPath}`)}`);
|
|
5531
5011
|
if (dryResolveTarget) {
|
|
5532
5012
|
console.log();
|
|
5533
|
-
console.log(` ${
|
|
5013
|
+
console.log(` ${pc8.dim(`Resolved (not executed) "${dryResolveTarget.stepId}":`)}`);
|
|
5534
5014
|
renderDryResolution([dryResolveTarget]);
|
|
5535
5015
|
}
|
|
5536
5016
|
if (stoppedAfter) {
|
|
5537
5017
|
note(
|
|
5538
|
-
`Stopped after step "${stoppedAfter}". Inspect step outputs with: ${
|
|
5018
|
+
`Stopped after step "${stoppedAfter}". Inspect step outputs with: ${pc8.cyan(`one flow inspect ${runId}`)}`,
|
|
5539
5019
|
"Stopped"
|
|
5540
5020
|
);
|
|
5541
5021
|
} else if (options.dryRun) {
|
|
@@ -5557,13 +5037,13 @@ ${pc9.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<st
|
|
|
5557
5037
|
});
|
|
5558
5038
|
process.exit(1);
|
|
5559
5039
|
}
|
|
5560
|
-
console.log(` ${
|
|
5561
|
-
console.log(` ${
|
|
5040
|
+
console.log(` ${pc8.dim(`Run ID: ${runId}`)}`);
|
|
5041
|
+
console.log(` ${pc8.dim(`Log: ${logPath}`)}`);
|
|
5562
5042
|
error(`Workflow failed: ${errorMsg}`);
|
|
5563
5043
|
}
|
|
5564
5044
|
}
|
|
5565
5045
|
async function flowListCommand() {
|
|
5566
|
-
intro(
|
|
5046
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5567
5047
|
const flows = listFlows();
|
|
5568
5048
|
if (isAgentMode()) {
|
|
5569
5049
|
json({ workflows: flows });
|
|
@@ -5595,7 +5075,7 @@ async function flowListCommand() {
|
|
|
5595
5075
|
console.log();
|
|
5596
5076
|
}
|
|
5597
5077
|
async function flowValidateCommand(keyOrPath) {
|
|
5598
|
-
intro(
|
|
5078
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5599
5079
|
const spinner = createSpinner();
|
|
5600
5080
|
spinner.start(`Validating "${keyOrPath}"...`);
|
|
5601
5081
|
let flowData;
|
|
@@ -5607,9 +5087,9 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
5607
5087
|
rootDir = loaded.rootDir;
|
|
5608
5088
|
} catch {
|
|
5609
5089
|
const flowPath = resolveFlowPath(keyOrPath);
|
|
5610
|
-
const content =
|
|
5090
|
+
const content = fs4.readFileSync(flowPath, "utf-8");
|
|
5611
5091
|
flowData = JSON.parse(content);
|
|
5612
|
-
rootDir =
|
|
5092
|
+
rootDir = path4.dirname(flowPath);
|
|
5613
5093
|
}
|
|
5614
5094
|
} catch (err) {
|
|
5615
5095
|
spinner.stop("Validation failed");
|
|
@@ -5624,7 +5104,7 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
5624
5104
|
}
|
|
5625
5105
|
console.log();
|
|
5626
5106
|
for (const e of errors) {
|
|
5627
|
-
console.log(` ${
|
|
5107
|
+
console.log(` ${pc8.red("\u2717")} ${pc8.dim(e.path)}: ${e.message}`);
|
|
5628
5108
|
}
|
|
5629
5109
|
console.log();
|
|
5630
5110
|
error(`${errors.length} validation error(s) found`);
|
|
@@ -5637,7 +5117,7 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
5637
5117
|
note(`Workflow "${flowData.key}" passed all validation checks`, "Valid");
|
|
5638
5118
|
}
|
|
5639
5119
|
async function flowResumeCommand(runId, options = {}) {
|
|
5640
|
-
intro(
|
|
5120
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5641
5121
|
const state = FlowRunner.loadRunState(runId);
|
|
5642
5122
|
if (!state) {
|
|
5643
5123
|
error(`Run "${runId}" not found`);
|
|
@@ -5690,8 +5170,8 @@ async function flowResumeCommand(runId, options = {}) {
|
|
|
5690
5170
|
});
|
|
5691
5171
|
return;
|
|
5692
5172
|
}
|
|
5693
|
-
console.log(` ${
|
|
5694
|
-
console.log(` ${
|
|
5173
|
+
console.log(` ${pc8.green("\u2713")} Resumed and completed successfully`);
|
|
5174
|
+
console.log(` ${pc8.dim(`Log: ${runner.getLogPath()}`)}`);
|
|
5695
5175
|
} catch (error2) {
|
|
5696
5176
|
spinner.stop("Resume failed");
|
|
5697
5177
|
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -5703,7 +5183,7 @@ async function flowResumeCommand(runId, options = {}) {
|
|
|
5703
5183
|
}
|
|
5704
5184
|
}
|
|
5705
5185
|
async function flowRunsCommand(flowKey) {
|
|
5706
|
-
intro(
|
|
5186
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5707
5187
|
const runs = FlowRunner.listRuns(flowKey);
|
|
5708
5188
|
if (isAgentMode()) {
|
|
5709
5189
|
json({
|
|
@@ -5743,7 +5223,7 @@ async function flowRunsCommand(flowKey) {
|
|
|
5743
5223
|
console.log();
|
|
5744
5224
|
}
|
|
5745
5225
|
async function flowInspectCommand(runId, options = {}) {
|
|
5746
|
-
intro(
|
|
5226
|
+
intro(pc8.bgCyan(pc8.black(" One Workflow ")));
|
|
5747
5227
|
const state = FlowRunner.loadRunState(runId);
|
|
5748
5228
|
if (!state) {
|
|
5749
5229
|
const msg = `No run found for id "${runId}". List runs with: one flow runs`;
|
|
@@ -5772,44 +5252,44 @@ async function flowInspectCommand(runId, options = {}) {
|
|
|
5772
5252
|
return;
|
|
5773
5253
|
}
|
|
5774
5254
|
console.log();
|
|
5775
|
-
console.log(` ${
|
|
5776
|
-
console.log(` ${
|
|
5777
|
-
if (state.currentStepId) console.log(` ${
|
|
5255
|
+
console.log(` ${pc8.bold(state.flowKey)} ${pc8.dim(`run ${state.runId}`)} ${colorStatus(state.status)}`);
|
|
5256
|
+
console.log(` ${pc8.dim(`Started: ${state.startedAt}${state.completedAt ? ` \xB7 Ended: ${state.completedAt}` : ""}`)}`);
|
|
5257
|
+
if (state.currentStepId) console.log(` ${pc8.dim(`Current step: ${state.currentStepId}`)}`);
|
|
5778
5258
|
console.log();
|
|
5779
5259
|
if (stepEntries.length === 0) {
|
|
5780
5260
|
note("No step outputs recorded yet for this run.", "Steps");
|
|
5781
5261
|
} else {
|
|
5782
5262
|
for (const [id, result] of stepEntries) {
|
|
5783
|
-
const icon = result.status === "success" ?
|
|
5784
|
-
const dur = result.durationMs !== void 0 ?
|
|
5785
|
-
const retries = result.retries ?
|
|
5786
|
-
console.log(` ${icon} ${id} ${
|
|
5263
|
+
const icon = result.status === "success" ? pc8.green("\u2713") : result.status === "skipped" ? pc8.dim("\u25CB") : result.status === "timeout" ? pc8.yellow("\u29D6") : pc8.red("\u2717");
|
|
5264
|
+
const dur = result.durationMs !== void 0 ? pc8.dim(` ${result.durationMs}ms`) : "";
|
|
5265
|
+
const retries = result.retries ? pc8.dim(` (${result.retries} retr${result.retries === 1 ? "y" : "ies"})`) : "";
|
|
5266
|
+
console.log(` ${icon} ${id} ${pc8.dim(`[${result.status}]`)}${dur}${retries}`);
|
|
5787
5267
|
if (result.error) {
|
|
5788
|
-
console.log(` ${
|
|
5268
|
+
console.log(` ${pc8.red("error")} ${result.error}${result.errorCode ? pc8.dim(` (${result.errorCode})`) : ""}`);
|
|
5789
5269
|
}
|
|
5790
5270
|
if (result.output !== void 0) {
|
|
5791
5271
|
const json2 = JSON.stringify(result.output, null, options.full ? 2 : 0) ?? String(result.output);
|
|
5792
|
-
const shown = options.full || json2.length <= 240 ? json2 : `${json2.slice(0, 239)}\u2026 ${
|
|
5793
|
-
const indented = options.full ? shown.split("\n").map((l) => ` ${l}`).join("\n") : ` ${
|
|
5272
|
+
const shown = options.full || json2.length <= 240 ? json2 : `${json2.slice(0, 239)}\u2026 ${pc8.dim("(--full for all)")}`;
|
|
5273
|
+
const indented = options.full ? shown.split("\n").map((l) => ` ${l}`).join("\n") : ` ${pc8.dim("output")} ${shown}`;
|
|
5794
5274
|
console.log(indented);
|
|
5795
5275
|
}
|
|
5796
5276
|
}
|
|
5797
5277
|
}
|
|
5798
5278
|
console.log();
|
|
5799
|
-
console.log(` ${
|
|
5800
|
-
console.log(` ${
|
|
5279
|
+
console.log(` ${pc8.dim(`State: ${statePath}`)}`);
|
|
5280
|
+
console.log(` ${pc8.dim(`Log: ${path4.join(".one/flows/.logs", `${state.flowKey}-${state.runId}.log`)}`)}`);
|
|
5801
5281
|
console.log();
|
|
5802
5282
|
}
|
|
5803
5283
|
function colorStatus(status2) {
|
|
5804
5284
|
switch (status2) {
|
|
5805
5285
|
case "completed":
|
|
5806
|
-
return
|
|
5286
|
+
return pc8.green(status2);
|
|
5807
5287
|
case "running":
|
|
5808
|
-
return
|
|
5288
|
+
return pc8.cyan(status2);
|
|
5809
5289
|
case "paused":
|
|
5810
|
-
return
|
|
5290
|
+
return pc8.yellow(status2);
|
|
5811
5291
|
case "failed":
|
|
5812
|
-
return
|
|
5292
|
+
return pc8.red(status2);
|
|
5813
5293
|
default:
|
|
5814
5294
|
return status2;
|
|
5815
5295
|
}
|
|
@@ -5987,7 +5467,7 @@ async function flowScaffoldCommand(template) {
|
|
|
5987
5467
|
}
|
|
5988
5468
|
|
|
5989
5469
|
// src/commands/relay.ts
|
|
5990
|
-
import
|
|
5470
|
+
import pc9 from "picocolors";
|
|
5991
5471
|
function getConfig3() {
|
|
5992
5472
|
const apiKey = getApiKey();
|
|
5993
5473
|
if (!apiKey) {
|
|
@@ -6028,15 +5508,15 @@ async function relayCreateCommand(options) {
|
|
|
6028
5508
|
}
|
|
6029
5509
|
spinner.stop("Relay endpoint created");
|
|
6030
5510
|
console.log();
|
|
6031
|
-
console.log(` ${
|
|
6032
|
-
console.log(` ${
|
|
6033
|
-
console.log(` ${
|
|
6034
|
-
if (result.description) console.log(` ${
|
|
6035
|
-
if (result.eventFilters?.length) console.log(` ${
|
|
6036
|
-
if (result.webhookPayload?.id) console.log(` ${
|
|
5511
|
+
console.log(` ${pc9.dim("ID:")} ${result.id}`);
|
|
5512
|
+
console.log(` ${pc9.dim("URL:")} ${result.url}`);
|
|
5513
|
+
console.log(` ${pc9.dim("Active:")} ${result.active}`);
|
|
5514
|
+
if (result.description) console.log(` ${pc9.dim("Description:")} ${result.description}`);
|
|
5515
|
+
if (result.eventFilters?.length) console.log(` ${pc9.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
5516
|
+
if (result.webhookPayload?.id) console.log(` ${pc9.dim("Webhook ID:")} ${result.webhookPayload.id}`);
|
|
6037
5517
|
if (result.warning) {
|
|
6038
5518
|
console.log();
|
|
6039
|
-
console.log(` ${
|
|
5519
|
+
console.log(` ${pc9.yellow("\u26A0 Warning:")} ${result.warning}`);
|
|
6040
5520
|
}
|
|
6041
5521
|
console.log();
|
|
6042
5522
|
} catch (error2) {
|
|
@@ -6082,12 +5562,12 @@ async function relayListCommand(options) {
|
|
|
6082
5562
|
{ key: "description", label: "Description" },
|
|
6083
5563
|
{ key: "events", label: "Events" },
|
|
6084
5564
|
{ key: "actions", label: "Actions" },
|
|
6085
|
-
{ key: "id", label: "ID", color:
|
|
5565
|
+
{ key: "id", label: "ID", color: pc9.dim }
|
|
6086
5566
|
],
|
|
6087
5567
|
endpoints.map((e) => ({
|
|
6088
|
-
status: e.active ?
|
|
6089
|
-
description: e.description ||
|
|
6090
|
-
events: e.eventFilters?.join(", ") ||
|
|
5568
|
+
status: e.active ? pc9.green("\u25CF") : pc9.dim("\u25CB"),
|
|
5569
|
+
description: e.description || pc9.dim("(none)"),
|
|
5570
|
+
events: e.eventFilters?.join(", ") || pc9.dim("all"),
|
|
6091
5571
|
actions: String(e.actions?.length || 0),
|
|
6092
5572
|
id: e.id.slice(0, 8)
|
|
6093
5573
|
}))
|
|
@@ -6110,18 +5590,18 @@ async function relayGetCommand(id) {
|
|
|
6110
5590
|
}
|
|
6111
5591
|
spinner.stop("Relay endpoint loaded");
|
|
6112
5592
|
console.log();
|
|
6113
|
-
console.log(` ${
|
|
6114
|
-
console.log(` ${
|
|
6115
|
-
console.log(` ${
|
|
6116
|
-
if (result.description) console.log(` ${
|
|
6117
|
-
if (result.eventFilters?.length) console.log(` ${
|
|
6118
|
-
console.log(` ${
|
|
5593
|
+
console.log(` ${pc9.dim("ID:")} ${result.id}`);
|
|
5594
|
+
console.log(` ${pc9.dim("URL:")} ${result.url}`);
|
|
5595
|
+
console.log(` ${pc9.dim("Active:")} ${result.active}`);
|
|
5596
|
+
if (result.description) console.log(` ${pc9.dim("Description:")} ${result.description}`);
|
|
5597
|
+
if (result.eventFilters?.length) console.log(` ${pc9.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
5598
|
+
console.log(` ${pc9.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
6119
5599
|
if (result.actions?.length) {
|
|
6120
5600
|
for (const [i, action] of result.actions.entries()) {
|
|
6121
|
-
console.log(` ${
|
|
5601
|
+
console.log(` ${pc9.dim(`[${i}]`)} type=${action.type}${action.actionId ? ` actionId=${action.actionId}` : ""}${action.url ? ` url=${action.url}` : ""}`);
|
|
6122
5602
|
}
|
|
6123
5603
|
}
|
|
6124
|
-
console.log(` ${
|
|
5604
|
+
console.log(` ${pc9.dim("Created:")} ${result.createdAt}`);
|
|
6125
5605
|
console.log();
|
|
6126
5606
|
} catch (error2) {
|
|
6127
5607
|
spinner.stop("Failed to load relay endpoint");
|
|
@@ -6146,9 +5626,9 @@ async function relayUpdateCommand(id, options) {
|
|
|
6146
5626
|
return;
|
|
6147
5627
|
}
|
|
6148
5628
|
spinner.stop("Relay endpoint updated");
|
|
6149
|
-
console.log(` ${
|
|
6150
|
-
console.log(` ${
|
|
6151
|
-
console.log(` ${
|
|
5629
|
+
console.log(` ${pc9.dim("ID:")} ${result.id}`);
|
|
5630
|
+
console.log(` ${pc9.dim("Active:")} ${result.active}`);
|
|
5631
|
+
console.log(` ${pc9.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
6152
5632
|
console.log();
|
|
6153
5633
|
} catch (error2) {
|
|
6154
5634
|
spinner.stop("Failed to update relay endpoint");
|
|
@@ -6189,9 +5669,9 @@ async function relayActivateCommand(id, options) {
|
|
|
6189
5669
|
return;
|
|
6190
5670
|
}
|
|
6191
5671
|
spinner.stop("Relay endpoint activated");
|
|
6192
|
-
console.log(` ${
|
|
6193
|
-
console.log(` ${
|
|
6194
|
-
console.log(` ${
|
|
5672
|
+
console.log(` ${pc9.dim("ID:")} ${result.id}`);
|
|
5673
|
+
console.log(` ${pc9.dim("Active:")} ${result.active}`);
|
|
5674
|
+
console.log(` ${pc9.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
6195
5675
|
console.log();
|
|
6196
5676
|
} catch (error2) {
|
|
6197
5677
|
spinner.stop("Failed to activate relay endpoint");
|
|
@@ -6236,11 +5716,11 @@ async function relayEventsCommand(options) {
|
|
|
6236
5716
|
{ key: "platform", label: "Platform" },
|
|
6237
5717
|
{ key: "eventType", label: "Event Type" },
|
|
6238
5718
|
{ key: "timestamp", label: "Timestamp" },
|
|
6239
|
-
{ key: "id", label: "ID", color:
|
|
5719
|
+
{ key: "id", label: "ID", color: pc9.dim }
|
|
6240
5720
|
],
|
|
6241
5721
|
events.map((e) => ({
|
|
6242
5722
|
platform: e.platform,
|
|
6243
|
-
eventType: e.eventType ||
|
|
5723
|
+
eventType: e.eventType || pc9.dim("unknown"),
|
|
6244
5724
|
timestamp: e.timestamp || e.createdAt,
|
|
6245
5725
|
id: e.id.slice(0, 8)
|
|
6246
5726
|
}))
|
|
@@ -6263,11 +5743,11 @@ async function relayEventGetCommand(id) {
|
|
|
6263
5743
|
}
|
|
6264
5744
|
spinner.stop("Relay event loaded");
|
|
6265
5745
|
console.log();
|
|
6266
|
-
console.log(` ${
|
|
6267
|
-
console.log(` ${
|
|
6268
|
-
console.log(` ${
|
|
6269
|
-
console.log(` ${
|
|
6270
|
-
console.log(` ${
|
|
5746
|
+
console.log(` ${pc9.dim("ID:")} ${result.id}`);
|
|
5747
|
+
console.log(` ${pc9.dim("Platform:")} ${result.platform}`);
|
|
5748
|
+
console.log(` ${pc9.dim("Event:")} ${result.eventType}`);
|
|
5749
|
+
console.log(` ${pc9.dim("Timestamp:")} ${result.timestamp || result.createdAt}`);
|
|
5750
|
+
console.log(` ${pc9.dim("Payload:")}`);
|
|
6271
5751
|
console.log(JSON.stringify(result.payload, null, 2));
|
|
6272
5752
|
console.log();
|
|
6273
5753
|
} catch (error2) {
|
|
@@ -6304,11 +5784,11 @@ async function relayDeliveriesCommand(options) {
|
|
|
6304
5784
|
{ key: "error", label: "Error" }
|
|
6305
5785
|
],
|
|
6306
5786
|
items.map((d) => ({
|
|
6307
|
-
status: d.status === "success" ?
|
|
6308
|
-
code: d.statusCode != null ? String(d.statusCode) :
|
|
5787
|
+
status: d.status === "success" ? pc9.green(d.status) : pc9.red(d.status),
|
|
5788
|
+
code: d.statusCode != null ? String(d.statusCode) : pc9.dim("-"),
|
|
6309
5789
|
attempt: String(d.attempt),
|
|
6310
|
-
deliveredAt: d.deliveredAt ||
|
|
6311
|
-
error: d.error ?
|
|
5790
|
+
deliveredAt: d.deliveredAt || pc9.dim("-"),
|
|
5791
|
+
error: d.error ? pc9.red(d.error.slice(0, 50)) : pc9.dim("-")
|
|
6312
5792
|
}))
|
|
6313
5793
|
);
|
|
6314
5794
|
} catch (error2) {
|
|
@@ -6336,14 +5816,14 @@ async function relayPlatformsCommand() {
|
|
|
6336
5816
|
printTable(
|
|
6337
5817
|
[
|
|
6338
5818
|
{ key: "platform", label: "Platform" },
|
|
6339
|
-
{ key: "eventTypeCount", label: "Event types", color:
|
|
5819
|
+
{ key: "eventTypeCount", label: "Event types", color: pc9.dim }
|
|
6340
5820
|
],
|
|
6341
5821
|
platforms.map((p9) => ({ platform: p9.platform, eventTypeCount: String(p9.eventTypeCount) }))
|
|
6342
5822
|
);
|
|
6343
5823
|
console.log();
|
|
6344
5824
|
console.log(
|
|
6345
|
-
|
|
6346
|
-
` Run ${
|
|
5825
|
+
pc9.dim(
|
|
5826
|
+
` Run ${pc9.cyan("one relay event-types <platform>")} to see the full event list for a platform.
|
|
6347
5827
|
`
|
|
6348
5828
|
)
|
|
6349
5829
|
);
|
|
@@ -6356,7 +5836,7 @@ async function relayEventTypesCommand(platform) {
|
|
|
6356
5836
|
const { apiKey } = getConfig3();
|
|
6357
5837
|
const api = new OneApi(apiKey, getApiBase());
|
|
6358
5838
|
const spinner = createSpinner();
|
|
6359
|
-
spinner.start(`Loading event types for ${
|
|
5839
|
+
spinner.start(`Loading event types for ${pc9.cyan(platform)}...`);
|
|
6360
5840
|
try {
|
|
6361
5841
|
const eventTypes = await api.listRelayEventTypes(platform);
|
|
6362
5842
|
if (isAgentMode()) {
|
|
@@ -6502,11 +5982,11 @@ function handleId(response, config2, records) {
|
|
|
6502
5982
|
}
|
|
6503
5983
|
|
|
6504
5984
|
// src/lib/memory/sync/state.ts
|
|
6505
|
-
import
|
|
6506
|
-
import
|
|
6507
|
-
var SYNC_DIR =
|
|
6508
|
-
var STATE_DIR =
|
|
6509
|
-
var LEGACY_SINGLE_FILE =
|
|
5985
|
+
import fs5 from "fs";
|
|
5986
|
+
import path5 from "path";
|
|
5987
|
+
var SYNC_DIR = path5.join(".one", "sync");
|
|
5988
|
+
var STATE_DIR = path5.join(SYNC_DIR, "state");
|
|
5989
|
+
var LEGACY_SINGLE_FILE = path5.join(SYNC_DIR, "sync_state.json");
|
|
6510
5990
|
var legacyMigrationDone = false;
|
|
6511
5991
|
function rowToState(row) {
|
|
6512
5992
|
return {
|
|
@@ -6534,9 +6014,9 @@ function stateToRow(platform, model, state, lastError) {
|
|
|
6534
6014
|
async function migrateLegacyOnce() {
|
|
6535
6015
|
if (legacyMigrationDone) return;
|
|
6536
6016
|
legacyMigrationDone = true;
|
|
6537
|
-
if (
|
|
6017
|
+
if (fs5.existsSync(LEGACY_SINGLE_FILE)) {
|
|
6538
6018
|
try {
|
|
6539
|
-
const raw =
|
|
6019
|
+
const raw = fs5.readFileSync(LEGACY_SINGLE_FILE, "utf-8");
|
|
6540
6020
|
const legacy = JSON.parse(raw);
|
|
6541
6021
|
const backend = await getBackend();
|
|
6542
6022
|
for (const [platform, models] of Object.entries(legacy)) {
|
|
@@ -6546,32 +6026,32 @@ async function migrateLegacyOnce() {
|
|
|
6546
6026
|
await backend.setSyncState(stateToRow(platform, model, modelState));
|
|
6547
6027
|
}
|
|
6548
6028
|
}
|
|
6549
|
-
|
|
6029
|
+
fs5.unlinkSync(LEGACY_SINGLE_FILE);
|
|
6550
6030
|
} catch {
|
|
6551
6031
|
try {
|
|
6552
|
-
|
|
6032
|
+
fs5.unlinkSync(LEGACY_SINGLE_FILE);
|
|
6553
6033
|
} catch {
|
|
6554
6034
|
}
|
|
6555
6035
|
}
|
|
6556
6036
|
}
|
|
6557
|
-
if (
|
|
6037
|
+
if (fs5.existsSync(STATE_DIR)) {
|
|
6558
6038
|
try {
|
|
6559
6039
|
const backend = await getBackend();
|
|
6560
|
-
const platforms =
|
|
6040
|
+
const platforms = fs5.readdirSync(STATE_DIR);
|
|
6561
6041
|
for (const platform of platforms) {
|
|
6562
|
-
const platformDir =
|
|
6042
|
+
const platformDir = path5.join(STATE_DIR, platform);
|
|
6563
6043
|
let entries;
|
|
6564
6044
|
try {
|
|
6565
|
-
entries =
|
|
6045
|
+
entries = fs5.readdirSync(platformDir);
|
|
6566
6046
|
} catch {
|
|
6567
6047
|
continue;
|
|
6568
6048
|
}
|
|
6569
6049
|
for (const entry of entries) {
|
|
6570
6050
|
if (!entry.endsWith(".json")) continue;
|
|
6571
6051
|
const model = entry.slice(0, -".json".length);
|
|
6572
|
-
const filePath =
|
|
6052
|
+
const filePath = path5.join(platformDir, entry);
|
|
6573
6053
|
try {
|
|
6574
|
-
const raw =
|
|
6054
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
6575
6055
|
const modelState = JSON.parse(raw);
|
|
6576
6056
|
const existing = await backend.getSyncState(platform, model);
|
|
6577
6057
|
if (!existing) {
|
|
@@ -6581,7 +6061,7 @@ async function migrateLegacyOnce() {
|
|
|
6581
6061
|
}
|
|
6582
6062
|
}
|
|
6583
6063
|
}
|
|
6584
|
-
|
|
6064
|
+
fs5.rmSync(STATE_DIR, { recursive: true, force: true });
|
|
6585
6065
|
} catch {
|
|
6586
6066
|
}
|
|
6587
6067
|
}
|
|
@@ -6625,12 +6105,12 @@ async function removeModelState(platform, model) {
|
|
|
6625
6105
|
}
|
|
6626
6106
|
|
|
6627
6107
|
// src/lib/memory/sync/lock.ts
|
|
6628
|
-
import
|
|
6629
|
-
import
|
|
6630
|
-
var LOCK_DIR_REL =
|
|
6108
|
+
import fs6 from "fs";
|
|
6109
|
+
import path6 from "path";
|
|
6110
|
+
var LOCK_DIR_REL = path6.join(".one", "sync", "locks");
|
|
6631
6111
|
var STALE_MS = 30 * 60 * 1e3;
|
|
6632
6112
|
function lockPath(platform, model) {
|
|
6633
|
-
return
|
|
6113
|
+
return path6.join(LOCK_DIR_REL, `${platform}_${model}`);
|
|
6634
6114
|
}
|
|
6635
6115
|
function isProcessAlive(pid) {
|
|
6636
6116
|
try {
|
|
@@ -6647,15 +6127,15 @@ var SyncLockError = class extends Error {
|
|
|
6647
6127
|
}
|
|
6648
6128
|
};
|
|
6649
6129
|
function acquireSyncLock(platform, model) {
|
|
6650
|
-
|
|
6130
|
+
fs6.mkdirSync(LOCK_DIR_REL, { recursive: true });
|
|
6651
6131
|
const dir = lockPath(platform, model);
|
|
6652
|
-
const pidFile =
|
|
6132
|
+
const pidFile = path6.join(dir, "pid");
|
|
6653
6133
|
try {
|
|
6654
|
-
|
|
6134
|
+
fs6.mkdirSync(dir);
|
|
6655
6135
|
} catch (err) {
|
|
6656
6136
|
const stat = (() => {
|
|
6657
6137
|
try {
|
|
6658
|
-
return
|
|
6138
|
+
return fs6.statSync(dir);
|
|
6659
6139
|
} catch {
|
|
6660
6140
|
return null;
|
|
6661
6141
|
}
|
|
@@ -6664,7 +6144,7 @@ function acquireSyncLock(platform, model) {
|
|
|
6664
6144
|
const age = Date.now() - stat.mtimeMs;
|
|
6665
6145
|
let ownerPid = null;
|
|
6666
6146
|
try {
|
|
6667
|
-
const raw =
|
|
6147
|
+
const raw = fs6.readFileSync(pidFile, "utf-8");
|
|
6668
6148
|
const parsed = parseInt(raw.trim(), 10);
|
|
6669
6149
|
if (!isNaN(parsed)) ownerPid = parsed;
|
|
6670
6150
|
} catch {
|
|
@@ -6673,8 +6153,8 @@ function acquireSyncLock(platform, model) {
|
|
|
6673
6153
|
const veryOld = age > STALE_MS;
|
|
6674
6154
|
if (ownerDead || veryOld) {
|
|
6675
6155
|
try {
|
|
6676
|
-
|
|
6677
|
-
|
|
6156
|
+
fs6.rmSync(dir, { recursive: true, force: true });
|
|
6157
|
+
fs6.mkdirSync(dir);
|
|
6678
6158
|
} catch {
|
|
6679
6159
|
throw new SyncLockError(
|
|
6680
6160
|
`Could not take over stale lock at ${dir}. Remove it manually if no sync is running.`
|
|
@@ -6691,13 +6171,13 @@ function acquireSyncLock(platform, model) {
|
|
|
6691
6171
|
}
|
|
6692
6172
|
}
|
|
6693
6173
|
try {
|
|
6694
|
-
|
|
6174
|
+
fs6.writeFileSync(pidFile, String(process.pid));
|
|
6695
6175
|
} catch {
|
|
6696
6176
|
}
|
|
6697
6177
|
return {
|
|
6698
6178
|
release() {
|
|
6699
6179
|
try {
|
|
6700
|
-
|
|
6180
|
+
fs6.rmSync(dir, { recursive: true, force: true });
|
|
6701
6181
|
} catch {
|
|
6702
6182
|
}
|
|
6703
6183
|
}
|
|
@@ -6706,9 +6186,9 @@ function acquireSyncLock(platform, model) {
|
|
|
6706
6186
|
|
|
6707
6187
|
// src/lib/memory/sync/hooks.ts
|
|
6708
6188
|
import { spawn as spawn2 } from "child_process";
|
|
6709
|
-
import
|
|
6710
|
-
import
|
|
6711
|
-
var EVENTS_DIR =
|
|
6189
|
+
import fs7 from "fs";
|
|
6190
|
+
import path7 from "path";
|
|
6191
|
+
var EVENTS_DIR = path7.join(".one", "sync", "events");
|
|
6712
6192
|
function classifyRecords(db, model, records, idField, tableExists2) {
|
|
6713
6193
|
if (!tableExists2 || records.length === 0) {
|
|
6714
6194
|
return { inserts: records, updates: [] };
|
|
@@ -6754,10 +6234,10 @@ async function fireHooks(hookCommand, events) {
|
|
|
6754
6234
|
function appendEventLog(events) {
|
|
6755
6235
|
if (events.length === 0) return;
|
|
6756
6236
|
const { platform, model } = events[0];
|
|
6757
|
-
|
|
6758
|
-
const logPath =
|
|
6237
|
+
fs7.mkdirSync(EVENTS_DIR, { recursive: true });
|
|
6238
|
+
const logPath = path7.join(EVENTS_DIR, `${platform}_${model}.jsonl`);
|
|
6759
6239
|
const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
6760
|
-
|
|
6240
|
+
fs7.appendFileSync(logPath, lines);
|
|
6761
6241
|
}
|
|
6762
6242
|
function runShellHook(command, events) {
|
|
6763
6243
|
return new Promise((resolve) => {
|
|
@@ -6861,8 +6341,8 @@ function sleep(ms) {
|
|
|
6861
6341
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6862
6342
|
}
|
|
6863
6343
|
function interpolate(template, record) {
|
|
6864
|
-
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_,
|
|
6865
|
-
const parts =
|
|
6344
|
+
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_, path13) => {
|
|
6345
|
+
const parts = path13.split(".");
|
|
6866
6346
|
let value = record;
|
|
6867
6347
|
for (const part2 of parts) {
|
|
6868
6348
|
if (typeof value !== "object" || value === null) return "";
|
|
@@ -6890,8 +6370,8 @@ function deepMerge(target, source) {
|
|
|
6890
6370
|
}
|
|
6891
6371
|
return result;
|
|
6892
6372
|
}
|
|
6893
|
-
function getByDotPath2(obj,
|
|
6894
|
-
const parts =
|
|
6373
|
+
function getByDotPath2(obj, path13) {
|
|
6374
|
+
const parts = path13.split(".");
|
|
6895
6375
|
let current = obj;
|
|
6896
6376
|
for (const part2 of parts) {
|
|
6897
6377
|
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
@@ -6900,8 +6380,8 @@ function getByDotPath2(obj, path16) {
|
|
|
6900
6380
|
return current;
|
|
6901
6381
|
}
|
|
6902
6382
|
function stripExcludedFields(obj, paths) {
|
|
6903
|
-
for (const
|
|
6904
|
-
stripOnePath(obj,
|
|
6383
|
+
for (const path13 of paths) {
|
|
6384
|
+
stripOnePath(obj, path13.replace(/\[\]/g, ".*").split("."));
|
|
6905
6385
|
}
|
|
6906
6386
|
}
|
|
6907
6387
|
function stripOnePath(obj, parts) {
|
|
@@ -7067,7 +6547,7 @@ async function enrichPhase(api, db, config2, model, idField, connectionKey, plat
|
|
|
7067
6547
|
);
|
|
7068
6548
|
let batchHitRateLimit = false;
|
|
7069
6549
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7070
|
-
const
|
|
6550
|
+
const pending = [];
|
|
7071
6551
|
for (let j = 0; j < results.length; j++) {
|
|
7072
6552
|
const result = results[j];
|
|
7073
6553
|
const row = batch[j];
|
|
@@ -7086,7 +6566,7 @@ async function enrichPhase(api, db, config2, model, idField, connectionKey, plat
|
|
|
7086
6566
|
const fp = merged[config2.invalidateOn] ?? row[config2.invalidateOn];
|
|
7087
6567
|
merged[ENRICH_FINGERPRINT_COLUMN] = fp == null ? null : String(fp);
|
|
7088
6568
|
}
|
|
7089
|
-
|
|
6569
|
+
pending.push({ merged, id });
|
|
7090
6570
|
} else if (result.status === "fulfilled" && result.value === null) {
|
|
7091
6571
|
rateLimited++;
|
|
7092
6572
|
skipped++;
|
|
@@ -7095,14 +6575,14 @@ async function enrichPhase(api, db, config2, model, idField, connectionKey, plat
|
|
|
7095
6575
|
skipped++;
|
|
7096
6576
|
}
|
|
7097
6577
|
}
|
|
7098
|
-
let writes =
|
|
7099
|
-
if (ctx.transform &&
|
|
7100
|
-
const transformed = await transformRecords(ctx.transform,
|
|
6578
|
+
let writes = pending;
|
|
6579
|
+
if (ctx.transform && pending.length > 0) {
|
|
6580
|
+
const transformed = await transformRecords(ctx.transform, pending.map((p9) => p9.merged));
|
|
7101
6581
|
if (transformed) {
|
|
7102
6582
|
const byId = /* @__PURE__ */ new Map();
|
|
7103
6583
|
for (const r of transformed) byId.set(r[idField], r);
|
|
7104
6584
|
writes = [];
|
|
7105
|
-
for (const p9 of
|
|
6585
|
+
for (const p9 of pending) {
|
|
7106
6586
|
const t = byId.get(p9.id);
|
|
7107
6587
|
if (!t) continue;
|
|
7108
6588
|
if (!t[tsField]) t[tsField] = now;
|
|
@@ -7322,8 +6802,8 @@ function sleep2(ms) {
|
|
|
7322
6802
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7323
6803
|
}
|
|
7324
6804
|
function stripFields(record, paths) {
|
|
7325
|
-
for (const
|
|
7326
|
-
stripOnePath2(record,
|
|
6805
|
+
for (const path13 of paths) {
|
|
6806
|
+
stripOnePath2(record, path13.split("."));
|
|
7327
6807
|
}
|
|
7328
6808
|
}
|
|
7329
6809
|
function stripOnePath2(obj, parts) {
|
|
@@ -8416,19 +7896,19 @@ function inferProfileFromKnowledge(knowledge, modelName, platform) {
|
|
|
8416
7896
|
|
|
8417
7897
|
// src/lib/memory/sync/schedule.ts
|
|
8418
7898
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
8419
|
-
import
|
|
8420
|
-
import
|
|
8421
|
-
import
|
|
7899
|
+
import fs9 from "fs";
|
|
7900
|
+
import os from "os";
|
|
7901
|
+
import path9 from "path";
|
|
8422
7902
|
|
|
8423
7903
|
// src/lib/memory/sync/schedule-registry.ts
|
|
8424
|
-
import
|
|
8425
|
-
import
|
|
8426
|
-
var REGISTRY_DIR = () =>
|
|
8427
|
-
var REGISTRY_FILE = () =>
|
|
7904
|
+
import fs8 from "fs";
|
|
7905
|
+
import path8 from "path";
|
|
7906
|
+
var REGISTRY_DIR = () => path8.join(homeDir(), ".one", "sync");
|
|
7907
|
+
var REGISTRY_FILE = () => path8.join(REGISTRY_DIR(), "schedules.json");
|
|
8428
7908
|
function readRaw() {
|
|
8429
7909
|
try {
|
|
8430
|
-
if (!
|
|
8431
|
-
const raw =
|
|
7910
|
+
if (!fs8.existsSync(REGISTRY_FILE())) return { schedules: [] };
|
|
7911
|
+
const raw = fs8.readFileSync(REGISTRY_FILE(), "utf-8");
|
|
8432
7912
|
const parsed = JSON.parse(raw);
|
|
8433
7913
|
if (!parsed || !Array.isArray(parsed.schedules)) return { schedules: [] };
|
|
8434
7914
|
return parsed;
|
|
@@ -8437,13 +7917,13 @@ function readRaw() {
|
|
|
8437
7917
|
}
|
|
8438
7918
|
}
|
|
8439
7919
|
function writeRaw(file) {
|
|
8440
|
-
|
|
7920
|
+
fs8.mkdirSync(REGISTRY_DIR(), { recursive: true });
|
|
8441
7921
|
const tmp = REGISTRY_FILE() + ".tmp";
|
|
8442
|
-
|
|
8443
|
-
|
|
7922
|
+
fs8.writeFileSync(tmp, JSON.stringify(file, null, 2));
|
|
7923
|
+
fs8.renameSync(tmp, REGISTRY_FILE());
|
|
8444
7924
|
}
|
|
8445
7925
|
function makeScheduleId(platform, cwd) {
|
|
8446
|
-
const slug =
|
|
7926
|
+
const slug = path8.basename(cwd).replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
|
|
8447
7927
|
return `${platform}-${slug}`;
|
|
8448
7928
|
}
|
|
8449
7929
|
function listRegistered() {
|
|
@@ -8477,7 +7957,7 @@ function removeRegistered(id) {
|
|
|
8477
7957
|
|
|
8478
7958
|
// src/lib/memory/sync/schedule.ts
|
|
8479
7959
|
var MARKER = "# one-sync";
|
|
8480
|
-
var LOG_DIR_REL =
|
|
7960
|
+
var LOG_DIR_REL = path9.join(".one", "sync", "logs");
|
|
8481
7961
|
function durationToCron(every) {
|
|
8482
7962
|
const match = every.match(/^(\d+)([mhd])$/);
|
|
8483
7963
|
if (!match) return null;
|
|
@@ -8510,13 +7990,13 @@ function cronExprToDuration(expr) {
|
|
|
8510
7990
|
return null;
|
|
8511
7991
|
}
|
|
8512
7992
|
function isWindows() {
|
|
8513
|
-
return
|
|
7993
|
+
return os.platform() === "win32";
|
|
8514
7994
|
}
|
|
8515
7995
|
function resolveOneBinary() {
|
|
8516
7996
|
try {
|
|
8517
7997
|
const entry = process.argv[1];
|
|
8518
|
-
if (entry &&
|
|
8519
|
-
return
|
|
7998
|
+
if (entry && fs9.existsSync(entry)) {
|
|
7999
|
+
return fs9.realpathSync(entry);
|
|
8520
8000
|
}
|
|
8521
8001
|
} catch {
|
|
8522
8002
|
}
|
|
@@ -8594,7 +8074,7 @@ function migrateLegacyCronEntries() {
|
|
|
8594
8074
|
const modelsMatch = command.match(/--models\s+(\S+)/);
|
|
8595
8075
|
const models = modelsMatch ? modelsMatch[1].split(",") : void 0;
|
|
8596
8076
|
const logMatch = command.match(/>>\s+"([^"]+)"/);
|
|
8597
|
-
const logFile = logMatch ? logMatch[1] :
|
|
8077
|
+
const logFile = logMatch ? logMatch[1] : path9.resolve(cwd, LOG_DIR_REL, `${platform}.log`);
|
|
8598
8078
|
const id = makeScheduleId(platform, cwd);
|
|
8599
8079
|
if (registeredIds.has(id)) continue;
|
|
8600
8080
|
upsertRegistered({
|
|
@@ -8628,9 +8108,9 @@ function addSchedule(opts) {
|
|
|
8628
8108
|
const cwd = process.cwd();
|
|
8629
8109
|
const id = makeScheduleId(opts.platform, cwd);
|
|
8630
8110
|
const replaced = getRegistered(id) !== void 0;
|
|
8631
|
-
const logDir =
|
|
8632
|
-
|
|
8633
|
-
const logFile =
|
|
8111
|
+
const logDir = path9.join(cwd, LOG_DIR_REL);
|
|
8112
|
+
fs9.mkdirSync(logDir, { recursive: true });
|
|
8113
|
+
const logFile = path9.join(logDir, `${opts.platform}.log`);
|
|
8634
8114
|
const entry = {
|
|
8635
8115
|
id,
|
|
8636
8116
|
platform: opts.platform,
|
|
@@ -8684,15 +8164,15 @@ function removeSchedule(idOrPlatform, options) {
|
|
|
8684
8164
|
function scheduleStatus() {
|
|
8685
8165
|
const entries = listSchedules();
|
|
8686
8166
|
return entries.map((entry) => {
|
|
8687
|
-
const logExists =
|
|
8688
|
-
const logSize = logExists ?
|
|
8167
|
+
const logExists = fs9.existsSync(entry.logFile);
|
|
8168
|
+
const logSize = logExists ? fs9.statSync(entry.logFile).size : 0;
|
|
8689
8169
|
let logTail = [];
|
|
8690
8170
|
let lastRunAt = null;
|
|
8691
8171
|
if (logExists) {
|
|
8692
8172
|
try {
|
|
8693
|
-
lastRunAt =
|
|
8173
|
+
lastRunAt = fs9.statSync(entry.logFile).mtime.toISOString();
|
|
8694
8174
|
if (logSize > 0) {
|
|
8695
|
-
const content =
|
|
8175
|
+
const content = fs9.readFileSync(entry.logFile, "utf-8");
|
|
8696
8176
|
logTail = content.trim().split("\n").slice(-10);
|
|
8697
8177
|
}
|
|
8698
8178
|
} catch {
|
|
@@ -8700,8 +8180,8 @@ function scheduleStatus() {
|
|
|
8700
8180
|
}
|
|
8701
8181
|
let drift = "ok";
|
|
8702
8182
|
if (!entry.cronInstalled) drift = "missing-cron";
|
|
8703
|
-
else if (!
|
|
8704
|
-
else if (!
|
|
8183
|
+
else if (!fs9.existsSync(entry.nodeBin)) drift = "stale-node-bin";
|
|
8184
|
+
else if (!fs9.existsSync(entry.cliBin)) drift = "stale-cli-bin";
|
|
8705
8185
|
return { entry, logExists, logSize, logTail, lastRunAt, drift };
|
|
8706
8186
|
});
|
|
8707
8187
|
}
|
|
@@ -8974,11 +8454,11 @@ function isNoise(s) {
|
|
|
8974
8454
|
if (/^-?\d+(\.\d+)?([eE][-+]?\d+)?$/.test(s)) return true;
|
|
8975
8455
|
return false;
|
|
8976
8456
|
}
|
|
8977
|
-
function recordSample(stats,
|
|
8978
|
-
let s = stats.get(
|
|
8457
|
+
function recordSample(stats, path13, value, jsType, recordIndex, totalSamples) {
|
|
8458
|
+
let s = stats.get(path13);
|
|
8979
8459
|
if (!s) {
|
|
8980
8460
|
s = {
|
|
8981
|
-
path:
|
|
8461
|
+
path: path13,
|
|
8982
8462
|
total: totalSamples,
|
|
8983
8463
|
recordIndices: /* @__PURE__ */ new Set(),
|
|
8984
8464
|
lenSum: 0,
|
|
@@ -8987,7 +8467,7 @@ function recordSample(stats, path16, value, jsType, recordIndex, totalSamples) {
|
|
|
8987
8467
|
primaryType: jsType,
|
|
8988
8468
|
examples: []
|
|
8989
8469
|
};
|
|
8990
|
-
stats.set(
|
|
8470
|
+
stats.set(path13, s);
|
|
8991
8471
|
}
|
|
8992
8472
|
s.recordIndices.add(recordIndex);
|
|
8993
8473
|
s.lenSum += value.length;
|
|
@@ -8996,28 +8476,28 @@ function recordSample(stats, path16, value, jsType, recordIndex, totalSamples) {
|
|
|
8996
8476
|
if (s.primaryType !== jsType) s.primaryType = "mixed";
|
|
8997
8477
|
if (s.examples.length < 3 && value.length < 200) s.examples.push(value);
|
|
8998
8478
|
}
|
|
8999
|
-
function walkRecord(record,
|
|
8479
|
+
function walkRecord(record, path13, stats, recordIndex, totalSamples) {
|
|
9000
8480
|
if (record === null || record === void 0) return;
|
|
9001
8481
|
if (typeof record === "string") {
|
|
9002
8482
|
const trimmed = record.trim();
|
|
9003
|
-
if (trimmed) recordSample(stats,
|
|
8483
|
+
if (trimmed) recordSample(stats, path13, trimmed, "string", recordIndex, totalSamples);
|
|
9004
8484
|
return;
|
|
9005
8485
|
}
|
|
9006
8486
|
if (typeof record === "number" || typeof record === "boolean") {
|
|
9007
8487
|
const str = String(record);
|
|
9008
8488
|
const kind = typeof record === "number" ? "number" : "boolean";
|
|
9009
|
-
if (str) recordSample(stats,
|
|
8489
|
+
if (str) recordSample(stats, path13, str, kind, recordIndex, totalSamples);
|
|
9010
8490
|
return;
|
|
9011
8491
|
}
|
|
9012
8492
|
if (Array.isArray(record)) {
|
|
9013
|
-
const childPath =
|
|
8493
|
+
const childPath = path13 ? `${path13}[]` : "[]";
|
|
9014
8494
|
for (const item of record) walkRecord(item, childPath, stats, recordIndex, totalSamples);
|
|
9015
8495
|
return;
|
|
9016
8496
|
}
|
|
9017
8497
|
if (typeof record === "object") {
|
|
9018
8498
|
for (const [key, value] of Object.entries(record)) {
|
|
9019
8499
|
if (key.startsWith("_")) continue;
|
|
9020
|
-
const childPath =
|
|
8500
|
+
const childPath = path13 ? `${path13}.${key}` : key;
|
|
9021
8501
|
walkRecord(value, childPath, stats, recordIndex, totalSamples);
|
|
9022
8502
|
}
|
|
9023
8503
|
}
|
|
@@ -9055,7 +8535,7 @@ function suggestSearchablePaths(records, limit = 15) {
|
|
|
9055
8535
|
// src/lib/memory/sync/index.ts
|
|
9056
8536
|
import { spawn as spawn4 } from "child_process";
|
|
9057
8537
|
import * as p6 from "@clack/prompts";
|
|
9058
|
-
import
|
|
8538
|
+
import pc10 from "picocolors";
|
|
9059
8539
|
async function syncInstallCommand() {
|
|
9060
8540
|
if (await isSqliteAvailable()) {
|
|
9061
8541
|
if (isAgentMode()) {
|
|
@@ -9120,15 +8600,15 @@ async function syncDoctorCommand() {
|
|
|
9120
8600
|
return;
|
|
9121
8601
|
}
|
|
9122
8602
|
for (const c of checks) {
|
|
9123
|
-
const mark = c.ok ?
|
|
9124
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8603
|
+
const mark = c.ok ? pc10.green("\u2713") : pc10.red("\u2717");
|
|
8604
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc10.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
9125
8605
|
}
|
|
9126
8606
|
if (!allOk) {
|
|
9127
8607
|
console.log(`
|
|
9128
|
-
${
|
|
8608
|
+
${pc10.yellow("Sync is not ready.")} Try: ${pc10.bold("one sync install")}`);
|
|
9129
8609
|
} else {
|
|
9130
8610
|
console.log(`
|
|
9131
|
-
${
|
|
8611
|
+
${pc10.green("Sync is ready.")}`);
|
|
9132
8612
|
}
|
|
9133
8613
|
}
|
|
9134
8614
|
function getApi() {
|
|
@@ -9171,11 +8651,11 @@ async function syncProfilesCommand(platform) {
|
|
|
9171
8651
|
if (p9.enrich) extras.push("enrich");
|
|
9172
8652
|
if (p9.identityKey || p9.identityKeys) extras.push("identity");
|
|
9173
8653
|
if (p9.dateFilter) extras.push("incremental");
|
|
9174
|
-
const tags = extras.length > 0 ? ` ${
|
|
9175
|
-
console.log(` ${
|
|
8654
|
+
const tags = extras.length > 0 ? ` ${pc10.dim(`[${extras.join(", ")}]`)}` : "";
|
|
8655
|
+
console.log(` ${pc10.bold(`${p9.platform}/${p9.model}`.padEnd(35))} ${p9.description}${tags}`);
|
|
9176
8656
|
}
|
|
9177
8657
|
console.log(`
|
|
9178
|
-
${profiles.length} built-in profile(s). Run ${
|
|
8658
|
+
${profiles.length} built-in profile(s). Run ${pc10.bold("one sync init <platform> <model>")} to use one.`);
|
|
9179
8659
|
}
|
|
9180
8660
|
async function syncModelsCommand(platform) {
|
|
9181
8661
|
const api = getApi();
|
|
@@ -9193,7 +8673,7 @@ async function syncModelsCommand(platform) {
|
|
|
9193
8673
|
return;
|
|
9194
8674
|
}
|
|
9195
8675
|
const lines = models.map(
|
|
9196
|
-
(m) => ` ${
|
|
8676
|
+
(m) => ` ${pc10.bold(m.name.padEnd(30))} ${pc10.dim(m.listAction.method)} ${pc10.dim(m.listAction.path)}`
|
|
9197
8677
|
);
|
|
9198
8678
|
note(lines.join("\n"), `${platform} \u2014 ${models.length} models`);
|
|
9199
8679
|
} catch (err) {
|
|
@@ -9297,15 +8777,15 @@ async function syncInitCommand(platform, model, options) {
|
|
|
9297
8777
|
note(JSON.stringify(template, null, 2), "Sync profile template");
|
|
9298
8778
|
if (inferred && inferred.reasoning.length > 0) {
|
|
9299
8779
|
console.log(`
|
|
9300
|
-
${
|
|
9301
|
-
for (const r of inferred.reasoning) console.log(` ${
|
|
8780
|
+
${pc10.bold("Inferred from knowledge:")}`);
|
|
8781
|
+
for (const r of inferred.reasoning) console.log(` ${pc10.dim("\u2022")} ${r}`);
|
|
9302
8782
|
}
|
|
9303
8783
|
if (testReport) {
|
|
9304
8784
|
console.log(`
|
|
9305
|
-
${
|
|
8785
|
+
${pc10.bold("Test results:")}`);
|
|
9306
8786
|
for (const c of testReport.checks) {
|
|
9307
|
-
const mark = c.ok ?
|
|
9308
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8787
|
+
const mark = c.ok ? pc10.green("\u2713") : pc10.red("\u2717");
|
|
8788
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc10.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
9309
8789
|
}
|
|
9310
8790
|
}
|
|
9311
8791
|
console.log(`
|
|
@@ -9388,17 +8868,17 @@ async function syncTestCommand(platformModel, options = {}) {
|
|
|
9388
8868
|
return;
|
|
9389
8869
|
}
|
|
9390
8870
|
for (const c of report2.checks) {
|
|
9391
|
-
const mark = c.ok ?
|
|
9392
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8871
|
+
const mark = c.ok ? pc10.green("\u2713") : pc10.red("\u2717");
|
|
8872
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc10.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
9393
8873
|
}
|
|
9394
8874
|
if (report2.detectedColumns && report2.detectedColumns.length > 0) {
|
|
9395
8875
|
console.log(`
|
|
9396
|
-
${
|
|
8876
|
+
${pc10.bold("Detected columns:")}`);
|
|
9397
8877
|
for (const col of report2.detectedColumns.slice(0, 20)) {
|
|
9398
|
-
console.log(` ${col.name.padEnd(30)} ${
|
|
8878
|
+
console.log(` ${col.name.padEnd(30)} ${pc10.dim(col.type)}`);
|
|
9399
8879
|
}
|
|
9400
8880
|
if (report2.detectedColumns.length > 20) {
|
|
9401
|
-
console.log(
|
|
8881
|
+
console.log(pc10.dim(` ... and ${report2.detectedColumns.length - 20} more`));
|
|
9402
8882
|
}
|
|
9403
8883
|
}
|
|
9404
8884
|
if (report2.identityKeysPreview) {
|
|
@@ -9406,45 +8886,45 @@ async function syncTestCommand(platformModel, options = {}) {
|
|
|
9406
8886
|
const total = perRecord.reduce((a, b) => a + b, 0);
|
|
9407
8887
|
const min = perRecord.length ? Math.min(...perRecord) : 0;
|
|
9408
8888
|
const max = perRecord.length ? Math.max(...perRecord) : 0;
|
|
9409
|
-
const mark = total === 0 ?
|
|
8889
|
+
const mark = total === 0 ? pc10.yellow("~") : pc10.green("\u2713");
|
|
9410
8890
|
console.log(`
|
|
9411
|
-
${
|
|
8891
|
+
${pc10.bold("Merge + identity keys")} ${pc10.dim(`(cross-platform \u2014 #128)`)}`);
|
|
9412
8892
|
console.log(` ${mark} ${perRecord.length} sample${perRecord.length === 1 ? "" : "s"}, ${min}\u2013${max} key${max === 1 ? "" : "s"} per record`);
|
|
9413
8893
|
if (sampleKeys.length > 0) {
|
|
9414
|
-
console.log(` ${
|
|
8894
|
+
console.log(` ${pc10.dim("e.g.")} ${sampleKeys.slice(0, 8).map((k) => pc10.cyan(k)).join(", ")}`);
|
|
9415
8895
|
} else if (resolvesAfterEnrich) {
|
|
9416
|
-
console.log(` ${
|
|
8896
|
+
console.log(` ${pc10.dim("note:")} 0 on these list-shape samples \u2014 this profile enriches, and its identityKeys paths resolve in the enrich phase.`);
|
|
9417
8897
|
} else {
|
|
9418
|
-
console.log(` ${
|
|
8898
|
+
console.log(` ${pc10.yellow("note:")} no identity keys resolved on these samples \u2014 check the identityKey/identityKeys paths.`);
|
|
9419
8899
|
}
|
|
9420
8900
|
if (entityFanOut) {
|
|
9421
|
-
console.log(` ${
|
|
9422
|
-
console.log(` ${
|
|
9423
|
-
console.log(` ${
|
|
9424
|
-
console.log(` ${
|
|
8901
|
+
console.log(` ${pc10.yellow("warn:")} identityKey resolved to MULTIPLE values on ${entityFanOut.count} of ${perRecord.length} samples \u2014 those records get NO merge key.`);
|
|
8902
|
+
console.log(` ${pc10.dim("saw:")} ${entityFanOut.sampleValues.map((v) => pc10.cyan(v)).join(", ")}`);
|
|
8903
|
+
console.log(` ${pc10.dim('A singular identityKey means "this record IS this entity", so a fan-out has no safe answer.')}`);
|
|
8904
|
+
console.log(` ${pc10.dim("Point it at a single-valued path, or move it to identityKeys[] for participant associations.")}`);
|
|
9425
8905
|
}
|
|
9426
8906
|
}
|
|
9427
8907
|
if (searchablePreview) {
|
|
9428
8908
|
console.log(`
|
|
9429
|
-
${
|
|
9430
|
-
console.log(` ${
|
|
9431
|
-
console.log(` ${
|
|
8909
|
+
${pc10.bold("Searchable preview")} ${pc10.dim(`(${searchablePreview.mode}, ${searchablePreview.sampledRecords} sample${searchablePreview.sampledRecords === 1 ? "" : "s"})`)}`);
|
|
8910
|
+
console.log(` ${pc10.dim("length:")} ${searchablePreview.length} chars (first sample)`);
|
|
8911
|
+
console.log(` ${pc10.dim("text:")} ${searchablePreview.text.slice(0, 300)}${searchablePreview.length > 300 ? pc10.dim(" \u2026") : ""}`);
|
|
9432
8912
|
if (searchablePreview.paths) {
|
|
9433
|
-
console.log(` ${
|
|
8913
|
+
console.log(` ${pc10.dim("paths:")} ${pc10.dim('(hit rate across all samples \u2014 differentiates "wrong path" from "field sometimes missing")')}`);
|
|
9434
8914
|
for (const p9 of searchablePreview.paths) {
|
|
9435
8915
|
const rate = `${p9.hits}/${p9.total}`;
|
|
9436
|
-
const mark = p9.hits === p9.total ?
|
|
9437
|
-
const trailer = p9.sample ?
|
|
8916
|
+
const mark = p9.hits === p9.total ? pc10.green("\u2713") : p9.hits === 0 ? pc10.red("\u2717") : pc10.yellow("~");
|
|
8917
|
+
const trailer = p9.sample ? pc10.dim(` \u2192 "${p9.sample}"`) : p9.hits === 0 ? pc10.dim(" (no sample matched \u2014 typo, or field never populated in this page)") : "";
|
|
9438
8918
|
console.log(` ${mark} ${rate.padStart(5)} ${p9.path}${trailer}`);
|
|
9439
8919
|
}
|
|
9440
8920
|
} else {
|
|
9441
|
-
console.log(` ${
|
|
9442
|
-
console.log(` ${
|
|
8921
|
+
console.log(` ${pc10.yellow("note:")} no memory.searchable declared \u2014 using the default walker (walks every field, often noisy).`);
|
|
8922
|
+
console.log(` ${pc10.dim("tip:")} run \`one sync suggest-searchable ${platform}/${model}\` for an auto-ranked starter list, or pick paths by hand and add them to profile.memory.searchable.`);
|
|
9443
8923
|
}
|
|
9444
8924
|
}
|
|
9445
8925
|
console.log(
|
|
9446
8926
|
`
|
|
9447
|
-
${report2.ok ?
|
|
8927
|
+
${report2.ok ? pc10.green("Profile looks good.") : pc10.red("Profile has issues.")} ` + (report2.ok ? `Run: ${pc10.bold(`one sync run ${platform} --models ${model}`)}` : "Fix the issues above and test again.")
|
|
9448
8928
|
);
|
|
9449
8929
|
}
|
|
9450
8930
|
function buildSearchablePreview(profile, samples) {
|
|
@@ -9452,7 +8932,7 @@ function buildSearchablePreview(profile, samples) {
|
|
|
9452
8932
|
const first = samples[0];
|
|
9453
8933
|
const paths = getSearchablePaths(profile);
|
|
9454
8934
|
if (paths) {
|
|
9455
|
-
const perPathAgg = paths.map((
|
|
8935
|
+
const perPathAgg = paths.map((path13) => ({ path: path13, hits: 0, total: samples.length, sample: "" }));
|
|
9456
8936
|
for (const record of samples) {
|
|
9457
8937
|
const { paths: perPath } = extractSearchableFromPaths(record, paths);
|
|
9458
8938
|
perPath.forEach((p9, i) => {
|
|
@@ -9485,8 +8965,8 @@ async function syncRunCommand(platform, options) {
|
|
|
9485
8965
|
if (profileDrift.length > 0 && !isAgentMode()) {
|
|
9486
8966
|
for (const d of profileDrift) {
|
|
9487
8967
|
console.log(
|
|
9488
|
-
` ${
|
|
9489
|
-
Run ${
|
|
8968
|
+
` ${pc10.yellow("!")} ${platform}/${d.model} is missing ${d.missing.map((f) => pc10.bold(f)).join(", ")} from the current built-in profile.
|
|
8969
|
+
Run ${pc10.bold(`one sync init ${platform} ${d.model}`)} to pick ${d.missing.length > 1 ? "them" : "it"} up.`
|
|
9490
8970
|
);
|
|
9491
8971
|
}
|
|
9492
8972
|
}
|
|
@@ -9529,21 +9009,21 @@ async function syncRunCommand(platform, options) {
|
|
|
9529
9009
|
return;
|
|
9530
9010
|
}
|
|
9531
9011
|
for (const r of results) {
|
|
9532
|
-
const status2 = r.status === "complete" ?
|
|
9533
|
-
console.log(` ${
|
|
9012
|
+
const status2 = r.status === "complete" ? pc10.green("complete") : r.status === "dry-run" ? pc10.yellow("dry-run") : pc10.red("failed");
|
|
9013
|
+
console.log(` ${pc10.bold(r.model)} \u2014 ${r.recordsSynced} records, ${r.pagesProcessed} pages, ${r.duration} [${status2}]`);
|
|
9534
9014
|
if (r.reconcileSkipped) {
|
|
9535
|
-
console.log(` ${
|
|
9015
|
+
console.log(` ${pc10.yellow("--full-refresh reconcile skipped \u2014 pagination truncated (e.g. --max-pages). Re-run without the cap to prune stale rows.")}`);
|
|
9536
9016
|
}
|
|
9537
9017
|
const sc = r.statusCounts;
|
|
9538
9018
|
if (sc && (sc.archived > 0 || sc.active > 0)) {
|
|
9539
|
-
const archivedColor = sc.archived > sc.active ?
|
|
9540
|
-
console.log(` memory: ${
|
|
9019
|
+
const archivedColor = sc.archived > sc.active ? pc10.red : pc10.dim;
|
|
9020
|
+
console.log(` memory: ${pc10.green(String(sc.active))} active, ${archivedColor(String(sc.archived))} archived`);
|
|
9541
9021
|
}
|
|
9542
9022
|
if (r.error) {
|
|
9543
9023
|
const errParts = [r.error.message];
|
|
9544
9024
|
if (r.error.httpStatus) errParts.push(`HTTP ${r.error.httpStatus}`);
|
|
9545
9025
|
if (r.error.retryAfter) errParts.push(`retry after ${r.error.retryAfter}s`);
|
|
9546
|
-
console.log(` ${
|
|
9026
|
+
console.log(` ${pc10.red(errParts.join(" \u2014 "))}`);
|
|
9547
9027
|
}
|
|
9548
9028
|
}
|
|
9549
9029
|
}
|
|
@@ -9569,8 +9049,8 @@ async function syncQueryCommand(platformModel, options) {
|
|
|
9569
9049
|
json(result);
|
|
9570
9050
|
return;
|
|
9571
9051
|
}
|
|
9572
|
-
console.log(
|
|
9573
|
-
console.log(
|
|
9052
|
+
console.log(pc10.dim(`Query: ${result.query}`));
|
|
9053
|
+
console.log(pc10.dim(`Source: local | Last sync: ${result.lastSync ?? "never"} | Age: ${result.syncAge ?? "n/a"}`));
|
|
9574
9054
|
console.log(JSON.stringify(result.results, null, 2));
|
|
9575
9055
|
console.log(`
|
|
9576
9056
|
${result.total} results`);
|
|
@@ -9592,7 +9072,7 @@ async function syncSearchCommand(query, options) {
|
|
|
9592
9072
|
return;
|
|
9593
9073
|
}
|
|
9594
9074
|
for (const r of result.results) {
|
|
9595
|
-
console.log(` ${
|
|
9075
|
+
console.log(` ${pc10.bold(`${r.platform}/${r.model}`)} ${pc10.dim(`(rank: ${r.rank.toFixed(2)})`)}`);
|
|
9596
9076
|
console.log(` ${JSON.stringify(r.record)}`);
|
|
9597
9077
|
}
|
|
9598
9078
|
console.log(`
|
|
@@ -9602,7 +9082,7 @@ ${result.total} results`);
|
|
|
9602
9082
|
}
|
|
9603
9083
|
}
|
|
9604
9084
|
async function syncSqlCommand(platformModel, sql) {
|
|
9605
|
-
const { syncSqlCommand: runSyncSql } = await import("./sql-
|
|
9085
|
+
const { syncSqlCommand: runSyncSql } = await import("./sql-NDMMFQP6.js");
|
|
9606
9086
|
await runSyncSql(platformModel, sql);
|
|
9607
9087
|
}
|
|
9608
9088
|
async function syncDeleteCommand(platformModel, options) {
|
|
@@ -9696,7 +9176,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
9696
9176
|
` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
|
|
9697
9177
|
`
|
|
9698
9178
|
);
|
|
9699
|
-
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-
|
|
9179
|
+
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-KWEEEQ3E.js");
|
|
9700
9180
|
await memMigrateCommand3({ platform, yes: true });
|
|
9701
9181
|
return;
|
|
9702
9182
|
}
|
|
@@ -9705,7 +9185,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
9705
9185
|
initialValue: true
|
|
9706
9186
|
});
|
|
9707
9187
|
if (p6.isCancel(shouldMigrate) || !shouldMigrate) return;
|
|
9708
|
-
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-
|
|
9188
|
+
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-KWEEEQ3E.js");
|
|
9709
9189
|
await memMigrateCommand2({ platform, yes: true });
|
|
9710
9190
|
}
|
|
9711
9191
|
async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
@@ -9743,25 +9223,25 @@ async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
|
9743
9223
|
return;
|
|
9744
9224
|
}
|
|
9745
9225
|
console.log(`
|
|
9746
|
-
${
|
|
9226
|
+
${pc10.bold("memory.searchable \u2014 ranked suggestions")} ${pc10.dim(`(${samples.length} samples)`)}`);
|
|
9747
9227
|
if (suggestions.length === 0) {
|
|
9748
|
-
console.log(` ${
|
|
9228
|
+
console.log(` ${pc10.yellow("no high-signal leaves found")} \u2014 page may be all UUIDs / timestamps / enum markers. Inspect the sample with \`sync test\` and pick paths manually.`);
|
|
9749
9229
|
return;
|
|
9750
9230
|
}
|
|
9751
9231
|
for (const s of suggestions) {
|
|
9752
9232
|
const hitPct = Math.round(s.hitRate * 100);
|
|
9753
9233
|
const noisePct = Math.round(s.noiseFraction * 100);
|
|
9754
|
-
const noiseBadge = noisePct > 0 ?
|
|
9234
|
+
const noiseBadge = noisePct > 0 ? pc10.dim(` noise=${noisePct}%`) : "";
|
|
9755
9235
|
console.log(
|
|
9756
|
-
` ${
|
|
9236
|
+
` ${pc10.green(String(s.score).padStart(5))} ${pc10.cyan(s.path.padEnd(52))}` + pc10.dim(` ${hitPct}% hit`) + pc10.dim(` avg=${s.avgLength}ch`) + noiseBadge + (s.sampleValue ? pc10.dim(`
|
|
9757
9237
|
\u2192 "${s.sampleValue.slice(0, 140)}"`) : "")
|
|
9758
9238
|
);
|
|
9759
9239
|
}
|
|
9760
9240
|
console.log(`
|
|
9761
|
-
${
|
|
9762
|
-
console.log(" " +
|
|
9241
|
+
${pc10.bold("Paste-ready:")}`);
|
|
9242
|
+
console.log(" " + pc10.cyan(`one sync init ${platform} ${model} --config '${JSON.stringify(configPatch)}'`));
|
|
9763
9243
|
console.log(`
|
|
9764
|
-
${
|
|
9244
|
+
${pc10.dim("then preview: ")}${pc10.cyan(`one sync test ${platform}/${model} --show-searchable`)}`);
|
|
9765
9245
|
}
|
|
9766
9246
|
async function syncListCommand(platform) {
|
|
9767
9247
|
const profiles = listProfiles(platform);
|
|
@@ -9795,10 +9275,10 @@ async function syncListCommand(platform) {
|
|
|
9795
9275
|
return;
|
|
9796
9276
|
}
|
|
9797
9277
|
for (const s of syncs) {
|
|
9798
|
-
const status2 = s.status === "idle" ?
|
|
9799
|
-
const legacy = s.legacyDbSize && s.legacyDbSize !== "0 B" ?
|
|
9278
|
+
const status2 = s.status === "idle" ? pc10.green("idle") : s.status === "syncing" ? pc10.yellow(`syncing \u2014 page ${s.pagesProcessed}`) : pc10.red("failed");
|
|
9279
|
+
const legacy = s.legacyDbSize && s.legacyDbSize !== "0 B" ? pc10.yellow(` legacy .db ${s.legacyDbSize}`) : "";
|
|
9800
9280
|
console.log(
|
|
9801
|
-
` ${
|
|
9281
|
+
` ${pc10.bold(`${s.platform}/${s.model}`.padEnd(35))} ${String(s.totalRecords).padStart(8)} records ${status2} ${pc10.dim(s.lastSync ? `last: ${s.lastSync}` : "never synced")}` + legacy
|
|
9802
9282
|
);
|
|
9803
9283
|
}
|
|
9804
9284
|
}
|
|
@@ -9877,8 +9357,8 @@ async function syncScheduleAddCommand(platform, options) {
|
|
|
9877
9357
|
}
|
|
9878
9358
|
const verb = replaced ? "Replaced existing schedule" : "Scheduled sync";
|
|
9879
9359
|
outro(
|
|
9880
|
-
`${verb} ${
|
|
9881
|
-
Logs: ${
|
|
9360
|
+
`${verb} ${pc10.bold(entry.id)} \u2014 every ${pc10.bold(entry.every)} (cron: ${pc10.dim(entry.cronExpr)})
|
|
9361
|
+
Logs: ${pc10.dim(entry.logFile)}`
|
|
9882
9362
|
);
|
|
9883
9363
|
} catch (err) {
|
|
9884
9364
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -9897,14 +9377,14 @@ async function syncScheduleListCommand() {
|
|
|
9897
9377
|
}
|
|
9898
9378
|
for (const e of entries) {
|
|
9899
9379
|
const modelsStr = e.models ? ` [${e.models.join(",")}]` : "";
|
|
9900
|
-
const installed = e.cronInstalled ?
|
|
9380
|
+
const installed = e.cronInstalled ? pc10.green("\u25CF") : pc10.red("\u2717");
|
|
9901
9381
|
console.log(
|
|
9902
|
-
` ${installed} ${
|
|
9382
|
+
` ${installed} ${pc10.bold(e.id.padEnd(32))} every ${pc10.bold(e.every.padEnd(5))} ${pc10.dim(e.cronExpr.padEnd(13))}${modelsStr}`
|
|
9903
9383
|
);
|
|
9904
|
-
console.log(` ${
|
|
9384
|
+
console.log(` ${pc10.dim("cwd:")} ${e.cwd}`);
|
|
9905
9385
|
}
|
|
9906
9386
|
console.log(`
|
|
9907
|
-
${
|
|
9387
|
+
${pc10.dim("\u25CF = cron line installed \u2717 = registry drift, run `sync schedule repair <id>`")}`);
|
|
9908
9388
|
} catch (err) {
|
|
9909
9389
|
error(err instanceof Error ? err.message : String(err));
|
|
9910
9390
|
}
|
|
@@ -9928,7 +9408,7 @@ async function syncScheduleRemoveCommand(idOrPlatform, options) {
|
|
|
9928
9408
|
return;
|
|
9929
9409
|
}
|
|
9930
9410
|
for (const r of result.removed) {
|
|
9931
|
-
console.log(` ${
|
|
9411
|
+
console.log(` ${pc10.green("\u2713")} removed ${pc10.bold(r.id)} ${pc10.dim(`(${r.cwd})`)}`);
|
|
9932
9412
|
}
|
|
9933
9413
|
} catch (err) {
|
|
9934
9414
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -9946,21 +9426,21 @@ async function syncScheduleStatusCommand() {
|
|
|
9946
9426
|
return;
|
|
9947
9427
|
}
|
|
9948
9428
|
for (const s of statuses) {
|
|
9949
|
-
const driftMarker = s.drift === "ok" ?
|
|
9950
|
-
console.log(` ${driftMarker} ${
|
|
9951
|
-
console.log(` ${
|
|
9952
|
-
console.log(` ${
|
|
9953
|
-
console.log(` ${
|
|
9429
|
+
const driftMarker = s.drift === "ok" ? pc10.green("\u25CF") : s.drift === "missing-cron" ? pc10.red("\u2717 missing cron line") : pc10.yellow(`\u26A0 ${s.drift}`);
|
|
9430
|
+
console.log(` ${driftMarker} ${pc10.bold(s.entry.id)} \u2014 every ${s.entry.every} (${pc10.dim(s.entry.cronExpr)})`);
|
|
9431
|
+
console.log(` ${pc10.dim("cwd:")} ${s.entry.cwd}`);
|
|
9432
|
+
console.log(` ${pc10.dim("last run:")} ${s.lastRunAt ?? pc10.yellow("never")}`);
|
|
9433
|
+
console.log(` ${pc10.dim("log:")} ${s.entry.logFile} ${s.logExists ? pc10.dim(`(${s.logSize} bytes)`) : pc10.yellow("(empty)")}`);
|
|
9954
9434
|
if (s.logTail.length > 0) {
|
|
9955
|
-
console.log(
|
|
9435
|
+
console.log(pc10.dim(" last lines:"));
|
|
9956
9436
|
for (const line of s.logTail.slice(-3)) {
|
|
9957
|
-
console.log(
|
|
9437
|
+
console.log(pc10.dim(` ${line}`));
|
|
9958
9438
|
}
|
|
9959
9439
|
}
|
|
9960
9440
|
}
|
|
9961
9441
|
if (statuses.some((s) => s.drift !== "ok")) {
|
|
9962
9442
|
console.log(`
|
|
9963
|
-
${
|
|
9443
|
+
${pc10.yellow("Drift detected.")} Run ${pc10.bold("one sync schedule repair <id>")} to heal.`);
|
|
9964
9444
|
}
|
|
9965
9445
|
} catch (err) {
|
|
9966
9446
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -9973,7 +9453,7 @@ async function syncScheduleRepairCommand(id) {
|
|
|
9973
9453
|
json({ status: "repaired", ...healed });
|
|
9974
9454
|
return;
|
|
9975
9455
|
}
|
|
9976
|
-
outro(`Repaired ${
|
|
9456
|
+
outro(`Repaired ${pc10.bold(healed.id)}: re-installed cron line with current node/cli paths.`);
|
|
9977
9457
|
} catch (err) {
|
|
9978
9458
|
error(err instanceof Error ? err.message : String(err));
|
|
9979
9459
|
}
|
|
@@ -10042,7 +9522,7 @@ function registerSyncSubcommands(sync) {
|
|
|
10042
9522
|
await syncSqlCommand(platformModel, sql);
|
|
10043
9523
|
});
|
|
10044
9524
|
sync.command("schema <platform/model>").description("Inspect the JSON structure of synced records (field paths, types, examples) \u2014 useful before writing `sync sql` queries").action(async (platformModel) => {
|
|
10045
|
-
const { syncSchemaCommand } = await import("./schema-
|
|
9525
|
+
const { syncSchemaCommand } = await import("./schema-YJ7JTGFL.js");
|
|
10046
9526
|
await syncSchemaCommand(platformModel);
|
|
10047
9527
|
});
|
|
10048
9528
|
sync.command("delete <platform/model>").description('Delete records from local sync data (e.g. one sync delete notion/pages --id "abc-123")').option("--id <value>", "Delete record by ID").option("--where <conditions>", 'Delete records matching conditions (e.g. "status=archived")').option("--where-sql <predicate>", `Delete using a raw SQL WHERE clause (e.g. "json_extract(data, '$.type') = 'promotion'")`).option("--yes", "Skip confirmation prompt").action(async (platformModel, options) => {
|
|
@@ -10409,16 +9889,16 @@ function projectEmbeddingApiKey(cfg) {
|
|
|
10409
9889
|
}
|
|
10410
9890
|
function redactSecrets(cfg) {
|
|
10411
9891
|
const copy = JSON.parse(JSON.stringify(cfg));
|
|
10412
|
-
for (const
|
|
10413
|
-
const val = getPath(copy,
|
|
9892
|
+
for (const path13 of SECRET_PATHS) {
|
|
9893
|
+
const val = getPath(copy, path13);
|
|
10414
9894
|
if (typeof val === "string" && val.length > 0) {
|
|
10415
|
-
setPath(copy,
|
|
9895
|
+
setPath(copy, path13, `${val.slice(0, 6)}\u2026(redacted, use --show-secrets)`);
|
|
10416
9896
|
}
|
|
10417
9897
|
}
|
|
10418
9898
|
return copy;
|
|
10419
9899
|
}
|
|
10420
|
-
function getPath(obj,
|
|
10421
|
-
const parts =
|
|
9900
|
+
function getPath(obj, path13) {
|
|
9901
|
+
const parts = path13.split(".");
|
|
10422
9902
|
let cur = obj;
|
|
10423
9903
|
for (const part2 of parts) {
|
|
10424
9904
|
if (cur == null || typeof cur !== "object") return void 0;
|
|
@@ -10426,8 +9906,8 @@ function getPath(obj, path16) {
|
|
|
10426
9906
|
}
|
|
10427
9907
|
return cur;
|
|
10428
9908
|
}
|
|
10429
|
-
function setPath(obj,
|
|
10430
|
-
const parts =
|
|
9909
|
+
function setPath(obj, path13, value) {
|
|
9910
|
+
const parts = path13.split(".");
|
|
10431
9911
|
let cur = obj;
|
|
10432
9912
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
10433
9913
|
const part2 = parts[i];
|
|
@@ -10437,8 +9917,8 @@ function setPath(obj, path16, value) {
|
|
|
10437
9917
|
cur[parts[parts.length - 1]] = value;
|
|
10438
9918
|
return obj;
|
|
10439
9919
|
}
|
|
10440
|
-
function unsetPath(obj,
|
|
10441
|
-
const parts =
|
|
9920
|
+
function unsetPath(obj, path13) {
|
|
9921
|
+
const parts = path13.split(".");
|
|
10442
9922
|
let cur = obj;
|
|
10443
9923
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
10444
9924
|
const part2 = parts[i];
|
|
@@ -10464,7 +9944,7 @@ function parseValue(raw) {
|
|
|
10464
9944
|
}
|
|
10465
9945
|
|
|
10466
9946
|
// src/commands/mem/records.ts
|
|
10467
|
-
import
|
|
9947
|
+
import pc11 from "picocolors";
|
|
10468
9948
|
async function memAddCommand(type, dataRaw, flags) {
|
|
10469
9949
|
requireMemoryInit();
|
|
10470
9950
|
const data = parseJsonArg(dataRaw, "data");
|
|
@@ -10663,7 +10143,7 @@ function summarizeRecord(r) {
|
|
|
10663
10143
|
const v = d[field];
|
|
10664
10144
|
if (typeof v === "string" && v.trim()) return v.trim().slice(0, 80);
|
|
10665
10145
|
}
|
|
10666
|
-
return
|
|
10146
|
+
return pc11.dim("(untitled)");
|
|
10667
10147
|
}
|
|
10668
10148
|
function relativeTime(iso) {
|
|
10669
10149
|
if (!iso) return "";
|
|
@@ -10726,7 +10206,7 @@ async function memFindByKeyCommand(key, secondKey, flags) {
|
|
|
10726
10206
|
});
|
|
10727
10207
|
return;
|
|
10728
10208
|
}
|
|
10729
|
-
const label = matchedKeys.map((k) =>
|
|
10209
|
+
const label = matchedKeys.map((k) => pc11.cyan(k)).join(pc11.dim(" + "));
|
|
10730
10210
|
if (records.length === 0) {
|
|
10731
10211
|
console.log(`
|
|
10732
10212
|
No records linked to ${label}.
|
|
@@ -10734,27 +10214,27 @@ async function memFindByKeyCommand(key, secondKey, flags) {
|
|
|
10734
10214
|
return;
|
|
10735
10215
|
}
|
|
10736
10216
|
console.log();
|
|
10737
|
-
console.log(` ${label} ${
|
|
10217
|
+
console.log(` ${label} ${pc11.dim("\u2014")} ${records.length}${truncated ? "+" : ""} record${records.length === 1 ? "" : "s"} across ${byType.size} type${byType.size === 1 ? "" : "s"}`);
|
|
10738
10218
|
console.log();
|
|
10739
10219
|
const typeWidth = Math.min(30, Math.max(...[...byType.keys()].map((t) => t.length)));
|
|
10740
10220
|
for (const [type, list] of byType) {
|
|
10741
|
-
console.log(` ${
|
|
10221
|
+
console.log(` ${pc11.bold(type.padEnd(typeWidth))} ${pc11.dim(`${list.length} record${list.length === 1 ? "" : "s"}`)}`);
|
|
10742
10222
|
for (const r of list.slice(0, perType)) {
|
|
10743
|
-
console.log(` ${
|
|
10223
|
+
console.log(` ${pc11.dim("\xB7")} ${summarizeRecord(r)} ${pc11.dim(relativeTime(r.updated_at))} ${pc11.dim(r.id)}`);
|
|
10744
10224
|
}
|
|
10745
10225
|
if (list.length > perType) {
|
|
10746
|
-
console.log(` ${
|
|
10226
|
+
console.log(` ${pc11.dim(`\u2026 and ${list.length - perType} more (raise --limit)`)}`);
|
|
10747
10227
|
}
|
|
10748
10228
|
}
|
|
10749
10229
|
if (truncated) {
|
|
10750
10230
|
console.log();
|
|
10751
|
-
console.log(` ${
|
|
10231
|
+
console.log(` ${pc11.yellow("\u26A0")} Stopped at ${FIND_BY_KEY_FETCH_CAP} matches \u2014 there are more, and types sorting after the last one shown are missing entirely. Re-run with --type <type> to see them.`);
|
|
10752
10232
|
}
|
|
10753
10233
|
console.log();
|
|
10754
10234
|
}
|
|
10755
10235
|
|
|
10756
10236
|
// src/commands/mem/doctor.ts
|
|
10757
|
-
import
|
|
10237
|
+
import pc12 from "picocolors";
|
|
10758
10238
|
async function memDoctorCommand() {
|
|
10759
10239
|
const checks = [];
|
|
10760
10240
|
const cfg = getMemoryConfig();
|
|
@@ -10861,23 +10341,23 @@ function emit(checks, capInfo) {
|
|
|
10861
10341
|
return;
|
|
10862
10342
|
}
|
|
10863
10343
|
for (const c of checks) {
|
|
10864
|
-
const mark = c.ok ?
|
|
10865
|
-
const detail = c.detail ?
|
|
10344
|
+
const mark = c.ok ? pc12.green("\u2713") : pc12.red("\u2717");
|
|
10345
|
+
const detail = c.detail ? pc12.dim(` \u2014 ${c.detail}`) : "";
|
|
10866
10346
|
console.log(` ${mark} ${c.name}${detail}`);
|
|
10867
10347
|
}
|
|
10868
10348
|
if (!allOk) {
|
|
10869
|
-
console.log("\n" +
|
|
10349
|
+
console.log("\n" + pc12.yellow("Memory is not fully healthy."));
|
|
10870
10350
|
process.exitCode = 1;
|
|
10871
10351
|
} else {
|
|
10872
|
-
console.log("\n" +
|
|
10352
|
+
console.log("\n" + pc12.green("Memory is healthy."));
|
|
10873
10353
|
}
|
|
10874
10354
|
const line = semanticSearchUpgradeLine({ vectorSearchAvailable: capInfo.vectorSearchAvailable });
|
|
10875
10355
|
if (line) console.log(`
|
|
10876
|
-
${
|
|
10356
|
+
${pc12.dim(line)}`);
|
|
10877
10357
|
}
|
|
10878
10358
|
|
|
10879
10359
|
// src/commands/mem/export.ts
|
|
10880
|
-
import
|
|
10360
|
+
import fs10 from "fs";
|
|
10881
10361
|
import { once } from "events";
|
|
10882
10362
|
async function writeLine(stream, line) {
|
|
10883
10363
|
if (!stream.write(line)) {
|
|
@@ -10889,7 +10369,7 @@ async function memExportCommand(outfile) {
|
|
|
10889
10369
|
const backend = await getBackend();
|
|
10890
10370
|
const stats = await backend.stats();
|
|
10891
10371
|
const toFile = !!outfile && outfile !== "-";
|
|
10892
|
-
const stream = toFile ?
|
|
10372
|
+
const stream = toFile ? fs10.createWriteStream(outfile, "utf-8") : process.stdout;
|
|
10893
10373
|
const all = await listAllTypes(backend);
|
|
10894
10374
|
const pageSize = 500;
|
|
10895
10375
|
let written = 0;
|
|
@@ -10920,9 +10400,9 @@ async function memExportCommand(outfile) {
|
|
|
10920
10400
|
}
|
|
10921
10401
|
async function memImportCommand(file) {
|
|
10922
10402
|
requireMemoryInit();
|
|
10923
|
-
if (!
|
|
10403
|
+
if (!fs10.existsSync(file)) error(`File not found: ${file}`);
|
|
10924
10404
|
const backend = await getBackend();
|
|
10925
|
-
const raw =
|
|
10405
|
+
const raw = fs10.readFileSync(file, "utf-8");
|
|
10926
10406
|
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
10927
10407
|
let inserted = 0;
|
|
10928
10408
|
let updated = 0;
|
|
@@ -11168,7 +10648,7 @@ function registerMemoryCommands(program2) {
|
|
|
11168
10648
|
}
|
|
11169
10649
|
|
|
11170
10650
|
// src/commands/cache.ts
|
|
11171
|
-
import
|
|
10651
|
+
import pc13 from "picocolors";
|
|
11172
10652
|
async function cacheClearCommand(actionId) {
|
|
11173
10653
|
if (actionId) {
|
|
11174
10654
|
const deleted = clearEntry(actionId);
|
|
@@ -11177,9 +10657,9 @@ async function cacheClearCommand(actionId) {
|
|
|
11177
10657
|
return;
|
|
11178
10658
|
}
|
|
11179
10659
|
if (deleted) {
|
|
11180
|
-
console.log(`Cleared cache for ${
|
|
10660
|
+
console.log(`Cleared cache for ${pc13.cyan(actionId)}`);
|
|
11181
10661
|
} else {
|
|
11182
|
-
console.log(`No cache entry found for ${
|
|
10662
|
+
console.log(`No cache entry found for ${pc13.dim(actionId)}`);
|
|
11183
10663
|
}
|
|
11184
10664
|
} else {
|
|
11185
10665
|
const count = clearAll();
|
|
@@ -11216,7 +10696,7 @@ async function cacheListCommand(options) {
|
|
|
11216
10696
|
type: e.type,
|
|
11217
10697
|
key: e.entry.key,
|
|
11218
10698
|
age: formatAge(getAge(e.entry)),
|
|
11219
|
-
status: isFresh(e.entry) ?
|
|
10699
|
+
status: isFresh(e.entry) ? pc13.green("fresh") : pc13.yellow("expired")
|
|
11220
10700
|
}));
|
|
11221
10701
|
printTable(
|
|
11222
10702
|
[
|
|
@@ -11269,13 +10749,13 @@ async function cacheUpdateAllCommand() {
|
|
|
11269
10749
|
if (errors.length > 0) {
|
|
11270
10750
|
console.log();
|
|
11271
10751
|
for (const e of errors) {
|
|
11272
|
-
console.log(` ${
|
|
10752
|
+
console.log(` ${pc13.red("\u2717")} ${e.key}: ${pc13.dim(e.error)}`);
|
|
11273
10753
|
}
|
|
11274
10754
|
}
|
|
11275
10755
|
}
|
|
11276
10756
|
|
|
11277
10757
|
// src/commands/guide.ts
|
|
11278
|
-
import
|
|
10758
|
+
import pc14 from "picocolors";
|
|
11279
10759
|
|
|
11280
10760
|
// src/lib/guide-content.ts
|
|
11281
10761
|
var GUIDE_OVERVIEW = `# One CLI \u2014 Agent Guide
|
|
@@ -11411,7 +10891,7 @@ Request specific sections:
|
|
|
11411
10891
|
- Always use the **exact action ID** from a find answer \u2014 don't guess
|
|
11412
10892
|
- Always read **knowledge** before executing any action
|
|
11413
10893
|
- Connection keys come from \`one connection list\` \u2014 don't hardcode them
|
|
11414
|
-
- \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`) \u2014
|
|
10894
|
+
- \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`, plus a \`level\`: full, read-write, read-only, custom, none) \u2014 what One enforces for this key, narrowed by \`one config\`. Read it before planning so you don't propose an action that will be refused. \`accessSource: "local"\` means One did not report it, so it is unverified
|
|
11415
10895
|
- Skills stay in lockstep with the CLI version automatically \u2014 every command checks a \`.one-cli-version\` marker in the canonical skill dir and refreshes the files if the CLI has been upgraded. Check manually with \`one config skills status\`; force a resync with \`one config skills sync\`
|
|
11416
10896
|
- Building an app whose users connect their own tools? \`one skills add connect\` (run inside the app) installs the One Connect skill from the \`@withone/connect\` version the app uses, into \`.agents/skills/one-connect\` and \`.claude/skills/one-connect\`. \`one --agent skills list\` shows what is installed; any \`one\` command in the project refreshes it after an SDK upgrade
|
|
11417
10897
|
`;
|
|
@@ -11427,7 +10907,7 @@ Always follow this sequence. Never execute without reading the action's document
|
|
|
11427
10907
|
one --agent connection list
|
|
11428
10908
|
\`\`\`
|
|
11429
10909
|
|
|
11430
|
-
Returns platforms, status, connection keys, tags, and an \`access\` field per connection
|
|
10910
|
+
Returns platforms, status, connection keys, tags, and an \`access\` field per connection: what One enforces for this key (the consent page's choices, or the dashboard's), narrowed by \`one config\`. \`access.level\` names it as the consent page does (full, read-write, read-only, custom, none):
|
|
11431
10911
|
|
|
11432
10912
|
| \`access\` | Meaning |
|
|
11433
10913
|
|----------|---------|
|
|
@@ -11435,9 +10915,9 @@ Returns platforms, status, connection keys, tags, and an \`access\` field per co
|
|
|
11435
10915
|
| \`{"policy": "methods", "methods": ["GET"]}\` | Only actions with these HTTP methods will execute |
|
|
11436
10916
|
| \`{"policy": "actions", "actions": [{"actionId", "title", "method"}]}\` | Only these exact actions \u2014 use them directly: \`actions load <actionId>\` reads their docs, no find needed |
|
|
11437
10917
|
|
|
11438
|
-
Also present when relevant: \`knowledgeOnly: true\` (execution disabled \u2014 read the docs and write code instead), \`unresolvedActionIds\` (allowlisted ids that could not be looked up), and \`accessHint\` (a one-line summary of the restriction).
|
|
10918
|
+
\`accessSource\` is \`server\` when One reported it, \`local\` when it could not (then it is unverified). Also present when relevant: \`knowledgeOnly: true\` (execution disabled \u2014 read the docs and write code instead), \`unresolvedActionIds\` (allowlisted ids that could not be looked up), and \`accessHint\` (a one-line summary of the restriction).
|
|
11439
10919
|
|
|
11440
|
-
Read \`access\` before planning \u2014 it prevents proposing an action
|
|
10920
|
+
Read \`access\` before planning \u2014 it prevents proposing an action that will be refused. The key's access changes in the dashboard (API keys); this CLI's own limits with \`one config\`.
|
|
11441
10921
|
|
|
11442
10922
|
### 1b. Delete a Connection
|
|
11443
10923
|
|
|
@@ -12478,14 +11958,14 @@ async function guideCommand(topic = "all") {
|
|
|
12478
11958
|
json({ topic, title, content, availableTopics });
|
|
12479
11959
|
return;
|
|
12480
11960
|
}
|
|
12481
|
-
intro(
|
|
11961
|
+
intro(pc14.bgCyan(pc14.black(" One Guide ")));
|
|
12482
11962
|
console.log();
|
|
12483
11963
|
console.log(content);
|
|
12484
|
-
console.log(
|
|
11964
|
+
console.log(pc14.dim("\u2500".repeat(60)));
|
|
12485
11965
|
console.log(
|
|
12486
|
-
|
|
11966
|
+
pc14.dim("Available topics: ") + availableTopics.map((t) => pc14.cyan(t.topic)).join(", ")
|
|
12487
11967
|
);
|
|
12488
|
-
console.log(
|
|
11968
|
+
console.log(pc14.dim(`Run ${pc14.cyan("one guide <topic>")} for a specific section.`));
|
|
12489
11969
|
}
|
|
12490
11970
|
|
|
12491
11971
|
// src/lib/platform-meta.ts
|
|
@@ -12805,24 +12285,24 @@ function buildWorkflowIdeas(connections) {
|
|
|
12805
12285
|
}
|
|
12806
12286
|
|
|
12807
12287
|
// src/commands/logout.ts
|
|
12808
|
-
import
|
|
12288
|
+
import fs11 from "fs";
|
|
12809
12289
|
import * as p8 from "@clack/prompts";
|
|
12810
|
-
function formatWhoami(config2, apiKey,
|
|
12290
|
+
function formatWhoami(config2, apiKey, pc16) {
|
|
12811
12291
|
const whoami = config2.whoami;
|
|
12812
12292
|
const env = getEnvFromApiKey(apiKey);
|
|
12813
|
-
const envLabel = env === "test" ?
|
|
12293
|
+
const envLabel = env === "test" ? pc16.yellow("test") : pc16.green("live");
|
|
12814
12294
|
const lines = [];
|
|
12815
12295
|
if (whoami) {
|
|
12816
12296
|
const contextParts = [];
|
|
12817
12297
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
12818
12298
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
12819
12299
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
12820
|
-
lines.push(`${
|
|
12821
|
-
lines.push(`${whoami.user.name} ${
|
|
12822
|
-
if (config2.apiKeyName) lines.push(`${
|
|
12300
|
+
lines.push(`${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
12301
|
+
lines.push(`${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`);
|
|
12302
|
+
if (config2.apiKeyName) lines.push(`${pc16.dim("Key:")} ${config2.apiKeyName}`);
|
|
12823
12303
|
} else {
|
|
12824
12304
|
const keyLabel = config2.apiKeyName ?? `${apiKey.slice(0, 8)}...`;
|
|
12825
|
-
lines.push(`${
|
|
12305
|
+
lines.push(`${pc16.dim("Key:")} ${keyLabel} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
12826
12306
|
}
|
|
12827
12307
|
return lines;
|
|
12828
12308
|
}
|
|
@@ -12840,18 +12320,18 @@ async function logoutCommand() {
|
|
|
12840
12320
|
const globalPath = getGlobalConfigPath();
|
|
12841
12321
|
const projectPath = getProjectConfigPath();
|
|
12842
12322
|
let cleared = false;
|
|
12843
|
-
if (
|
|
12844
|
-
|
|
12323
|
+
if (fs11.existsSync(projectPath)) {
|
|
12324
|
+
fs11.unlinkSync(projectPath);
|
|
12845
12325
|
cleared = true;
|
|
12846
12326
|
}
|
|
12847
|
-
if (
|
|
12848
|
-
|
|
12327
|
+
if (fs11.existsSync(globalPath)) {
|
|
12328
|
+
fs11.unlinkSync(globalPath);
|
|
12849
12329
|
cleared = true;
|
|
12850
12330
|
}
|
|
12851
12331
|
json({ status: cleared ? "logged_out" : "not_logged_in", message: cleared ? "Credentials cleared." : "No config found." });
|
|
12852
12332
|
return;
|
|
12853
12333
|
}
|
|
12854
|
-
const
|
|
12334
|
+
const pc16 = (await import("picocolors")).default;
|
|
12855
12335
|
const globalConfig = readGlobalConfig();
|
|
12856
12336
|
const projectConfig = readProjectConfig();
|
|
12857
12337
|
const hasGlobal = globalConfig?.apiKey != null;
|
|
@@ -12860,13 +12340,13 @@ async function logoutCommand() {
|
|
|
12860
12340
|
if (hasGlobal && hasProject) {
|
|
12861
12341
|
const infoLines = ["You are logged in with multiple configs.", ""];
|
|
12862
12342
|
if (projectConfig) {
|
|
12863
|
-
infoLines.push(`${
|
|
12864
|
-
infoLines.push(...formatWhoami(projectConfig, projectConfig.apiKey,
|
|
12343
|
+
infoLines.push(`${pc16.cyan("Local config:")}`);
|
|
12344
|
+
infoLines.push(...formatWhoami(projectConfig, projectConfig.apiKey, pc16));
|
|
12865
12345
|
infoLines.push("");
|
|
12866
12346
|
}
|
|
12867
12347
|
if (globalConfig) {
|
|
12868
|
-
infoLines.push(`${
|
|
12869
|
-
infoLines.push(...formatWhoami(globalConfig, globalConfig.apiKey,
|
|
12348
|
+
infoLines.push(`${pc16.magenta("Global config:")}`);
|
|
12349
|
+
infoLines.push(...formatWhoami(globalConfig, globalConfig.apiKey, pc16));
|
|
12870
12350
|
}
|
|
12871
12351
|
p8.note(infoLines.join("\n"));
|
|
12872
12352
|
const choice = await p8.select({
|
|
@@ -12884,14 +12364,14 @@ async function logoutCommand() {
|
|
|
12884
12364
|
targetScope = choice;
|
|
12885
12365
|
} else if (hasProject) {
|
|
12886
12366
|
const infoLines = ["You are logged in.", ""];
|
|
12887
|
-
infoLines.push(`${
|
|
12888
|
-
infoLines.push(...formatWhoami(projectConfig, projectConfig.apiKey,
|
|
12367
|
+
infoLines.push(`${pc16.dim("Stored in")} ${pc16.cyan("local config")}`);
|
|
12368
|
+
infoLines.push(...formatWhoami(projectConfig, projectConfig.apiKey, pc16));
|
|
12889
12369
|
p8.note(infoLines.join("\n"));
|
|
12890
12370
|
targetScope = "project";
|
|
12891
12371
|
} else if (hasGlobal) {
|
|
12892
12372
|
const infoLines = ["You are logged in.", ""];
|
|
12893
|
-
infoLines.push(`${
|
|
12894
|
-
infoLines.push(...formatWhoami(globalConfig, globalConfig.apiKey,
|
|
12373
|
+
infoLines.push(`${pc16.dim("Stored in")} ${pc16.magenta("global config")}`);
|
|
12374
|
+
infoLines.push(...formatWhoami(globalConfig, globalConfig.apiKey, pc16));
|
|
12895
12375
|
p8.note(infoLines.join("\n"));
|
|
12896
12376
|
targetScope = "global";
|
|
12897
12377
|
} else {
|
|
@@ -12914,11 +12394,11 @@ async function logoutCommand() {
|
|
|
12914
12394
|
}
|
|
12915
12395
|
if (targetScope === "project" || targetScope === "both") {
|
|
12916
12396
|
const projectPath = getProjectConfigPath();
|
|
12917
|
-
if (
|
|
12397
|
+
if (fs11.existsSync(projectPath)) fs11.unlinkSync(projectPath);
|
|
12918
12398
|
}
|
|
12919
12399
|
if (targetScope === "global" || targetScope === "both") {
|
|
12920
12400
|
const globalPath = getGlobalConfigPath();
|
|
12921
|
-
if (
|
|
12401
|
+
if (fs11.existsSync(globalPath)) fs11.unlinkSync(globalPath);
|
|
12922
12402
|
}
|
|
12923
12403
|
p8.log.success("Credentials cleared.");
|
|
12924
12404
|
p8.log.info("Your API key is still active. Manage keys at app.withone.ai/settings");
|
|
@@ -12927,9 +12407,9 @@ async function logoutCommand() {
|
|
|
12927
12407
|
|
|
12928
12408
|
// src/lib/project-skills.ts
|
|
12929
12409
|
import crypto2 from "crypto";
|
|
12930
|
-
import
|
|
12931
|
-
import
|
|
12932
|
-
import
|
|
12410
|
+
import fs12 from "fs";
|
|
12411
|
+
import os2 from "os";
|
|
12412
|
+
import path10 from "path";
|
|
12933
12413
|
import zlib from "zlib";
|
|
12934
12414
|
var OPTIONAL_SKILLS = [
|
|
12935
12415
|
{
|
|
@@ -12961,27 +12441,27 @@ function findAgentTarget(id) {
|
|
|
12961
12441
|
return SKILL_AGENT_TARGETS.find((a) => a.id === id.trim().toLowerCase());
|
|
12962
12442
|
}
|
|
12963
12443
|
function findProjectRoot(start) {
|
|
12964
|
-
let dir =
|
|
12444
|
+
let dir = path10.resolve(start);
|
|
12965
12445
|
for (; ; ) {
|
|
12966
|
-
if (
|
|
12967
|
-
const parent =
|
|
12446
|
+
if (fs12.existsSync(path10.join(dir, "package.json")) || fs12.existsSync(path10.join(dir, ".git"))) return dir;
|
|
12447
|
+
const parent = path10.dirname(dir);
|
|
12968
12448
|
if (parent === dir) return null;
|
|
12969
12449
|
dir = parent;
|
|
12970
12450
|
}
|
|
12971
12451
|
}
|
|
12972
12452
|
function findInstalledPackage(start, packageName) {
|
|
12973
|
-
let dir =
|
|
12453
|
+
let dir = path10.resolve(start);
|
|
12974
12454
|
for (; ; ) {
|
|
12975
|
-
const pkgDir =
|
|
12976
|
-
const manifest =
|
|
12977
|
-
if (
|
|
12455
|
+
const pkgDir = path10.join(dir, "node_modules", ...packageName.split("/"));
|
|
12456
|
+
const manifest = path10.join(pkgDir, "package.json");
|
|
12457
|
+
if (fs12.existsSync(manifest)) {
|
|
12978
12458
|
try {
|
|
12979
|
-
const { version: version2 } = JSON.parse(
|
|
12459
|
+
const { version: version2 } = JSON.parse(fs12.readFileSync(manifest, "utf-8"));
|
|
12980
12460
|
if (version2) return { dir: pkgDir, version: version2 };
|
|
12981
12461
|
} catch {
|
|
12982
12462
|
}
|
|
12983
12463
|
}
|
|
12984
|
-
const parent =
|
|
12464
|
+
const parent = path10.dirname(dir);
|
|
12985
12465
|
if (parent === dir) return null;
|
|
12986
12466
|
dir = parent;
|
|
12987
12467
|
}
|
|
@@ -12995,8 +12475,8 @@ var SkillSourceError = class extends Error {
|
|
|
12995
12475
|
function projectSkillSource(skill, projectDir) {
|
|
12996
12476
|
const installed = findInstalledPackage(projectDir, skill.packageName);
|
|
12997
12477
|
if (!installed) return null;
|
|
12998
|
-
const dir =
|
|
12999
|
-
if (!
|
|
12478
|
+
const dir = path10.join(installed.dir, ...skill.packagePath.split("/"));
|
|
12479
|
+
if (!fs12.existsSync(path10.join(dir, "SKILL.md"))) {
|
|
13000
12480
|
throw new SkillSourceError(
|
|
13001
12481
|
`${skill.packageName} ${installed.version} does not include the ${skill.title} skill. Upgrade it: npm install ${skill.packageName}@latest`,
|
|
13002
12482
|
"skill-missing"
|
|
@@ -13039,11 +12519,11 @@ async function registrySkillSource(skill, fetchImpl = fetch) {
|
|
|
13039
12519
|
if (!files.some((f) => f.path === "SKILL.md")) {
|
|
13040
12520
|
throw new SkillSourceError(`${skill.packageName}@${version2} does not include the ${skill.title} skill.`, "not-in-package");
|
|
13041
12521
|
}
|
|
13042
|
-
const tmp =
|
|
12522
|
+
const tmp = fs12.mkdtempSync(path10.join(os2.tmpdir(), "one-skill-"));
|
|
13043
12523
|
for (const file of files) {
|
|
13044
|
-
const dest =
|
|
13045
|
-
|
|
13046
|
-
|
|
12524
|
+
const dest = path10.join(tmp, ...file.path.split("/"));
|
|
12525
|
+
fs12.mkdirSync(path10.dirname(dest), { recursive: true });
|
|
12526
|
+
fs12.writeFileSync(dest, file.data);
|
|
13047
12527
|
}
|
|
13048
12528
|
return {
|
|
13049
12529
|
kind: "registry",
|
|
@@ -13052,7 +12532,7 @@ async function registrySkillSource(skill, fetchImpl = fetch) {
|
|
|
13052
12532
|
origin: tarball,
|
|
13053
12533
|
cleanup: () => {
|
|
13054
12534
|
try {
|
|
13055
|
-
|
|
12535
|
+
fs12.rmSync(tmp, { recursive: true, force: true });
|
|
13056
12536
|
} catch {
|
|
13057
12537
|
}
|
|
13058
12538
|
}
|
|
@@ -13096,7 +12576,7 @@ function readTarEntries(tar, prefix) {
|
|
|
13096
12576
|
if ((type === "0" || type === "\0") && full.startsWith(prefix)) {
|
|
13097
12577
|
const rel = full.slice(prefix.length);
|
|
13098
12578
|
const parts = rel.split("/");
|
|
13099
|
-
if (rel && !
|
|
12579
|
+
if (rel && !path10.isAbsolute(rel) && !parts.includes("..") && !parts.includes("")) {
|
|
13100
12580
|
out.push({ path: rel, data: Buffer.from(body) });
|
|
13101
12581
|
}
|
|
13102
12582
|
}
|
|
@@ -13107,11 +12587,11 @@ function readTarEntries(tar, prefix) {
|
|
|
13107
12587
|
}
|
|
13108
12588
|
var SKILL_STAMP = ".one-skill.json";
|
|
13109
12589
|
function canonicalSkillDir(skill, plan) {
|
|
13110
|
-
return
|
|
12590
|
+
return path10.join(plan.root, ...UNIVERSAL_PROJECT_DIR.split("/"), skill.dirName);
|
|
13111
12591
|
}
|
|
13112
12592
|
function readStamp(dir) {
|
|
13113
12593
|
try {
|
|
13114
|
-
return JSON.parse(
|
|
12594
|
+
return JSON.parse(fs12.readFileSync(path10.join(dir, SKILL_STAMP), "utf-8"));
|
|
13115
12595
|
} catch {
|
|
13116
12596
|
return null;
|
|
13117
12597
|
}
|
|
@@ -13121,9 +12601,9 @@ function resolveAgentFolders(plan) {
|
|
|
13121
12601
|
const chosen = SKILL_AGENT_TARGETS.filter((agent) => {
|
|
13122
12602
|
if (explicit) return plan.agents.includes(agent.id);
|
|
13123
12603
|
if (plan.scope === "global") {
|
|
13124
|
-
return
|
|
12604
|
+
return fs12.existsSync(path10.join(plan.root, path10.dirname(agent.homeDir)));
|
|
13125
12605
|
}
|
|
13126
|
-
return agent.projectMarker === null ||
|
|
12606
|
+
return agent.projectMarker === null || fs12.existsSync(path10.join(plan.root, agent.projectMarker));
|
|
13127
12607
|
});
|
|
13128
12608
|
const readers = [];
|
|
13129
12609
|
const byDir = /* @__PURE__ */ new Map();
|
|
@@ -13138,33 +12618,33 @@ function resolveAgentFolders(plan) {
|
|
|
13138
12618
|
return { readers, folders: [...byDir].map(([dir, agents]) => ({ dir, agents })) };
|
|
13139
12619
|
}
|
|
13140
12620
|
function copyDir(src, dest) {
|
|
13141
|
-
|
|
13142
|
-
for (const entry of
|
|
12621
|
+
fs12.mkdirSync(dest, { recursive: true });
|
|
12622
|
+
for (const entry of fs12.readdirSync(src, { withFileTypes: true })) {
|
|
13143
12623
|
if (entry.name === SKILL_STAMP) continue;
|
|
13144
|
-
const from =
|
|
13145
|
-
const to =
|
|
12624
|
+
const from = path10.join(src, entry.name);
|
|
12625
|
+
const to = path10.join(dest, entry.name);
|
|
13146
12626
|
if (entry.isDirectory()) copyDir(from, to);
|
|
13147
|
-
else
|
|
12627
|
+
else fs12.copyFileSync(from, to);
|
|
13148
12628
|
}
|
|
13149
12629
|
}
|
|
13150
12630
|
function removePath(target) {
|
|
13151
12631
|
try {
|
|
13152
|
-
const stat =
|
|
13153
|
-
if (stat.isSymbolicLink())
|
|
13154
|
-
else
|
|
12632
|
+
const stat = fs12.lstatSync(target);
|
|
12633
|
+
if (stat.isSymbolicLink()) fs12.unlinkSync(target);
|
|
12634
|
+
else fs12.rmSync(target, { recursive: true, force: true });
|
|
13155
12635
|
} catch {
|
|
13156
12636
|
}
|
|
13157
12637
|
}
|
|
13158
12638
|
function linkDir(target, linkPath) {
|
|
13159
12639
|
removePath(linkPath);
|
|
13160
|
-
|
|
12640
|
+
fs12.mkdirSync(path10.dirname(linkPath), { recursive: true });
|
|
13161
12641
|
try {
|
|
13162
|
-
|
|
12642
|
+
fs12.symlinkSync(path10.relative(path10.dirname(linkPath), target), linkPath, "dir");
|
|
13163
12643
|
return "symlink";
|
|
13164
12644
|
} catch {
|
|
13165
12645
|
}
|
|
13166
12646
|
try {
|
|
13167
|
-
|
|
12647
|
+
fs12.symlinkSync(target, linkPath, "junction");
|
|
13168
12648
|
return "junction";
|
|
13169
12649
|
} catch {
|
|
13170
12650
|
}
|
|
@@ -13195,17 +12675,17 @@ function installSkill(skill, source, plan, cliVersion2) {
|
|
|
13195
12675
|
installedBy: `@withone/cli@${cliVersion2}`,
|
|
13196
12676
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13197
12677
|
};
|
|
13198
|
-
|
|
12678
|
+
fs12.writeFileSync(path10.join(canonical, SKILL_STAMP), JSON.stringify(stamp, null, 2) + "\n");
|
|
13199
12679
|
return { skill, version: source.version, source: source.kind, origin: source.origin, scope: plan.scope, root: plan.root, canonical, readers, links };
|
|
13200
12680
|
}
|
|
13201
12681
|
function removeSkill(skill, plan) {
|
|
13202
12682
|
const canonical = canonicalSkillDir(skill, plan);
|
|
13203
12683
|
const stamp = readStamp(canonical);
|
|
13204
|
-
if (!stamp && !
|
|
12684
|
+
if (!stamp && !fs12.existsSync(path10.join(canonical, "SKILL.md"))) return { removed: false, paths: [] };
|
|
13205
12685
|
const paths = [];
|
|
13206
12686
|
for (const link of stamp?.links ?? []) {
|
|
13207
12687
|
const full = fromStamp(plan.root, link.path);
|
|
13208
|
-
if (
|
|
12688
|
+
if (fs12.existsSync(full) || isDanglingLink(full)) {
|
|
13209
12689
|
removePath(full);
|
|
13210
12690
|
paths.push(full);
|
|
13211
12691
|
}
|
|
@@ -13218,18 +12698,18 @@ function toPosix(p9) {
|
|
|
13218
12698
|
return p9.split("\\").join("/");
|
|
13219
12699
|
}
|
|
13220
12700
|
function fromStamp(root, rel) {
|
|
13221
|
-
return
|
|
12701
|
+
return path10.join(root, ...toPosix(rel).split("/"));
|
|
13222
12702
|
}
|
|
13223
12703
|
function isDanglingLink(p9) {
|
|
13224
12704
|
try {
|
|
13225
|
-
return
|
|
12705
|
+
return fs12.lstatSync(p9).isSymbolicLink();
|
|
13226
12706
|
} catch {
|
|
13227
12707
|
return false;
|
|
13228
12708
|
}
|
|
13229
12709
|
}
|
|
13230
12710
|
function installedSkill(skill, plan) {
|
|
13231
12711
|
const canonical = canonicalSkillDir(skill, plan);
|
|
13232
|
-
if (!
|
|
12712
|
+
if (!fs12.existsSync(path10.join(canonical, "SKILL.md"))) return null;
|
|
13233
12713
|
const stamp = readStamp(canonical);
|
|
13234
12714
|
return { scope: plan.scope, root: plan.root, canonical, version: stamp?.version ?? null, source: stamp?.source ?? null, links: stamp?.links ?? [] };
|
|
13235
12715
|
}
|
|
@@ -13238,7 +12718,7 @@ function globalRoot() {
|
|
|
13238
12718
|
}
|
|
13239
12719
|
function refreshProjectSkills(cwd, cliVersion2) {
|
|
13240
12720
|
const root = findProjectRoot(cwd);
|
|
13241
|
-
if (!root ||
|
|
12721
|
+
if (!root || path10.resolve(root) === path10.resolve(homeDir())) return [];
|
|
13242
12722
|
const results = [];
|
|
13243
12723
|
for (const skill of OPTIONAL_SKILLS) {
|
|
13244
12724
|
const canonical = canonicalSkillDir(skill, { scope: "project", root });
|
|
@@ -13261,8 +12741,8 @@ function refreshProjectSkills(cwd, cliVersion2) {
|
|
|
13261
12741
|
}
|
|
13262
12742
|
|
|
13263
12743
|
// src/commands/skills.ts
|
|
13264
|
-
import
|
|
13265
|
-
import
|
|
12744
|
+
import path11 from "path";
|
|
12745
|
+
import pc15 from "picocolors";
|
|
13266
12746
|
function requireSkill(name) {
|
|
13267
12747
|
const skill = findOptionalSkill(name);
|
|
13268
12748
|
if (!skill) {
|
|
@@ -13285,7 +12765,7 @@ function resolvePlan(options) {
|
|
|
13285
12765
|
const agents = parseAgents(options.agents);
|
|
13286
12766
|
if (options.global) return { scope: "global", root: globalRoot(), agents };
|
|
13287
12767
|
const root = findProjectRoot(process.cwd());
|
|
13288
|
-
if (!root ||
|
|
12768
|
+
if (!root || path11.resolve(root) === path11.resolve(homeDir())) {
|
|
13289
12769
|
error("No project here: run this inside your app (a folder with package.json or .git), or pass --global.");
|
|
13290
12770
|
}
|
|
13291
12771
|
return { scope: "project", root, agents };
|
|
@@ -13301,7 +12781,7 @@ async function resolveSource(skill, plan) {
|
|
|
13301
12781
|
}
|
|
13302
12782
|
}
|
|
13303
12783
|
function display(p9, root) {
|
|
13304
|
-
const rel =
|
|
12784
|
+
const rel = path11.relative(root, p9);
|
|
13305
12785
|
return rel && !rel.startsWith("..") ? rel : p9;
|
|
13306
12786
|
}
|
|
13307
12787
|
function report(command, result, packageInProject) {
|
|
@@ -13317,7 +12797,7 @@ function report(command, result, packageInProject) {
|
|
|
13317
12797
|
root: result.root,
|
|
13318
12798
|
installedTo: [
|
|
13319
12799
|
{ path: result.canonical, kind: "folder", agents: result.readers },
|
|
13320
|
-
...result.links.map((l) => ({ path:
|
|
12800
|
+
...result.links.map((l) => ({ path: path11.join(result.root, ...l.path.split("/")), kind: l.kind, agents: l.agents }))
|
|
13321
12801
|
],
|
|
13322
12802
|
next: nextSteps(result, packageInProject)
|
|
13323
12803
|
});
|
|
@@ -13325,20 +12805,20 @@ function report(command, result, packageInProject) {
|
|
|
13325
12805
|
}
|
|
13326
12806
|
const scopeLabel2 = result.scope === "project" ? "this project" : "every project on this machine";
|
|
13327
12807
|
console.log();
|
|
13328
|
-
console.log(` ${
|
|
12808
|
+
console.log(` ${pc15.green("\u2713")} ${pc15.bold(`${result.skill.title} skill ${result.version}`)} installed for ${scopeLabel2}`);
|
|
13329
12809
|
console.log();
|
|
13330
|
-
const from = result.source === "project" ? `${where(result.origin)} ${
|
|
13331
|
-
console.log(` ${
|
|
12810
|
+
const from = result.source === "project" ? `${where(result.origin)} ${pc15.dim("(the version your code uses)")}` : `npm ${pc15.dim(result.scope === "project" ? `(latest ${result.skill.packageName}; not installed in this project yet)` : `(latest ${result.skill.packageName})`)}`;
|
|
12811
|
+
console.log(` ${pc15.dim("From")} ${from}`);
|
|
13332
12812
|
const rows = [
|
|
13333
12813
|
{ path: where(result.canonical), agents: result.readers },
|
|
13334
|
-
...result.links.map((l) => ({ path: `${l.path}${l.kind === "copy" ?
|
|
12814
|
+
...result.links.map((l) => ({ path: `${l.path}${l.kind === "copy" ? pc15.dim(" (copy)") : ""}`, agents: l.agents }))
|
|
13335
12815
|
];
|
|
13336
12816
|
rows.forEach((row, i) => {
|
|
13337
|
-
const agents = row.agents.length ?
|
|
13338
|
-
console.log(` ${
|
|
12817
|
+
const agents = row.agents.length ? pc15.dim(row.agents.join(", ")) : pc15.dim("shared copy the links point to");
|
|
12818
|
+
console.log(` ${pc15.dim(i === 0 ? "To " : " ")} ${row.path} ${agents}`);
|
|
13339
12819
|
});
|
|
13340
12820
|
console.log();
|
|
13341
|
-
console.log(` ${
|
|
12821
|
+
console.log(` ${pc15.bold("Next")}`);
|
|
13342
12822
|
nextSteps(result, packageInProject).forEach((step, i) => console.log(` ${i + 1}. ${step}`));
|
|
13343
12823
|
console.log();
|
|
13344
12824
|
}
|
|
@@ -13401,7 +12881,7 @@ async function skillsUpdateCommand(name, options) {
|
|
|
13401
12881
|
console.log("No optional skills are installed here. See: one skills list");
|
|
13402
12882
|
return;
|
|
13403
12883
|
}
|
|
13404
|
-
for (const r of updated) console.log(` ${
|
|
12884
|
+
for (const r of updated) console.log(` ${pc15.green("\u2713")} ${r.skill.title} skill ${r.version} ${pc15.dim(display(r.canonical, r.root))}`);
|
|
13405
12885
|
}
|
|
13406
12886
|
async function skillsRemoveCommand(name, options) {
|
|
13407
12887
|
const skill = requireSkill(name);
|
|
@@ -13415,12 +12895,12 @@ async function skillsRemoveCommand(name, options) {
|
|
|
13415
12895
|
console.log(`${skill.title} skill is not installed ${plan.scope === "global" ? "globally" : "in this project"}.`);
|
|
13416
12896
|
return;
|
|
13417
12897
|
}
|
|
13418
|
-
console.log(` ${
|
|
13419
|
-
for (const p9 of result.paths) console.log(` ${
|
|
12898
|
+
console.log(` ${pc15.green("\u2713")} Removed the ${skill.title} skill`);
|
|
12899
|
+
for (const p9 of result.paths) console.log(` ${pc15.dim(display(p9, plan.root))}`);
|
|
13420
12900
|
}
|
|
13421
12901
|
async function skillsListCommand() {
|
|
13422
12902
|
const projectRoot = findProjectRoot(process.cwd());
|
|
13423
|
-
const inProject = projectRoot &&
|
|
12903
|
+
const inProject = projectRoot && path11.resolve(projectRoot) !== path11.resolve(homeDir()) ? projectRoot : null;
|
|
13424
12904
|
const optional = OPTIONAL_SKILLS.map((skill) => {
|
|
13425
12905
|
const project = inProject ? installedSkill(skill, { scope: "project", root: inProject }) : null;
|
|
13426
12906
|
const global = installedSkill(skill, { scope: "global", root: globalRoot() });
|
|
@@ -13448,19 +12928,19 @@ async function skillsListCommand() {
|
|
|
13448
12928
|
return;
|
|
13449
12929
|
}
|
|
13450
12930
|
console.log();
|
|
13451
|
-
console.log(` ${
|
|
12931
|
+
console.log(` ${pc15.bold("one")} ${oneSkill.installed ? pc15.green(`installed ${oneSkill.version ?? ""}`.trim()) : pc15.yellow("not installed")} ${pc15.dim("managed by one init")}`);
|
|
13452
12932
|
for (const s of optional) {
|
|
13453
|
-
const state = s.project ?
|
|
13454
|
-
console.log(` ${
|
|
13455
|
-
console.log(` ${" ".repeat(8)} ${
|
|
12933
|
+
const state = s.project ? pc15.green(`project ${s.project.version ?? ""}`.trim()) + (s.project.upToDate ? "" : pc15.yellow(` (package is ${s.packageInProject}: run one skills update ${s.skill})`)) : s.global ? pc15.green(`global ${s.global.version ?? ""}`.trim()) : pc15.dim(`not installed \u2014 one skills add ${s.skill}`);
|
|
12934
|
+
console.log(` ${pc15.bold(s.skill.padEnd(8))} ${state}`);
|
|
12935
|
+
console.log(` ${" ".repeat(8)} ${pc15.dim(s.description)}`);
|
|
13456
12936
|
}
|
|
13457
12937
|
console.log();
|
|
13458
12938
|
}
|
|
13459
12939
|
|
|
13460
12940
|
// src/cli.ts
|
|
13461
12941
|
silenceWarningsInAgentMode();
|
|
13462
|
-
var
|
|
13463
|
-
var { version } =
|
|
12942
|
+
var require2 = createRequire(import.meta.url);
|
|
12943
|
+
var { version } = require2("../package.json");
|
|
13464
12944
|
var program = new Command();
|
|
13465
12945
|
program.name("one").option("--agent", "Machine-readable JSON output (no colors, spinners, or prompts)").description(`One CLI \u2014 Connect AI agents to 750+ platforms through one interface.
|
|
13466
12946
|
|
|
@@ -13698,8 +13178,8 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
13698
13178
|
return;
|
|
13699
13179
|
}
|
|
13700
13180
|
}
|
|
13701
|
-
const
|
|
13702
|
-
|
|
13181
|
+
const fs14 = await import("fs");
|
|
13182
|
+
fs14.unlinkSync(globalPath);
|
|
13703
13183
|
if (isAgentMode()) {
|
|
13704
13184
|
json({ deleted: true, scope: "global" });
|
|
13705
13185
|
} else {
|
|
@@ -13716,15 +13196,15 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
13716
13196
|
}
|
|
13717
13197
|
return;
|
|
13718
13198
|
}
|
|
13719
|
-
const
|
|
13720
|
-
const configContent =
|
|
13721
|
-
|
|
13199
|
+
const fs13 = await import("fs");
|
|
13200
|
+
const configContent = fs13.readFileSync(resolved.path, "utf-8");
|
|
13201
|
+
fs13.unlinkSync(resolved.path);
|
|
13722
13202
|
const next = resolveConfig();
|
|
13723
|
-
|
|
13724
|
-
|
|
13203
|
+
fs13.mkdirSync(path12.dirname(resolved.path), { recursive: true });
|
|
13204
|
+
fs13.writeFileSync(resolved.path, configContent);
|
|
13725
13205
|
let fallbackLabel;
|
|
13726
13206
|
if (next.scope === "project") {
|
|
13727
|
-
fallbackLabel = `parent project config (${
|
|
13207
|
+
fallbackLabel = `parent project config (${path12.basename(next.projectRoot)})`;
|
|
13728
13208
|
} else if (next.scope === "global") {
|
|
13729
13209
|
fallbackLabel = "global config";
|
|
13730
13210
|
} else {
|
|
@@ -13733,7 +13213,7 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
13733
13213
|
if (!isAgentMode()) {
|
|
13734
13214
|
const p9 = await import("@clack/prompts");
|
|
13735
13215
|
const confirmed = await p9.confirm({
|
|
13736
|
-
message: `Delete project config for ${
|
|
13216
|
+
message: `Delete project config for ${path12.basename(resolved.projectRoot)}? Will fall back to ${fallbackLabel}.`,
|
|
13737
13217
|
initialValue: false
|
|
13738
13218
|
});
|
|
13739
13219
|
if (p9.isCancel(confirmed) || !confirmed) {
|
|
@@ -13741,9 +13221,9 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
13741
13221
|
return;
|
|
13742
13222
|
}
|
|
13743
13223
|
}
|
|
13744
|
-
|
|
13224
|
+
fs13.unlinkSync(resolved.path);
|
|
13745
13225
|
try {
|
|
13746
|
-
|
|
13226
|
+
fs13.rmdirSync(path12.dirname(resolved.path));
|
|
13747
13227
|
} catch {
|
|
13748
13228
|
}
|
|
13749
13229
|
if (isAgentMode()) {
|
|
@@ -13906,22 +13386,22 @@ program.command("whoami").description("Show the user, organization, and project
|
|
|
13906
13386
|
});
|
|
13907
13387
|
return;
|
|
13908
13388
|
}
|
|
13909
|
-
const
|
|
13389
|
+
const pc16 = (await import("picocolors")).default;
|
|
13910
13390
|
const contextParts = [];
|
|
13911
13391
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
13912
13392
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
13913
13393
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
13914
|
-
const envLabel = env === "test" ?
|
|
13915
|
-
const configLabel = configScope === "project" ?
|
|
13394
|
+
const envLabel = env === "test" ? pc16.yellow("test") : pc16.green("live");
|
|
13395
|
+
const configLabel = configScope === "project" ? pc16.cyan("project config") : pc16.magenta("global config");
|
|
13916
13396
|
console.log();
|
|
13917
|
-
console.log(` ${
|
|
13918
|
-
console.log(` ${whoami.user.name} ${
|
|
13919
|
-
if (keyName) console.log(` ${
|
|
13920
|
-
if (whoami.organization) console.log(` ${
|
|
13921
|
-
if (whoami.project) console.log(` ${
|
|
13397
|
+
console.log(` ${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
13398
|
+
console.log(` ${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`);
|
|
13399
|
+
if (keyName) console.log(` ${pc16.dim("Key:")} ${keyName}`);
|
|
13400
|
+
if (whoami.organization) console.log(` ${pc16.dim("Org:")} ${whoami.organization.name} ${pc16.dim(`(${whoami.organization.id})`)}`);
|
|
13401
|
+
if (whoami.project) console.log(` ${pc16.dim("Project:")} ${whoami.project.name} ${pc16.dim(`(${whoami.project.id})`)}`);
|
|
13922
13402
|
console.log();
|
|
13923
|
-
console.log(` ${
|
|
13924
|
-
console.log(` ${
|
|
13403
|
+
console.log(` ${pc16.dim("Using")} ${configLabel}`);
|
|
13404
|
+
console.log(` ${pc16.dim("API:")} ${apiBase}`);
|
|
13925
13405
|
console.log();
|
|
13926
13406
|
});
|
|
13927
13407
|
program.command("add [platform]").description("Shortcut for: connection add").option("--tag <name>", "Tag the new connection (disambiguates multiple connections per platform in sync/flow profiles)").action(async (platform, options) => {
|