@withone/cli 1.55.4 → 1.56.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 +6 -0
- package/dist/{chunk-EVEUGRCB.js → chunk-6UB623BG.js} +31 -2
- package/dist/{chunk-OWDR5L3Q.js → chunk-KAF5SVJS.js} +2 -2
- package/dist/{chunk-GNSR3NYN.js → chunk-OLQ55K6B.js} +2 -2
- package/dist/{chunk-WXJWF7QG.js → chunk-QCXFSOTS.js} +2 -2
- package/dist/{chunk-DDCDPVJH.js → chunk-VH46MAE4.js} +2 -2
- package/dist/{chunk-FS4HAKZ6.js → chunk-XWTV7FA3.js} +2 -2
- package/dist/{chunk-5O5KODGV.js → chunk-YMUY55U2.js} +1 -1
- package/dist/{embedding-Z2WCDN6R.js → embedding-OXX4OF65.js} +2 -2
- package/dist/{flow-runner-MVSJ2GB7.js → flow-runner-QQ675PJD.js} +2 -2
- package/dist/index.js +1337 -1199
- package/dist/{migrate-37A463L6.js → migrate-IJI3BTWL.js} +5 -5
- package/dist/{runtime-AFXLC4IC.js → runtime-65IPTPVD.js} +3 -3
- package/dist/{schema-4JJO2CIZ.js → schema-OO4WK5ND.js} +4 -4
- package/dist/sql-QIVDWTL3.js +12 -0
- package/package.json +1 -1
- package/skills/one/SKILL.md +2 -0
- package/dist/sql-3WNYRCWP.js +0 -12
package/dist/index.js
CHANGED
|
@@ -32,10 +32,10 @@ import {
|
|
|
32
32
|
validateActionInput,
|
|
33
33
|
walkSteps,
|
|
34
34
|
writeCache
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-QCXFSOTS.js";
|
|
36
36
|
import {
|
|
37
37
|
memSqlCommand
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-KAF5SVJS.js";
|
|
39
39
|
import {
|
|
40
40
|
collectIdentityKeys,
|
|
41
41
|
countRecords,
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
writeDraftProfile,
|
|
67
67
|
writePageToMemory,
|
|
68
68
|
writeProfile
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-XWTV7FA3.js";
|
|
70
70
|
import {
|
|
71
71
|
getByDotPath
|
|
72
72
|
} from "./chunk-44CV5IMX.js";
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
semanticSearchUpgradeLine,
|
|
91
91
|
setAgentMode,
|
|
92
92
|
silenceWarningsInAgentMode
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-OLQ55K6B.js";
|
|
94
94
|
import {
|
|
95
95
|
SCHEMA_VERSION,
|
|
96
96
|
addRecord,
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
listBackendPlugins,
|
|
101
101
|
loadBackendFromConfig,
|
|
102
102
|
updateRecord
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-VH46MAE4.js";
|
|
104
104
|
import {
|
|
105
105
|
DEFAULT_MEMORY_CONFIG,
|
|
106
106
|
defaultSearchableText,
|
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
memoryConfigExists,
|
|
111
111
|
setOpenAiApiKey,
|
|
112
112
|
updateMemoryConfig
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-YMUY55U2.js";
|
|
114
114
|
import {
|
|
115
115
|
appendAnalyticsQueue,
|
|
116
116
|
appendUsageLog,
|
|
@@ -138,6 +138,7 @@ import {
|
|
|
138
138
|
readProjectConfig,
|
|
139
139
|
readUsageState,
|
|
140
140
|
resolveConfig,
|
|
141
|
+
saveCredentials,
|
|
141
142
|
telemetryNoticeShown,
|
|
142
143
|
updateAccessControl,
|
|
143
144
|
updateApiBase,
|
|
@@ -146,18 +147,18 @@ import {
|
|
|
146
147
|
writeConfig,
|
|
147
148
|
writeUsageLog,
|
|
148
149
|
writeUsageState
|
|
149
|
-
} from "./chunk-
|
|
150
|
+
} from "./chunk-6UB623BG.js";
|
|
150
151
|
|
|
151
152
|
// src/cli.ts
|
|
152
153
|
import { createRequire as createRequire3 } from "module";
|
|
153
|
-
import
|
|
154
|
+
import path13 from "path";
|
|
154
155
|
import { Command } from "commander";
|
|
155
156
|
|
|
156
157
|
// src/commands/init.ts
|
|
157
158
|
import * as p3 from "@clack/prompts";
|
|
158
|
-
import
|
|
159
|
-
import
|
|
160
|
-
import
|
|
159
|
+
import pc4 from "picocolors";
|
|
160
|
+
import fs4 from "fs";
|
|
161
|
+
import path5 from "path";
|
|
161
162
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
162
163
|
|
|
163
164
|
// src/lib/agents.ts
|
|
@@ -259,6 +260,12 @@ function getAgents() {
|
|
|
259
260
|
}
|
|
260
261
|
];
|
|
261
262
|
}
|
|
263
|
+
function detectInstalledAgents() {
|
|
264
|
+
return getAgents().filter((agent) => {
|
|
265
|
+
const detectDir = expandPath(agent.detectDir);
|
|
266
|
+
return fs.existsSync(detectDir);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
262
269
|
function getAgentConfigPath(agent, scope = "global") {
|
|
263
270
|
if (scope === "project" && agent.projectConfigPath) {
|
|
264
271
|
return path.join(process.cwd(), agent.projectConfigPath);
|
|
@@ -341,94 +348,539 @@ function getAgentStatuses() {
|
|
|
341
348
|
|
|
342
349
|
// src/lib/browser.ts
|
|
343
350
|
import open from "open";
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
351
|
+
|
|
352
|
+
// src/lib/install-context.ts
|
|
353
|
+
import fs2 from "fs";
|
|
354
|
+
import os from "os";
|
|
355
|
+
import path3 from "path";
|
|
356
|
+
|
|
357
|
+
// src/lib/analytics.ts
|
|
358
|
+
import { createRequire as createRequire2 } from "module";
|
|
359
|
+
import { randomUUID, createHash } from "crypto";
|
|
360
|
+
import pc from "picocolors";
|
|
361
|
+
|
|
362
|
+
// src/lib/version.ts
|
|
363
|
+
import { createRequire } from "module";
|
|
364
|
+
import { existsSync } from "fs";
|
|
365
|
+
import path2 from "path";
|
|
366
|
+
import { fileURLToPath } from "url";
|
|
367
|
+
var require2 = createRequire(import.meta.url);
|
|
368
|
+
var cached = null;
|
|
369
|
+
function cliVersion() {
|
|
370
|
+
if (cached !== null) return cached;
|
|
371
|
+
const dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
372
|
+
for (let i = 1; i <= 4; i++) {
|
|
373
|
+
const candidate = path2.resolve(dir, ...Array(i).fill(".."), "package.json");
|
|
374
|
+
if (!existsSync(candidate)) continue;
|
|
375
|
+
try {
|
|
376
|
+
const version2 = require2(candidate).version;
|
|
377
|
+
if (version2) {
|
|
378
|
+
cached = version2;
|
|
379
|
+
return cached;
|
|
380
|
+
}
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
cached = "unknown";
|
|
385
|
+
return cached;
|
|
352
386
|
}
|
|
353
|
-
|
|
354
|
-
|
|
387
|
+
|
|
388
|
+
// src/lib/analytics.ts
|
|
389
|
+
var require3 = createRequire2(import.meta.url);
|
|
390
|
+
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
391
|
+
var DEFAULT_POSTHOG_KEY = "phc_a9ok4w0uxiZcVoSWOISIlin85lHMXQD3vWPaYnuRlRV";
|
|
392
|
+
var SEND_MAX_ATTEMPTS = 3;
|
|
393
|
+
var QUEUE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
394
|
+
var EXIT_GRACE_MS = 300;
|
|
395
|
+
var inFlight = /* @__PURE__ */ new Set();
|
|
396
|
+
var pending = /* @__PURE__ */ new Set();
|
|
397
|
+
var dispatched = /* @__PURE__ */ new Set();
|
|
398
|
+
var delivered = /* @__PURE__ */ new Set();
|
|
399
|
+
var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
400
|
+
function uuidFromInsertId(insertId) {
|
|
401
|
+
if (UUID_SHAPE.test(insertId)) return insertId.toLowerCase();
|
|
402
|
+
const h = createHash("sha1").update(`one-cli-event:${insertId}`).digest("hex");
|
|
403
|
+
const variant = (parseInt(h[16], 16) & 3 | 8).toString(16);
|
|
404
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
355
405
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
await open(url);
|
|
406
|
+
function posthogHost() {
|
|
407
|
+
return process.env.ONE_POSTHOG_HOST || DEFAULT_POSTHOG_HOST;
|
|
359
408
|
}
|
|
360
|
-
|
|
361
|
-
|
|
409
|
+
function posthogKey() {
|
|
410
|
+
return process.env.ONE_POSTHOG_KEY || DEFAULT_POSTHOG_KEY;
|
|
362
411
|
}
|
|
363
|
-
function
|
|
364
|
-
|
|
412
|
+
function envName() {
|
|
413
|
+
const key = getApiKey();
|
|
414
|
+
return key ? getEnvFromApiKey(key) : "live";
|
|
365
415
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
await open(url);
|
|
416
|
+
function isOn(value) {
|
|
417
|
+
return value === "1" || value === "true";
|
|
369
418
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
async function configCommand() {
|
|
375
|
-
if (isAgentMode()) {
|
|
376
|
-
error("This command requires interactive input. Run without --agent.");
|
|
419
|
+
function debugLog(message) {
|
|
420
|
+
if (isOn(process.env.ONE_ANALYTICS_DEBUG)) {
|
|
421
|
+
process.stderr.write(`[analytics] ${message}
|
|
422
|
+
`);
|
|
377
423
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
424
|
+
}
|
|
425
|
+
function isTelemetryDisabled() {
|
|
426
|
+
if (isOn(process.env.ONE_NO_TELEMETRY) || isOn(process.env.ONE_DISABLE_TELEMETRY)) return true;
|
|
427
|
+
if (isOn(process.env.DO_NOT_TRACK)) return true;
|
|
428
|
+
if (isOn(process.env.CI)) return true;
|
|
429
|
+
if (readConfig()?.telemetry === "off") return true;
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
function distinctId() {
|
|
433
|
+
return getWhoAmI()?.user?.id ?? getDeviceId();
|
|
434
|
+
}
|
|
435
|
+
function isAuthenticated() {
|
|
436
|
+
return !!getWhoAmI()?.user || !!getApiKey();
|
|
437
|
+
}
|
|
438
|
+
function baseProperties() {
|
|
439
|
+
return {
|
|
440
|
+
$lib: "one-cli",
|
|
441
|
+
cli_version: cliVersion(),
|
|
442
|
+
agent_mode: isAgentMode(),
|
|
443
|
+
env: envName(),
|
|
444
|
+
os: process.platform,
|
|
445
|
+
arch: process.arch,
|
|
446
|
+
node_version: process.versions.node,
|
|
447
|
+
authenticated: isAuthenticated()
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function personSet() {
|
|
451
|
+
const whoami = getWhoAmI();
|
|
452
|
+
if (!whoami?.user) return void 0;
|
|
453
|
+
const set = {};
|
|
454
|
+
if (whoami.user.email) set.email = whoami.user.email;
|
|
455
|
+
if (whoami.user.name) set.name = whoami.user.name;
|
|
456
|
+
if (whoami.organization?.id) set.organization_id = whoami.organization.id;
|
|
457
|
+
return Object.keys(set).length ? set : void 0;
|
|
458
|
+
}
|
|
459
|
+
function send(item) {
|
|
460
|
+
const insertId = item.properties.$insert_id;
|
|
461
|
+
if (insertId) dispatched.add(insertId);
|
|
462
|
+
const controller = new AbortController();
|
|
463
|
+
inFlight.add(controller);
|
|
464
|
+
const run = (async () => {
|
|
465
|
+
try {
|
|
466
|
+
const res = await fetch(`${posthogHost()}/i/v0/e/`, {
|
|
467
|
+
method: "POST",
|
|
468
|
+
headers: { "Content-Type": "application/json" },
|
|
469
|
+
body: JSON.stringify({
|
|
470
|
+
api_key: posthogKey(),
|
|
471
|
+
event: item.event,
|
|
472
|
+
distinct_id: item.distinct_id,
|
|
473
|
+
// PostHog's dedupe key — a re-sent copy is dropped on ingest.
|
|
474
|
+
uuid: item.uuid ?? (insertId ? uuidFromInsertId(insertId) : void 0),
|
|
475
|
+
properties: item.properties,
|
|
476
|
+
timestamp: item.timestamp
|
|
477
|
+
}),
|
|
478
|
+
signal: controller.signal
|
|
479
|
+
});
|
|
480
|
+
if (res.ok && insertId) delivered.add(insertId);
|
|
481
|
+
debugLog(`"${item.event}" -> HTTP ${res.status}${res.ok ? "" : " (retry next run)"}`);
|
|
482
|
+
} catch (err) {
|
|
483
|
+
debugLog(`"${item.event}" not sent: ${err instanceof Error ? err.message : String(err)} (retry next run)`);
|
|
484
|
+
} finally {
|
|
485
|
+
inFlight.delete(controller);
|
|
486
|
+
}
|
|
487
|
+
})();
|
|
488
|
+
pending.add(run);
|
|
489
|
+
void run.finally(() => pending.delete(run));
|
|
490
|
+
}
|
|
491
|
+
function capture(event, properties = {}, opts = {}) {
|
|
492
|
+
if (isTelemetryDisabled()) {
|
|
493
|
+
debugLog(`disabled \u2014 skipping "${event}"`);
|
|
381
494
|
return;
|
|
382
495
|
}
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
console.log();
|
|
393
|
-
const permissions = await p.select({
|
|
394
|
-
message: "Permission level",
|
|
395
|
-
options: [
|
|
396
|
-
{ value: "admin", label: "Admin", hint: "Full access (GET, POST, PUT, PATCH, DELETE)" },
|
|
397
|
-
{ value: "write", label: "Write", hint: "GET, POST, PUT, PATCH" },
|
|
398
|
-
{ value: "read", label: "Read", hint: "GET only" }
|
|
399
|
-
],
|
|
400
|
-
initialValue: current.permissions ?? "admin"
|
|
401
|
-
});
|
|
402
|
-
if (p.isCancel(permissions)) {
|
|
403
|
-
p.outro("No changes made.");
|
|
404
|
-
return;
|
|
496
|
+
const did = opts.distinctId ?? distinctId();
|
|
497
|
+
const props = { ...baseProperties(), ...properties };
|
|
498
|
+
if (props.$insert_id === void 0) props.$insert_id = randomUUID();
|
|
499
|
+
const insertId = props.$insert_id;
|
|
500
|
+
if (opts.personProfile === false) {
|
|
501
|
+
props.$process_person_profile = false;
|
|
502
|
+
} else if (did === distinctId()) {
|
|
503
|
+
const set = personSet();
|
|
504
|
+
if (set) props.$set = set;
|
|
405
505
|
}
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
506
|
+
const item = {
|
|
507
|
+
event,
|
|
508
|
+
distinct_id: did,
|
|
509
|
+
properties: props,
|
|
510
|
+
timestamp: opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
511
|
+
uuid: uuidFromInsertId(insertId)
|
|
512
|
+
};
|
|
513
|
+
appendAnalyticsQueue(JSON.stringify(item));
|
|
514
|
+
}
|
|
515
|
+
var ROLLUP_WINDOW_MS = 5 * 60 * 1e3;
|
|
516
|
+
var ROLLUP_MAX_BATCH = 500;
|
|
517
|
+
function utcDay(ts) {
|
|
518
|
+
return new Date(ts).toISOString().slice(0, 10);
|
|
519
|
+
}
|
|
520
|
+
var PRE_AUTH_COMMANDS = /* @__PURE__ */ new Set([
|
|
521
|
+
"init",
|
|
522
|
+
"login",
|
|
523
|
+
"logout",
|
|
524
|
+
"guide",
|
|
525
|
+
"platforms",
|
|
526
|
+
"onboard",
|
|
527
|
+
"config",
|
|
528
|
+
"update",
|
|
529
|
+
"help"
|
|
530
|
+
]);
|
|
531
|
+
function shouldRecord(commandPath2) {
|
|
532
|
+
if (isAuthenticated()) return true;
|
|
533
|
+
return PRE_AUTH_COMMANDS.has(commandPath2.split(" ")[0]);
|
|
534
|
+
}
|
|
535
|
+
function recordCommand(command) {
|
|
536
|
+
if (isTelemetryDisabled()) {
|
|
537
|
+
writeUsageLog([]);
|
|
416
538
|
return;
|
|
417
539
|
}
|
|
418
|
-
|
|
419
|
-
if (
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
540
|
+
const cmdPath = commandPath(command);
|
|
541
|
+
if (!shouldRecord(cmdPath)) return;
|
|
542
|
+
const did = distinctId();
|
|
543
|
+
const entry = { ts: Date.now(), command: cmdPath, agent: isAgentMode(), did };
|
|
544
|
+
appendUsageLog(JSON.stringify(entry));
|
|
545
|
+
const today = utcDay(entry.ts);
|
|
546
|
+
const state = readUsageState();
|
|
547
|
+
const firstTouch = state.lastDay !== today || state.distinctId !== did;
|
|
548
|
+
flushUsageRollups({ force: firstTouch });
|
|
549
|
+
if (firstTouch) writeUsageState({ lastDay: today, distinctId: did });
|
|
550
|
+
}
|
|
551
|
+
function flushUsageRollups(opts = {}) {
|
|
552
|
+
if (isTelemetryDisabled()) {
|
|
553
|
+
writeUsageLog([]);
|
|
554
|
+
return;
|
|
429
555
|
}
|
|
430
|
-
const
|
|
431
|
-
|
|
556
|
+
const lines = claimUsageLog();
|
|
557
|
+
if (!lines || lines.length === 0) return;
|
|
558
|
+
const entries = [];
|
|
559
|
+
for (const line of lines) {
|
|
560
|
+
try {
|
|
561
|
+
const e = JSON.parse(line);
|
|
562
|
+
if (e && typeof e.ts === "number" && typeof e.command === "string" && typeof e.did === "string") {
|
|
563
|
+
entries.push(e);
|
|
564
|
+
}
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (entries.length === 0) return;
|
|
569
|
+
const currentDid = entries[entries.length - 1].did;
|
|
570
|
+
const now = Date.now();
|
|
571
|
+
const groups = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const e of entries) {
|
|
573
|
+
const g = groups.get(e.did);
|
|
574
|
+
if (g) g.push(e);
|
|
575
|
+
else groups.set(e.did, [e]);
|
|
576
|
+
}
|
|
577
|
+
const kept = [];
|
|
578
|
+
for (const [did, group] of groups) {
|
|
579
|
+
const due = opts.force === true || did !== currentDid || // a superseded login's batch — flush it now
|
|
580
|
+
group.length >= ROLLUP_MAX_BATCH || now - group[0].ts >= ROLLUP_WINDOW_MS;
|
|
581
|
+
if (due) emitRollup(did, group);
|
|
582
|
+
else kept.push(...group);
|
|
583
|
+
}
|
|
584
|
+
for (const e of kept) appendUsageLog(JSON.stringify(e));
|
|
585
|
+
}
|
|
586
|
+
function emitRollup(did, group) {
|
|
587
|
+
const byCommand = {};
|
|
588
|
+
let agentCount = 0;
|
|
589
|
+
for (const e of group) {
|
|
590
|
+
byCommand[e.command] = (byCommand[e.command] ?? 0) + 1;
|
|
591
|
+
if (e.agent) agentCount += 1;
|
|
592
|
+
}
|
|
593
|
+
const insertId = createHash("sha1").update(`${did}|${group.map((e) => `${e.ts}:${e.command}:${e.agent ? 1 : 0}`).join("|")}`).digest("hex");
|
|
594
|
+
capture(
|
|
595
|
+
"CLI Usage Rollup",
|
|
596
|
+
{
|
|
597
|
+
command_count: group.length,
|
|
598
|
+
by_command: byCommand,
|
|
599
|
+
agent_count: agentCount,
|
|
600
|
+
human_count: group.length - agentCount,
|
|
601
|
+
window_start: new Date(group[0].ts).toISOString(),
|
|
602
|
+
window_end: new Date(group[group.length - 1].ts).toISOString(),
|
|
603
|
+
$insert_id: insertId
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
distinctId: did,
|
|
607
|
+
timestamp: new Date(group[group.length - 1].ts).toISOString(),
|
|
608
|
+
// Rollups bill at the anonymous rate; the person already exists.
|
|
609
|
+
personProfile: false
|
|
610
|
+
}
|
|
611
|
+
);
|
|
612
|
+
debugLog(`rollup \u2014 ${group.length} command(s) for ${did}`);
|
|
613
|
+
}
|
|
614
|
+
function commandPath(command) {
|
|
615
|
+
const parts = [];
|
|
616
|
+
let current = command;
|
|
617
|
+
while (current && current.name() && current.name() !== "one") {
|
|
618
|
+
parts.unshift(current.name());
|
|
619
|
+
current = current.parent;
|
|
620
|
+
}
|
|
621
|
+
return parts.join(" ") || command.name();
|
|
622
|
+
}
|
|
623
|
+
function drainQueue() {
|
|
624
|
+
if (isTelemetryDisabled()) {
|
|
625
|
+
writeAnalyticsQueue([]);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const now = Date.now();
|
|
629
|
+
const kept = [];
|
|
630
|
+
let changed = false;
|
|
631
|
+
for (const line of readAnalyticsQueue()) {
|
|
632
|
+
let item;
|
|
633
|
+
try {
|
|
634
|
+
item = JSON.parse(line);
|
|
635
|
+
} catch {
|
|
636
|
+
changed = true;
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
const insertId = item?.properties?.$insert_id;
|
|
640
|
+
if (!insertId) {
|
|
641
|
+
changed = true;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const age = now - Date.parse(item.timestamp);
|
|
645
|
+
const attempts = item.attempts ?? 0;
|
|
646
|
+
if (!(age < QUEUE_MAX_AGE_MS) || attempts >= SEND_MAX_ATTEMPTS) {
|
|
647
|
+
debugLog(`"${item.event}" dropped (${attempts} attempts, ${Math.round(age / 6e4)} min old)`);
|
|
648
|
+
changed = true;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
if (dispatched.has(insertId)) {
|
|
652
|
+
kept.push(line);
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
item.attempts = attempts + 1;
|
|
656
|
+
if (!item.uuid) item.uuid = uuidFromInsertId(insertId);
|
|
657
|
+
kept.push(JSON.stringify(item));
|
|
658
|
+
changed = true;
|
|
659
|
+
send(item);
|
|
660
|
+
}
|
|
661
|
+
if (changed) writeAnalyticsQueue(kept);
|
|
662
|
+
}
|
|
663
|
+
async function flush() {
|
|
664
|
+
if (pending.size > 0) {
|
|
665
|
+
await Promise.race([
|
|
666
|
+
Promise.allSettled([...pending]),
|
|
667
|
+
new Promise((resolve) => setTimeout(resolve, EXIT_GRACE_MS))
|
|
668
|
+
]);
|
|
669
|
+
}
|
|
670
|
+
for (const controller of inFlight) controller.abort();
|
|
671
|
+
const remaining = readAnalyticsQueue().filter((line) => {
|
|
672
|
+
try {
|
|
673
|
+
const item = JSON.parse(line);
|
|
674
|
+
const id = item.properties?.$insert_id;
|
|
675
|
+
if (!id || delivered.has(id)) return false;
|
|
676
|
+
return (item.attempts ?? 0) < SEND_MAX_ATTEMPTS;
|
|
677
|
+
} catch {
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
writeAnalyticsQueue(remaining);
|
|
682
|
+
dispatched.clear();
|
|
683
|
+
delivered.clear();
|
|
684
|
+
}
|
|
685
|
+
function maybeShowTelemetryNotice() {
|
|
686
|
+
if (isTelemetryDisabled() || isAgentMode()) return;
|
|
687
|
+
if (telemetryNoticeShown()) return;
|
|
688
|
+
markTelemetryNoticeShown();
|
|
689
|
+
process.stderr.write(
|
|
690
|
+
pc.dim(
|
|
691
|
+
"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"
|
|
692
|
+
)
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// src/lib/install-context.ts
|
|
697
|
+
var EXTRA_HARNESS_DIRS = [
|
|
698
|
+
{ id: "gemini-cli", dir: ".gemini" },
|
|
699
|
+
{ id: "openclaw", dir: ".openclaw" },
|
|
700
|
+
{ id: "hermes", dir: ".hermes" },
|
|
701
|
+
{ id: "devin", dir: ".devin" }
|
|
702
|
+
];
|
|
703
|
+
var LAUNCHER_ENV = [
|
|
704
|
+
{ id: "claude-code", vars: ["CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT"] },
|
|
705
|
+
{ id: "codex", vars: ["CODEX_SANDBOX", "CODEX_CI", "CODEX_THREAD_ID"] },
|
|
706
|
+
{ id: "gemini-cli", vars: ["GEMINI_CLI"] },
|
|
707
|
+
// CURSOR_TRACE_ID is deliberately absent: Cursor exports it into every
|
|
708
|
+
// integrated-terminal shell, so it marks the editor, not an agent.
|
|
709
|
+
{ id: "cursor", vars: ["CURSOR_AGENT"] },
|
|
710
|
+
{ id: "windsurf", vars: ["WINDSURF_AGENT"] },
|
|
711
|
+
{ id: "kiro", vars: ["KIRO_AGENT"] },
|
|
712
|
+
{ id: "openclaw", vars: ["OPENCLAW_AGENT", "OPENCLAW_SESSION"] },
|
|
713
|
+
{ id: "hermes", vars: ["HERMES_AGENT", "HERMES_SESSION"] },
|
|
714
|
+
{ id: "devin", vars: ["DEVIN_SESSION_ID"] }
|
|
715
|
+
];
|
|
716
|
+
function detectLauncher(env = process.env) {
|
|
717
|
+
for (const entry of LAUNCHER_ENV) {
|
|
718
|
+
if (entry.vars.some((v) => env[v] !== void 0 && env[v] !== "")) return entry.id;
|
|
719
|
+
}
|
|
720
|
+
return void 0;
|
|
721
|
+
}
|
|
722
|
+
function detectInstalledHarnesses() {
|
|
723
|
+
const ids = new Set(detectInstalledAgents().map((a) => a.id));
|
|
724
|
+
for (const { id, dir } of EXTRA_HARNESS_DIRS) {
|
|
725
|
+
if (fs2.existsSync(path3.join(homeDir(), dir))) ids.add(id);
|
|
726
|
+
}
|
|
727
|
+
return [...ids].sort();
|
|
728
|
+
}
|
|
729
|
+
function tryRead(read) {
|
|
730
|
+
try {
|
|
731
|
+
const value = read();
|
|
732
|
+
return value === null || value === "" ? void 0 : value;
|
|
733
|
+
} catch {
|
|
734
|
+
return void 0;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
function collectInstallContext(opts) {
|
|
738
|
+
const env = opts.env ?? process.env;
|
|
739
|
+
const ctx = {
|
|
740
|
+
scope: opts.scope,
|
|
741
|
+
harnesses: tryRead(() => detectInstalledHarnesses()) ?? []
|
|
742
|
+
};
|
|
743
|
+
if (opts.scope === "project") {
|
|
744
|
+
ctx.path = opts.projectRoot ?? tryRead(() => getProjectRoot());
|
|
745
|
+
}
|
|
746
|
+
ctx.host = tryRead(() => os.hostname());
|
|
747
|
+
ctx.os = process.platform;
|
|
748
|
+
ctx.osVersion = tryRead(() => os.release());
|
|
749
|
+
ctx.arch = process.arch;
|
|
750
|
+
ctx.user = tryRead(() => os.userInfo().username);
|
|
751
|
+
if (!isTelemetryDisabled()) ctx.device = tryRead(() => getDeviceId());
|
|
752
|
+
const cli = tryRead(() => cliVersion());
|
|
753
|
+
ctx.cli = cli === "unknown" ? void 0 : cli;
|
|
754
|
+
ctx.launcher = detectLauncher(env);
|
|
755
|
+
return ctx;
|
|
756
|
+
}
|
|
757
|
+
function installContextToParams(ctx) {
|
|
758
|
+
const params = new URLSearchParams();
|
|
759
|
+
const set = (key, value) => {
|
|
760
|
+
if (value !== void 0 && value !== "") params.set(key, value);
|
|
761
|
+
};
|
|
762
|
+
set("scope", ctx.scope);
|
|
763
|
+
set("path", ctx.path);
|
|
764
|
+
set("host", ctx.host);
|
|
765
|
+
set("os", ctx.os);
|
|
766
|
+
set("osv", ctx.osVersion);
|
|
767
|
+
set("arch", ctx.arch);
|
|
768
|
+
set("user", ctx.user);
|
|
769
|
+
set("device", ctx.device);
|
|
770
|
+
set("cli", ctx.cli);
|
|
771
|
+
if (ctx.harnesses.length > 0) params.set("harnesses", ctx.harnesses.join(","));
|
|
772
|
+
set("launcher", ctx.launcher);
|
|
773
|
+
return params;
|
|
774
|
+
}
|
|
775
|
+
function describeInstallContext(ctx) {
|
|
776
|
+
const lines = [`scope: ${ctx.scope}`];
|
|
777
|
+
if (ctx.path) lines.push(`path: ${ctx.path}`);
|
|
778
|
+
if (ctx.host || ctx.os) {
|
|
779
|
+
const osPart = [ctx.os, ctx.osVersion].filter(Boolean).join(" ");
|
|
780
|
+
const detail = [osPart, ctx.arch].filter(Boolean).join(", ");
|
|
781
|
+
lines.push(`machine: ${ctx.host ?? "unknown"}${detail ? ` (${detail})` : ""}`);
|
|
782
|
+
}
|
|
783
|
+
if (ctx.user) lines.push(`user: ${ctx.user}`);
|
|
784
|
+
if (ctx.device) lines.push(`device: ${ctx.device}`);
|
|
785
|
+
if (ctx.harnesses.length > 0) lines.push(`harnesses: ${ctx.harnesses.join(", ")}`);
|
|
786
|
+
if (ctx.launcher) lines.push(`launched by: ${ctx.launcher}`);
|
|
787
|
+
if (ctx.cli) lines.push(`cli: ${ctx.cli}`);
|
|
788
|
+
return lines.join("\n");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// src/lib/browser.ts
|
|
792
|
+
var DEFAULT_APP_URL = "https://app.withone.ai";
|
|
793
|
+
function oneAppUrl() {
|
|
794
|
+
const override = process.env.ONE_APP_URL?.trim();
|
|
795
|
+
return (override || DEFAULT_APP_URL).replace(/\/+$/, "");
|
|
796
|
+
}
|
|
797
|
+
function getConnectionUrl(platform, params) {
|
|
798
|
+
const searchParams = new URLSearchParams();
|
|
799
|
+
if (params?.orgId) searchParams.set("orgId", params.orgId);
|
|
800
|
+
if (params?.projectId) searchParams.set("projectId", params.projectId);
|
|
801
|
+
if (params?.env) searchParams.set("env", params.env);
|
|
802
|
+
const qs = searchParams.toString();
|
|
803
|
+
return `${oneAppUrl()}/${qs ? `?${qs}` : ""}#open=${platform}`;
|
|
804
|
+
}
|
|
805
|
+
function getApiKeyUrl() {
|
|
806
|
+
return `${oneAppUrl()}/settings/api-keys`;
|
|
807
|
+
}
|
|
808
|
+
async function openConnectionPage(platform, params) {
|
|
809
|
+
await open(getConnectionUrl(platform, params));
|
|
810
|
+
}
|
|
811
|
+
async function openApiKeyPage() {
|
|
812
|
+
await open(getApiKeyUrl());
|
|
813
|
+
}
|
|
814
|
+
function getCliAuthUrl(port, state, context) {
|
|
815
|
+
const params = new URLSearchParams([
|
|
816
|
+
["port", String(port)],
|
|
817
|
+
["state", state],
|
|
818
|
+
...context ? installContextToParams(context) : []
|
|
819
|
+
]);
|
|
820
|
+
return `${oneAppUrl()}/cli/auth?${params.toString()}`;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/commands/config.ts
|
|
824
|
+
import * as p from "@clack/prompts";
|
|
825
|
+
import pc2 from "picocolors";
|
|
826
|
+
async function configCommand() {
|
|
827
|
+
if (isAgentMode()) {
|
|
828
|
+
error("This command requires interactive input. Run without --agent.");
|
|
829
|
+
}
|
|
830
|
+
const config2 = readConfig();
|
|
831
|
+
if (!config2) {
|
|
832
|
+
p.log.error(`No One config found. Run ${pc2.cyan("one init")} first.`);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
p.intro(pc2.bgCyan(pc2.black(" One Access Control ")));
|
|
836
|
+
const current = getAccessControl();
|
|
837
|
+
console.log();
|
|
838
|
+
console.log(` ${pc2.bold("Current Access Control")}`);
|
|
839
|
+
console.log(` ${pc2.dim("\u2500".repeat(42))}`);
|
|
840
|
+
console.log(` ${pc2.dim("Permissions:")} ${current.permissions ?? "admin"}`);
|
|
841
|
+
console.log(` ${pc2.dim("Connections:")} ${formatList(current.connectionKeys)}`);
|
|
842
|
+
console.log(` ${pc2.dim("Action IDs:")} ${formatList(current.actionIds)}`);
|
|
843
|
+
console.log(` ${pc2.dim("Knowledge only:")} ${current.knowledgeAgent ? "yes" : "no"}`);
|
|
844
|
+
console.log();
|
|
845
|
+
const permissions = await p.select({
|
|
846
|
+
message: "Permission level",
|
|
847
|
+
options: [
|
|
848
|
+
{ value: "admin", label: "Admin", hint: "Full access (GET, POST, PUT, PATCH, DELETE)" },
|
|
849
|
+
{ value: "write", label: "Write", hint: "GET, POST, PUT, PATCH" },
|
|
850
|
+
{ value: "read", label: "Read", hint: "GET only" }
|
|
851
|
+
],
|
|
852
|
+
initialValue: current.permissions ?? "admin"
|
|
853
|
+
});
|
|
854
|
+
if (p.isCancel(permissions)) {
|
|
855
|
+
p.outro("No changes made.");
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const connectionMode = await p.select({
|
|
859
|
+
message: "Connection scope",
|
|
860
|
+
options: [
|
|
861
|
+
{ value: "all", label: "All connections" },
|
|
862
|
+
{ value: "specific", label: "Select specific connections" }
|
|
863
|
+
],
|
|
864
|
+
initialValue: current.connectionKeys ? "specific" : "all"
|
|
865
|
+
});
|
|
866
|
+
if (p.isCancel(connectionMode)) {
|
|
867
|
+
p.outro("No changes made.");
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
let connectionKeys;
|
|
871
|
+
if (connectionMode === "specific") {
|
|
872
|
+
connectionKeys = await selectConnections(config2.apiKey);
|
|
873
|
+
if (connectionKeys === void 0) {
|
|
874
|
+
p.outro("No changes made.");
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (connectionKeys.length === 0) {
|
|
878
|
+
p.log.info(`No connections found. Defaulting to all. Use ${pc2.cyan("one add")} to connect platforms.`);
|
|
879
|
+
connectionKeys = void 0;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
const actionMode = await p.select({
|
|
883
|
+
message: "Action scope",
|
|
432
884
|
options: [
|
|
433
885
|
{ value: "all", label: "All actions" },
|
|
434
886
|
{ value: "specific", label: "Restrict to specific action IDs" }
|
|
@@ -464,8 +916,8 @@ async function configCommand() {
|
|
|
464
916
|
p.outro("No changes made.");
|
|
465
917
|
return;
|
|
466
918
|
}
|
|
467
|
-
const
|
|
468
|
-
const isCustomBase = !!
|
|
919
|
+
const storedBase = readConfig()?.apiBase;
|
|
920
|
+
const isCustomBase = !!storedBase;
|
|
469
921
|
const baseUrlMode = await p.select({
|
|
470
922
|
message: "API base URL",
|
|
471
923
|
options: [
|
|
@@ -483,7 +935,7 @@ async function configCommand() {
|
|
|
483
935
|
const customUrl = await p.text({
|
|
484
936
|
message: "Enter API base URL:",
|
|
485
937
|
placeholder: "https://development-api.withone.ai",
|
|
486
|
-
initialValue:
|
|
938
|
+
initialValue: storedBase ? storedBase.replace(/\/v1$/, "") : "",
|
|
487
939
|
validate: (value) => {
|
|
488
940
|
if (!value) return "URL is required";
|
|
489
941
|
try {
|
|
@@ -500,7 +952,7 @@ async function configCommand() {
|
|
|
500
952
|
}
|
|
501
953
|
const normalized = customUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
502
954
|
const apiKey = await p.text({
|
|
503
|
-
message: `Enter your API key for ${
|
|
955
|
+
message: `Enter your API key for ${pc2.cyan(normalized)}:`,
|
|
504
956
|
placeholder: "sk_live_...",
|
|
505
957
|
validate: (value) => {
|
|
506
958
|
if (!value) return "API key is required";
|
|
@@ -514,29 +966,29 @@ async function configCommand() {
|
|
|
514
966
|
p.outro("No changes made.");
|
|
515
967
|
return;
|
|
516
968
|
}
|
|
517
|
-
const
|
|
518
|
-
|
|
969
|
+
const spinner4 = p.spinner();
|
|
970
|
+
spinner4.start("Validating API key...");
|
|
519
971
|
let isValid = false;
|
|
520
972
|
try {
|
|
521
973
|
const api = new OneApi(apiKey, `${normalized}/v1`);
|
|
522
974
|
isValid = Boolean(await api.validateApiKey());
|
|
523
975
|
} catch (err) {
|
|
524
|
-
|
|
976
|
+
spinner4.stop("Connection failed");
|
|
525
977
|
const msg = err instanceof Error ? err.message : String(err);
|
|
526
|
-
p.log.error(`Could not reach ${
|
|
978
|
+
p.log.error(`Could not reach ${pc2.cyan(normalized)}: ${msg}`);
|
|
527
979
|
return;
|
|
528
980
|
}
|
|
529
981
|
if (!isValid) {
|
|
530
|
-
|
|
531
|
-
p.log.error(`Invalid API key for ${
|
|
982
|
+
spinner4.stop("Invalid API key");
|
|
983
|
+
p.log.error(`Invalid API key for ${pc2.cyan(normalized)}.`);
|
|
532
984
|
return;
|
|
533
985
|
}
|
|
534
|
-
|
|
986
|
+
spinner4.stop("API key validated");
|
|
535
987
|
updateApiBase(normalized);
|
|
536
988
|
newApiKey = apiKey;
|
|
537
989
|
} else if (isCustomBase) {
|
|
538
990
|
const apiKey = await p.text({
|
|
539
|
-
message: `Enter your API key for ${
|
|
991
|
+
message: `Enter your API key for ${pc2.cyan("https://api.withone.ai")}:`,
|
|
540
992
|
placeholder: "sk_live_...",
|
|
541
993
|
validate: (value) => {
|
|
542
994
|
if (!value) return "API key is required";
|
|
@@ -550,24 +1002,24 @@ async function configCommand() {
|
|
|
550
1002
|
p.outro("No changes made.");
|
|
551
1003
|
return;
|
|
552
1004
|
}
|
|
553
|
-
const
|
|
554
|
-
|
|
1005
|
+
const spinner4 = p.spinner();
|
|
1006
|
+
spinner4.start("Validating API key...");
|
|
555
1007
|
let isValid = false;
|
|
556
1008
|
try {
|
|
557
1009
|
const api = new OneApi(apiKey, "https://api.withone.ai/v1");
|
|
558
1010
|
isValid = Boolean(await api.validateApiKey());
|
|
559
1011
|
} catch (err) {
|
|
560
|
-
|
|
1012
|
+
spinner4.stop("Connection failed");
|
|
561
1013
|
const msg = err instanceof Error ? err.message : String(err);
|
|
562
|
-
p.log.error(`Could not reach ${
|
|
1014
|
+
p.log.error(`Could not reach ${pc2.cyan("https://api.withone.ai")}: ${msg}`);
|
|
563
1015
|
return;
|
|
564
1016
|
}
|
|
565
1017
|
if (!isValid) {
|
|
566
|
-
|
|
1018
|
+
spinner4.stop("Invalid API key");
|
|
567
1019
|
p.log.error(`Invalid API key. Get a valid key at ${getApiKeyUrl()}`);
|
|
568
1020
|
return;
|
|
569
1021
|
}
|
|
570
|
-
|
|
1022
|
+
spinner4.stop("API key validated");
|
|
571
1023
|
updateApiBase(null);
|
|
572
1024
|
newApiKey = apiKey;
|
|
573
1025
|
}
|
|
@@ -581,7 +1033,9 @@ async function configCommand() {
|
|
|
581
1033
|
const updatedConfig = readConfig();
|
|
582
1034
|
if (updatedConfig && newApiKey !== config2.apiKey) {
|
|
583
1035
|
updatedConfig.apiKey = newApiKey;
|
|
1036
|
+
delete updatedConfig.apiKeyName;
|
|
584
1037
|
delete updatedConfig.whoami;
|
|
1038
|
+
delete updatedConfig.whoamiApiBase;
|
|
585
1039
|
writeConfig(updatedConfig);
|
|
586
1040
|
}
|
|
587
1041
|
const ac = getAccessControl();
|
|
@@ -603,16 +1057,16 @@ async function configCommand() {
|
|
|
603
1057
|
p.outro("Configuration updated.");
|
|
604
1058
|
}
|
|
605
1059
|
async function selectConnections(apiKey) {
|
|
606
|
-
const
|
|
607
|
-
|
|
1060
|
+
const spinner4 = p.spinner();
|
|
1061
|
+
spinner4.start("Fetching connections...");
|
|
608
1062
|
let connections;
|
|
609
1063
|
try {
|
|
610
1064
|
const api = new OneApi(apiKey, getApiBase());
|
|
611
1065
|
const rawConnections = await api.listConnections();
|
|
612
1066
|
connections = rawConnections.map((c) => ({ platform: c.platform, key: c.key }));
|
|
613
|
-
|
|
1067
|
+
spinner4.stop(`Found ${connections.length} connection(s)`);
|
|
614
1068
|
} catch {
|
|
615
|
-
|
|
1069
|
+
spinner4.stop("Could not fetch connections");
|
|
616
1070
|
const manual = await p.text({
|
|
617
1071
|
message: "Enter connection keys manually (comma-separated):",
|
|
618
1072
|
placeholder: "conn_key_1, conn_key_2",
|
|
@@ -645,46 +1099,18 @@ function formatList(list) {
|
|
|
645
1099
|
}
|
|
646
1100
|
|
|
647
1101
|
// src/commands/init.ts
|
|
648
|
-
import
|
|
1102
|
+
import open3 from "open";
|
|
649
1103
|
|
|
650
1104
|
// src/lib/skill-sync.ts
|
|
651
|
-
import
|
|
652
|
-
import
|
|
1105
|
+
import fs3 from "fs";
|
|
1106
|
+
import path4 from "path";
|
|
653
1107
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
654
1108
|
|
|
655
1109
|
// src/commands/update.ts
|
|
656
1110
|
import { spawn } from "child_process";
|
|
657
1111
|
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, rmSync, openSync, closeSync } from "fs";
|
|
658
1112
|
import { delimiter, dirname, join } from "path";
|
|
659
|
-
import
|
|
660
|
-
|
|
661
|
-
// src/lib/version.ts
|
|
662
|
-
import { createRequire } from "module";
|
|
663
|
-
import { existsSync } from "fs";
|
|
664
|
-
import path2 from "path";
|
|
665
|
-
import { fileURLToPath } from "url";
|
|
666
|
-
var require2 = createRequire(import.meta.url);
|
|
667
|
-
var cached = null;
|
|
668
|
-
function cliVersion() {
|
|
669
|
-
if (cached !== null) return cached;
|
|
670
|
-
const dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
671
|
-
for (let i = 1; i <= 4; i++) {
|
|
672
|
-
const candidate = path2.resolve(dir, ...Array(i).fill(".."), "package.json");
|
|
673
|
-
if (!existsSync(candidate)) continue;
|
|
674
|
-
try {
|
|
675
|
-
const version2 = require2(candidate).version;
|
|
676
|
-
if (version2) {
|
|
677
|
-
cached = version2;
|
|
678
|
-
return cached;
|
|
679
|
-
}
|
|
680
|
-
} catch {
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
cached = "unknown";
|
|
684
|
-
return cached;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// src/commands/update.ts
|
|
1113
|
+
import pc3 from "picocolors";
|
|
688
1114
|
var currentVersion = cliVersion();
|
|
689
1115
|
var ONE_DIR = () => join(homeDir(), ".one");
|
|
690
1116
|
var CACHE_PATH = () => join(ONE_DIR(), "update-check.json");
|
|
@@ -860,10 +1286,10 @@ function maybeWarnAboutFailedUpdates(targetVersion) {
|
|
|
860
1286
|
if (!shouldWarnAboutFailedUpdates(state)) return;
|
|
861
1287
|
writeAutoUpdateState({ ...state, lastNoticeAt: Date.now() });
|
|
862
1288
|
process.stderr.write(
|
|
863
|
-
|
|
1289
|
+
pc3.yellow(
|
|
864
1290
|
`One CLI could not auto-update (v${currentVersion} \u2192 v${targetVersion}) after ${state.failures} attempts.
|
|
865
1291
|
`
|
|
866
|
-
) +
|
|
1292
|
+
) + pc3.dim(
|
|
867
1293
|
`Update manually with: npm install -g @withone/cli@latest
|
|
868
1294
|
Details: ${LOG_PATH()}. Silence this with ONE_NO_AUTO_UPDATE=1.
|
|
869
1295
|
`
|
|
@@ -960,42 +1386,42 @@ function autoUpdate(targetVersion, publishedAt) {
|
|
|
960
1386
|
var CANONICAL_SKILL_DIR = ".agents/skills";
|
|
961
1387
|
var VERSION_MARKER = ".one-cli-version";
|
|
962
1388
|
function getPackagedSkillDir() {
|
|
963
|
-
const here =
|
|
964
|
-
return
|
|
1389
|
+
const here = path4.dirname(fileURLToPath2(import.meta.url));
|
|
1390
|
+
return path4.resolve(here, "..", "skills", "one");
|
|
965
1391
|
}
|
|
966
1392
|
function getCanonicalSkillPath() {
|
|
967
|
-
return
|
|
1393
|
+
return path4.join(homeDir(), CANONICAL_SKILL_DIR, "one");
|
|
968
1394
|
}
|
|
969
1395
|
function getVersionMarkerPath() {
|
|
970
|
-
return
|
|
1396
|
+
return path4.join(getCanonicalSkillPath(), VERSION_MARKER);
|
|
971
1397
|
}
|
|
972
1398
|
function isSkillInstalled() {
|
|
973
|
-
return
|
|
1399
|
+
return fs3.existsSync(path4.join(getCanonicalSkillPath(), "SKILL.md"));
|
|
974
1400
|
}
|
|
975
1401
|
function readInstalledSkillVersion() {
|
|
976
1402
|
try {
|
|
977
|
-
return
|
|
1403
|
+
return fs3.readFileSync(getVersionMarkerPath(), "utf-8").trim() || null;
|
|
978
1404
|
} catch {
|
|
979
1405
|
return null;
|
|
980
1406
|
}
|
|
981
1407
|
}
|
|
982
1408
|
function writeInstalledSkillVersion(version2) {
|
|
983
1409
|
try {
|
|
984
|
-
|
|
985
|
-
|
|
1410
|
+
fs3.mkdirSync(getCanonicalSkillPath(), { recursive: true });
|
|
1411
|
+
fs3.writeFileSync(getVersionMarkerPath(), `${version2}
|
|
986
1412
|
`);
|
|
987
1413
|
} catch {
|
|
988
1414
|
}
|
|
989
1415
|
}
|
|
990
1416
|
function copyDirSync(src, dest) {
|
|
991
|
-
|
|
992
|
-
for (const entry of
|
|
993
|
-
const srcPath =
|
|
994
|
-
const destPath =
|
|
1417
|
+
fs3.mkdirSync(dest, { recursive: true });
|
|
1418
|
+
for (const entry of fs3.readdirSync(src, { withFileTypes: true })) {
|
|
1419
|
+
const srcPath = path4.join(src, entry.name);
|
|
1420
|
+
const destPath = path4.join(dest, entry.name);
|
|
995
1421
|
if (entry.isDirectory()) {
|
|
996
1422
|
copyDirSync(srcPath, destPath);
|
|
997
1423
|
} else {
|
|
998
|
-
|
|
1424
|
+
fs3.copyFileSync(srcPath, destPath);
|
|
999
1425
|
}
|
|
1000
1426
|
}
|
|
1001
1427
|
}
|
|
@@ -1018,7 +1444,7 @@ function forceSyncSkills() {
|
|
|
1018
1444
|
}
|
|
1019
1445
|
function performSync(current, reason) {
|
|
1020
1446
|
const source = getPackagedSkillDir();
|
|
1021
|
-
if (!
|
|
1447
|
+
if (!fs3.existsSync(path4.join(source, "SKILL.md"))) {
|
|
1022
1448
|
return { synced: false, reason: "source-missing" };
|
|
1023
1449
|
}
|
|
1024
1450
|
const canonical = getCanonicalSkillPath();
|
|
@@ -1047,21 +1473,36 @@ function getSkillStatus() {
|
|
|
1047
1473
|
// src/commands/login.ts
|
|
1048
1474
|
import http from "http";
|
|
1049
1475
|
import crypto from "crypto";
|
|
1476
|
+
import open2 from "open";
|
|
1050
1477
|
import * as p2 from "@clack/prompts";
|
|
1051
1478
|
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1052
1479
|
var PORT_RANGE_START = 49152;
|
|
1053
1480
|
var PORT_RANGE_END = 65535;
|
|
1054
1481
|
var MAX_PORT_ATTEMPTS = 5;
|
|
1055
|
-
var
|
|
1482
|
+
var MAX_KEY_NAME_LENGTH = 120;
|
|
1483
|
+
var MAX_ERROR_LENGTH = 200;
|
|
1484
|
+
var CHECK_MARK = `<div style="width:48px;height:48px;border-radius:50%;background:rgba(34,197,94,0.1);display:flex;align-items:center;justify-content:center;margin:0 auto 16px">
|
|
1485
|
+
<svg width="24" height="24" fill="none" stroke="#22c55e" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
|
|
1486
|
+
</div>`;
|
|
1487
|
+
function statusPage(title, body, check = false) {
|
|
1488
|
+
return `<!DOCTYPE html>
|
|
1056
1489
|
<html><head><title>One CLI</title></head>
|
|
1057
1490
|
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#fafafa">
|
|
1058
1491
|
<div style="text-align:center">
|
|
1059
|
-
|
|
1060
|
-
<
|
|
1061
|
-
</
|
|
1062
|
-
<h1 style="font-size:20px;margin:0 0 8px">You're all set!</h1>
|
|
1063
|
-
<p style="color:#a1a1aa;font-size:14px">Return to your terminal. You can close this tab.</p>
|
|
1492
|
+
${check ? CHECK_MARK : ""}
|
|
1493
|
+
<h1 style="font-size:20px;margin:0 0 8px">${title}</h1>
|
|
1494
|
+
<p style="color:#a1a1aa;font-size:14px">${body}</p>
|
|
1064
1495
|
</div></body></html>`;
|
|
1496
|
+
}
|
|
1497
|
+
var SUCCESS_HTML = statusPage("You're all set!", "Return to your terminal. You can close this tab.", true);
|
|
1498
|
+
var CANCELLED_HTML = statusPage("Login cancelled", "No key was created. You can close this tab and run <code>one login</code> again.");
|
|
1499
|
+
var FAILED_HTML = statusPage("Login did not complete", "The consent page reported an error. Return to your terminal for details, then run <code>one login</code> again.");
|
|
1500
|
+
function cleanParam(value, max) {
|
|
1501
|
+
if (value === null) return void 0;
|
|
1502
|
+
const cleaned = value.replace(/[\u0000-\u001f\u007f-\u009f]/g, "").trim();
|
|
1503
|
+
if (!cleaned) return void 0;
|
|
1504
|
+
return Array.from(cleaned).slice(0, max).join("");
|
|
1505
|
+
}
|
|
1065
1506
|
function randomPort() {
|
|
1066
1507
|
return PORT_RANGE_START + Math.floor(Math.random() * (PORT_RANGE_END - PORT_RANGE_START));
|
|
1067
1508
|
}
|
|
@@ -1082,12 +1523,10 @@ function startCallbackServer(expectedState) {
|
|
|
1082
1523
|
res.end("Not found");
|
|
1083
1524
|
return;
|
|
1084
1525
|
}
|
|
1085
|
-
const encodedKey = url.searchParams.get("s");
|
|
1086
1526
|
const state = url.searchParams.get("state");
|
|
1087
|
-
|
|
1088
|
-
if (!apiKey || !state) {
|
|
1527
|
+
if (!state) {
|
|
1089
1528
|
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1090
|
-
res.end("Missing
|
|
1529
|
+
res.end("Missing state");
|
|
1091
1530
|
return;
|
|
1092
1531
|
}
|
|
1093
1532
|
if (state !== expectedState) {
|
|
@@ -1095,12 +1534,38 @@ function startCallbackServer(expectedState) {
|
|
|
1095
1534
|
res.end("State mismatch");
|
|
1096
1535
|
return;
|
|
1097
1536
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1537
|
+
const encodedKey = url.searchParams.get("s");
|
|
1538
|
+
if (encodedKey) {
|
|
1539
|
+
const apiKey = Buffer.from(encodedKey, "base64").toString("utf-8");
|
|
1540
|
+
if (!apiKey) {
|
|
1541
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1542
|
+
res.end("Missing required parameters");
|
|
1543
|
+
return;
|
|
1544
|
+
}
|
|
1545
|
+
const keyName = cleanParam(url.searchParams.get("name"), MAX_KEY_NAME_LENGTH);
|
|
1546
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1547
|
+
res.end(SUCCESS_HTML);
|
|
1548
|
+
resolveResult({ kind: "key", apiKey, keyName });
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
const error2 = cleanParam(url.searchParams.get("error"), MAX_ERROR_LENGTH);
|
|
1552
|
+
if (error2 === "cancelled") {
|
|
1553
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1554
|
+
res.end(CANCELLED_HTML);
|
|
1555
|
+
resolveResult({ kind: "cancelled" });
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
if (error2) {
|
|
1559
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1560
|
+
res.end(FAILED_HTML);
|
|
1561
|
+
resolveResult({ kind: "failed", reason: error2 });
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1565
|
+
res.end("Missing required parameters");
|
|
1101
1566
|
});
|
|
1102
1567
|
server.on("error", (err) => {
|
|
1103
|
-
if (err.code === "EADDRINUSE" && attempts < MAX_PORT_ATTEMPTS) {
|
|
1568
|
+
if ((err.code === "EADDRINUSE" || err.code === "EACCES") && attempts < MAX_PORT_ATTEMPTS) {
|
|
1104
1569
|
tryListen();
|
|
1105
1570
|
return;
|
|
1106
1571
|
}
|
|
@@ -1113,9 +1578,9 @@ function startCallbackServer(expectedState) {
|
|
|
1113
1578
|
tryListen();
|
|
1114
1579
|
});
|
|
1115
1580
|
}
|
|
1116
|
-
async function browserLogin() {
|
|
1581
|
+
async function browserLogin(opts) {
|
|
1117
1582
|
const state = crypto.randomUUID();
|
|
1118
|
-
const spin =
|
|
1583
|
+
const spin = createSpinner();
|
|
1119
1584
|
let server;
|
|
1120
1585
|
let port;
|
|
1121
1586
|
let resultPromise;
|
|
@@ -1125,14 +1590,24 @@ async function browserLogin() {
|
|
|
1125
1590
|
error("Could not start local server. Try: one init");
|
|
1126
1591
|
return null;
|
|
1127
1592
|
}
|
|
1128
|
-
const
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1593
|
+
const context = collectInstallContext({ scope: opts.scope });
|
|
1594
|
+
const authUrl = getCliAuthUrl(port, state, context);
|
|
1595
|
+
if (isAgentMode()) {
|
|
1596
|
+
process.stderr.write(`Opening the browser for authentication. If it doesn't open, visit:
|
|
1597
|
+
${authUrl}
|
|
1598
|
+
`);
|
|
1599
|
+
} else {
|
|
1600
|
+
note(
|
|
1601
|
+
`If the browser doesn't open, visit:
|
|
1602
|
+
${authUrl}
|
|
1603
|
+
|
|
1604
|
+
The consent page records this on the key so you can find the install later:
|
|
1605
|
+
${describeInstallContext(context)}`,
|
|
1606
|
+
"Opening browser for authentication..."
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1134
1609
|
try {
|
|
1135
|
-
await
|
|
1610
|
+
await open2(authUrl);
|
|
1136
1611
|
} catch {
|
|
1137
1612
|
}
|
|
1138
1613
|
spin.start("Waiting for authentication... (timeout: 5 min)");
|
|
@@ -1143,12 +1618,20 @@ ${authUrl}`,
|
|
|
1143
1618
|
timer.unref();
|
|
1144
1619
|
});
|
|
1145
1620
|
try {
|
|
1146
|
-
const
|
|
1621
|
+
const outcome = await Promise.race([resultPromise, timeout]);
|
|
1622
|
+
if (outcome.kind === "cancelled") {
|
|
1623
|
+
spin.stop("Login cancelled in the browser.");
|
|
1624
|
+
return null;
|
|
1625
|
+
}
|
|
1626
|
+
if (outcome.kind === "failed") {
|
|
1627
|
+
spin.stop("Authentication failed.");
|
|
1628
|
+
error(`The consent page reported an error: ${outcome.reason}. Try again with: one login`);
|
|
1629
|
+
}
|
|
1147
1630
|
spin.stop("Authentication received!");
|
|
1148
1631
|
const apiBase = getApiBase();
|
|
1149
|
-
const api = new OneApi(
|
|
1632
|
+
const api = new OneApi(outcome.apiKey, apiBase);
|
|
1150
1633
|
const whoami = await api.whoami();
|
|
1151
|
-
return { apiKey:
|
|
1634
|
+
return { apiKey: outcome.apiKey, whoami, keyName: outcome.keyName };
|
|
1152
1635
|
} catch (err) {
|
|
1153
1636
|
spin.stop("Authentication failed.");
|
|
1154
1637
|
if (err instanceof Error && err.message === "timeout") {
|
|
@@ -1164,17 +1647,6 @@ ${authUrl}`,
|
|
|
1164
1647
|
server.close();
|
|
1165
1648
|
}
|
|
1166
1649
|
}
|
|
1167
|
-
function saveCredentials(apiKey, scope) {
|
|
1168
|
-
const existing = scope === "project" ? readProjectConfig() : readGlobalConfig();
|
|
1169
|
-
writeConfig({
|
|
1170
|
-
apiKey,
|
|
1171
|
-
installedAgents: existing?.installedAgents ?? [],
|
|
1172
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1173
|
-
accessControl: existing?.accessControl,
|
|
1174
|
-
cacheTtl: existing?.cacheTtl,
|
|
1175
|
-
apiBase: existing?.apiBase
|
|
1176
|
-
}, scope);
|
|
1177
|
-
}
|
|
1178
1650
|
async function loginCommand() {
|
|
1179
1651
|
if (isAgentMode()) {
|
|
1180
1652
|
json({ error: "Browser login not available in agent mode. Use: one init" });
|
|
@@ -1184,11 +1656,11 @@ async function loginCommand() {
|
|
|
1184
1656
|
const existingKey = getApiKey();
|
|
1185
1657
|
if (existingKey) {
|
|
1186
1658
|
const pc17 = (await import("picocolors")).default;
|
|
1187
|
-
const
|
|
1188
|
-
const whoami2 =
|
|
1659
|
+
const resolved = resolveConfig();
|
|
1660
|
+
const whoami2 = resolved.config?.whoami;
|
|
1189
1661
|
const env2 = getEnvFromApiKey(existingKey);
|
|
1190
1662
|
const envLabel2 = env2 === "test" ? pc17.yellow("test") : pc17.green("live");
|
|
1191
|
-
const currentScope =
|
|
1663
|
+
const currentScope = resolved.scope === "project" ? pc17.cyan("local config") : pc17.magenta("global config");
|
|
1192
1664
|
const lines = ["You are already logged in.", ""];
|
|
1193
1665
|
if (whoami2) {
|
|
1194
1666
|
const contextParts2 = [];
|
|
@@ -1216,14 +1688,10 @@ async function loginCommand() {
|
|
|
1216
1688
|
}
|
|
1217
1689
|
targetScope = scopeChoice;
|
|
1218
1690
|
}
|
|
1219
|
-
const result = await browserLogin();
|
|
1691
|
+
const result = await browserLogin({ scope: targetScope });
|
|
1220
1692
|
if (!result) return;
|
|
1221
|
-
const { apiKey, whoami } = result;
|
|
1222
|
-
saveCredentials(apiKey, targetScope);
|
|
1223
|
-
const resolved = resolveConfig();
|
|
1224
|
-
if (resolved.config) {
|
|
1225
|
-
writeConfig({ ...resolved.config, whoami }, targetScope);
|
|
1226
|
-
}
|
|
1693
|
+
const { apiKey, whoami, keyName } = result;
|
|
1694
|
+
saveCredentials(apiKey, targetScope, { keyName, whoami });
|
|
1227
1695
|
const pc16 = (await import("picocolors")).default;
|
|
1228
1696
|
const env = getEnvFromApiKey(apiKey);
|
|
1229
1697
|
const contextParts = [];
|
|
@@ -1236,6 +1704,7 @@ async function loginCommand() {
|
|
|
1236
1704
|
`${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`,
|
|
1237
1705
|
`${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`
|
|
1238
1706
|
];
|
|
1707
|
+
if (keyName) infoLines.push(`${pc16.dim("Key:")} ${keyName}`);
|
|
1239
1708
|
if (whoami.organization) infoLines.push(`${pc16.dim("Org:")} ${whoami.organization.name}`);
|
|
1240
1709
|
if (whoami.project) infoLines.push(`${pc16.dim("Project:")} ${whoami.project.name}`);
|
|
1241
1710
|
infoLines.push("");
|
|
@@ -1291,13 +1760,15 @@ async function nonInteractiveInit(options) {
|
|
|
1291
1760
|
}
|
|
1292
1761
|
const scope = options.global ? "global" : options.project ? "project" : "global";
|
|
1293
1762
|
let apiKey;
|
|
1763
|
+
let keyName;
|
|
1294
1764
|
let whoami;
|
|
1295
1765
|
if (auth === "browser") {
|
|
1296
|
-
const result = await browserLogin();
|
|
1766
|
+
const result = await browserLogin({ scope });
|
|
1297
1767
|
if (!result) {
|
|
1298
1768
|
error("Browser login did not complete. Try again: one init --auth browser");
|
|
1299
1769
|
}
|
|
1300
1770
|
apiKey = result.apiKey;
|
|
1771
|
+
keyName = result.keyName;
|
|
1301
1772
|
whoami = result.whoami;
|
|
1302
1773
|
} else {
|
|
1303
1774
|
const key = options.apiKey?.trim();
|
|
@@ -1321,19 +1792,7 @@ async function nonInteractiveInit(options) {
|
|
|
1321
1792
|
apiKey = key;
|
|
1322
1793
|
whoami = validated;
|
|
1323
1794
|
}
|
|
1324
|
-
|
|
1325
|
-
writeConfig(
|
|
1326
|
-
{
|
|
1327
|
-
apiKey,
|
|
1328
|
-
installedAgents: existing?.installedAgents ?? [],
|
|
1329
|
-
createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1330
|
-
accessControl: existing?.accessControl,
|
|
1331
|
-
apiBase: existing?.apiBase,
|
|
1332
|
-
cacheTtl: existing?.cacheTtl,
|
|
1333
|
-
whoami
|
|
1334
|
-
},
|
|
1335
|
-
scope
|
|
1336
|
-
);
|
|
1795
|
+
saveCredentials(apiKey, scope, { keyName, whoami });
|
|
1337
1796
|
if (options.openaiKey?.trim()) {
|
|
1338
1797
|
try {
|
|
1339
1798
|
setOpenAiApiKey(options.openaiKey.trim());
|
|
@@ -1355,6 +1814,7 @@ async function nonInteractiveInit(options) {
|
|
|
1355
1814
|
project: whoami.project,
|
|
1356
1815
|
env: getEnvFromApiKey(apiKey)
|
|
1357
1816
|
},
|
|
1817
|
+
keyName,
|
|
1358
1818
|
skillInstalled: installed,
|
|
1359
1819
|
skillFailed: failed
|
|
1360
1820
|
});
|
|
@@ -1365,18 +1825,19 @@ async function nonInteractiveInit(options) {
|
|
|
1365
1825
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
1366
1826
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
1367
1827
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1368
|
-
const envLabel = env === "test" ?
|
|
1828
|
+
const envLabel = env === "test" ? pc4.yellow("test") : pc4.green("live");
|
|
1369
1829
|
console.log();
|
|
1370
|
-
console.log(` ${
|
|
1371
|
-
console.log(` ${
|
|
1372
|
-
console.log(` ${
|
|
1373
|
-
console.log(` ${
|
|
1374
|
-
console.log(` ${
|
|
1830
|
+
console.log(` ${pc4.bold("Setup complete")} ${scopeLabel(scope)}`);
|
|
1831
|
+
console.log(` ${pc4.dim("\u2500".repeat(42))}`);
|
|
1832
|
+
console.log(` ${pc4.dim("Account:")} ${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`);
|
|
1833
|
+
console.log(` ${pc4.dim("User:")} ${whoami.user.name} ${pc4.dim(`(${whoami.user.email})`)}`);
|
|
1834
|
+
if (keyName) console.log(` ${pc4.dim("Key:")} ${keyName}`);
|
|
1835
|
+
console.log(` ${pc4.dim("Config:")} ${tildify(configPath)}`);
|
|
1375
1836
|
if (installed.length > 0) {
|
|
1376
|
-
console.log(` ${
|
|
1837
|
+
console.log(` ${pc4.dim("Skill:")} ${pc4.green("installed")} ${pc4.dim("\xB7 " + installed.join(", "))}`);
|
|
1377
1838
|
}
|
|
1378
1839
|
console.log();
|
|
1379
|
-
console.log(` ${
|
|
1840
|
+
console.log(` ${pc4.dim("Connect a platform later with")} ${pc4.cyan("one add <platform>")}`);
|
|
1380
1841
|
printOnboardingPrompt();
|
|
1381
1842
|
}
|
|
1382
1843
|
async function chooseConfigScope(options) {
|
|
@@ -1386,13 +1847,13 @@ async function chooseConfigScope(options) {
|
|
|
1386
1847
|
const hasGlobal = globalConfigExists();
|
|
1387
1848
|
const hasProject = projectConfigExists();
|
|
1388
1849
|
const projectRoot = resolved.projectRoot;
|
|
1389
|
-
const projectName =
|
|
1850
|
+
const projectName = path5.basename(projectRoot);
|
|
1390
1851
|
const homeGlobal = tildify(getGlobalConfigPath());
|
|
1391
1852
|
const homeProject = tildify(getProjectConfigPath(projectRoot));
|
|
1392
1853
|
if (hasProject) {
|
|
1393
1854
|
console.log();
|
|
1394
|
-
console.log(` ${
|
|
1395
|
-
console.log(` ${
|
|
1855
|
+
console.log(` ${pc4.dim("Project:")} ${projectName} ${pc4.dim(projectRoot)}`);
|
|
1856
|
+
console.log(` ${pc4.bold("Active config:")} ${pc4.cyan("project")} ${pc4.dim("\xB7 " + homeProject)}`);
|
|
1396
1857
|
console.log();
|
|
1397
1858
|
if (hasGlobal) {
|
|
1398
1859
|
const which2 = await p3.select({
|
|
@@ -1409,11 +1870,11 @@ async function chooseConfigScope(options) {
|
|
|
1409
1870
|
return "project";
|
|
1410
1871
|
}
|
|
1411
1872
|
console.log();
|
|
1412
|
-
console.log(` ${
|
|
1413
|
-
console.log(` ${
|
|
1414
|
-
console.log(` ${
|
|
1415
|
-
console.log(` ${
|
|
1416
|
-
console.log(` ${
|
|
1873
|
+
console.log(` ${pc4.bold("Initializing One")}`);
|
|
1874
|
+
console.log(` ${pc4.dim("\u2500".repeat(42))}`);
|
|
1875
|
+
console.log(` ${pc4.dim("Project:")} ${projectName} ${pc4.dim(projectRoot)}`);
|
|
1876
|
+
console.log(` ${pc4.dim("Global:")} ${hasGlobal ? pc4.green("\u2713 configured") : pc4.yellow("\u2014 not set up")} ${pc4.dim(homeGlobal)}`);
|
|
1877
|
+
console.log(` ${pc4.dim("Project:")} ${pc4.yellow("\u2014 not set up")} ${pc4.dim(homeProject)}`);
|
|
1417
1878
|
console.log();
|
|
1418
1879
|
const defaultScope = hasGlobal ? "project" : "global";
|
|
1419
1880
|
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.";
|
|
@@ -1442,7 +1903,7 @@ function tildify(filePath) {
|
|
|
1442
1903
|
return filePath.startsWith(home) ? "~" + filePath.slice(home.length) : filePath;
|
|
1443
1904
|
}
|
|
1444
1905
|
function scopeLabel(scope) {
|
|
1445
|
-
return scope === "project" ?
|
|
1906
|
+
return scope === "project" ? pc4.cyan("[project]") : pc4.magenta("[global]");
|
|
1446
1907
|
}
|
|
1447
1908
|
function scopedMessage(scope, message) {
|
|
1448
1909
|
return `${scopeLabel(scope)} ${message}`;
|
|
@@ -1453,20 +1914,20 @@ async function handleExistingConfig(apiKey, scope, options) {
|
|
|
1453
1914
|
const skillInstalled = isSkillInstalled2();
|
|
1454
1915
|
const activeConfigPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
|
|
1455
1916
|
console.log();
|
|
1456
|
-
console.log(` ${
|
|
1457
|
-
console.log(` ${
|
|
1458
|
-
console.log(` ${
|
|
1459
|
-
console.log(` ${
|
|
1460
|
-
console.log(` ${
|
|
1917
|
+
console.log(` ${pc4.bold("Current Setup")} ${scopeLabel(scope)}`);
|
|
1918
|
+
console.log(` ${pc4.dim("\u2500".repeat(42))}`);
|
|
1919
|
+
console.log(` ${pc4.dim("API Key:")} ${masked}`);
|
|
1920
|
+
console.log(` ${pc4.dim("Skill:")} ${skillInstalled ? pc4.green("installed") : pc4.yellow("not installed")}`);
|
|
1921
|
+
console.log(` ${pc4.dim("Config:")} ${tildify(activeConfigPath)}`);
|
|
1461
1922
|
const ac = getAccessControl();
|
|
1462
1923
|
if (Object.keys(ac).length > 0) {
|
|
1463
1924
|
console.log();
|
|
1464
|
-
console.log(` ${
|
|
1465
|
-
console.log(` ${
|
|
1466
|
-
if (ac.permissions) console.log(` ${
|
|
1467
|
-
if (ac.connectionKeys) console.log(` ${
|
|
1468
|
-
if (ac.actionIds) console.log(` ${
|
|
1469
|
-
if (ac.knowledgeAgent) console.log(` ${
|
|
1925
|
+
console.log(` ${pc4.bold("Access Control")}`);
|
|
1926
|
+
console.log(` ${pc4.dim("\u2500".repeat(42))}`);
|
|
1927
|
+
if (ac.permissions) console.log(` ${pc4.dim("Permissions:")} ${ac.permissions}`);
|
|
1928
|
+
if (ac.connectionKeys) console.log(` ${pc4.dim("Connections:")} ${ac.connectionKeys.join(", ")}`);
|
|
1929
|
+
if (ac.actionIds) console.log(` ${pc4.dim("Action IDs:")} ${ac.actionIds.join(", ")}`);
|
|
1930
|
+
if (ac.knowledgeAgent) console.log(` ${pc4.dim("Knowledge only:")} yes`);
|
|
1470
1931
|
}
|
|
1471
1932
|
console.log();
|
|
1472
1933
|
const actionOptions = [];
|
|
@@ -1565,18 +2026,20 @@ async function handleUpdateKey(statuses, scope) {
|
|
|
1565
2026
|
process.exit(0);
|
|
1566
2027
|
}
|
|
1567
2028
|
let newKey;
|
|
2029
|
+
let keyName;
|
|
1568
2030
|
let whoamiResult;
|
|
1569
2031
|
if (authMethod === "browser") {
|
|
1570
|
-
const result = await browserLogin();
|
|
2032
|
+
const result = await browserLogin({ scope });
|
|
1571
2033
|
if (!result) {
|
|
1572
2034
|
p3.cancel("Browser login did not complete.");
|
|
1573
2035
|
process.exit(1);
|
|
1574
2036
|
}
|
|
1575
2037
|
newKey = result.apiKey;
|
|
2038
|
+
keyName = result.keyName;
|
|
1576
2039
|
whoamiResult = result.whoami;
|
|
1577
2040
|
} else {
|
|
1578
2041
|
p3.note(`Get your API key at:
|
|
1579
|
-
${
|
|
2042
|
+
${pc4.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
1580
2043
|
const openBrowser = await p3.confirm({
|
|
1581
2044
|
message: scopedMessage(scope, "Open browser to get API key?"),
|
|
1582
2045
|
initialValue: true
|
|
@@ -1604,16 +2067,16 @@ ${pc3.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
1604
2067
|
process.exit(0);
|
|
1605
2068
|
}
|
|
1606
2069
|
newKey = inputKey;
|
|
1607
|
-
const
|
|
1608
|
-
|
|
2070
|
+
const spinner4 = p3.spinner();
|
|
2071
|
+
spinner4.start("Validating API key...");
|
|
1609
2072
|
const api = new OneApi(newKey, getApiBase());
|
|
1610
2073
|
const validated = await api.validateApiKey();
|
|
1611
2074
|
if (!validated) {
|
|
1612
|
-
|
|
2075
|
+
spinner4.stop("Invalid API key");
|
|
1613
2076
|
p3.cancel(`Invalid API key. Get a valid key at ${getApiKeyUrl()}`);
|
|
1614
2077
|
process.exit(1);
|
|
1615
2078
|
}
|
|
1616
|
-
|
|
2079
|
+
spinner4.stop("API key validated");
|
|
1617
2080
|
whoamiResult = validated;
|
|
1618
2081
|
}
|
|
1619
2082
|
const env = getEnvFromApiKey(newKey);
|
|
@@ -1621,10 +2084,13 @@ ${pc3.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
1621
2084
|
if (whoamiResult.organization) contextParts.push(whoamiResult.organization.name);
|
|
1622
2085
|
if (whoamiResult.project) contextParts.push(whoamiResult.project.name);
|
|
1623
2086
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1624
|
-
const envLabel = env === "test" ?
|
|
2087
|
+
const envLabel = env === "test" ? pc4.yellow("test") : pc4.green("live");
|
|
1625
2088
|
p3.note(
|
|
1626
|
-
|
|
1627
|
-
|
|
2089
|
+
[
|
|
2090
|
+
`${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`,
|
|
2091
|
+
`${whoamiResult.user.name} ${pc4.dim(`(${whoamiResult.user.email})`)}`,
|
|
2092
|
+
...keyName ? [`${pc4.dim("Key:")} ${keyName}`] : []
|
|
2093
|
+
].join("\n"),
|
|
1628
2094
|
"Account"
|
|
1629
2095
|
);
|
|
1630
2096
|
const ac = getAccessControl();
|
|
@@ -1639,19 +2105,7 @@ ${whoamiResult.user.name} ${pc3.dim(`(${whoamiResult.user.email})`)}`,
|
|
|
1639
2105
|
reinstalled.push(`${s.agent.name} (project)`);
|
|
1640
2106
|
}
|
|
1641
2107
|
}
|
|
1642
|
-
|
|
1643
|
-
writeConfig(
|
|
1644
|
-
{
|
|
1645
|
-
apiKey: newKey,
|
|
1646
|
-
installedAgents: current?.installedAgents ?? [],
|
|
1647
|
-
createdAt: current?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1648
|
-
accessControl: current?.accessControl,
|
|
1649
|
-
apiBase: current?.apiBase,
|
|
1650
|
-
cacheTtl: current?.cacheTtl,
|
|
1651
|
-
whoami: whoamiResult
|
|
1652
|
-
},
|
|
1653
|
-
scope
|
|
1654
|
-
);
|
|
2108
|
+
saveCredentials(newKey, scope, { keyName, whoami: whoamiResult });
|
|
1655
2109
|
if (reinstalled.length > 0) {
|
|
1656
2110
|
p3.log.success(`Updated MCP configs: ${reinstalled.join(", ")}`);
|
|
1657
2111
|
}
|
|
@@ -1671,30 +2125,30 @@ var SKILL_AGENTS = [
|
|
|
1671
2125
|
];
|
|
1672
2126
|
var CANONICAL_SKILL_DIR2 = ".agents/skills";
|
|
1673
2127
|
function getSkillSourceDir() {
|
|
1674
|
-
const __dirname2 =
|
|
1675
|
-
return
|
|
2128
|
+
const __dirname2 = path5.dirname(fileURLToPath3(import.meta.url));
|
|
2129
|
+
return path5.resolve(__dirname2, "..", "skills", "one");
|
|
1676
2130
|
}
|
|
1677
2131
|
function getCanonicalSkillPath2() {
|
|
1678
|
-
return
|
|
2132
|
+
return path5.join(homeDir(), CANONICAL_SKILL_DIR2, "one");
|
|
1679
2133
|
}
|
|
1680
2134
|
function getAgentSkillPath(agent) {
|
|
1681
|
-
return
|
|
2135
|
+
return path5.join(homeDir(), agent.skillDir, "one");
|
|
1682
2136
|
}
|
|
1683
2137
|
function isSkillInstalled2() {
|
|
1684
|
-
return
|
|
2138
|
+
return fs4.existsSync(path5.join(getCanonicalSkillPath2(), "SKILL.md"));
|
|
1685
2139
|
}
|
|
1686
2140
|
function isSkillInstalledForAgent(agent) {
|
|
1687
|
-
return
|
|
2141
|
+
return fs4.existsSync(path5.join(getAgentSkillPath(agent), "SKILL.md"));
|
|
1688
2142
|
}
|
|
1689
2143
|
function copyDirSync2(src, dest) {
|
|
1690
|
-
|
|
1691
|
-
for (const entry of
|
|
1692
|
-
const srcPath =
|
|
1693
|
-
const destPath =
|
|
2144
|
+
fs4.mkdirSync(dest, { recursive: true });
|
|
2145
|
+
for (const entry of fs4.readdirSync(src, { withFileTypes: true })) {
|
|
2146
|
+
const srcPath = path5.join(src, entry.name);
|
|
2147
|
+
const destPath = path5.join(dest, entry.name);
|
|
1694
2148
|
if (entry.isDirectory()) {
|
|
1695
2149
|
copyDirSync2(srcPath, destPath);
|
|
1696
2150
|
} else {
|
|
1697
|
-
|
|
2151
|
+
fs4.copyFileSync(srcPath, destPath);
|
|
1698
2152
|
}
|
|
1699
2153
|
}
|
|
1700
2154
|
}
|
|
@@ -1703,12 +2157,12 @@ function installSkillForAgents(agentIds) {
|
|
|
1703
2157
|
const canonical = getCanonicalSkillPath2();
|
|
1704
2158
|
const installed = [];
|
|
1705
2159
|
const failed = [];
|
|
1706
|
-
if (!
|
|
2160
|
+
if (!fs4.existsSync(path5.join(source, "SKILL.md"))) {
|
|
1707
2161
|
return { installed: [], failed: ["skill source not found"] };
|
|
1708
2162
|
}
|
|
1709
2163
|
try {
|
|
1710
|
-
if (
|
|
1711
|
-
|
|
2164
|
+
if (fs4.existsSync(canonical)) {
|
|
2165
|
+
fs4.rmSync(canonical, { recursive: true });
|
|
1712
2166
|
}
|
|
1713
2167
|
copyDirSync2(source, canonical);
|
|
1714
2168
|
writeInstalledSkillVersion(getCurrentVersion());
|
|
@@ -1725,15 +2179,15 @@ function installSkillForAgents(agentIds) {
|
|
|
1725
2179
|
continue;
|
|
1726
2180
|
}
|
|
1727
2181
|
try {
|
|
1728
|
-
const agentSkillsDir =
|
|
1729
|
-
|
|
2182
|
+
const agentSkillsDir = path5.dirname(agentPath);
|
|
2183
|
+
fs4.mkdirSync(agentSkillsDir, { recursive: true });
|
|
1730
2184
|
try {
|
|
1731
|
-
|
|
1732
|
-
|
|
2185
|
+
fs4.lstatSync(agentPath);
|
|
2186
|
+
fs4.rmSync(agentPath, { recursive: true });
|
|
1733
2187
|
} catch {
|
|
1734
2188
|
}
|
|
1735
|
-
const relative =
|
|
1736
|
-
|
|
2189
|
+
const relative = path5.relative(agentSkillsDir, canonical);
|
|
2190
|
+
fs4.symlinkSync(relative, agentPath);
|
|
1737
2191
|
installed.push(agent.name);
|
|
1738
2192
|
seen.set(agentPath, true);
|
|
1739
2193
|
} catch {
|
|
@@ -1748,7 +2202,7 @@ async function promptOpenAiKey(scope) {
|
|
|
1748
2202
|
const entered = await p3.password({
|
|
1749
2203
|
message: scopedMessage(
|
|
1750
2204
|
scope,
|
|
1751
|
-
`OpenAI API key ${
|
|
2205
|
+
`OpenAI API key ${pc4.dim("(optional \u2014 enables semantic search in `one mem`)")}`
|
|
1752
2206
|
),
|
|
1753
2207
|
mask: "\u2022",
|
|
1754
2208
|
// Validator accepts empty → treated as "skip".
|
|
@@ -1803,7 +2257,7 @@ async function promptSkillInstall() {
|
|
|
1803
2257
|
...primaryAgents.map((a) => ({
|
|
1804
2258
|
value: a.id,
|
|
1805
2259
|
label: a.name,
|
|
1806
|
-
hint: isSkillInstalledForAgent(a) ?
|
|
2260
|
+
hint: isSkillInstalledForAgent(a) ? pc4.green("installed") : void 0
|
|
1807
2261
|
})),
|
|
1808
2262
|
{
|
|
1809
2263
|
value: "_other",
|
|
@@ -1827,7 +2281,7 @@ async function promptSkillInstall() {
|
|
|
1827
2281
|
options: otherAgents.map((a) => ({
|
|
1828
2282
|
value: a.id,
|
|
1829
2283
|
label: a.name,
|
|
1830
|
-
hint: isSkillInstalledForAgent(a) ?
|
|
2284
|
+
hint: isSkillInstalledForAgent(a) ? pc4.green("installed") : void 0
|
|
1831
2285
|
}))
|
|
1832
2286
|
});
|
|
1833
2287
|
if (!p3.isCancel(otherChoice)) {
|
|
@@ -1838,12 +2292,12 @@ async function promptSkillInstall() {
|
|
|
1838
2292
|
p3.log.info("No agents selected.");
|
|
1839
2293
|
return false;
|
|
1840
2294
|
}
|
|
1841
|
-
const
|
|
1842
|
-
|
|
2295
|
+
const spinner4 = p3.spinner();
|
|
2296
|
+
spinner4.start("Installing skill...");
|
|
1843
2297
|
const { installed, failed } = installSkillForAgents(selectedIds);
|
|
1844
|
-
|
|
2298
|
+
spinner4.stop(installed.length > 0 ? "Skill installed" : "Installation failed");
|
|
1845
2299
|
for (const name of installed) {
|
|
1846
|
-
p3.log.success(`${name}: ${
|
|
2300
|
+
p3.log.success(`${name}: ${pc4.green("\u2713")} skill installed`);
|
|
1847
2301
|
}
|
|
1848
2302
|
for (const name of failed) {
|
|
1849
2303
|
p3.log.warn(`${name}: failed to install`);
|
|
@@ -1852,19 +2306,19 @@ async function promptSkillInstall() {
|
|
|
1852
2306
|
}
|
|
1853
2307
|
function printOnboardingPrompt() {
|
|
1854
2308
|
console.log();
|
|
1855
|
-
console.log(
|
|
2309
|
+
console.log(pc4.bold(" Copy-paste this to your AI agent:"));
|
|
1856
2310
|
console.log();
|
|
1857
|
-
console.log(
|
|
1858
|
-
console.log(
|
|
1859
|
-
console.log(
|
|
1860
|
-
console.log(
|
|
1861
|
-
console.log(
|
|
1862
|
-
console.log(
|
|
1863
|
-
console.log(
|
|
1864
|
-
console.log(
|
|
1865
|
-
console.log(
|
|
1866
|
-
console.log(
|
|
1867
|
-
console.log(
|
|
2311
|
+
console.log(pc4.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"));
|
|
2312
|
+
console.log(pc4.cyan(" \u2502"));
|
|
2313
|
+
console.log(pc4.cyan(" \u2502 The One CLI (`one`) is now installed on this machine. It"));
|
|
2314
|
+
console.log(pc4.cyan(" \u2502 lets you interact with 600+ third-party platforms (Gmail,"));
|
|
2315
|
+
console.log(pc4.cyan(" \u2502 Slack, Shopify, HubSpot, Stripe, GitHub, etc.) through"));
|
|
2316
|
+
console.log(pc4.cyan(" \u2502 their APIs. Whenever you need to interact with any"));
|
|
2317
|
+
console.log(pc4.cyan(" \u2502 third-party platform or external service, use the `one`"));
|
|
2318
|
+
console.log(pc4.cyan(" \u2502 skill. Please save this to your project instructions or"));
|
|
2319
|
+
console.log(pc4.cyan(" \u2502 memory so you remember it in future conversations."));
|
|
2320
|
+
console.log(pc4.cyan(" \u2502"));
|
|
2321
|
+
console.log(pc4.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"));
|
|
1868
2322
|
console.log();
|
|
1869
2323
|
}
|
|
1870
2324
|
async function freshSetup(scope, options) {
|
|
@@ -1881,7 +2335,7 @@ async function freshSetup(scope, options) {
|
|
|
1881
2335
|
}
|
|
1882
2336
|
let apiKey;
|
|
1883
2337
|
if (authMethod === "browser") {
|
|
1884
|
-
const result = await browserLogin();
|
|
2338
|
+
const result = await browserLogin({ scope });
|
|
1885
2339
|
if (!result) {
|
|
1886
2340
|
p3.cancel("Browser login did not complete. Try: one init");
|
|
1887
2341
|
process.exit(1);
|
|
@@ -1892,24 +2346,19 @@ async function freshSetup(scope, options) {
|
|
|
1892
2346
|
if (result.whoami.organization) contextParts.push(result.whoami.organization.name);
|
|
1893
2347
|
if (result.whoami.project) contextParts.push(result.whoami.project.name);
|
|
1894
2348
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1895
|
-
const envLabel = env2 === "test" ?
|
|
2349
|
+
const envLabel = env2 === "test" ? pc4.yellow("test") : pc4.green("live");
|
|
1896
2350
|
p3.note(
|
|
1897
|
-
|
|
1898
|
-
|
|
2351
|
+
[
|
|
2352
|
+
`${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}`,
|
|
2353
|
+
`${result.whoami.user.name} ${pc4.dim(`(${result.whoami.user.email})`)}`,
|
|
2354
|
+
...result.keyName ? [`${pc4.dim("Key:")} ${result.keyName}`] : []
|
|
2355
|
+
].join("\n"),
|
|
1899
2356
|
"Account"
|
|
1900
2357
|
);
|
|
1901
|
-
|
|
1902
|
-
{
|
|
1903
|
-
apiKey,
|
|
1904
|
-
installedAgents: [],
|
|
1905
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1906
|
-
whoami: result.whoami
|
|
1907
|
-
},
|
|
1908
|
-
scope
|
|
1909
|
-
);
|
|
2358
|
+
saveCredentials(apiKey, scope, { keyName: result.keyName, whoami: result.whoami });
|
|
1910
2359
|
} else {
|
|
1911
2360
|
p3.note(`Get your API key at:
|
|
1912
|
-
${
|
|
2361
|
+
${pc4.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
1913
2362
|
const openBrowser = await p3.confirm({
|
|
1914
2363
|
message: scopedMessage(scope, "Open browser to get API key?"),
|
|
1915
2364
|
initialValue: true
|
|
@@ -1937,36 +2386,28 @@ ${pc3.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
|
|
|
1937
2386
|
process.exit(0);
|
|
1938
2387
|
}
|
|
1939
2388
|
apiKey = inputKey;
|
|
1940
|
-
const
|
|
1941
|
-
|
|
2389
|
+
const spinner4 = p3.spinner();
|
|
2390
|
+
spinner4.start("Validating API key...");
|
|
1942
2391
|
const api = new OneApi(apiKey, getApiBase());
|
|
1943
2392
|
const whoami = await api.validateApiKey();
|
|
1944
2393
|
if (!whoami) {
|
|
1945
|
-
|
|
2394
|
+
spinner4.stop("Invalid API key");
|
|
1946
2395
|
p3.cancel(`Invalid API key. Get a valid key at ${getApiKeyUrl()}`);
|
|
1947
2396
|
process.exit(1);
|
|
1948
2397
|
}
|
|
1949
|
-
|
|
2398
|
+
spinner4.stop("API key validated");
|
|
1950
2399
|
const env2 = getEnvFromApiKey(apiKey);
|
|
1951
2400
|
const contextParts = [];
|
|
1952
2401
|
if (whoami.organization) contextParts.push(whoami.organization.name);
|
|
1953
2402
|
if (whoami.project) contextParts.push(whoami.project.name);
|
|
1954
2403
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
1955
|
-
const envLabel = env2 === "test" ?
|
|
2404
|
+
const envLabel = env2 === "test" ? pc4.yellow("test") : pc4.green("live");
|
|
1956
2405
|
p3.note(
|
|
1957
|
-
`${scopeDisplay} ${
|
|
1958
|
-
${whoami.user.name} ${
|
|
2406
|
+
`${scopeDisplay} ${pc4.dim("\xB7")} ${envLabel}
|
|
2407
|
+
${whoami.user.name} ${pc4.dim(`(${whoami.user.email})`)}`,
|
|
1959
2408
|
"Account"
|
|
1960
2409
|
);
|
|
1961
|
-
|
|
1962
|
-
{
|
|
1963
|
-
apiKey,
|
|
1964
|
-
installedAgents: [],
|
|
1965
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1966
|
-
whoami
|
|
1967
|
-
},
|
|
1968
|
-
scope
|
|
1969
|
-
);
|
|
2410
|
+
saveCredentials(apiKey, scope, { whoami });
|
|
1970
2411
|
}
|
|
1971
2412
|
await promptOpenAiKey(scope);
|
|
1972
2413
|
await promptSkillInstall();
|
|
@@ -1979,11 +2420,11 @@ ${whoami.user.name} ${pc3.dim(`(${whoami.user.email})`)}`,
|
|
|
1979
2420
|
};
|
|
1980
2421
|
await promptConnectIntegrations(apiKey, connParams);
|
|
1981
2422
|
const savedPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
|
|
1982
|
-
const resolutionHint = scope === "project" ? `When you run ${
|
|
2423
|
+
const resolutionHint = scope === "project" ? `When you run ${pc4.cyan("one")} from ${pc4.bold(path5.basename(getProjectRoot()))}, it uses this project config.
|
|
1983
2424
|
From anywhere else, it falls back to your global config.` : `This config applies to every folder unless a project config is set.`;
|
|
1984
2425
|
p3.note(
|
|
1985
2426
|
`${scopeLabel(scope)} Config saved to:
|
|
1986
|
-
${
|
|
2427
|
+
${pc4.dim(tildify(savedPath))}
|
|
1987
2428
|
|
|
1988
2429
|
${resolutionHint}`,
|
|
1989
2430
|
"Setup Complete"
|
|
@@ -1993,18 +2434,18 @@ ${resolutionHint}`,
|
|
|
1993
2434
|
}
|
|
1994
2435
|
function printBanner() {
|
|
1995
2436
|
console.log();
|
|
1996
|
-
console.log(
|
|
1997
|
-
console.log(
|
|
1998
|
-
console.log(
|
|
1999
|
-
console.log(
|
|
2000
|
-
console.log(
|
|
2001
|
-
console.log(
|
|
2002
|
-
console.log(
|
|
2003
|
-
console.log(
|
|
2004
|
-
console.log(
|
|
2005
|
-
console.log(
|
|
2437
|
+
console.log(pc4.yellow(" \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"));
|
|
2438
|
+
console.log(pc4.yellow(" \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\u2588"));
|
|
2439
|
+
console.log(pc4.yellow(" \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 "));
|
|
2440
|
+
console.log(pc4.yellow(" \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 "));
|
|
2441
|
+
console.log(pc4.yellow(" \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 "));
|
|
2442
|
+
console.log(pc4.yellow(" \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 "));
|
|
2443
|
+
console.log(pc4.yellow(" \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 "));
|
|
2444
|
+
console.log(pc4.yellow(" \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 "));
|
|
2445
|
+
console.log(pc4.yellow(" \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"));
|
|
2446
|
+
console.log(pc4.yellow(" \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"));
|
|
2006
2447
|
console.log();
|
|
2007
|
-
console.log(
|
|
2448
|
+
console.log(pc4.dim(" I N F R A S T R U C T U R E F O R A G E N T S"));
|
|
2008
2449
|
console.log();
|
|
2009
2450
|
}
|
|
2010
2451
|
var TOP_INTEGRATIONS = [
|
|
@@ -2043,19 +2484,20 @@ async function promptConnectIntegrations(apiKey, connParams) {
|
|
|
2043
2484
|
break;
|
|
2044
2485
|
}
|
|
2045
2486
|
if (choice === "more") {
|
|
2487
|
+
const connectionsUrl = `${oneAppUrl()}/connections`;
|
|
2046
2488
|
try {
|
|
2047
|
-
await
|
|
2489
|
+
await open3(connectionsUrl);
|
|
2048
2490
|
p3.log.info("Opened One dashboard in browser.");
|
|
2049
2491
|
} catch {
|
|
2050
|
-
p3.note(
|
|
2492
|
+
p3.note(connectionsUrl, "Open in browser");
|
|
2051
2493
|
}
|
|
2052
|
-
p3.log.info(`Connect from the dashboard, or use ${
|
|
2494
|
+
p3.log.info(`Connect from the dashboard, or use ${pc4.cyan("one add <platform>")}`);
|
|
2053
2495
|
break;
|
|
2054
2496
|
}
|
|
2055
2497
|
const platform = choice;
|
|
2056
2498
|
const integration = TOP_INTEGRATIONS.find((i) => i.value === platform);
|
|
2057
2499
|
const label = integration?.label ?? platform;
|
|
2058
|
-
p3.log.info(`Opening browser to connect ${
|
|
2500
|
+
p3.log.info(`Opening browser to connect ${pc4.cyan(label)}...`);
|
|
2059
2501
|
try {
|
|
2060
2502
|
await openConnectionPage(platform, connParams);
|
|
2061
2503
|
} catch {
|
|
@@ -2063,18 +2505,18 @@ async function promptConnectIntegrations(apiKey, connParams) {
|
|
|
2063
2505
|
p3.log.warn("Could not open browser automatically.");
|
|
2064
2506
|
p3.note(url, "Open manually");
|
|
2065
2507
|
}
|
|
2066
|
-
const
|
|
2067
|
-
|
|
2508
|
+
const spinner4 = p3.spinner();
|
|
2509
|
+
spinner4.start("Waiting for connection... (complete auth in browser)");
|
|
2068
2510
|
try {
|
|
2069
2511
|
await api.waitForConnection(platform, 5 * 60 * 1e3, 5e3);
|
|
2070
|
-
|
|
2071
|
-
p3.log.success(`${
|
|
2512
|
+
spinner4.stop(`${label} connected!`);
|
|
2513
|
+
p3.log.success(`${pc4.green("\u2713")} ${label} is now available to your AI agents`);
|
|
2072
2514
|
connected.push(platform);
|
|
2073
2515
|
first = false;
|
|
2074
2516
|
} catch (error2) {
|
|
2075
|
-
|
|
2517
|
+
spinner4.stop("Connection timed out");
|
|
2076
2518
|
if (error2 instanceof TimeoutError) {
|
|
2077
|
-
p3.log.warn(`No worries. Connect later with: ${
|
|
2519
|
+
p3.log.warn(`No worries. Connect later with: ${pc4.cyan(`one add ${platform}`)}`);
|
|
2078
2520
|
}
|
|
2079
2521
|
first = false;
|
|
2080
2522
|
}
|
|
@@ -2091,7 +2533,7 @@ function maskApiKey(key) {
|
|
|
2091
2533
|
|
|
2092
2534
|
// src/commands/connection.ts
|
|
2093
2535
|
import * as p4 from "@clack/prompts";
|
|
2094
|
-
import
|
|
2536
|
+
import pc6 from "picocolors";
|
|
2095
2537
|
|
|
2096
2538
|
// src/lib/access.ts
|
|
2097
2539
|
async function resolveAllowedActions(api, actionIds) {
|
|
@@ -2177,7 +2619,7 @@ function countMatchingChars(a, b) {
|
|
|
2177
2619
|
}
|
|
2178
2620
|
|
|
2179
2621
|
// src/lib/table.ts
|
|
2180
|
-
import
|
|
2622
|
+
import pc5 from "picocolors";
|
|
2181
2623
|
function printTable(columns, rows) {
|
|
2182
2624
|
if (rows.length === 0) return;
|
|
2183
2625
|
const gap = " ";
|
|
@@ -2189,10 +2631,10 @@ function printTable(columns, rows) {
|
|
|
2189
2631
|
});
|
|
2190
2632
|
const header = columns.map((col, i) => {
|
|
2191
2633
|
const padded = col.align === "right" ? col.label.padStart(widths[i]) : col.label.padEnd(widths[i]);
|
|
2192
|
-
return
|
|
2634
|
+
return pc5.dim(padded);
|
|
2193
2635
|
}).join(gap);
|
|
2194
2636
|
console.log(`${indent}${header}`);
|
|
2195
|
-
const separator = columns.map((_, i) =>
|
|
2637
|
+
const separator = columns.map((_, i) => pc5.dim("\u2500".repeat(widths[i]))).join(gap);
|
|
2196
2638
|
console.log(`${indent}${separator}`);
|
|
2197
2639
|
for (const row of rows) {
|
|
2198
2640
|
const line = columns.map((col, i) => {
|
|
@@ -2217,21 +2659,21 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2217
2659
|
if (isAgentMode()) {
|
|
2218
2660
|
error("This command requires interactive input. Run without --agent.");
|
|
2219
2661
|
}
|
|
2220
|
-
p4.intro(
|
|
2662
|
+
p4.intro(pc6.bgCyan(pc6.black(" One ")));
|
|
2221
2663
|
const apiKey = getApiKey();
|
|
2222
2664
|
if (!apiKey) {
|
|
2223
2665
|
p4.cancel("Not configured. Run `one init` first.");
|
|
2224
2666
|
process.exit(1);
|
|
2225
2667
|
}
|
|
2226
2668
|
const api = new OneApi(apiKey, getApiBase());
|
|
2227
|
-
const
|
|
2228
|
-
|
|
2669
|
+
const spinner4 = p4.spinner();
|
|
2670
|
+
spinner4.start("Loading platforms...");
|
|
2229
2671
|
let platforms;
|
|
2230
2672
|
try {
|
|
2231
2673
|
platforms = await api.listPlatforms();
|
|
2232
|
-
|
|
2674
|
+
spinner4.stop(`${platforms.length} platforms available`);
|
|
2233
2675
|
} catch (error2) {
|
|
2234
|
-
|
|
2676
|
+
spinner4.stop("Failed to load platforms");
|
|
2235
2677
|
p4.cancel(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2236
2678
|
process.exit(1);
|
|
2237
2679
|
}
|
|
@@ -2252,7 +2694,7 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2252
2694
|
]
|
|
2253
2695
|
});
|
|
2254
2696
|
if (p4.isCancel(suggestion) || suggestion === "__other__") {
|
|
2255
|
-
p4.note(`Run ${
|
|
2697
|
+
p4.note(`Run ${pc6.cyan("one platforms")} to see all available platforms.`);
|
|
2256
2698
|
p4.cancel("Connection cancelled.");
|
|
2257
2699
|
process.exit(0);
|
|
2258
2700
|
}
|
|
@@ -2260,7 +2702,7 @@ async function connectionAddCommand(platformArg, options) {
|
|
|
2260
2702
|
} else {
|
|
2261
2703
|
p4.cancel(`Unknown platform: ${platformArg}
|
|
2262
2704
|
|
|
2263
|
-
Run ${
|
|
2705
|
+
Run ${pc6.cyan("one platforms")} to see available platforms.`);
|
|
2264
2706
|
process.exit(1);
|
|
2265
2707
|
}
|
|
2266
2708
|
}
|
|
@@ -2283,7 +2725,7 @@ Run ${pc5.cyan("one platforms")} to see available platforms.`);
|
|
|
2283
2725
|
} else {
|
|
2284
2726
|
p4.cancel(`Unknown platform: ${platformInput}
|
|
2285
2727
|
|
|
2286
|
-
Run ${
|
|
2728
|
+
Run ${pc6.cyan("one platforms")} to see available platforms.`);
|
|
2287
2729
|
process.exit(1);
|
|
2288
2730
|
}
|
|
2289
2731
|
}
|
|
@@ -2294,8 +2736,8 @@ Run ${pc5.cyan("one platforms")} to see available platforms.`);
|
|
|
2294
2736
|
...whoami?.project && { projectId: whoami.project.id }
|
|
2295
2737
|
};
|
|
2296
2738
|
const url = getConnectionUrl(platform, connParams);
|
|
2297
|
-
p4.log.info(`Opening browser to connect ${
|
|
2298
|
-
p4.note(
|
|
2739
|
+
p4.log.info(`Opening browser to connect ${pc6.cyan(platform)}...`);
|
|
2740
|
+
p4.note(pc6.dim(url), "URL");
|
|
2299
2741
|
try {
|
|
2300
2742
|
await openConnectionPage(platform, connParams);
|
|
2301
2743
|
} catch {
|
|
@@ -2323,7 +2765,7 @@ The connection is usable; set the tag later in the dashboard or retry.`
|
|
|
2323
2765
|
);
|
|
2324
2766
|
}
|
|
2325
2767
|
}
|
|
2326
|
-
p4.log.success(`${
|
|
2768
|
+
p4.log.success(`${pc6.green("\u2713")} ${connection2.platform} is now available to your AI agents.${tag ? ` (tag: ${tag})` : ""}`);
|
|
2327
2769
|
p4.outro("Connection complete!");
|
|
2328
2770
|
} catch (error2) {
|
|
2329
2771
|
pollSpinner.stop("Connection timed out");
|
|
@@ -2334,7 +2776,7 @@ The connection is usable; set the tag later in the dashboard or retry.`
|
|
|
2334
2776
|
- Browser popup was blocked
|
|
2335
2777
|
- Wrong account selected
|
|
2336
2778
|
|
|
2337
|
-
Try again with: ${
|
|
2779
|
+
Try again with: ${pc6.cyan(`one connection add ${platform}`)}`,
|
|
2338
2780
|
"Timed Out"
|
|
2339
2781
|
);
|
|
2340
2782
|
} else {
|
|
@@ -2349,8 +2791,8 @@ async function connectionListCommand(options) {
|
|
|
2349
2791
|
error("Not configured. Run `one init` first.");
|
|
2350
2792
|
}
|
|
2351
2793
|
const api = new OneApi(apiKey, getApiBase());
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2794
|
+
const spinner4 = createSpinner();
|
|
2795
|
+
spinner4.start("Loading connections...");
|
|
2354
2796
|
try {
|
|
2355
2797
|
const allConnections = await api.listConnections();
|
|
2356
2798
|
const ac = getAccessControlFromAllSources();
|
|
@@ -2392,20 +2834,20 @@ async function connectionListCommand(options) {
|
|
|
2392
2834
|
return;
|
|
2393
2835
|
}
|
|
2394
2836
|
const displayed = limitArg !== void 0 ? filtered.slice(0, limitArg) : filtered;
|
|
2395
|
-
|
|
2837
|
+
spinner4.stop(`${filtered.length} connection${filtered.length === 1 ? "" : "s"} found`);
|
|
2396
2838
|
if (filtered.length === 0) {
|
|
2397
2839
|
if (searchQuery) {
|
|
2398
2840
|
p4.note(
|
|
2399
2841
|
`No connections matching "${searchQuery}".
|
|
2400
2842
|
|
|
2401
|
-
Try: ${
|
|
2843
|
+
Try: ${pc6.cyan("one connection list")} to see all connections.`,
|
|
2402
2844
|
"No Results"
|
|
2403
2845
|
);
|
|
2404
2846
|
} else {
|
|
2405
2847
|
p4.note(
|
|
2406
2848
|
`No connections yet.
|
|
2407
2849
|
|
|
2408
|
-
Add one with: ${
|
|
2850
|
+
Add one with: ${pc6.cyan("one connection add gmail")}`,
|
|
2409
2851
|
"No Connections"
|
|
2410
2852
|
);
|
|
2411
2853
|
}
|
|
@@ -2427,9 +2869,9 @@ Add one with: ${pc5.cyan("one connection add gmail")}`,
|
|
|
2427
2869
|
{ key: "status", label: "" },
|
|
2428
2870
|
{ key: "platform", label: "Platform" },
|
|
2429
2871
|
{ key: "state", label: "Status" },
|
|
2430
|
-
{ key: "key", label: "Connection Key", color:
|
|
2431
|
-
...hasTags ? [{ key: "tags", label: "Tags", color:
|
|
2432
|
-
...hasScopedAccess ? [{ key: "access", label: "Access", color:
|
|
2872
|
+
{ key: "key", label: "Connection Key", color: pc6.dim },
|
|
2873
|
+
...hasTags ? [{ key: "tags", label: "Tags", color: pc6.dim }] : [],
|
|
2874
|
+
...hasScopedAccess ? [{ key: "access", label: "Access", color: pc6.yellow }] : []
|
|
2433
2875
|
],
|
|
2434
2876
|
rows
|
|
2435
2877
|
);
|
|
@@ -2443,7 +2885,7 @@ Add one with: ${pc5.cyan("one connection add gmail")}`,
|
|
|
2443
2885
|
}
|
|
2444
2886
|
p4.note(`${wrapText(lines.join("\n"))}
|
|
2445
2887
|
|
|
2446
|
-
Change it with: ${
|
|
2888
|
+
Change it with: ${pc6.cyan("one config")}`, "Access");
|
|
2447
2889
|
}
|
|
2448
2890
|
if (displayed.length < filtered.length) {
|
|
2449
2891
|
p4.note(
|
|
@@ -2451,10 +2893,10 @@ Change it with: ${pc5.cyan("one config")}`, "Access");
|
|
|
2451
2893
|
"Limited"
|
|
2452
2894
|
);
|
|
2453
2895
|
} else {
|
|
2454
|
-
p4.note(`Add more with: ${
|
|
2896
|
+
p4.note(`Add more with: ${pc6.cyan("one connection add <platform>")}`, "Tip");
|
|
2455
2897
|
}
|
|
2456
2898
|
} catch (error2) {
|
|
2457
|
-
|
|
2899
|
+
spinner4.stop("Failed to load connections");
|
|
2458
2900
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2459
2901
|
}
|
|
2460
2902
|
}
|
|
@@ -2464,13 +2906,13 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
2464
2906
|
error("Not configured. Run `one init` first.");
|
|
2465
2907
|
}
|
|
2466
2908
|
const api = new OneApi(apiKey, getApiBase());
|
|
2467
|
-
const
|
|
2468
|
-
|
|
2909
|
+
const spinner4 = createSpinner();
|
|
2910
|
+
spinner4.start("Finding connection...");
|
|
2469
2911
|
let allConnections;
|
|
2470
2912
|
try {
|
|
2471
2913
|
allConnections = await api.listConnections();
|
|
2472
2914
|
} catch (error2) {
|
|
2473
|
-
|
|
2915
|
+
spinner4.stop("Failed to load connections");
|
|
2474
2916
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2475
2917
|
return;
|
|
2476
2918
|
}
|
|
@@ -2479,15 +2921,15 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
2479
2921
|
const connections = allowedKeys.includes("*") ? allConnections : allConnections.filter((conn) => allowedKeys.includes(conn.key));
|
|
2480
2922
|
const match = connections.find((conn) => conn.key === connectionKey);
|
|
2481
2923
|
if (!match) {
|
|
2482
|
-
|
|
2924
|
+
spinner4.stop("Connection not found");
|
|
2483
2925
|
error(`No connection found with key: ${connectionKey}`);
|
|
2484
2926
|
return;
|
|
2485
2927
|
}
|
|
2486
2928
|
const connection2 = match;
|
|
2487
|
-
|
|
2929
|
+
spinner4.stop(`Found ${connection2.platform} (${connection2.state})`);
|
|
2488
2930
|
if (!isAgentMode() && !options?.force) {
|
|
2489
2931
|
console.log();
|
|
2490
|
-
console.log(` ${getStatusIndicator(connection2.state)} ${connection2.platform} ${
|
|
2932
|
+
console.log(` ${getStatusIndicator(connection2.state)} ${connection2.platform} ${pc6.dim(connection2.key)}`);
|
|
2491
2933
|
console.log();
|
|
2492
2934
|
const confirmed = await p4.confirm({
|
|
2493
2935
|
message: "Are you sure you want to delete this connection?",
|
|
@@ -2511,7 +2953,7 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
2511
2953
|
});
|
|
2512
2954
|
return;
|
|
2513
2955
|
}
|
|
2514
|
-
p4.log.success(`${
|
|
2956
|
+
p4.log.success(`${pc6.green("\u2713")} ${connection2.platform} connection removed.`);
|
|
2515
2957
|
} catch (error2) {
|
|
2516
2958
|
deleteSpinner.stop("Failed to delete connection");
|
|
2517
2959
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
@@ -2551,19 +2993,19 @@ function wrapText(text5, width = 72) {
|
|
|
2551
2993
|
function getStatusIndicator(state) {
|
|
2552
2994
|
switch (state) {
|
|
2553
2995
|
case "operational":
|
|
2554
|
-
return
|
|
2996
|
+
return pc6.green("\u25CF");
|
|
2555
2997
|
case "degraded":
|
|
2556
|
-
return
|
|
2998
|
+
return pc6.yellow("\u25CF");
|
|
2557
2999
|
case "failed":
|
|
2558
|
-
return
|
|
3000
|
+
return pc6.red("\u25CF");
|
|
2559
3001
|
default:
|
|
2560
|
-
return
|
|
3002
|
+
return pc6.dim("\u25CB");
|
|
2561
3003
|
}
|
|
2562
3004
|
}
|
|
2563
3005
|
|
|
2564
3006
|
// src/commands/platforms.ts
|
|
2565
3007
|
import * as p5 from "@clack/prompts";
|
|
2566
|
-
import
|
|
3008
|
+
import pc7 from "picocolors";
|
|
2567
3009
|
async function platformsCommand(options) {
|
|
2568
3010
|
const apiKey = getApiKey();
|
|
2569
3011
|
if (!apiKey) {
|
|
@@ -2573,11 +3015,11 @@ async function platformsCommand(options) {
|
|
|
2573
3015
|
options.json = true;
|
|
2574
3016
|
}
|
|
2575
3017
|
const api = new OneApi(apiKey, getApiBase());
|
|
2576
|
-
const
|
|
2577
|
-
|
|
3018
|
+
const spinner4 = createSpinner();
|
|
3019
|
+
spinner4.start("Loading platforms...");
|
|
2578
3020
|
try {
|
|
2579
3021
|
const platforms = await api.listPlatforms();
|
|
2580
|
-
|
|
3022
|
+
spinner4.stop(`${platforms.length} platforms available`);
|
|
2581
3023
|
let filtered = platforms;
|
|
2582
3024
|
if (options.category) {
|
|
2583
3025
|
filtered = platforms.filter((plat) => (plat.category || "Other") === options.category);
|
|
@@ -2629,16 +3071,16 @@ async function platformsCommand(options) {
|
|
|
2629
3071
|
);
|
|
2630
3072
|
}
|
|
2631
3073
|
console.log();
|
|
2632
|
-
p5.note(`Connect with: ${
|
|
3074
|
+
p5.note(`Connect with: ${pc7.cyan("one connection add <platform>")}`, "Tip");
|
|
2633
3075
|
} catch (error2) {
|
|
2634
|
-
|
|
3076
|
+
spinner4.stop("Failed to load platforms");
|
|
2635
3077
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2636
3078
|
}
|
|
2637
3079
|
}
|
|
2638
3080
|
|
|
2639
3081
|
// src/commands/actions.ts
|
|
2640
3082
|
import * as p6 from "@clack/prompts";
|
|
2641
|
-
import
|
|
3083
|
+
import pc8 from "picocolors";
|
|
2642
3084
|
function getConfig() {
|
|
2643
3085
|
const apiKey = getApiKey();
|
|
2644
3086
|
if (!apiKey) {
|
|
@@ -2659,11 +3101,11 @@ function parseJsonArg2(value, argName) {
|
|
|
2659
3101
|
}
|
|
2660
3102
|
}
|
|
2661
3103
|
async function actionsSearchCommand(platform, query, options) {
|
|
2662
|
-
intro(
|
|
3104
|
+
intro(pc8.bgCyan(pc8.black(" One ")));
|
|
2663
3105
|
const { apiKey, permissions, actionIds, knowledgeAgent } = getConfig();
|
|
2664
3106
|
const api = new OneApi(apiKey, getApiBase());
|
|
2665
|
-
const
|
|
2666
|
-
|
|
3107
|
+
const spinner4 = createSpinner();
|
|
3108
|
+
spinner4.start(`Searching actions on ${pc8.cyan(platform)} for "${query}"...`);
|
|
2667
3109
|
try {
|
|
2668
3110
|
const agentType = knowledgeAgent ? "knowledge" : options.type || "execute";
|
|
2669
3111
|
const useCache = options.cache !== false;
|
|
@@ -2729,14 +3171,14 @@ async function actionsSearchCommand(platform, query, options) {
|
|
|
2729
3171
|
return;
|
|
2730
3172
|
}
|
|
2731
3173
|
if (cleanedActions.length === 0) {
|
|
2732
|
-
|
|
3174
|
+
spinner4.stop("No actions found");
|
|
2733
3175
|
p6.note(
|
|
2734
3176
|
`No actions found for platform '${platform}' matching query '${query}'.
|
|
2735
3177
|
|
|
2736
3178
|
Suggestions:
|
|
2737
3179
|
- Try a more general query (e.g., 'list', 'get', 'search', 'create')
|
|
2738
3180
|
- Verify the platform name is correct
|
|
2739
|
-
- Check available platforms with ${
|
|
3181
|
+
- Check available platforms with ${pc8.cyan("one platforms")}
|
|
2740
3182
|
|
|
2741
3183
|
Examples of good queries:
|
|
2742
3184
|
- "search contacts"
|
|
@@ -2747,7 +3189,7 @@ Examples of good queries:
|
|
|
2747
3189
|
);
|
|
2748
3190
|
return;
|
|
2749
3191
|
}
|
|
2750
|
-
|
|
3192
|
+
spinner4.stop(
|
|
2751
3193
|
`Found ${cleanedActions.length} action(s) for '${platform}' matching '${query}'`
|
|
2752
3194
|
);
|
|
2753
3195
|
console.log();
|
|
@@ -2761,19 +3203,19 @@ Examples of good queries:
|
|
|
2761
3203
|
[
|
|
2762
3204
|
{ key: "method", label: "Method" },
|
|
2763
3205
|
{ key: "title", label: "Title" },
|
|
2764
|
-
{ key: "actionId", label: "Action ID", color:
|
|
2765
|
-
{ key: "path", label: "Path", color:
|
|
3206
|
+
{ key: "actionId", label: "Action ID", color: pc8.dim },
|
|
3207
|
+
{ key: "path", label: "Path", color: pc8.dim }
|
|
2766
3208
|
],
|
|
2767
3209
|
rows
|
|
2768
3210
|
);
|
|
2769
3211
|
console.log();
|
|
2770
3212
|
p6.note(
|
|
2771
|
-
`Get details: ${
|
|
2772
|
-
Execute: ${
|
|
3213
|
+
`Get details: ${pc8.cyan(`one actions knowledge ${platform} <actionId>`)}
|
|
3214
|
+
Execute: ${pc8.cyan(`one actions execute ${platform} <actionId> <connectionKey>`)}`,
|
|
2773
3215
|
"Next Steps"
|
|
2774
3216
|
);
|
|
2775
3217
|
} catch (error2) {
|
|
2776
|
-
|
|
3218
|
+
spinner4.stop("Search failed");
|
|
2777
3219
|
error(
|
|
2778
3220
|
`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
2779
3221
|
);
|
|
@@ -2802,32 +3244,32 @@ async function actionsKnowledgeCommand(platform, actionId, options) {
|
|
|
2802
3244
|
}
|
|
2803
3245
|
return;
|
|
2804
3246
|
}
|
|
2805
|
-
intro(
|
|
3247
|
+
intro(pc8.bgCyan(pc8.black(" One ")));
|
|
2806
3248
|
const { apiKey, actionIds, connectionKeys } = getConfig();
|
|
2807
3249
|
const api = new OneApi(apiKey, getApiBase());
|
|
2808
3250
|
if (!isActionAllowed(actionId, actionIds)) {
|
|
2809
3251
|
error(`Action "${actionId}" is not in the allowed action list.`);
|
|
2810
3252
|
}
|
|
2811
3253
|
if (!connectionKeys.includes("*")) {
|
|
2812
|
-
const
|
|
2813
|
-
|
|
3254
|
+
const spinner5 = createSpinner();
|
|
3255
|
+
spinner5.start("Checking connections...");
|
|
2814
3256
|
try {
|
|
2815
3257
|
const connections = await api.listConnections();
|
|
2816
3258
|
const connectedPlatforms = connections.map((c) => c.platform);
|
|
2817
3259
|
if (!connectedPlatforms.includes(platform)) {
|
|
2818
|
-
|
|
3260
|
+
spinner5.stop("Platform not connected");
|
|
2819
3261
|
error(`Platform "${platform}" has no allowed connections.`);
|
|
2820
3262
|
}
|
|
2821
|
-
|
|
3263
|
+
spinner5.stop("Connection verified");
|
|
2822
3264
|
} catch (error2) {
|
|
2823
|
-
|
|
3265
|
+
spinner5.stop("Failed to check connections");
|
|
2824
3266
|
error(
|
|
2825
3267
|
`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
2826
3268
|
);
|
|
2827
3269
|
}
|
|
2828
3270
|
}
|
|
2829
|
-
const
|
|
2830
|
-
|
|
3271
|
+
const spinner4 = createSpinner();
|
|
3272
|
+
spinner4.start(`Loading knowledge for action ${pc8.dim(actionId)}...`);
|
|
2831
3273
|
try {
|
|
2832
3274
|
const { details, cacheHit, entry } = await resolveActionDetails(api, actionId, {
|
|
2833
3275
|
useCache: options.cache !== false
|
|
@@ -2851,23 +3293,23 @@ async function actionsKnowledgeCommand(platform, actionId, options) {
|
|
|
2851
3293
|
json(response);
|
|
2852
3294
|
return;
|
|
2853
3295
|
}
|
|
2854
|
-
|
|
3296
|
+
spinner4.stop("Knowledge loaded");
|
|
2855
3297
|
console.log();
|
|
2856
3298
|
console.log(knowledgeWithGuidance);
|
|
2857
3299
|
console.log();
|
|
2858
3300
|
p6.note(
|
|
2859
|
-
`Execute: ${
|
|
3301
|
+
`Execute: ${pc8.cyan(`one actions execute ${platform} ${actionId} <connectionKey>`)}`,
|
|
2860
3302
|
"Next Step"
|
|
2861
3303
|
);
|
|
2862
3304
|
} catch (error2) {
|
|
2863
|
-
|
|
3305
|
+
spinner4.stop("Failed to load knowledge");
|
|
2864
3306
|
error(
|
|
2865
3307
|
`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
2866
3308
|
);
|
|
2867
3309
|
}
|
|
2868
3310
|
}
|
|
2869
3311
|
async function actionsExecuteCommand(platform, actionId, connectionKey, options) {
|
|
2870
|
-
intro(
|
|
3312
|
+
intro(pc8.bgCyan(pc8.black(" One ")));
|
|
2871
3313
|
const { apiKey, permissions, actionIds, connectionKeys, knowledgeAgent } = getConfig();
|
|
2872
3314
|
if (knowledgeAgent) {
|
|
2873
3315
|
error(
|
|
@@ -2881,18 +3323,18 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2881
3323
|
error(`Connection key "${connectionKey}" is not allowed.`);
|
|
2882
3324
|
}
|
|
2883
3325
|
const api = new OneApi(apiKey, getApiBase());
|
|
2884
|
-
const
|
|
2885
|
-
|
|
3326
|
+
const spinner4 = createSpinner();
|
|
3327
|
+
spinner4.start("Resolving action details...");
|
|
2886
3328
|
try {
|
|
2887
3329
|
const { details: actionDetails, cacheHit: preflightCacheHit } = await resolveActionDetails(api, actionId, { useCache: options.cache !== false });
|
|
2888
3330
|
if (!isMethodAllowed(actionDetails.method, permissions)) {
|
|
2889
|
-
|
|
3331
|
+
spinner4.stop("Permission denied");
|
|
2890
3332
|
error(
|
|
2891
3333
|
`Method "${actionDetails.method}" is not allowed under "${permissions}" permission level.`
|
|
2892
3334
|
);
|
|
2893
3335
|
}
|
|
2894
|
-
|
|
2895
|
-
`Action: ${actionDetails.title} [${actionDetails.method}]` + (preflightCacheHit ?
|
|
3336
|
+
spinner4.stop(
|
|
3337
|
+
`Action: ${actionDetails.title} [${actionDetails.method}]` + (preflightCacheHit ? pc8.dim(" (cached)") : "")
|
|
2896
3338
|
);
|
|
2897
3339
|
const data = options.data ? parseJsonArg2(options.data, "--data") : void 0;
|
|
2898
3340
|
const pathVariables = options.pathVars ? parseJsonArg2(options.pathVars, "--path-vars") : void 0;
|
|
@@ -2901,7 +3343,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2901
3343
|
if (!options.skipValidation) {
|
|
2902
3344
|
const validation = validateActionInput(actionDetails, { data, pathVariables, queryParams });
|
|
2903
3345
|
if (!validation.valid) {
|
|
2904
|
-
|
|
3346
|
+
spinner4.stop("Validation failed");
|
|
2905
3347
|
if (isAgentMode()) {
|
|
2906
3348
|
json({
|
|
2907
3349
|
error: "Validation failed: missing required parameters",
|
|
@@ -2912,9 +3354,9 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2912
3354
|
}
|
|
2913
3355
|
console.log();
|
|
2914
3356
|
for (const m of validation.missing) {
|
|
2915
|
-
console.log(
|
|
3357
|
+
console.log(pc8.red(` ${m.flag} is missing "${m.param}"`));
|
|
2916
3358
|
if (m.description) {
|
|
2917
|
-
console.log(
|
|
3359
|
+
console.log(pc8.dim(` ${m.description}`));
|
|
2918
3360
|
}
|
|
2919
3361
|
}
|
|
2920
3362
|
console.log();
|
|
@@ -2922,7 +3364,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2922
3364
|
}
|
|
2923
3365
|
}
|
|
2924
3366
|
if (options.mock) {
|
|
2925
|
-
|
|
3367
|
+
spinner4.stop("Mock \u2014 returning example response");
|
|
2926
3368
|
const mockResponse = actionDetails.ioSchema?.ioExample?.output ?? null;
|
|
2927
3369
|
if (isAgentMode()) {
|
|
2928
3370
|
json({
|
|
@@ -2939,7 +3381,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2939
3381
|
}
|
|
2940
3382
|
console.log();
|
|
2941
3383
|
if (mockResponse) {
|
|
2942
|
-
console.log(
|
|
3384
|
+
console.log(pc8.bold("Mock Response:"));
|
|
2943
3385
|
console.log(JSON.stringify(mockResponse, null, 2));
|
|
2944
3386
|
} else {
|
|
2945
3387
|
note("No example output available for this action", "Mock");
|
|
@@ -2980,33 +3422,33 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
|
|
|
2980
3422
|
return;
|
|
2981
3423
|
}
|
|
2982
3424
|
console.log();
|
|
2983
|
-
console.log(
|
|
3425
|
+
console.log(pc8.dim("Request:"));
|
|
2984
3426
|
console.log(
|
|
2985
|
-
|
|
3427
|
+
pc8.dim(
|
|
2986
3428
|
` ${result.requestConfig.method} ${result.requestConfig.url}`
|
|
2987
3429
|
)
|
|
2988
3430
|
);
|
|
2989
3431
|
if (options.dryRun) {
|
|
2990
3432
|
if (result.requestConfig.data) {
|
|
2991
3433
|
console.log();
|
|
2992
|
-
console.log(
|
|
2993
|
-
console.log(
|
|
3434
|
+
console.log(pc8.dim("Body:"));
|
|
3435
|
+
console.log(pc8.dim(JSON.stringify(result.requestConfig.data, null, 2)));
|
|
2994
3436
|
}
|
|
2995
3437
|
console.log();
|
|
2996
3438
|
note("Dry run \u2014 request was not sent", "Dry Run");
|
|
2997
3439
|
} else {
|
|
2998
3440
|
console.log();
|
|
2999
|
-
console.log(
|
|
3441
|
+
console.log(pc8.bold("Response:"));
|
|
3000
3442
|
const rd = result.responseData;
|
|
3001
3443
|
if (rd && typeof rd === "object" && typeof rd.text === "string" && "contentType" in rd) {
|
|
3002
|
-
if (rd.contentType) console.log(
|
|
3444
|
+
if (rd.contentType) console.log(pc8.dim(`(${rd.contentType})`));
|
|
3003
3445
|
console.log(rd.text);
|
|
3004
3446
|
} else {
|
|
3005
3447
|
console.log(JSON.stringify(result.responseData, null, 2));
|
|
3006
3448
|
}
|
|
3007
3449
|
}
|
|
3008
3450
|
} catch (error2) {
|
|
3009
|
-
|
|
3451
|
+
spinner4.stop("Execution failed");
|
|
3010
3452
|
error(
|
|
3011
3453
|
`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
|
|
3012
3454
|
);
|
|
@@ -3203,7 +3645,7 @@ async function actionsExecuteParallelCommand() {
|
|
|
3203
3645
|
}
|
|
3204
3646
|
console.log();
|
|
3205
3647
|
for (const e of errors) {
|
|
3206
|
-
console.log(` ${
|
|
3648
|
+
console.log(` ${pc8.red("\u2717")} Segment ${e.segment} (${e.label}):`);
|
|
3207
3649
|
for (const msg of e.messages) {
|
|
3208
3650
|
console.log(` ${msg}`);
|
|
3209
3651
|
}
|
|
@@ -3298,17 +3740,17 @@ async function actionsExecuteParallelCommand() {
|
|
|
3298
3740
|
console.log();
|
|
3299
3741
|
for (const r of results) {
|
|
3300
3742
|
const label = `${r.platform}/${r.actionId}`;
|
|
3301
|
-
const time =
|
|
3743
|
+
const time = pc8.dim(`(${(r.durationMs / 1e3).toFixed(2)}s)`);
|
|
3302
3744
|
if (r.mock) {
|
|
3303
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3304
|
-
if (r.response) console.log(` ${
|
|
3745
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc8.cyan("\u25C7 mock")} ${time}`);
|
|
3746
|
+
if (r.response) console.log(` ${pc8.dim(JSON.stringify(r.response, null, 2).split("\n").join("\n "))}`);
|
|
3305
3747
|
} else if (r.dryRun) {
|
|
3306
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3748
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc8.yellow("\u2298 dry-run")} ${time}`);
|
|
3307
3749
|
} else if (r.status === "success") {
|
|
3308
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3309
|
-
if (r.response) console.log(` ${
|
|
3750
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc8.green("\u2713")} ${time}`);
|
|
3751
|
+
if (r.response) console.log(` ${pc8.dim(JSON.stringify(r.response, null, 2).split("\n").join("\n "))}`);
|
|
3310
3752
|
} else {
|
|
3311
|
-
console.log(` [${r.segment}/${total}] ${label} ${
|
|
3753
|
+
console.log(` [${r.segment}/${total}] ${label} ${pc8.red("\u2717")} ${time} \u2014 ${r.error}`);
|
|
3312
3754
|
}
|
|
3313
3755
|
}
|
|
3314
3756
|
console.log();
|
|
@@ -3323,26 +3765,26 @@ async function actionsExecuteParallelCommand() {
|
|
|
3323
3765
|
function colorMethod(method) {
|
|
3324
3766
|
switch (method.toUpperCase()) {
|
|
3325
3767
|
case "GET":
|
|
3326
|
-
return
|
|
3768
|
+
return pc8.green(method);
|
|
3327
3769
|
case "POST":
|
|
3328
|
-
return
|
|
3770
|
+
return pc8.yellow(method);
|
|
3329
3771
|
case "PUT":
|
|
3330
|
-
return
|
|
3772
|
+
return pc8.blue(method);
|
|
3331
3773
|
case "PATCH":
|
|
3332
|
-
return
|
|
3774
|
+
return pc8.magenta(method);
|
|
3333
3775
|
case "DELETE":
|
|
3334
|
-
return
|
|
3776
|
+
return pc8.red(method);
|
|
3335
3777
|
default:
|
|
3336
3778
|
return method;
|
|
3337
3779
|
}
|
|
3338
3780
|
}
|
|
3339
3781
|
|
|
3340
3782
|
// src/commands/flow.ts
|
|
3341
|
-
import
|
|
3783
|
+
import pc9 from "picocolors";
|
|
3342
3784
|
|
|
3343
3785
|
// src/lib/flow-validator.ts
|
|
3344
|
-
import
|
|
3345
|
-
import
|
|
3786
|
+
import fs5 from "fs";
|
|
3787
|
+
import path6 from "path";
|
|
3346
3788
|
import { spawnSync } from "child_process";
|
|
3347
3789
|
function validateFlowSchema(flow2) {
|
|
3348
3790
|
const errors = [];
|
|
@@ -3417,32 +3859,32 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3417
3859
|
const validTypes = FLOW_SCHEMA.stepTypes.map((st) => st.type);
|
|
3418
3860
|
for (let i = 0; i < steps.length; i++) {
|
|
3419
3861
|
const step = steps[i];
|
|
3420
|
-
const
|
|
3862
|
+
const path14 = `${pathPrefix}[${i}]`;
|
|
3421
3863
|
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
3422
|
-
errors.push({ path:
|
|
3864
|
+
errors.push({ path: path14, message: "Step must be an object" });
|
|
3423
3865
|
continue;
|
|
3424
3866
|
}
|
|
3425
3867
|
const s = step;
|
|
3426
3868
|
if (!s.id || typeof s.id !== "string") {
|
|
3427
|
-
errors.push({ path: `${
|
|
3869
|
+
errors.push({ path: `${path14}.id`, message: 'Step must have a string "id"' });
|
|
3428
3870
|
}
|
|
3429
3871
|
if (!s.name || typeof s.name !== "string") {
|
|
3430
|
-
errors.push({ path: `${
|
|
3872
|
+
errors.push({ path: `${path14}.name`, message: 'Step must have a string "name"' });
|
|
3431
3873
|
}
|
|
3432
3874
|
if (!s.type || !validTypes.includes(s.type)) {
|
|
3433
|
-
errors.push({ path: `${
|
|
3875
|
+
errors.push({ path: `${path14}.type`, message: `Step type must be one of: ${validTypes.join(", ")}` });
|
|
3434
3876
|
continue;
|
|
3435
3877
|
}
|
|
3436
3878
|
if (s.requires !== void 0) {
|
|
3437
3879
|
if (!Array.isArray(s.requires)) {
|
|
3438
|
-
errors.push({ path: `${
|
|
3880
|
+
errors.push({ path: `${path14}.requires`, message: '"requires" must be an array of selector strings (e.g. ["$.steps.foo.output.bar"])' });
|
|
3439
3881
|
} else {
|
|
3440
3882
|
for (let r = 0; r < s.requires.length; r++) {
|
|
3441
3883
|
const sel = s.requires[r];
|
|
3442
3884
|
if (typeof sel !== "string") {
|
|
3443
|
-
errors.push({ path: `${
|
|
3885
|
+
errors.push({ path: `${path14}.requires[${r}]`, message: '"requires" entry must be a selector string' });
|
|
3444
3886
|
} else if (!sel.startsWith("$.")) {
|
|
3445
|
-
errors.push({ path: `${
|
|
3887
|
+
errors.push({ path: `${path14}.requires[${r}]`, message: `"requires" entry "${sel}" must be a selector starting with "$." (e.g. "$.steps.foo.output.bar")` });
|
|
3446
3888
|
}
|
|
3447
3889
|
}
|
|
3448
3890
|
}
|
|
@@ -3450,7 +3892,7 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3450
3892
|
if (s.onError && typeof s.onError === "object") {
|
|
3451
3893
|
const oe = s.onError;
|
|
3452
3894
|
if (!FLOW_SCHEMA.errorStrategies.includes(oe.strategy)) {
|
|
3453
|
-
errors.push({ path: `${
|
|
3895
|
+
errors.push({ path: `${path14}.onError.strategy`, message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
|
|
3454
3896
|
}
|
|
3455
3897
|
}
|
|
3456
3898
|
const descriptor = getStepTypeDescriptor(s.type);
|
|
@@ -3460,14 +3902,14 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3460
3902
|
if (!configObj || typeof configObj !== "object") {
|
|
3461
3903
|
const hint = detectFlatConfigHint(s, descriptor);
|
|
3462
3904
|
errors.push({
|
|
3463
|
-
path: `${
|
|
3905
|
+
path: `${path14}.${configKey}`,
|
|
3464
3906
|
message: `${capitalize(descriptor.type)} step must have a "${configKey}" config object${hint}`
|
|
3465
3907
|
});
|
|
3466
3908
|
continue;
|
|
3467
3909
|
}
|
|
3468
3910
|
const config2 = configObj;
|
|
3469
3911
|
for (const [fieldName, fd] of Object.entries(descriptor.fields)) {
|
|
3470
|
-
const fieldPath = `${
|
|
3912
|
+
const fieldPath = `${path14}.${configKey}.${fieldName}`;
|
|
3471
3913
|
const value = config2[fieldName];
|
|
3472
3914
|
if (fd.required && (value === void 0 || value === null || value === "")) {
|
|
3473
3915
|
errors.push({ path: fieldPath, message: `${capitalize(descriptor.type)} must have ${fd.type === "string" ? "a string" : fd.type === "array" ? "a" : "a"} "${fieldName}"` });
|
|
@@ -3500,30 +3942,30 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3500
3942
|
}
|
|
3501
3943
|
}
|
|
3502
3944
|
if (descriptor.type === "action") {
|
|
3503
|
-
validateConnectionForm(config2, `${
|
|
3945
|
+
validateConnectionForm(config2, `${path14}.${configKey}`, errors);
|
|
3504
3946
|
}
|
|
3505
3947
|
if (descriptor.type === "code") {
|
|
3506
3948
|
const hasSource = typeof config2.source === "string" && config2.source.length > 0;
|
|
3507
3949
|
const hasModule = typeof config2.module === "string" && config2.module.length > 0;
|
|
3508
3950
|
if (!hasSource && !hasModule) {
|
|
3509
|
-
errors.push({ path: `${
|
|
3951
|
+
errors.push({ path: `${path14}.${configKey}`, message: 'Code step must define either "source" (inline JS) or "module" (path to .mjs file)' });
|
|
3510
3952
|
} else if (hasSource && hasModule) {
|
|
3511
|
-
errors.push({ path: `${
|
|
3953
|
+
errors.push({ path: `${path14}.${configKey}`, message: 'Code step cannot define both "source" and "module" \u2014 pick one' });
|
|
3512
3954
|
}
|
|
3513
3955
|
if (hasModule) {
|
|
3514
3956
|
const m = config2.module;
|
|
3515
3957
|
if (m.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(m)) {
|
|
3516
|
-
errors.push({ path: `${
|
|
3958
|
+
errors.push({ path: `${path14}.${configKey}.module`, message: "Code module path must be relative to the flow folder (no absolute paths)" });
|
|
3517
3959
|
} else if (m.split(/[\\/]/).includes("..")) {
|
|
3518
|
-
errors.push({ path: `${
|
|
3960
|
+
errors.push({ path: `${path14}.${configKey}.module`, message: 'Code module path must not escape the flow folder ("..")' });
|
|
3519
3961
|
} else if (!m.endsWith(".mjs")) {
|
|
3520
|
-
errors.push({ path: `${
|
|
3962
|
+
errors.push({ path: `${path14}.${configKey}.module`, message: "Code module must be a .mjs file" });
|
|
3521
3963
|
}
|
|
3522
3964
|
}
|
|
3523
3965
|
if (hasSource) {
|
|
3524
3966
|
const syntaxError = checkCodeSourceSyntax(config2.source);
|
|
3525
3967
|
if (syntaxError) {
|
|
3526
|
-
errors.push({ path: `${
|
|
3968
|
+
errors.push({ path: `${path14}.${configKey}.source`, message: `Syntax error in code step: ${syntaxError}` });
|
|
3527
3969
|
}
|
|
3528
3970
|
}
|
|
3529
3971
|
}
|
|
@@ -3595,16 +4037,16 @@ function validateStepIds(flow2) {
|
|
|
3595
4037
|
function collectIds(steps, pathPrefix) {
|
|
3596
4038
|
for (let i = 0; i < steps.length; i++) {
|
|
3597
4039
|
const step = steps[i];
|
|
3598
|
-
const
|
|
4040
|
+
const path14 = `${pathPrefix}[${i}]`;
|
|
3599
4041
|
if (seen.has(step.id)) {
|
|
3600
|
-
errors.push({ path: `${
|
|
4042
|
+
errors.push({ path: `${path14}.id`, message: `Duplicate step ID: "${step.id}"` });
|
|
3601
4043
|
} else {
|
|
3602
4044
|
seen.add(step.id);
|
|
3603
4045
|
}
|
|
3604
4046
|
for (const { configKey, fieldName } of nestedKeys) {
|
|
3605
4047
|
const config2 = step[configKey];
|
|
3606
4048
|
if (config2 && Array.isArray(config2[fieldName])) {
|
|
3607
|
-
collectIds(config2[fieldName], `${
|
|
4049
|
+
collectIds(config2[fieldName], `${path14}.${configKey}.${fieldName}`);
|
|
3608
4050
|
}
|
|
3609
4051
|
}
|
|
3610
4052
|
}
|
|
@@ -3652,7 +4094,7 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3652
4094
|
}
|
|
3653
4095
|
return selectors;
|
|
3654
4096
|
}
|
|
3655
|
-
function checkSelectors(selectors,
|
|
4097
|
+
function checkSelectors(selectors, path14, precedingStepIds) {
|
|
3656
4098
|
for (const selector of selectors) {
|
|
3657
4099
|
const parts = selector.split(".");
|
|
3658
4100
|
if (parts.length < 3) continue;
|
|
@@ -3660,15 +4102,15 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3660
4102
|
if (root === "input") {
|
|
3661
4103
|
const inputName = parts[2];
|
|
3662
4104
|
if (!inputNames.has(inputName)) {
|
|
3663
|
-
errors.push({ path:
|
|
4105
|
+
errors.push({ path: path14, message: `Selector "${selector}" references undefined input "${inputName}"` });
|
|
3664
4106
|
}
|
|
3665
4107
|
} else if (root === "steps") {
|
|
3666
4108
|
const stepId = parts[2].replace(/[\[\]]/g, "").split(/[\[\]]/)[0];
|
|
3667
4109
|
if (!allStepIds.has(stepId)) {
|
|
3668
|
-
errors.push({ path:
|
|
4110
|
+
errors.push({ path: path14, message: `Selector "${selector}" references undefined step "${stepId}"` });
|
|
3669
4111
|
} else if (precedingStepIds && !precedingStepIds.has(stepId)) {
|
|
3670
4112
|
errors.push({
|
|
3671
|
-
path:
|
|
4113
|
+
path: path14,
|
|
3672
4114
|
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.`
|
|
3673
4115
|
});
|
|
3674
4116
|
}
|
|
@@ -3676,20 +4118,20 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3676
4118
|
}
|
|
3677
4119
|
}
|
|
3678
4120
|
const EXPRESSION_FIELDS = /* @__PURE__ */ new Set(["condition.expression", "while.condition"]);
|
|
3679
|
-
function checkOperatorsInSelectorField(value,
|
|
4121
|
+
function checkOperatorsInSelectorField(value, path14) {
|
|
3680
4122
|
if (typeof value === "string" && value.startsWith("$.")) {
|
|
3681
4123
|
if (value.includes("||")) {
|
|
3682
|
-
errors.push({ path:
|
|
4124
|
+
errors.push({ path: path14, 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.` });
|
|
3683
4125
|
} else if (value.includes("&&")) {
|
|
3684
|
-
errors.push({ path:
|
|
4126
|
+
errors.push({ path: path14, 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.` });
|
|
3685
4127
|
}
|
|
3686
4128
|
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3687
4129
|
for (const [k, v] of Object.entries(value)) {
|
|
3688
|
-
checkOperatorsInSelectorField(v, `${
|
|
4130
|
+
checkOperatorsInSelectorField(v, `${path14}.${k}`);
|
|
3689
4131
|
}
|
|
3690
4132
|
} else if (Array.isArray(value)) {
|
|
3691
4133
|
for (let i = 0; i < value.length; i++) {
|
|
3692
|
-
checkOperatorsInSelectorField(value[i], `${
|
|
4134
|
+
checkOperatorsInSelectorField(value[i], `${path14}[${i}]`);
|
|
3693
4135
|
}
|
|
3694
4136
|
}
|
|
3695
4137
|
}
|
|
@@ -3733,10 +4175,10 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3733
4175
|
}
|
|
3734
4176
|
const modulePath = step.type === "code" ? c.module : void 0;
|
|
3735
4177
|
if (rootDir && typeof modulePath === "string" && modulePath.length > 0) {
|
|
3736
|
-
const abs =
|
|
3737
|
-
if (
|
|
4178
|
+
const abs = path6.resolve(rootDir, modulePath);
|
|
4179
|
+
if (fs5.existsSync(abs)) {
|
|
3738
4180
|
try {
|
|
3739
|
-
const moduleText =
|
|
4181
|
+
const moduleText = fs5.readFileSync(abs, "utf-8");
|
|
3740
4182
|
checkSelectors(extractSelectors(moduleText), `${pathPrefix}.${descriptor.configKey}.module`, preceding2);
|
|
3741
4183
|
} catch {
|
|
3742
4184
|
}
|
|
@@ -3774,10 +4216,10 @@ var VALID_OUTPUT_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "number", "bo
|
|
|
3774
4216
|
function isOutputSchemaObject(v) {
|
|
3775
4217
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
3776
4218
|
}
|
|
3777
|
-
function walkOutputSchema(schema,
|
|
4219
|
+
function walkOutputSchema(schema, path14) {
|
|
3778
4220
|
let current = schema;
|
|
3779
|
-
for (let i = 0; i <
|
|
3780
|
-
const seg =
|
|
4221
|
+
for (let i = 0; i < path14.length; i++) {
|
|
4222
|
+
const seg = path14[i];
|
|
3781
4223
|
if (typeof current === "string") {
|
|
3782
4224
|
return current === "unknown" || current === "object" || current === "array" ? "opaque" : "opaque";
|
|
3783
4225
|
}
|
|
@@ -3929,8 +4371,8 @@ function validateCodeModules(flow2, rootDir) {
|
|
|
3929
4371
|
const stepPath = `${pathPrefix}[${i}]`;
|
|
3930
4372
|
if (step.type === "code" && step.code?.module) {
|
|
3931
4373
|
const m = step.code.module;
|
|
3932
|
-
const abs =
|
|
3933
|
-
if (!
|
|
4374
|
+
const abs = path6.resolve(rootDir, m);
|
|
4375
|
+
if (!fs5.existsSync(abs)) {
|
|
3934
4376
|
errors.push({
|
|
3935
4377
|
path: `${stepPath}.code.module`,
|
|
3936
4378
|
message: `Code module "${m}" not found at ${abs}`
|
|
@@ -4061,11 +4503,11 @@ function validateFileReadSchemas(flow2) {
|
|
|
4061
4503
|
}
|
|
4062
4504
|
|
|
4063
4505
|
// src/commands/flow.ts
|
|
4064
|
-
import
|
|
4065
|
-
import
|
|
4506
|
+
import fs6 from "fs";
|
|
4507
|
+
import path7 from "path";
|
|
4066
4508
|
async function writeFlowResultFile(filePath, meta, steps) {
|
|
4067
|
-
const abs =
|
|
4068
|
-
const ws =
|
|
4509
|
+
const abs = path7.resolve(filePath);
|
|
4510
|
+
const ws = fs6.createWriteStream(abs);
|
|
4069
4511
|
const done = new Promise((resolve, reject) => {
|
|
4070
4512
|
ws.on("finish", () => resolve());
|
|
4071
4513
|
ws.on("error", reject);
|
|
@@ -4096,25 +4538,25 @@ function previewValue(value, max = 120) {
|
|
|
4096
4538
|
}
|
|
4097
4539
|
function renderDryRef(ref) {
|
|
4098
4540
|
if (ref.status === "resolved") {
|
|
4099
|
-
return `${
|
|
4541
|
+
return `${pc9.green("\u2713")} ${ref.selector} ${pc9.dim("\u2192")} ${previewValue(ref.value)}`;
|
|
4100
4542
|
}
|
|
4101
4543
|
if (ref.status === "deferred") {
|
|
4102
|
-
return `${
|
|
4544
|
+
return `${pc9.dim("\u25CB")} ${ref.selector} ${pc9.dim("\u2192 pending (produced by a later step)")}`;
|
|
4103
4545
|
}
|
|
4104
|
-
return `${
|
|
4546
|
+
return `${pc9.yellow("!")} ${ref.selector} ${pc9.yellow("\u2192 unresolved \u2014 check the input/env name")}`;
|
|
4105
4547
|
}
|
|
4106
4548
|
function renderDryResolution(steps) {
|
|
4107
4549
|
const isExpr = (t) => t === "transform" || t === "condition" || t === "while";
|
|
4108
4550
|
for (const s of steps) {
|
|
4109
|
-
const label = s.name ? `${s.stepId} ${
|
|
4110
|
-
console.log(` ${
|
|
4551
|
+
const label = s.name ? `${s.stepId} ${pc9.dim(`"${s.name}"`)}` : s.stepId;
|
|
4552
|
+
console.log(` ${pc9.cyan("\u25B8")} ${label} ${pc9.dim(`(${s.type})`)}`);
|
|
4111
4553
|
if (s.error !== void 0) {
|
|
4112
|
-
console.log(` ${
|
|
4554
|
+
console.log(` ${pc9.red("error")} ${s.error}`);
|
|
4113
4555
|
} else if (isExpr(s.type) && s.deferred) {
|
|
4114
4556
|
const deps = s.references.map((r) => r.selector).join(", ");
|
|
4115
|
-
console.log(` ${
|
|
4557
|
+
console.log(` ${pc9.dim("\u25CB pending \u2014 depends on")} ${deps} ${pc9.dim("(produced by a later step)")}`);
|
|
4116
4558
|
} else if (isExpr(s.type)) {
|
|
4117
|
-
console.log(` ${
|
|
4559
|
+
console.log(` ${pc9.dim("=")} ${previewValue(s.resolved)}`);
|
|
4118
4560
|
}
|
|
4119
4561
|
if (!(isExpr(s.type) && s.deferred)) {
|
|
4120
4562
|
for (const ref of s.references) {
|
|
@@ -4122,7 +4564,7 @@ function renderDryResolution(steps) {
|
|
|
4122
4564
|
}
|
|
4123
4565
|
}
|
|
4124
4566
|
if (!isExpr(s.type) && s.references.length === 0 && s.error === void 0) {
|
|
4125
|
-
console.log(` ${
|
|
4567
|
+
console.log(` ${pc9.dim("(no interpolations)")}`);
|
|
4126
4568
|
}
|
|
4127
4569
|
}
|
|
4128
4570
|
}
|
|
@@ -4176,14 +4618,14 @@ async function autoResolveConnectionInputs(flow2, inputs, api) {
|
|
|
4176
4618
|
return resolved;
|
|
4177
4619
|
}
|
|
4178
4620
|
async function flowCreateCommand(key, options) {
|
|
4179
|
-
intro(
|
|
4621
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4180
4622
|
let flow2;
|
|
4181
4623
|
if (options.definition) {
|
|
4182
4624
|
let raw = options.definition;
|
|
4183
4625
|
if (raw.startsWith("@")) {
|
|
4184
4626
|
const filePath = raw.slice(1);
|
|
4185
4627
|
try {
|
|
4186
|
-
raw =
|
|
4628
|
+
raw = fs6.readFileSync(filePath, "utf-8");
|
|
4187
4629
|
} catch (err) {
|
|
4188
4630
|
error(`Cannot read file "${filePath}": ${err.message}`);
|
|
4189
4631
|
}
|
|
@@ -4232,15 +4674,15 @@ ${errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
4232
4674
|
return;
|
|
4233
4675
|
}
|
|
4234
4676
|
note(`Workflow "${flow2.name}" saved to ${flowPath}`, "Created");
|
|
4235
|
-
outro(`Validate: ${
|
|
4236
|
-
Execute: ${
|
|
4677
|
+
outro(`Validate: ${pc9.cyan(`one flow validate ${flow2.key}`)}
|
|
4678
|
+
Execute: ${pc9.cyan(`one flow execute ${flow2.key}`)}`);
|
|
4237
4679
|
}
|
|
4238
4680
|
async function flowExecuteCommand(keyOrPath, options) {
|
|
4239
|
-
intro(
|
|
4681
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4240
4682
|
const { apiKey, permissions, actionIds } = getConfig2();
|
|
4241
4683
|
const api = new OneApi(apiKey, getApiBase());
|
|
4242
|
-
const
|
|
4243
|
-
|
|
4684
|
+
const spinner4 = createSpinner();
|
|
4685
|
+
spinner4.start(`Loading workflow "${keyOrPath}"...`);
|
|
4244
4686
|
let flow2;
|
|
4245
4687
|
let rootDir;
|
|
4246
4688
|
let flowFilePath;
|
|
@@ -4250,11 +4692,11 @@ async function flowExecuteCommand(keyOrPath, options) {
|
|
|
4250
4692
|
rootDir = loaded.rootDir;
|
|
4251
4693
|
flowFilePath = loaded.filePath;
|
|
4252
4694
|
} catch (err) {
|
|
4253
|
-
|
|
4695
|
+
spinner4.stop("Workflow not found");
|
|
4254
4696
|
error(err instanceof Error ? err.message : String(err));
|
|
4255
4697
|
return;
|
|
4256
4698
|
}
|
|
4257
|
-
|
|
4699
|
+
spinner4.stop(`Workflow: ${flow2.name} (${flow2.steps.length} steps)`);
|
|
4258
4700
|
const preflightErrors = validateFlow(flow2, rootDir);
|
|
4259
4701
|
if (preflightErrors.length > 0) {
|
|
4260
4702
|
if (isAgentMode()) {
|
|
@@ -4269,7 +4711,7 @@ ${preflightErrors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
4269
4711
|
if (isAgentMode()) {
|
|
4270
4712
|
json({ event: "flow:deprecation", flowKey: flow2.key, warning: msg });
|
|
4271
4713
|
} else {
|
|
4272
|
-
console.error(
|
|
4714
|
+
console.error(pc9.yellow(`\u26A0 ${msg}`));
|
|
4273
4715
|
}
|
|
4274
4716
|
}
|
|
4275
4717
|
if (!options.allowBash && flowRequiresBash(flow2)) {
|
|
@@ -4303,7 +4745,7 @@ ${preflightErrors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
|
|
|
4303
4745
|
runner.requestPause();
|
|
4304
4746
|
if (!isAgentMode()) {
|
|
4305
4747
|
console.log(`
|
|
4306
|
-
${
|
|
4748
|
+
${pc9.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
4307
4749
|
}
|
|
4308
4750
|
};
|
|
4309
4751
|
process.on("SIGINT", sigintHandler);
|
|
@@ -4323,12 +4765,12 @@ ${pc8.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
|
4323
4765
|
} else if (options.verbose) {
|
|
4324
4766
|
const ts = (/* @__PURE__ */ new Date()).toISOString().split("T")[1].slice(0, 8);
|
|
4325
4767
|
if (event.event === "step:start") {
|
|
4326
|
-
console.log(` ${
|
|
4768
|
+
console.log(` ${pc9.dim(ts)} ${pc9.cyan("\u25B6")} ${event.stepName} ${pc9.dim(`(${event.type})`)}`);
|
|
4327
4769
|
} else if (event.event === "step:complete") {
|
|
4328
|
-
const status = event.status === "success" ?
|
|
4329
|
-
console.log(` ${
|
|
4770
|
+
const status = event.status === "success" ? pc9.green("\u2713") : event.status === "skipped" ? pc9.dim("\u25CB") : pc9.red("\u2717");
|
|
4771
|
+
console.log(` ${pc9.dim(ts)} ${status} ${event.stepId} ${pc9.dim(`${event.durationMs}ms`)}`);
|
|
4330
4772
|
} else if (event.event === "step:error") {
|
|
4331
|
-
console.log(` ${
|
|
4773
|
+
console.log(` ${pc9.dim(ts)} ${pc9.red("\u2717")} ${event.stepId}: ${event.error}`);
|
|
4332
4774
|
}
|
|
4333
4775
|
}
|
|
4334
4776
|
};
|
|
@@ -4377,8 +4819,8 @@ ${pc8.yellow("Pausing after current step completes...")} (run ID: ${runId})`);
|
|
|
4377
4819
|
console.log();
|
|
4378
4820
|
const missing = dryRunSteps.reduce((n, s) => n + s.references.filter((r) => r.status === "missing").length, 0);
|
|
4379
4821
|
note(
|
|
4380
|
-
`Dry run \u2014 no steps executed. Resolved ${dryRunSteps.length} step(s)` + (missing > 0 ? `; ${
|
|
4381
|
-
${
|
|
4822
|
+
`Dry run \u2014 no steps executed. Resolved ${dryRunSteps.length} step(s)` + (missing > 0 ? `; ${pc9.yellow(`${missing} unresolved input/env reference(s)`)}` : "") + `.
|
|
4823
|
+
${pc9.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<stepId> to resolve them against real output.")}`,
|
|
4382
4824
|
"Dry Run"
|
|
4383
4825
|
);
|
|
4384
4826
|
return;
|
|
@@ -4388,17 +4830,17 @@ ${pc8.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<st
|
|
|
4388
4830
|
const failed = stepEntries.filter(([, r]) => r.status === "failed").length;
|
|
4389
4831
|
const skipped = stepEntries.filter(([, r]) => r.status === "skipped").length;
|
|
4390
4832
|
console.log();
|
|
4391
|
-
console.log(` ${
|
|
4392
|
-
console.log(` ${
|
|
4393
|
-
console.log(` ${
|
|
4833
|
+
console.log(` ${pc9.green("\u2713")} ${succeeded} succeeded ${failed > 0 ? pc9.red(`\u2717 ${failed} failed`) : ""} ${skipped > 0 ? pc9.dim(`\u25CB ${skipped} skipped`) : ""}`);
|
|
4834
|
+
console.log(` ${pc9.dim(`Run ID: ${runId}`)}`);
|
|
4835
|
+
console.log(` ${pc9.dim(`Log: ${logPath}`)}`);
|
|
4394
4836
|
if (dryResolveTarget) {
|
|
4395
4837
|
console.log();
|
|
4396
|
-
console.log(` ${
|
|
4838
|
+
console.log(` ${pc9.dim(`Resolved (not executed) "${dryResolveTarget.stepId}":`)}`);
|
|
4397
4839
|
renderDryResolution([dryResolveTarget]);
|
|
4398
4840
|
}
|
|
4399
4841
|
if (stoppedAfter) {
|
|
4400
4842
|
note(
|
|
4401
|
-
`Stopped after step "${stoppedAfter}". Inspect step outputs with: ${
|
|
4843
|
+
`Stopped after step "${stoppedAfter}". Inspect step outputs with: ${pc9.cyan(`one flow inspect ${runId}`)}`,
|
|
4402
4844
|
"Stopped"
|
|
4403
4845
|
);
|
|
4404
4846
|
} else if (options.dryRun) {
|
|
@@ -4420,13 +4862,13 @@ ${pc8.dim("$.steps.* refs resolve at runtime \u2014 re-run with --stop-after=<st
|
|
|
4420
4862
|
});
|
|
4421
4863
|
process.exit(1);
|
|
4422
4864
|
}
|
|
4423
|
-
console.log(` ${
|
|
4424
|
-
console.log(` ${
|
|
4865
|
+
console.log(` ${pc9.dim(`Run ID: ${runId}`)}`);
|
|
4866
|
+
console.log(` ${pc9.dim(`Log: ${logPath}`)}`);
|
|
4425
4867
|
error(`Workflow failed: ${errorMsg}`);
|
|
4426
4868
|
}
|
|
4427
4869
|
}
|
|
4428
4870
|
async function flowListCommand() {
|
|
4429
|
-
intro(
|
|
4871
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4430
4872
|
const flows = listFlows();
|
|
4431
4873
|
if (isAgentMode()) {
|
|
4432
4874
|
json({ workflows: flows });
|
|
@@ -4458,9 +4900,9 @@ async function flowListCommand() {
|
|
|
4458
4900
|
console.log();
|
|
4459
4901
|
}
|
|
4460
4902
|
async function flowValidateCommand(keyOrPath) {
|
|
4461
|
-
intro(
|
|
4462
|
-
const
|
|
4463
|
-
|
|
4903
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4904
|
+
const spinner4 = createSpinner();
|
|
4905
|
+
spinner4.start(`Validating "${keyOrPath}"...`);
|
|
4464
4906
|
let flowData;
|
|
4465
4907
|
let rootDir;
|
|
4466
4908
|
try {
|
|
@@ -4470,29 +4912,29 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
4470
4912
|
rootDir = loaded.rootDir;
|
|
4471
4913
|
} catch {
|
|
4472
4914
|
const flowPath = resolveFlowPath(keyOrPath);
|
|
4473
|
-
const content =
|
|
4915
|
+
const content = fs6.readFileSync(flowPath, "utf-8");
|
|
4474
4916
|
flowData = JSON.parse(content);
|
|
4475
|
-
rootDir =
|
|
4917
|
+
rootDir = path7.dirname(flowPath);
|
|
4476
4918
|
}
|
|
4477
4919
|
} catch (err) {
|
|
4478
|
-
|
|
4920
|
+
spinner4.stop("Validation failed");
|
|
4479
4921
|
error(`Could not read workflow: ${err instanceof Error ? err.message : String(err)}`);
|
|
4480
4922
|
}
|
|
4481
4923
|
const errors = validateFlow(flowData, rootDir);
|
|
4482
4924
|
if (errors.length > 0) {
|
|
4483
|
-
|
|
4925
|
+
spinner4.stop("Validation failed");
|
|
4484
4926
|
if (isAgentMode()) {
|
|
4485
4927
|
json({ valid: false, errors });
|
|
4486
4928
|
process.exit(1);
|
|
4487
4929
|
}
|
|
4488
4930
|
console.log();
|
|
4489
4931
|
for (const e of errors) {
|
|
4490
|
-
console.log(` ${
|
|
4932
|
+
console.log(` ${pc9.red("\u2717")} ${pc9.dim(e.path)}: ${e.message}`);
|
|
4491
4933
|
}
|
|
4492
4934
|
console.log();
|
|
4493
4935
|
error(`${errors.length} validation error(s) found`);
|
|
4494
4936
|
}
|
|
4495
|
-
|
|
4937
|
+
spinner4.stop("Workflow is valid");
|
|
4496
4938
|
if (isAgentMode()) {
|
|
4497
4939
|
json({ valid: true, key: flowData.key });
|
|
4498
4940
|
return;
|
|
@@ -4500,7 +4942,7 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
4500
4942
|
note(`Workflow "${flowData.key}" passed all validation checks`, "Valid");
|
|
4501
4943
|
}
|
|
4502
4944
|
async function flowResumeCommand(runId, options = {}) {
|
|
4503
|
-
intro(
|
|
4945
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4504
4946
|
const state = FlowRunner.loadRunState(runId);
|
|
4505
4947
|
if (!state) {
|
|
4506
4948
|
error(`Run "${runId}" not found`);
|
|
@@ -4534,15 +4976,15 @@ async function flowResumeCommand(runId, options = {}) {
|
|
|
4534
4976
|
json(event);
|
|
4535
4977
|
}
|
|
4536
4978
|
};
|
|
4537
|
-
const
|
|
4538
|
-
|
|
4979
|
+
const spinner4 = createSpinner();
|
|
4980
|
+
spinner4.start(`Resuming run ${runId} (${state.completedSteps.length} steps already completed)...`);
|
|
4539
4981
|
try {
|
|
4540
4982
|
const context = await runner.resume(flow2, api, permissions, actionIds, {
|
|
4541
4983
|
onEvent,
|
|
4542
4984
|
rootDir,
|
|
4543
4985
|
allowBash: options.allowBash
|
|
4544
4986
|
});
|
|
4545
|
-
|
|
4987
|
+
spinner4.stop("Workflow completed");
|
|
4546
4988
|
if (isAgentMode()) {
|
|
4547
4989
|
json({
|
|
4548
4990
|
event: "workflow:result",
|
|
@@ -4553,10 +4995,10 @@ async function flowResumeCommand(runId, options = {}) {
|
|
|
4553
4995
|
});
|
|
4554
4996
|
return;
|
|
4555
4997
|
}
|
|
4556
|
-
console.log(` ${
|
|
4557
|
-
console.log(` ${
|
|
4998
|
+
console.log(` ${pc9.green("\u2713")} Resumed and completed successfully`);
|
|
4999
|
+
console.log(` ${pc9.dim(`Log: ${runner.getLogPath()}`)}`);
|
|
4558
5000
|
} catch (error2) {
|
|
4559
|
-
|
|
5001
|
+
spinner4.stop("Resume failed");
|
|
4560
5002
|
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
4561
5003
|
if (isAgentMode()) {
|
|
4562
5004
|
json({ event: "workflow:result", runId, status: "failed", error: errorMsg });
|
|
@@ -4566,7 +5008,7 @@ async function flowResumeCommand(runId, options = {}) {
|
|
|
4566
5008
|
}
|
|
4567
5009
|
}
|
|
4568
5010
|
async function flowRunsCommand(flowKey) {
|
|
4569
|
-
intro(
|
|
5011
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4570
5012
|
const runs = FlowRunner.listRuns(flowKey);
|
|
4571
5013
|
if (isAgentMode()) {
|
|
4572
5014
|
json({
|
|
@@ -4606,7 +5048,7 @@ async function flowRunsCommand(flowKey) {
|
|
|
4606
5048
|
console.log();
|
|
4607
5049
|
}
|
|
4608
5050
|
async function flowInspectCommand(runId, options = {}) {
|
|
4609
|
-
intro(
|
|
5051
|
+
intro(pc9.bgCyan(pc9.black(" One Workflow ")));
|
|
4610
5052
|
const state = FlowRunner.loadRunState(runId);
|
|
4611
5053
|
if (!state) {
|
|
4612
5054
|
const msg = `No run found for id "${runId}". List runs with: one flow runs`;
|
|
@@ -4635,44 +5077,44 @@ async function flowInspectCommand(runId, options = {}) {
|
|
|
4635
5077
|
return;
|
|
4636
5078
|
}
|
|
4637
5079
|
console.log();
|
|
4638
|
-
console.log(` ${
|
|
4639
|
-
console.log(` ${
|
|
4640
|
-
if (state.currentStepId) console.log(` ${
|
|
5080
|
+
console.log(` ${pc9.bold(state.flowKey)} ${pc9.dim(`run ${state.runId}`)} ${colorStatus(state.status)}`);
|
|
5081
|
+
console.log(` ${pc9.dim(`Started: ${state.startedAt}${state.completedAt ? ` \xB7 Ended: ${state.completedAt}` : ""}`)}`);
|
|
5082
|
+
if (state.currentStepId) console.log(` ${pc9.dim(`Current step: ${state.currentStepId}`)}`);
|
|
4641
5083
|
console.log();
|
|
4642
5084
|
if (stepEntries.length === 0) {
|
|
4643
5085
|
note("No step outputs recorded yet for this run.", "Steps");
|
|
4644
5086
|
} else {
|
|
4645
5087
|
for (const [id, result] of stepEntries) {
|
|
4646
|
-
const icon = result.status === "success" ?
|
|
4647
|
-
const dur = result.durationMs !== void 0 ?
|
|
4648
|
-
const retries = result.retries ?
|
|
4649
|
-
console.log(` ${icon} ${id} ${
|
|
5088
|
+
const icon = result.status === "success" ? pc9.green("\u2713") : result.status === "skipped" ? pc9.dim("\u25CB") : result.status === "timeout" ? pc9.yellow("\u29D6") : pc9.red("\u2717");
|
|
5089
|
+
const dur = result.durationMs !== void 0 ? pc9.dim(` ${result.durationMs}ms`) : "";
|
|
5090
|
+
const retries = result.retries ? pc9.dim(` (${result.retries} retr${result.retries === 1 ? "y" : "ies"})`) : "";
|
|
5091
|
+
console.log(` ${icon} ${id} ${pc9.dim(`[${result.status}]`)}${dur}${retries}`);
|
|
4650
5092
|
if (result.error) {
|
|
4651
|
-
console.log(` ${
|
|
5093
|
+
console.log(` ${pc9.red("error")} ${result.error}${result.errorCode ? pc9.dim(` (${result.errorCode})`) : ""}`);
|
|
4652
5094
|
}
|
|
4653
5095
|
if (result.output !== void 0) {
|
|
4654
5096
|
const json2 = JSON.stringify(result.output, null, options.full ? 2 : 0) ?? String(result.output);
|
|
4655
|
-
const shown = options.full || json2.length <= 240 ? json2 : `${json2.slice(0, 239)}\u2026 ${
|
|
4656
|
-
const indented = options.full ? shown.split("\n").map((l) => ` ${l}`).join("\n") : ` ${
|
|
5097
|
+
const shown = options.full || json2.length <= 240 ? json2 : `${json2.slice(0, 239)}\u2026 ${pc9.dim("(--full for all)")}`;
|
|
5098
|
+
const indented = options.full ? shown.split("\n").map((l) => ` ${l}`).join("\n") : ` ${pc9.dim("output")} ${shown}`;
|
|
4657
5099
|
console.log(indented);
|
|
4658
5100
|
}
|
|
4659
5101
|
}
|
|
4660
5102
|
}
|
|
4661
5103
|
console.log();
|
|
4662
|
-
console.log(` ${
|
|
4663
|
-
console.log(` ${
|
|
5104
|
+
console.log(` ${pc9.dim(`State: ${statePath}`)}`);
|
|
5105
|
+
console.log(` ${pc9.dim(`Log: ${path7.join(".one/flows/.logs", `${state.flowKey}-${state.runId}.log`)}`)}`);
|
|
4664
5106
|
console.log();
|
|
4665
5107
|
}
|
|
4666
5108
|
function colorStatus(status) {
|
|
4667
5109
|
switch (status) {
|
|
4668
5110
|
case "completed":
|
|
4669
|
-
return
|
|
5111
|
+
return pc9.green(status);
|
|
4670
5112
|
case "running":
|
|
4671
|
-
return
|
|
5113
|
+
return pc9.cyan(status);
|
|
4672
5114
|
case "paused":
|
|
4673
|
-
return
|
|
5115
|
+
return pc9.yellow(status);
|
|
4674
5116
|
case "failed":
|
|
4675
|
-
return
|
|
5117
|
+
return pc9.red(status);
|
|
4676
5118
|
default:
|
|
4677
5119
|
return status;
|
|
4678
5120
|
}
|
|
@@ -4850,7 +5292,7 @@ async function flowScaffoldCommand(template) {
|
|
|
4850
5292
|
}
|
|
4851
5293
|
|
|
4852
5294
|
// src/commands/relay.ts
|
|
4853
|
-
import
|
|
5295
|
+
import pc10 from "picocolors";
|
|
4854
5296
|
function getConfig3() {
|
|
4855
5297
|
const apiKey = getApiKey();
|
|
4856
5298
|
if (!apiKey) {
|
|
@@ -4873,8 +5315,8 @@ async function relayCreateCommand(options) {
|
|
|
4873
5315
|
error(`Connection key "${options.connectionKey}" is not allowed.`);
|
|
4874
5316
|
}
|
|
4875
5317
|
const api = new OneApi(apiKey, getApiBase());
|
|
4876
|
-
const
|
|
4877
|
-
|
|
5318
|
+
const spinner4 = createSpinner();
|
|
5319
|
+
spinner4.start("Creating relay endpoint...");
|
|
4878
5320
|
try {
|
|
4879
5321
|
const body = {
|
|
4880
5322
|
connectionKey: options.connectionKey
|
|
@@ -4889,29 +5331,29 @@ async function relayCreateCommand(options) {
|
|
|
4889
5331
|
json(result);
|
|
4890
5332
|
return;
|
|
4891
5333
|
}
|
|
4892
|
-
|
|
5334
|
+
spinner4.stop("Relay endpoint created");
|
|
4893
5335
|
console.log();
|
|
4894
|
-
console.log(` ${
|
|
4895
|
-
console.log(` ${
|
|
4896
|
-
console.log(` ${
|
|
4897
|
-
if (result.description) console.log(` ${
|
|
4898
|
-
if (result.eventFilters?.length) console.log(` ${
|
|
4899
|
-
if (result.webhookPayload?.id) console.log(` ${
|
|
5336
|
+
console.log(` ${pc10.dim("ID:")} ${result.id}`);
|
|
5337
|
+
console.log(` ${pc10.dim("URL:")} ${result.url}`);
|
|
5338
|
+
console.log(` ${pc10.dim("Active:")} ${result.active}`);
|
|
5339
|
+
if (result.description) console.log(` ${pc10.dim("Description:")} ${result.description}`);
|
|
5340
|
+
if (result.eventFilters?.length) console.log(` ${pc10.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
5341
|
+
if (result.webhookPayload?.id) console.log(` ${pc10.dim("Webhook ID:")} ${result.webhookPayload.id}`);
|
|
4900
5342
|
if (result.warning) {
|
|
4901
5343
|
console.log();
|
|
4902
|
-
console.log(` ${
|
|
5344
|
+
console.log(` ${pc10.yellow("\u26A0 Warning:")} ${result.warning}`);
|
|
4903
5345
|
}
|
|
4904
5346
|
console.log();
|
|
4905
5347
|
} catch (error2) {
|
|
4906
|
-
|
|
5348
|
+
spinner4.stop("Failed to create relay endpoint");
|
|
4907
5349
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
4908
5350
|
}
|
|
4909
5351
|
}
|
|
4910
5352
|
async function relayListCommand(options) {
|
|
4911
5353
|
const { apiKey } = getConfig3();
|
|
4912
5354
|
const api = new OneApi(apiKey, getApiBase());
|
|
4913
|
-
const
|
|
4914
|
-
|
|
5355
|
+
const spinner4 = createSpinner();
|
|
5356
|
+
spinner4.start("Loading relay endpoints...");
|
|
4915
5357
|
try {
|
|
4916
5358
|
const query = {};
|
|
4917
5359
|
if (options.limit) query.limit = options.limit;
|
|
@@ -4934,7 +5376,7 @@ async function relayListCommand(options) {
|
|
|
4934
5376
|
});
|
|
4935
5377
|
return;
|
|
4936
5378
|
}
|
|
4937
|
-
|
|
5379
|
+
spinner4.stop(`${endpoints.length} relay endpoint${endpoints.length === 1 ? "" : "s"} found`);
|
|
4938
5380
|
if (endpoints.length === 0) {
|
|
4939
5381
|
console.log("\n No relay endpoints yet.\n");
|
|
4940
5382
|
return;
|
|
@@ -4945,57 +5387,57 @@ async function relayListCommand(options) {
|
|
|
4945
5387
|
{ key: "description", label: "Description" },
|
|
4946
5388
|
{ key: "events", label: "Events" },
|
|
4947
5389
|
{ key: "actions", label: "Actions" },
|
|
4948
|
-
{ key: "id", label: "ID", color:
|
|
5390
|
+
{ key: "id", label: "ID", color: pc10.dim }
|
|
4949
5391
|
],
|
|
4950
5392
|
endpoints.map((e) => ({
|
|
4951
|
-
status: e.active ?
|
|
4952
|
-
description: e.description ||
|
|
4953
|
-
events: e.eventFilters?.join(", ") ||
|
|
5393
|
+
status: e.active ? pc10.green("\u25CF") : pc10.dim("\u25CB"),
|
|
5394
|
+
description: e.description || pc10.dim("(none)"),
|
|
5395
|
+
events: e.eventFilters?.join(", ") || pc10.dim("all"),
|
|
4954
5396
|
actions: String(e.actions?.length || 0),
|
|
4955
5397
|
id: e.id.slice(0, 8)
|
|
4956
5398
|
}))
|
|
4957
5399
|
);
|
|
4958
5400
|
} catch (error2) {
|
|
4959
|
-
|
|
5401
|
+
spinner4.stop("Failed to list relay endpoints");
|
|
4960
5402
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
4961
5403
|
}
|
|
4962
5404
|
}
|
|
4963
5405
|
async function relayGetCommand(id) {
|
|
4964
5406
|
const { apiKey } = getConfig3();
|
|
4965
5407
|
const api = new OneApi(apiKey, getApiBase());
|
|
4966
|
-
const
|
|
4967
|
-
|
|
5408
|
+
const spinner4 = createSpinner();
|
|
5409
|
+
spinner4.start("Loading relay endpoint...");
|
|
4968
5410
|
try {
|
|
4969
5411
|
const result = await api.getRelayEndpoint(id);
|
|
4970
5412
|
if (isAgentMode()) {
|
|
4971
5413
|
json(result);
|
|
4972
5414
|
return;
|
|
4973
5415
|
}
|
|
4974
|
-
|
|
5416
|
+
spinner4.stop("Relay endpoint loaded");
|
|
4975
5417
|
console.log();
|
|
4976
|
-
console.log(` ${
|
|
4977
|
-
console.log(` ${
|
|
4978
|
-
console.log(` ${
|
|
4979
|
-
if (result.description) console.log(` ${
|
|
4980
|
-
if (result.eventFilters?.length) console.log(` ${
|
|
4981
|
-
console.log(` ${
|
|
5418
|
+
console.log(` ${pc10.dim("ID:")} ${result.id}`);
|
|
5419
|
+
console.log(` ${pc10.dim("URL:")} ${result.url}`);
|
|
5420
|
+
console.log(` ${pc10.dim("Active:")} ${result.active}`);
|
|
5421
|
+
if (result.description) console.log(` ${pc10.dim("Description:")} ${result.description}`);
|
|
5422
|
+
if (result.eventFilters?.length) console.log(` ${pc10.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
5423
|
+
console.log(` ${pc10.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
4982
5424
|
if (result.actions?.length) {
|
|
4983
5425
|
for (const [i, action] of result.actions.entries()) {
|
|
4984
|
-
console.log(` ${
|
|
5426
|
+
console.log(` ${pc10.dim(`[${i}]`)} type=${action.type}${action.actionId ? ` actionId=${action.actionId}` : ""}${action.url ? ` url=${action.url}` : ""}`);
|
|
4985
5427
|
}
|
|
4986
5428
|
}
|
|
4987
|
-
console.log(` ${
|
|
5429
|
+
console.log(` ${pc10.dim("Created:")} ${result.createdAt}`);
|
|
4988
5430
|
console.log();
|
|
4989
5431
|
} catch (error2) {
|
|
4990
|
-
|
|
5432
|
+
spinner4.stop("Failed to load relay endpoint");
|
|
4991
5433
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
4992
5434
|
}
|
|
4993
5435
|
}
|
|
4994
5436
|
async function relayUpdateCommand(id, options) {
|
|
4995
5437
|
const { apiKey } = getConfig3();
|
|
4996
5438
|
const api = new OneApi(apiKey, getApiBase());
|
|
4997
|
-
const
|
|
4998
|
-
|
|
5439
|
+
const spinner4 = createSpinner();
|
|
5440
|
+
spinner4.start("Updating relay endpoint...");
|
|
4999
5441
|
try {
|
|
5000
5442
|
const body = {};
|
|
5001
5443
|
if (options.description !== void 0) body.description = options.description;
|
|
@@ -5008,40 +5450,40 @@ async function relayUpdateCommand(id, options) {
|
|
|
5008
5450
|
json(result);
|
|
5009
5451
|
return;
|
|
5010
5452
|
}
|
|
5011
|
-
|
|
5012
|
-
console.log(` ${
|
|
5013
|
-
console.log(` ${
|
|
5014
|
-
console.log(` ${
|
|
5453
|
+
spinner4.stop("Relay endpoint updated");
|
|
5454
|
+
console.log(` ${pc10.dim("ID:")} ${result.id}`);
|
|
5455
|
+
console.log(` ${pc10.dim("Active:")} ${result.active}`);
|
|
5456
|
+
console.log(` ${pc10.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
5015
5457
|
console.log();
|
|
5016
5458
|
} catch (error2) {
|
|
5017
|
-
|
|
5459
|
+
spinner4.stop("Failed to update relay endpoint");
|
|
5018
5460
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5019
5461
|
}
|
|
5020
5462
|
}
|
|
5021
5463
|
async function relayDeleteCommand(id) {
|
|
5022
5464
|
const { apiKey } = getConfig3();
|
|
5023
5465
|
const api = new OneApi(apiKey, getApiBase());
|
|
5024
|
-
const
|
|
5025
|
-
|
|
5466
|
+
const spinner4 = createSpinner();
|
|
5467
|
+
spinner4.start("Deleting relay endpoint...");
|
|
5026
5468
|
try {
|
|
5027
5469
|
const result = await api.deleteRelayEndpoint(id);
|
|
5028
5470
|
if (isAgentMode()) {
|
|
5029
5471
|
json({ deleted: true, id: result.id });
|
|
5030
5472
|
return;
|
|
5031
5473
|
}
|
|
5032
|
-
|
|
5474
|
+
spinner4.stop("Relay endpoint deleted");
|
|
5033
5475
|
console.log(` Deleted: ${result.id}`);
|
|
5034
5476
|
console.log();
|
|
5035
5477
|
} catch (error2) {
|
|
5036
|
-
|
|
5478
|
+
spinner4.stop("Failed to delete relay endpoint");
|
|
5037
5479
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5038
5480
|
}
|
|
5039
5481
|
}
|
|
5040
5482
|
async function relayActivateCommand(id, options) {
|
|
5041
5483
|
const { apiKey } = getConfig3();
|
|
5042
5484
|
const api = new OneApi(apiKey, getApiBase());
|
|
5043
|
-
const
|
|
5044
|
-
|
|
5485
|
+
const spinner4 = createSpinner();
|
|
5486
|
+
spinner4.start("Activating relay endpoint...");
|
|
5045
5487
|
try {
|
|
5046
5488
|
const actions2 = parseJsonArg3(options.actions, "--actions");
|
|
5047
5489
|
const body = { actions: actions2 };
|
|
@@ -5051,21 +5493,21 @@ async function relayActivateCommand(id, options) {
|
|
|
5051
5493
|
json(result);
|
|
5052
5494
|
return;
|
|
5053
5495
|
}
|
|
5054
|
-
|
|
5055
|
-
console.log(` ${
|
|
5056
|
-
console.log(` ${
|
|
5057
|
-
console.log(` ${
|
|
5496
|
+
spinner4.stop("Relay endpoint activated");
|
|
5497
|
+
console.log(` ${pc10.dim("ID:")} ${result.id}`);
|
|
5498
|
+
console.log(` ${pc10.dim("Active:")} ${result.active}`);
|
|
5499
|
+
console.log(` ${pc10.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
5058
5500
|
console.log();
|
|
5059
5501
|
} catch (error2) {
|
|
5060
|
-
|
|
5502
|
+
spinner4.stop("Failed to activate relay endpoint");
|
|
5061
5503
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5062
5504
|
}
|
|
5063
5505
|
}
|
|
5064
5506
|
async function relayEventsCommand(options) {
|
|
5065
5507
|
const { apiKey } = getConfig3();
|
|
5066
5508
|
const api = new OneApi(apiKey, getApiBase());
|
|
5067
|
-
const
|
|
5068
|
-
|
|
5509
|
+
const spinner4 = createSpinner();
|
|
5510
|
+
spinner4.start("Loading relay events...");
|
|
5069
5511
|
try {
|
|
5070
5512
|
const query = {};
|
|
5071
5513
|
if (options.limit) query.limit = options.limit;
|
|
@@ -5089,7 +5531,7 @@ async function relayEventsCommand(options) {
|
|
|
5089
5531
|
});
|
|
5090
5532
|
return;
|
|
5091
5533
|
}
|
|
5092
|
-
|
|
5534
|
+
spinner4.stop(`${events.length} event${events.length === 1 ? "" : "s"} found`);
|
|
5093
5535
|
if (events.length === 0) {
|
|
5094
5536
|
console.log("\n No events found.\n");
|
|
5095
5537
|
return;
|
|
@@ -5099,42 +5541,42 @@ async function relayEventsCommand(options) {
|
|
|
5099
5541
|
{ key: "platform", label: "Platform" },
|
|
5100
5542
|
{ key: "eventType", label: "Event Type" },
|
|
5101
5543
|
{ key: "timestamp", label: "Timestamp" },
|
|
5102
|
-
{ key: "id", label: "ID", color:
|
|
5544
|
+
{ key: "id", label: "ID", color: pc10.dim }
|
|
5103
5545
|
],
|
|
5104
5546
|
events.map((e) => ({
|
|
5105
5547
|
platform: e.platform,
|
|
5106
|
-
eventType: e.eventType ||
|
|
5548
|
+
eventType: e.eventType || pc10.dim("unknown"),
|
|
5107
5549
|
timestamp: e.timestamp || e.createdAt,
|
|
5108
5550
|
id: e.id.slice(0, 8)
|
|
5109
5551
|
}))
|
|
5110
5552
|
);
|
|
5111
5553
|
} catch (error2) {
|
|
5112
|
-
|
|
5554
|
+
spinner4.stop("Failed to list relay events");
|
|
5113
5555
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5114
5556
|
}
|
|
5115
5557
|
}
|
|
5116
5558
|
async function relayEventGetCommand(id) {
|
|
5117
5559
|
const { apiKey } = getConfig3();
|
|
5118
5560
|
const api = new OneApi(apiKey, getApiBase());
|
|
5119
|
-
const
|
|
5120
|
-
|
|
5561
|
+
const spinner4 = createSpinner();
|
|
5562
|
+
spinner4.start("Loading relay event...");
|
|
5121
5563
|
try {
|
|
5122
5564
|
const result = await api.getRelayEvent(id);
|
|
5123
5565
|
if (isAgentMode()) {
|
|
5124
5566
|
json(result);
|
|
5125
5567
|
return;
|
|
5126
5568
|
}
|
|
5127
|
-
|
|
5569
|
+
spinner4.stop("Relay event loaded");
|
|
5128
5570
|
console.log();
|
|
5129
|
-
console.log(` ${
|
|
5130
|
-
console.log(` ${
|
|
5131
|
-
console.log(` ${
|
|
5132
|
-
console.log(` ${
|
|
5133
|
-
console.log(` ${
|
|
5571
|
+
console.log(` ${pc10.dim("ID:")} ${result.id}`);
|
|
5572
|
+
console.log(` ${pc10.dim("Platform:")} ${result.platform}`);
|
|
5573
|
+
console.log(` ${pc10.dim("Event:")} ${result.eventType}`);
|
|
5574
|
+
console.log(` ${pc10.dim("Timestamp:")} ${result.timestamp || result.createdAt}`);
|
|
5575
|
+
console.log(` ${pc10.dim("Payload:")}`);
|
|
5134
5576
|
console.log(JSON.stringify(result.payload, null, 2));
|
|
5135
5577
|
console.log();
|
|
5136
5578
|
} catch (error2) {
|
|
5137
|
-
|
|
5579
|
+
spinner4.stop("Failed to load relay event");
|
|
5138
5580
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5139
5581
|
}
|
|
5140
5582
|
}
|
|
@@ -5144,8 +5586,8 @@ async function relayDeliveriesCommand(options) {
|
|
|
5144
5586
|
}
|
|
5145
5587
|
const { apiKey } = getConfig3();
|
|
5146
5588
|
const api = new OneApi(apiKey, getApiBase());
|
|
5147
|
-
const
|
|
5148
|
-
|
|
5589
|
+
const spinner4 = createSpinner();
|
|
5590
|
+
spinner4.start("Loading deliveries...");
|
|
5149
5591
|
try {
|
|
5150
5592
|
const deliveries = options.endpointId ? await api.listRelayEndpointDeliveries(options.endpointId) : await api.listRelayEventDeliveries(options.eventId);
|
|
5151
5593
|
const items = Array.isArray(deliveries) ? deliveries : deliveries.rows || [];
|
|
@@ -5153,7 +5595,7 @@ async function relayDeliveriesCommand(options) {
|
|
|
5153
5595
|
json({ deliveries: items });
|
|
5154
5596
|
return;
|
|
5155
5597
|
}
|
|
5156
|
-
|
|
5598
|
+
spinner4.stop(`${items.length} deliver${items.length === 1 ? "y" : "ies"} found`);
|
|
5157
5599
|
if (items.length === 0) {
|
|
5158
5600
|
console.log("\n No deliveries found.\n");
|
|
5159
5601
|
return;
|
|
@@ -5167,30 +5609,30 @@ async function relayDeliveriesCommand(options) {
|
|
|
5167
5609
|
{ key: "error", label: "Error" }
|
|
5168
5610
|
],
|
|
5169
5611
|
items.map((d) => ({
|
|
5170
|
-
status: d.status === "success" ?
|
|
5171
|
-
code: d.statusCode != null ? String(d.statusCode) :
|
|
5612
|
+
status: d.status === "success" ? pc10.green(d.status) : pc10.red(d.status),
|
|
5613
|
+
code: d.statusCode != null ? String(d.statusCode) : pc10.dim("-"),
|
|
5172
5614
|
attempt: String(d.attempt),
|
|
5173
|
-
deliveredAt: d.deliveredAt ||
|
|
5174
|
-
error: d.error ?
|
|
5615
|
+
deliveredAt: d.deliveredAt || pc10.dim("-"),
|
|
5616
|
+
error: d.error ? pc10.red(d.error.slice(0, 50)) : pc10.dim("-")
|
|
5175
5617
|
}))
|
|
5176
5618
|
);
|
|
5177
5619
|
} catch (error2) {
|
|
5178
|
-
|
|
5620
|
+
spinner4.stop("Failed to load deliveries");
|
|
5179
5621
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5180
5622
|
}
|
|
5181
5623
|
}
|
|
5182
5624
|
async function relayPlatformsCommand() {
|
|
5183
5625
|
const { apiKey } = getConfig3();
|
|
5184
5626
|
const api = new OneApi(apiKey, getApiBase());
|
|
5185
|
-
const
|
|
5186
|
-
|
|
5627
|
+
const spinner4 = createSpinner();
|
|
5628
|
+
spinner4.start("Loading relay-capable platforms...");
|
|
5187
5629
|
try {
|
|
5188
5630
|
const platforms = await api.listRelayPlatforms();
|
|
5189
5631
|
if (isAgentMode()) {
|
|
5190
5632
|
json({ platforms });
|
|
5191
5633
|
return;
|
|
5192
5634
|
}
|
|
5193
|
-
|
|
5635
|
+
spinner4.stop(`${platforms.length} relay-capable platform${platforms.length === 1 ? "" : "s"} found`);
|
|
5194
5636
|
if (platforms.length === 0) {
|
|
5195
5637
|
console.log("\n No relay-capable platforms available.\n");
|
|
5196
5638
|
return;
|
|
@@ -5199,34 +5641,34 @@ async function relayPlatformsCommand() {
|
|
|
5199
5641
|
printTable(
|
|
5200
5642
|
[
|
|
5201
5643
|
{ key: "platform", label: "Platform" },
|
|
5202
|
-
{ key: "eventTypeCount", label: "Event types", color:
|
|
5644
|
+
{ key: "eventTypeCount", label: "Event types", color: pc10.dim }
|
|
5203
5645
|
],
|
|
5204
5646
|
platforms.map((p10) => ({ platform: p10.platform, eventTypeCount: String(p10.eventTypeCount) }))
|
|
5205
5647
|
);
|
|
5206
5648
|
console.log();
|
|
5207
5649
|
console.log(
|
|
5208
|
-
|
|
5209
|
-
` Run ${
|
|
5650
|
+
pc10.dim(
|
|
5651
|
+
` Run ${pc10.cyan("one relay event-types <platform>")} to see the full event list for a platform.
|
|
5210
5652
|
`
|
|
5211
5653
|
)
|
|
5212
5654
|
);
|
|
5213
5655
|
} catch (error2) {
|
|
5214
|
-
|
|
5656
|
+
spinner4.stop("Failed to load relay platforms");
|
|
5215
5657
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5216
5658
|
}
|
|
5217
5659
|
}
|
|
5218
5660
|
async function relayEventTypesCommand(platform) {
|
|
5219
5661
|
const { apiKey } = getConfig3();
|
|
5220
5662
|
const api = new OneApi(apiKey, getApiBase());
|
|
5221
|
-
const
|
|
5222
|
-
|
|
5663
|
+
const spinner4 = createSpinner();
|
|
5664
|
+
spinner4.start(`Loading event types for ${pc10.cyan(platform)}...`);
|
|
5223
5665
|
try {
|
|
5224
5666
|
const eventTypes = await api.listRelayEventTypes(platform);
|
|
5225
5667
|
if (isAgentMode()) {
|
|
5226
5668
|
json({ platform, eventTypes });
|
|
5227
5669
|
return;
|
|
5228
5670
|
}
|
|
5229
|
-
|
|
5671
|
+
spinner4.stop(`${eventTypes.length} event type${eventTypes.length === 1 ? "" : "s"} found`);
|
|
5230
5672
|
if (eventTypes.length === 0) {
|
|
5231
5673
|
console.log(`
|
|
5232
5674
|
No event types found for ${platform}.
|
|
@@ -5239,7 +5681,7 @@ async function relayEventTypesCommand(platform) {
|
|
|
5239
5681
|
}
|
|
5240
5682
|
console.log();
|
|
5241
5683
|
} catch (error2) {
|
|
5242
|
-
|
|
5684
|
+
spinner4.stop("Failed to load event types");
|
|
5243
5685
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
5244
5686
|
}
|
|
5245
5687
|
}
|
|
@@ -5365,11 +5807,11 @@ function handleId(response, config2, records) {
|
|
|
5365
5807
|
}
|
|
5366
5808
|
|
|
5367
5809
|
// src/lib/memory/sync/state.ts
|
|
5368
|
-
import
|
|
5369
|
-
import
|
|
5370
|
-
var SYNC_DIR =
|
|
5371
|
-
var STATE_DIR =
|
|
5372
|
-
var LEGACY_SINGLE_FILE =
|
|
5810
|
+
import fs7 from "fs";
|
|
5811
|
+
import path8 from "path";
|
|
5812
|
+
var SYNC_DIR = path8.join(".one", "sync");
|
|
5813
|
+
var STATE_DIR = path8.join(SYNC_DIR, "state");
|
|
5814
|
+
var LEGACY_SINGLE_FILE = path8.join(SYNC_DIR, "sync_state.json");
|
|
5373
5815
|
var legacyMigrationDone = false;
|
|
5374
5816
|
function rowToState(row) {
|
|
5375
5817
|
return {
|
|
@@ -5397,9 +5839,9 @@ function stateToRow(platform, model, state, lastError) {
|
|
|
5397
5839
|
async function migrateLegacyOnce() {
|
|
5398
5840
|
if (legacyMigrationDone) return;
|
|
5399
5841
|
legacyMigrationDone = true;
|
|
5400
|
-
if (
|
|
5842
|
+
if (fs7.existsSync(LEGACY_SINGLE_FILE)) {
|
|
5401
5843
|
try {
|
|
5402
|
-
const raw =
|
|
5844
|
+
const raw = fs7.readFileSync(LEGACY_SINGLE_FILE, "utf-8");
|
|
5403
5845
|
const legacy = JSON.parse(raw);
|
|
5404
5846
|
const backend = await getBackend();
|
|
5405
5847
|
for (const [platform, models] of Object.entries(legacy)) {
|
|
@@ -5409,32 +5851,32 @@ async function migrateLegacyOnce() {
|
|
|
5409
5851
|
await backend.setSyncState(stateToRow(platform, model, modelState));
|
|
5410
5852
|
}
|
|
5411
5853
|
}
|
|
5412
|
-
|
|
5854
|
+
fs7.unlinkSync(LEGACY_SINGLE_FILE);
|
|
5413
5855
|
} catch {
|
|
5414
5856
|
try {
|
|
5415
|
-
|
|
5857
|
+
fs7.unlinkSync(LEGACY_SINGLE_FILE);
|
|
5416
5858
|
} catch {
|
|
5417
5859
|
}
|
|
5418
5860
|
}
|
|
5419
5861
|
}
|
|
5420
|
-
if (
|
|
5862
|
+
if (fs7.existsSync(STATE_DIR)) {
|
|
5421
5863
|
try {
|
|
5422
5864
|
const backend = await getBackend();
|
|
5423
|
-
const platforms =
|
|
5865
|
+
const platforms = fs7.readdirSync(STATE_DIR);
|
|
5424
5866
|
for (const platform of platforms) {
|
|
5425
|
-
const platformDir =
|
|
5867
|
+
const platformDir = path8.join(STATE_DIR, platform);
|
|
5426
5868
|
let entries;
|
|
5427
5869
|
try {
|
|
5428
|
-
entries =
|
|
5870
|
+
entries = fs7.readdirSync(platformDir);
|
|
5429
5871
|
} catch {
|
|
5430
5872
|
continue;
|
|
5431
5873
|
}
|
|
5432
5874
|
for (const entry of entries) {
|
|
5433
5875
|
if (!entry.endsWith(".json")) continue;
|
|
5434
5876
|
const model = entry.slice(0, -".json".length);
|
|
5435
|
-
const filePath =
|
|
5877
|
+
const filePath = path8.join(platformDir, entry);
|
|
5436
5878
|
try {
|
|
5437
|
-
const raw =
|
|
5879
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
5438
5880
|
const modelState = JSON.parse(raw);
|
|
5439
5881
|
const existing = await backend.getSyncState(platform, model);
|
|
5440
5882
|
if (!existing) {
|
|
@@ -5444,7 +5886,7 @@ async function migrateLegacyOnce() {
|
|
|
5444
5886
|
}
|
|
5445
5887
|
}
|
|
5446
5888
|
}
|
|
5447
|
-
|
|
5889
|
+
fs7.rmSync(STATE_DIR, { recursive: true, force: true });
|
|
5448
5890
|
} catch {
|
|
5449
5891
|
}
|
|
5450
5892
|
}
|
|
@@ -5488,12 +5930,12 @@ async function removeModelState(platform, model) {
|
|
|
5488
5930
|
}
|
|
5489
5931
|
|
|
5490
5932
|
// src/lib/memory/sync/lock.ts
|
|
5491
|
-
import
|
|
5492
|
-
import
|
|
5493
|
-
var LOCK_DIR_REL =
|
|
5933
|
+
import fs8 from "fs";
|
|
5934
|
+
import path9 from "path";
|
|
5935
|
+
var LOCK_DIR_REL = path9.join(".one", "sync", "locks");
|
|
5494
5936
|
var STALE_MS = 30 * 60 * 1e3;
|
|
5495
5937
|
function lockPath(platform, model) {
|
|
5496
|
-
return
|
|
5938
|
+
return path9.join(LOCK_DIR_REL, `${platform}_${model}`);
|
|
5497
5939
|
}
|
|
5498
5940
|
function isProcessAlive(pid) {
|
|
5499
5941
|
try {
|
|
@@ -5510,15 +5952,15 @@ var SyncLockError = class extends Error {
|
|
|
5510
5952
|
}
|
|
5511
5953
|
};
|
|
5512
5954
|
function acquireSyncLock(platform, model) {
|
|
5513
|
-
|
|
5955
|
+
fs8.mkdirSync(LOCK_DIR_REL, { recursive: true });
|
|
5514
5956
|
const dir = lockPath(platform, model);
|
|
5515
|
-
const pidFile =
|
|
5957
|
+
const pidFile = path9.join(dir, "pid");
|
|
5516
5958
|
try {
|
|
5517
|
-
|
|
5959
|
+
fs8.mkdirSync(dir);
|
|
5518
5960
|
} catch (err) {
|
|
5519
5961
|
const stat = (() => {
|
|
5520
5962
|
try {
|
|
5521
|
-
return
|
|
5963
|
+
return fs8.statSync(dir);
|
|
5522
5964
|
} catch {
|
|
5523
5965
|
return null;
|
|
5524
5966
|
}
|
|
@@ -5527,7 +5969,7 @@ function acquireSyncLock(platform, model) {
|
|
|
5527
5969
|
const age = Date.now() - stat.mtimeMs;
|
|
5528
5970
|
let ownerPid = null;
|
|
5529
5971
|
try {
|
|
5530
|
-
const raw =
|
|
5972
|
+
const raw = fs8.readFileSync(pidFile, "utf-8");
|
|
5531
5973
|
const parsed = parseInt(raw.trim(), 10);
|
|
5532
5974
|
if (!isNaN(parsed)) ownerPid = parsed;
|
|
5533
5975
|
} catch {
|
|
@@ -5536,8 +5978,8 @@ function acquireSyncLock(platform, model) {
|
|
|
5536
5978
|
const veryOld = age > STALE_MS;
|
|
5537
5979
|
if (ownerDead || veryOld) {
|
|
5538
5980
|
try {
|
|
5539
|
-
|
|
5540
|
-
|
|
5981
|
+
fs8.rmSync(dir, { recursive: true, force: true });
|
|
5982
|
+
fs8.mkdirSync(dir);
|
|
5541
5983
|
} catch {
|
|
5542
5984
|
throw new SyncLockError(
|
|
5543
5985
|
`Could not take over stale lock at ${dir}. Remove it manually if no sync is running.`
|
|
@@ -5554,13 +5996,13 @@ function acquireSyncLock(platform, model) {
|
|
|
5554
5996
|
}
|
|
5555
5997
|
}
|
|
5556
5998
|
try {
|
|
5557
|
-
|
|
5999
|
+
fs8.writeFileSync(pidFile, String(process.pid));
|
|
5558
6000
|
} catch {
|
|
5559
6001
|
}
|
|
5560
6002
|
return {
|
|
5561
6003
|
release() {
|
|
5562
6004
|
try {
|
|
5563
|
-
|
|
6005
|
+
fs8.rmSync(dir, { recursive: true, force: true });
|
|
5564
6006
|
} catch {
|
|
5565
6007
|
}
|
|
5566
6008
|
}
|
|
@@ -5569,9 +6011,9 @@ function acquireSyncLock(platform, model) {
|
|
|
5569
6011
|
|
|
5570
6012
|
// src/lib/memory/sync/hooks.ts
|
|
5571
6013
|
import { spawn as spawn2 } from "child_process";
|
|
5572
|
-
import
|
|
5573
|
-
import
|
|
5574
|
-
var EVENTS_DIR =
|
|
6014
|
+
import fs9 from "fs";
|
|
6015
|
+
import path10 from "path";
|
|
6016
|
+
var EVENTS_DIR = path10.join(".one", "sync", "events");
|
|
5575
6017
|
function classifyRecords(db, model, records, idField, tableExists2) {
|
|
5576
6018
|
if (!tableExists2 || records.length === 0) {
|
|
5577
6019
|
return { inserts: records, updates: [] };
|
|
@@ -5617,10 +6059,10 @@ async function fireHooks(hookCommand, events) {
|
|
|
5617
6059
|
function appendEventLog(events) {
|
|
5618
6060
|
if (events.length === 0) return;
|
|
5619
6061
|
const { platform, model } = events[0];
|
|
5620
|
-
|
|
5621
|
-
const logPath =
|
|
6062
|
+
fs9.mkdirSync(EVENTS_DIR, { recursive: true });
|
|
6063
|
+
const logPath = path10.join(EVENTS_DIR, `${platform}_${model}.jsonl`);
|
|
5622
6064
|
const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
5623
|
-
|
|
6065
|
+
fs9.appendFileSync(logPath, lines);
|
|
5624
6066
|
}
|
|
5625
6067
|
function runShellHook(command, events) {
|
|
5626
6068
|
return new Promise((resolve) => {
|
|
@@ -5724,8 +6166,8 @@ function sleep(ms) {
|
|
|
5724
6166
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5725
6167
|
}
|
|
5726
6168
|
function interpolate(template, record) {
|
|
5727
|
-
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_,
|
|
5728
|
-
const parts =
|
|
6169
|
+
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_, path14) => {
|
|
6170
|
+
const parts = path14.split(".");
|
|
5729
6171
|
let value = record;
|
|
5730
6172
|
for (const part of parts) {
|
|
5731
6173
|
if (typeof value !== "object" || value === null) return "";
|
|
@@ -5753,8 +6195,8 @@ function deepMerge(target, source) {
|
|
|
5753
6195
|
}
|
|
5754
6196
|
return result;
|
|
5755
6197
|
}
|
|
5756
|
-
function getByDotPath2(obj,
|
|
5757
|
-
const parts =
|
|
6198
|
+
function getByDotPath2(obj, path14) {
|
|
6199
|
+
const parts = path14.split(".");
|
|
5758
6200
|
let current = obj;
|
|
5759
6201
|
for (const part of parts) {
|
|
5760
6202
|
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
@@ -5763,8 +6205,8 @@ function getByDotPath2(obj, path13) {
|
|
|
5763
6205
|
return current;
|
|
5764
6206
|
}
|
|
5765
6207
|
function stripExcludedFields(obj, paths) {
|
|
5766
|
-
for (const
|
|
5767
|
-
stripOnePath(obj,
|
|
6208
|
+
for (const path14 of paths) {
|
|
6209
|
+
stripOnePath(obj, path14.replace(/\[\]/g, ".*").split("."));
|
|
5768
6210
|
}
|
|
5769
6211
|
}
|
|
5770
6212
|
function stripOnePath(obj, parts) {
|
|
@@ -6185,8 +6627,8 @@ function sleep2(ms) {
|
|
|
6185
6627
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6186
6628
|
}
|
|
6187
6629
|
function stripFields(record, paths) {
|
|
6188
|
-
for (const
|
|
6189
|
-
stripOnePath2(record,
|
|
6630
|
+
for (const path14 of paths) {
|
|
6631
|
+
stripOnePath2(record, path14.split("."));
|
|
6190
6632
|
}
|
|
6191
6633
|
}
|
|
6192
6634
|
function stripOnePath2(obj, parts) {
|
|
@@ -6276,7 +6718,7 @@ async function syncModel(api, profile, options) {
|
|
|
6276
6718
|
updateModelState(platform, model, { status: "failed", pagesProcessed, lastCursor }),
|
|
6277
6719
|
(async () => {
|
|
6278
6720
|
try {
|
|
6279
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
6721
|
+
const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
|
|
6280
6722
|
const backend = await getBackend2();
|
|
6281
6723
|
await Promise.race([
|
|
6282
6724
|
backend.close(),
|
|
@@ -6642,7 +7084,7 @@ async function syncModel(api, profile, options) {
|
|
|
6642
7084
|
db.exec(`DROP TABLE IF EXISTS _seen_ids`);
|
|
6643
7085
|
}
|
|
6644
7086
|
if (options.toMemory !== false) {
|
|
6645
|
-
const backend = await (await import("./runtime-
|
|
7087
|
+
const backend = await (await import("./runtime-65IPTPVD.js")).getBackend();
|
|
6646
7088
|
const type = `${platform}/${model}`;
|
|
6647
7089
|
const existing = await backend.listKeysByType(type);
|
|
6648
7090
|
const sourcePrefix = `${type}:`;
|
|
@@ -6743,7 +7185,7 @@ async function syncModel(api, profile, options) {
|
|
|
6743
7185
|
let statusCounts;
|
|
6744
7186
|
if (options.toMemory !== false) {
|
|
6745
7187
|
try {
|
|
6746
|
-
const backend = await (await import("./runtime-
|
|
7188
|
+
const backend = await (await import("./runtime-65IPTPVD.js")).getBackend();
|
|
6747
7189
|
const typeName = `${platform}/${model}`;
|
|
6748
7190
|
const [active, archived] = await Promise.all([
|
|
6749
7191
|
backend.count(typeName, { status: "active" }),
|
|
@@ -7279,19 +7721,19 @@ function inferProfileFromKnowledge(knowledge, modelName, platform) {
|
|
|
7279
7721
|
|
|
7280
7722
|
// src/lib/memory/sync/schedule.ts
|
|
7281
7723
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7282
|
-
import
|
|
7283
|
-
import
|
|
7284
|
-
import
|
|
7724
|
+
import fs11 from "fs";
|
|
7725
|
+
import os2 from "os";
|
|
7726
|
+
import path12 from "path";
|
|
7285
7727
|
|
|
7286
7728
|
// src/lib/memory/sync/schedule-registry.ts
|
|
7287
|
-
import
|
|
7288
|
-
import
|
|
7289
|
-
var REGISTRY_DIR = () =>
|
|
7290
|
-
var REGISTRY_FILE = () =>
|
|
7729
|
+
import fs10 from "fs";
|
|
7730
|
+
import path11 from "path";
|
|
7731
|
+
var REGISTRY_DIR = () => path11.join(homeDir(), ".one", "sync");
|
|
7732
|
+
var REGISTRY_FILE = () => path11.join(REGISTRY_DIR(), "schedules.json");
|
|
7291
7733
|
function readRaw() {
|
|
7292
7734
|
try {
|
|
7293
|
-
if (!
|
|
7294
|
-
const raw =
|
|
7735
|
+
if (!fs10.existsSync(REGISTRY_FILE())) return { schedules: [] };
|
|
7736
|
+
const raw = fs10.readFileSync(REGISTRY_FILE(), "utf-8");
|
|
7295
7737
|
const parsed = JSON.parse(raw);
|
|
7296
7738
|
if (!parsed || !Array.isArray(parsed.schedules)) return { schedules: [] };
|
|
7297
7739
|
return parsed;
|
|
@@ -7300,13 +7742,13 @@ function readRaw() {
|
|
|
7300
7742
|
}
|
|
7301
7743
|
}
|
|
7302
7744
|
function writeRaw(file) {
|
|
7303
|
-
|
|
7745
|
+
fs10.mkdirSync(REGISTRY_DIR(), { recursive: true });
|
|
7304
7746
|
const tmp = REGISTRY_FILE() + ".tmp";
|
|
7305
|
-
|
|
7306
|
-
|
|
7747
|
+
fs10.writeFileSync(tmp, JSON.stringify(file, null, 2));
|
|
7748
|
+
fs10.renameSync(tmp, REGISTRY_FILE());
|
|
7307
7749
|
}
|
|
7308
7750
|
function makeScheduleId(platform, cwd) {
|
|
7309
|
-
const slug =
|
|
7751
|
+
const slug = path11.basename(cwd).replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
|
|
7310
7752
|
return `${platform}-${slug}`;
|
|
7311
7753
|
}
|
|
7312
7754
|
function listRegistered() {
|
|
@@ -7340,7 +7782,7 @@ function removeRegistered(id) {
|
|
|
7340
7782
|
|
|
7341
7783
|
// src/lib/memory/sync/schedule.ts
|
|
7342
7784
|
var MARKER = "# one-sync";
|
|
7343
|
-
var LOG_DIR_REL =
|
|
7785
|
+
var LOG_DIR_REL = path12.join(".one", "sync", "logs");
|
|
7344
7786
|
function durationToCron(every) {
|
|
7345
7787
|
const match = every.match(/^(\d+)([mhd])$/);
|
|
7346
7788
|
if (!match) return null;
|
|
@@ -7373,13 +7815,13 @@ function cronExprToDuration(expr) {
|
|
|
7373
7815
|
return null;
|
|
7374
7816
|
}
|
|
7375
7817
|
function isWindows() {
|
|
7376
|
-
return
|
|
7818
|
+
return os2.platform() === "win32";
|
|
7377
7819
|
}
|
|
7378
7820
|
function resolveOneBinary() {
|
|
7379
7821
|
try {
|
|
7380
7822
|
const entry = process.argv[1];
|
|
7381
|
-
if (entry &&
|
|
7382
|
-
return
|
|
7823
|
+
if (entry && fs11.existsSync(entry)) {
|
|
7824
|
+
return fs11.realpathSync(entry);
|
|
7383
7825
|
}
|
|
7384
7826
|
} catch {
|
|
7385
7827
|
}
|
|
@@ -7457,7 +7899,7 @@ function migrateLegacyCronEntries() {
|
|
|
7457
7899
|
const modelsMatch = command.match(/--models\s+(\S+)/);
|
|
7458
7900
|
const models = modelsMatch ? modelsMatch[1].split(",") : void 0;
|
|
7459
7901
|
const logMatch = command.match(/>>\s+"([^"]+)"/);
|
|
7460
|
-
const logFile = logMatch ? logMatch[1] :
|
|
7902
|
+
const logFile = logMatch ? logMatch[1] : path12.resolve(cwd, LOG_DIR_REL, `${platform}.log`);
|
|
7461
7903
|
const id = makeScheduleId(platform, cwd);
|
|
7462
7904
|
if (registeredIds.has(id)) continue;
|
|
7463
7905
|
upsertRegistered({
|
|
@@ -7491,9 +7933,9 @@ function addSchedule(opts) {
|
|
|
7491
7933
|
const cwd = process.cwd();
|
|
7492
7934
|
const id = makeScheduleId(opts.platform, cwd);
|
|
7493
7935
|
const replaced = getRegistered(id) !== void 0;
|
|
7494
|
-
const logDir =
|
|
7495
|
-
|
|
7496
|
-
const logFile =
|
|
7936
|
+
const logDir = path12.join(cwd, LOG_DIR_REL);
|
|
7937
|
+
fs11.mkdirSync(logDir, { recursive: true });
|
|
7938
|
+
const logFile = path12.join(logDir, `${opts.platform}.log`);
|
|
7497
7939
|
const entry = {
|
|
7498
7940
|
id,
|
|
7499
7941
|
platform: opts.platform,
|
|
@@ -7547,15 +7989,15 @@ function removeSchedule(idOrPlatform, options) {
|
|
|
7547
7989
|
function scheduleStatus() {
|
|
7548
7990
|
const entries = listSchedules();
|
|
7549
7991
|
return entries.map((entry) => {
|
|
7550
|
-
const logExists =
|
|
7551
|
-
const logSize = logExists ?
|
|
7992
|
+
const logExists = fs11.existsSync(entry.logFile);
|
|
7993
|
+
const logSize = logExists ? fs11.statSync(entry.logFile).size : 0;
|
|
7552
7994
|
let logTail = [];
|
|
7553
7995
|
let lastRunAt = null;
|
|
7554
7996
|
if (logExists) {
|
|
7555
7997
|
try {
|
|
7556
|
-
lastRunAt =
|
|
7998
|
+
lastRunAt = fs11.statSync(entry.logFile).mtime.toISOString();
|
|
7557
7999
|
if (logSize > 0) {
|
|
7558
|
-
const content =
|
|
8000
|
+
const content = fs11.readFileSync(entry.logFile, "utf-8");
|
|
7559
8001
|
logTail = content.trim().split("\n").slice(-10);
|
|
7560
8002
|
}
|
|
7561
8003
|
} catch {
|
|
@@ -7563,8 +8005,8 @@ function scheduleStatus() {
|
|
|
7563
8005
|
}
|
|
7564
8006
|
let drift = "ok";
|
|
7565
8007
|
if (!entry.cronInstalled) drift = "missing-cron";
|
|
7566
|
-
else if (!
|
|
7567
|
-
else if (!
|
|
8008
|
+
else if (!fs11.existsSync(entry.nodeBin)) drift = "stale-node-bin";
|
|
8009
|
+
else if (!fs11.existsSync(entry.cliBin)) drift = "stale-cli-bin";
|
|
7568
8010
|
return { entry, logExists, logSize, logTail, lastRunAt, drift };
|
|
7569
8011
|
});
|
|
7570
8012
|
}
|
|
@@ -7837,11 +8279,11 @@ function isNoise(s) {
|
|
|
7837
8279
|
if (/^-?\d+(\.\d+)?([eE][-+]?\d+)?$/.test(s)) return true;
|
|
7838
8280
|
return false;
|
|
7839
8281
|
}
|
|
7840
|
-
function recordSample(stats,
|
|
7841
|
-
let s = stats.get(
|
|
8282
|
+
function recordSample(stats, path14, value, jsType, recordIndex, totalSamples) {
|
|
8283
|
+
let s = stats.get(path14);
|
|
7842
8284
|
if (!s) {
|
|
7843
8285
|
s = {
|
|
7844
|
-
path:
|
|
8286
|
+
path: path14,
|
|
7845
8287
|
total: totalSamples,
|
|
7846
8288
|
recordIndices: /* @__PURE__ */ new Set(),
|
|
7847
8289
|
lenSum: 0,
|
|
@@ -7850,7 +8292,7 @@ function recordSample(stats, path13, value, jsType, recordIndex, totalSamples) {
|
|
|
7850
8292
|
primaryType: jsType,
|
|
7851
8293
|
examples: []
|
|
7852
8294
|
};
|
|
7853
|
-
stats.set(
|
|
8295
|
+
stats.set(path14, s);
|
|
7854
8296
|
}
|
|
7855
8297
|
s.recordIndices.add(recordIndex);
|
|
7856
8298
|
s.lenSum += value.length;
|
|
@@ -7859,28 +8301,28 @@ function recordSample(stats, path13, value, jsType, recordIndex, totalSamples) {
|
|
|
7859
8301
|
if (s.primaryType !== jsType) s.primaryType = "mixed";
|
|
7860
8302
|
if (s.examples.length < 3 && value.length < 200) s.examples.push(value);
|
|
7861
8303
|
}
|
|
7862
|
-
function walkRecord(record,
|
|
8304
|
+
function walkRecord(record, path14, stats, recordIndex, totalSamples) {
|
|
7863
8305
|
if (record === null || record === void 0) return;
|
|
7864
8306
|
if (typeof record === "string") {
|
|
7865
8307
|
const trimmed = record.trim();
|
|
7866
|
-
if (trimmed) recordSample(stats,
|
|
8308
|
+
if (trimmed) recordSample(stats, path14, trimmed, "string", recordIndex, totalSamples);
|
|
7867
8309
|
return;
|
|
7868
8310
|
}
|
|
7869
8311
|
if (typeof record === "number" || typeof record === "boolean") {
|
|
7870
8312
|
const str = String(record);
|
|
7871
8313
|
const kind = typeof record === "number" ? "number" : "boolean";
|
|
7872
|
-
if (str) recordSample(stats,
|
|
8314
|
+
if (str) recordSample(stats, path14, str, kind, recordIndex, totalSamples);
|
|
7873
8315
|
return;
|
|
7874
8316
|
}
|
|
7875
8317
|
if (Array.isArray(record)) {
|
|
7876
|
-
const childPath =
|
|
8318
|
+
const childPath = path14 ? `${path14}[]` : "[]";
|
|
7877
8319
|
for (const item of record) walkRecord(item, childPath, stats, recordIndex, totalSamples);
|
|
7878
8320
|
return;
|
|
7879
8321
|
}
|
|
7880
8322
|
if (typeof record === "object") {
|
|
7881
8323
|
for (const [key, value] of Object.entries(record)) {
|
|
7882
8324
|
if (key.startsWith("_")) continue;
|
|
7883
|
-
const childPath =
|
|
8325
|
+
const childPath = path14 ? `${path14}.${key}` : key;
|
|
7884
8326
|
walkRecord(value, childPath, stats, recordIndex, totalSamples);
|
|
7885
8327
|
}
|
|
7886
8328
|
}
|
|
@@ -7918,7 +8360,7 @@ function suggestSearchablePaths(records, limit = 15) {
|
|
|
7918
8360
|
// src/lib/memory/sync/index.ts
|
|
7919
8361
|
import { spawn as spawn4 } from "child_process";
|
|
7920
8362
|
import * as p7 from "@clack/prompts";
|
|
7921
|
-
import
|
|
8363
|
+
import pc11 from "picocolors";
|
|
7922
8364
|
async function syncInstallCommand() {
|
|
7923
8365
|
if (await isSqliteAvailable()) {
|
|
7924
8366
|
if (isAgentMode()) {
|
|
@@ -7983,15 +8425,15 @@ async function syncDoctorCommand() {
|
|
|
7983
8425
|
return;
|
|
7984
8426
|
}
|
|
7985
8427
|
for (const c of checks) {
|
|
7986
|
-
const mark = c.ok ?
|
|
7987
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8428
|
+
const mark = c.ok ? pc11.green("\u2713") : pc11.red("\u2717");
|
|
8429
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc11.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
7988
8430
|
}
|
|
7989
8431
|
if (!allOk) {
|
|
7990
8432
|
console.log(`
|
|
7991
|
-
${
|
|
8433
|
+
${pc11.yellow("Sync is not ready.")} Try: ${pc11.bold("one sync install")}`);
|
|
7992
8434
|
} else {
|
|
7993
8435
|
console.log(`
|
|
7994
|
-
${
|
|
8436
|
+
${pc11.green("Sync is ready.")}`);
|
|
7995
8437
|
}
|
|
7996
8438
|
}
|
|
7997
8439
|
function getApi() {
|
|
@@ -8034,19 +8476,19 @@ async function syncProfilesCommand(platform) {
|
|
|
8034
8476
|
if (p10.enrich) extras.push("enrich");
|
|
8035
8477
|
if (p10.identityKey || p10.identityKeys) extras.push("identity");
|
|
8036
8478
|
if (p10.dateFilter) extras.push("incremental");
|
|
8037
|
-
const tags = extras.length > 0 ? ` ${
|
|
8038
|
-
console.log(` ${
|
|
8479
|
+
const tags = extras.length > 0 ? ` ${pc11.dim(`[${extras.join(", ")}]`)}` : "";
|
|
8480
|
+
console.log(` ${pc11.bold(`${p10.platform}/${p10.model}`.padEnd(35))} ${p10.description}${tags}`);
|
|
8039
8481
|
}
|
|
8040
8482
|
console.log(`
|
|
8041
|
-
${profiles.length} built-in profile(s). Run ${
|
|
8483
|
+
${profiles.length} built-in profile(s). Run ${pc11.bold("one sync init <platform> <model>")} to use one.`);
|
|
8042
8484
|
}
|
|
8043
8485
|
async function syncModelsCommand(platform) {
|
|
8044
8486
|
const api = getApi();
|
|
8045
|
-
const
|
|
8046
|
-
|
|
8487
|
+
const spinner4 = createSpinner();
|
|
8488
|
+
spinner4.start(`Discovering models for ${platform}...`);
|
|
8047
8489
|
try {
|
|
8048
8490
|
const models = await discoverModels(api, platform);
|
|
8049
|
-
|
|
8491
|
+
spinner4.stop(`Found ${models.length} models`);
|
|
8050
8492
|
if (isAgentMode()) {
|
|
8051
8493
|
json({ platform, models, total: models.length });
|
|
8052
8494
|
return;
|
|
@@ -8056,19 +8498,19 @@ async function syncModelsCommand(platform) {
|
|
|
8056
8498
|
return;
|
|
8057
8499
|
}
|
|
8058
8500
|
const lines = models.map(
|
|
8059
|
-
(m) => ` ${
|
|
8501
|
+
(m) => ` ${pc11.bold(m.name.padEnd(30))} ${pc11.dim(m.listAction.method)} ${pc11.dim(m.listAction.path)}`
|
|
8060
8502
|
);
|
|
8061
8503
|
note(lines.join("\n"), `${platform} \u2014 ${models.length} models`);
|
|
8062
8504
|
} catch (err) {
|
|
8063
|
-
|
|
8505
|
+
spinner4.stop("Failed");
|
|
8064
8506
|
error(`Error discovering models: ${err instanceof Error ? err.message : String(err)}`);
|
|
8065
8507
|
}
|
|
8066
8508
|
}
|
|
8067
8509
|
async function syncInitCommand(platform, model, options) {
|
|
8068
8510
|
if (!options.config) {
|
|
8069
8511
|
const api = getApi();
|
|
8070
|
-
const
|
|
8071
|
-
|
|
8512
|
+
const spinner4 = createSpinner();
|
|
8513
|
+
spinner4.start(`Looking up ${platform}/${model}...`);
|
|
8072
8514
|
try {
|
|
8073
8515
|
const models = await discoverModels(api, platform);
|
|
8074
8516
|
const match = models.find((m) => m.name === model || m.name.toLowerCase() === model.toLowerCase());
|
|
@@ -8078,9 +8520,9 @@ async function syncInitCommand(platform, model, options) {
|
|
|
8078
8520
|
if (actionId && !actionId.startsWith("conn_mod_def::")) {
|
|
8079
8521
|
actionId = void 0;
|
|
8080
8522
|
}
|
|
8081
|
-
|
|
8523
|
+
spinner4.stop(actionId ? "Found model + action ID" : "Found model (action ID not resolved)");
|
|
8082
8524
|
} else {
|
|
8083
|
-
|
|
8525
|
+
spinner4.stop("Model not found in available actions");
|
|
8084
8526
|
}
|
|
8085
8527
|
const builtin = loadBuiltinProfile(platform, model);
|
|
8086
8528
|
let template;
|
|
@@ -8160,15 +8602,15 @@ async function syncInitCommand(platform, model, options) {
|
|
|
8160
8602
|
note(JSON.stringify(template, null, 2), "Sync profile template");
|
|
8161
8603
|
if (inferred && inferred.reasoning.length > 0) {
|
|
8162
8604
|
console.log(`
|
|
8163
|
-
${
|
|
8164
|
-
for (const r of inferred.reasoning) console.log(` ${
|
|
8605
|
+
${pc11.bold("Inferred from knowledge:")}`);
|
|
8606
|
+
for (const r of inferred.reasoning) console.log(` ${pc11.dim("\u2022")} ${r}`);
|
|
8165
8607
|
}
|
|
8166
8608
|
if (testReport) {
|
|
8167
8609
|
console.log(`
|
|
8168
|
-
${
|
|
8610
|
+
${pc11.bold("Test results:")}`);
|
|
8169
8611
|
for (const c of testReport.checks) {
|
|
8170
|
-
const mark = c.ok ?
|
|
8171
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8612
|
+
const mark = c.ok ? pc11.green("\u2713") : pc11.red("\u2717");
|
|
8613
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc11.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
8172
8614
|
}
|
|
8173
8615
|
}
|
|
8174
8616
|
console.log(`
|
|
@@ -8180,7 +8622,7 @@ Run with --config to save:
|
|
|
8180
8622
|
}
|
|
8181
8623
|
}
|
|
8182
8624
|
} catch (err) {
|
|
8183
|
-
|
|
8625
|
+
spinner4.stop("Failed");
|
|
8184
8626
|
error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
8185
8627
|
}
|
|
8186
8628
|
return;
|
|
@@ -8251,17 +8693,17 @@ async function syncTestCommand(platformModel, options = {}) {
|
|
|
8251
8693
|
return;
|
|
8252
8694
|
}
|
|
8253
8695
|
for (const c of report.checks) {
|
|
8254
|
-
const mark = c.ok ?
|
|
8255
|
-
console.log(` ${mark} ${c.name}${c.detail ?
|
|
8696
|
+
const mark = c.ok ? pc11.green("\u2713") : pc11.red("\u2717");
|
|
8697
|
+
console.log(` ${mark} ${c.name}${c.detail ? pc11.dim(` \u2014 ${c.detail}`) : ""}`);
|
|
8256
8698
|
}
|
|
8257
8699
|
if (report.detectedColumns && report.detectedColumns.length > 0) {
|
|
8258
8700
|
console.log(`
|
|
8259
|
-
${
|
|
8701
|
+
${pc11.bold("Detected columns:")}`);
|
|
8260
8702
|
for (const col of report.detectedColumns.slice(0, 20)) {
|
|
8261
|
-
console.log(` ${col.name.padEnd(30)} ${
|
|
8703
|
+
console.log(` ${col.name.padEnd(30)} ${pc11.dim(col.type)}`);
|
|
8262
8704
|
}
|
|
8263
8705
|
if (report.detectedColumns.length > 20) {
|
|
8264
|
-
console.log(
|
|
8706
|
+
console.log(pc11.dim(` ... and ${report.detectedColumns.length - 20} more`));
|
|
8265
8707
|
}
|
|
8266
8708
|
}
|
|
8267
8709
|
if (report.identityKeysPreview) {
|
|
@@ -8269,45 +8711,45 @@ async function syncTestCommand(platformModel, options = {}) {
|
|
|
8269
8711
|
const total = perRecord.reduce((a, b) => a + b, 0);
|
|
8270
8712
|
const min = perRecord.length ? Math.min(...perRecord) : 0;
|
|
8271
8713
|
const max = perRecord.length ? Math.max(...perRecord) : 0;
|
|
8272
|
-
const mark = total === 0 ?
|
|
8714
|
+
const mark = total === 0 ? pc11.yellow("~") : pc11.green("\u2713");
|
|
8273
8715
|
console.log(`
|
|
8274
|
-
${
|
|
8716
|
+
${pc11.bold("Merge + identity keys")} ${pc11.dim(`(cross-platform \u2014 #128)`)}`);
|
|
8275
8717
|
console.log(` ${mark} ${perRecord.length} sample${perRecord.length === 1 ? "" : "s"}, ${min}\u2013${max} key${max === 1 ? "" : "s"} per record`);
|
|
8276
8718
|
if (sampleKeys.length > 0) {
|
|
8277
|
-
console.log(` ${
|
|
8719
|
+
console.log(` ${pc11.dim("e.g.")} ${sampleKeys.slice(0, 8).map((k) => pc11.cyan(k)).join(", ")}`);
|
|
8278
8720
|
} else if (resolvesAfterEnrich) {
|
|
8279
|
-
console.log(` ${
|
|
8721
|
+
console.log(` ${pc11.dim("note:")} 0 on these list-shape samples \u2014 this profile enriches, and its identityKeys paths resolve in the enrich phase.`);
|
|
8280
8722
|
} else {
|
|
8281
|
-
console.log(` ${
|
|
8723
|
+
console.log(` ${pc11.yellow("note:")} no identity keys resolved on these samples \u2014 check the identityKey/identityKeys paths.`);
|
|
8282
8724
|
}
|
|
8283
8725
|
if (entityFanOut) {
|
|
8284
|
-
console.log(` ${
|
|
8285
|
-
console.log(` ${
|
|
8286
|
-
console.log(` ${
|
|
8287
|
-
console.log(` ${
|
|
8726
|
+
console.log(` ${pc11.yellow("warn:")} identityKey resolved to MULTIPLE values on ${entityFanOut.count} of ${perRecord.length} samples \u2014 those records get NO merge key.`);
|
|
8727
|
+
console.log(` ${pc11.dim("saw:")} ${entityFanOut.sampleValues.map((v) => pc11.cyan(v)).join(", ")}`);
|
|
8728
|
+
console.log(` ${pc11.dim('A singular identityKey means "this record IS this entity", so a fan-out has no safe answer.')}`);
|
|
8729
|
+
console.log(` ${pc11.dim("Point it at a single-valued path, or move it to identityKeys[] for participant associations.")}`);
|
|
8288
8730
|
}
|
|
8289
8731
|
}
|
|
8290
8732
|
if (searchablePreview) {
|
|
8291
8733
|
console.log(`
|
|
8292
|
-
${
|
|
8293
|
-
console.log(` ${
|
|
8294
|
-
console.log(` ${
|
|
8734
|
+
${pc11.bold("Searchable preview")} ${pc11.dim(`(${searchablePreview.mode}, ${searchablePreview.sampledRecords} sample${searchablePreview.sampledRecords === 1 ? "" : "s"})`)}`);
|
|
8735
|
+
console.log(` ${pc11.dim("length:")} ${searchablePreview.length} chars (first sample)`);
|
|
8736
|
+
console.log(` ${pc11.dim("text:")} ${searchablePreview.text.slice(0, 300)}${searchablePreview.length > 300 ? pc11.dim(" \u2026") : ""}`);
|
|
8295
8737
|
if (searchablePreview.paths) {
|
|
8296
|
-
console.log(` ${
|
|
8738
|
+
console.log(` ${pc11.dim("paths:")} ${pc11.dim('(hit rate across all samples \u2014 differentiates "wrong path" from "field sometimes missing")')}`);
|
|
8297
8739
|
for (const p10 of searchablePreview.paths) {
|
|
8298
8740
|
const rate = `${p10.hits}/${p10.total}`;
|
|
8299
|
-
const mark = p10.hits === p10.total ?
|
|
8300
|
-
const trailer = p10.sample ?
|
|
8741
|
+
const mark = p10.hits === p10.total ? pc11.green("\u2713") : p10.hits === 0 ? pc11.red("\u2717") : pc11.yellow("~");
|
|
8742
|
+
const trailer = p10.sample ? pc11.dim(` \u2192 "${p10.sample}"`) : p10.hits === 0 ? pc11.dim(" (no sample matched \u2014 typo, or field never populated in this page)") : "";
|
|
8301
8743
|
console.log(` ${mark} ${rate.padStart(5)} ${p10.path}${trailer}`);
|
|
8302
8744
|
}
|
|
8303
8745
|
} else {
|
|
8304
|
-
console.log(` ${
|
|
8305
|
-
console.log(` ${
|
|
8746
|
+
console.log(` ${pc11.yellow("note:")} no memory.searchable declared \u2014 using the default walker (walks every field, often noisy).`);
|
|
8747
|
+
console.log(` ${pc11.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.`);
|
|
8306
8748
|
}
|
|
8307
8749
|
}
|
|
8308
8750
|
console.log(
|
|
8309
8751
|
`
|
|
8310
|
-
${report.ok ?
|
|
8752
|
+
${report.ok ? pc11.green("Profile looks good.") : pc11.red("Profile has issues.")} ` + (report.ok ? `Run: ${pc11.bold(`one sync run ${platform} --models ${model}`)}` : "Fix the issues above and test again.")
|
|
8311
8753
|
);
|
|
8312
8754
|
}
|
|
8313
8755
|
function buildSearchablePreview(profile, samples) {
|
|
@@ -8315,7 +8757,7 @@ function buildSearchablePreview(profile, samples) {
|
|
|
8315
8757
|
const first = samples[0];
|
|
8316
8758
|
const paths = getSearchablePaths(profile);
|
|
8317
8759
|
if (paths) {
|
|
8318
|
-
const perPathAgg = paths.map((
|
|
8760
|
+
const perPathAgg = paths.map((path14) => ({ path: path14, hits: 0, total: samples.length, sample: "" }));
|
|
8319
8761
|
for (const record of samples) {
|
|
8320
8762
|
const { paths: perPath } = extractSearchableFromPaths(record, paths);
|
|
8321
8763
|
perPath.forEach((p10, i) => {
|
|
@@ -8348,8 +8790,8 @@ async function syncRunCommand(platform, options) {
|
|
|
8348
8790
|
if (profileDrift.length > 0 && !isAgentMode()) {
|
|
8349
8791
|
for (const d of profileDrift) {
|
|
8350
8792
|
console.log(
|
|
8351
|
-
` ${
|
|
8352
|
-
Run ${
|
|
8793
|
+
` ${pc11.yellow("!")} ${platform}/${d.model} is missing ${d.missing.map((f) => pc11.bold(f)).join(", ")} from the current built-in profile.
|
|
8794
|
+
Run ${pc11.bold(`one sync init ${platform} ${d.model}`)} to pick ${d.missing.length > 1 ? "them" : "it"} up.`
|
|
8353
8795
|
);
|
|
8354
8796
|
}
|
|
8355
8797
|
}
|
|
@@ -8392,21 +8834,21 @@ async function syncRunCommand(platform, options) {
|
|
|
8392
8834
|
return;
|
|
8393
8835
|
}
|
|
8394
8836
|
for (const r of results) {
|
|
8395
|
-
const status = r.status === "complete" ?
|
|
8396
|
-
console.log(` ${
|
|
8837
|
+
const status = r.status === "complete" ? pc11.green("complete") : r.status === "dry-run" ? pc11.yellow("dry-run") : pc11.red("failed");
|
|
8838
|
+
console.log(` ${pc11.bold(r.model)} \u2014 ${r.recordsSynced} records, ${r.pagesProcessed} pages, ${r.duration} [${status}]`);
|
|
8397
8839
|
if (r.reconcileSkipped) {
|
|
8398
|
-
console.log(` ${
|
|
8840
|
+
console.log(` ${pc11.yellow("--full-refresh reconcile skipped \u2014 pagination truncated (e.g. --max-pages). Re-run without the cap to prune stale rows.")}`);
|
|
8399
8841
|
}
|
|
8400
8842
|
const sc = r.statusCounts;
|
|
8401
8843
|
if (sc && (sc.archived > 0 || sc.active > 0)) {
|
|
8402
|
-
const archivedColor = sc.archived > sc.active ?
|
|
8403
|
-
console.log(` memory: ${
|
|
8844
|
+
const archivedColor = sc.archived > sc.active ? pc11.red : pc11.dim;
|
|
8845
|
+
console.log(` memory: ${pc11.green(String(sc.active))} active, ${archivedColor(String(sc.archived))} archived`);
|
|
8404
8846
|
}
|
|
8405
8847
|
if (r.error) {
|
|
8406
8848
|
const errParts = [r.error.message];
|
|
8407
8849
|
if (r.error.httpStatus) errParts.push(`HTTP ${r.error.httpStatus}`);
|
|
8408
8850
|
if (r.error.retryAfter) errParts.push(`retry after ${r.error.retryAfter}s`);
|
|
8409
|
-
console.log(` ${
|
|
8851
|
+
console.log(` ${pc11.red(errParts.join(" \u2014 "))}`);
|
|
8410
8852
|
}
|
|
8411
8853
|
}
|
|
8412
8854
|
}
|
|
@@ -8432,8 +8874,8 @@ async function syncQueryCommand(platformModel, options) {
|
|
|
8432
8874
|
json(result);
|
|
8433
8875
|
return;
|
|
8434
8876
|
}
|
|
8435
|
-
console.log(
|
|
8436
|
-
console.log(
|
|
8877
|
+
console.log(pc11.dim(`Query: ${result.query}`));
|
|
8878
|
+
console.log(pc11.dim(`Source: local | Last sync: ${result.lastSync ?? "never"} | Age: ${result.syncAge ?? "n/a"}`));
|
|
8437
8879
|
console.log(JSON.stringify(result.results, null, 2));
|
|
8438
8880
|
console.log(`
|
|
8439
8881
|
${result.total} results`);
|
|
@@ -8455,7 +8897,7 @@ async function syncSearchCommand(query, options) {
|
|
|
8455
8897
|
return;
|
|
8456
8898
|
}
|
|
8457
8899
|
for (const r of result.results) {
|
|
8458
|
-
console.log(` ${
|
|
8900
|
+
console.log(` ${pc11.bold(`${r.platform}/${r.model}`)} ${pc11.dim(`(rank: ${r.rank.toFixed(2)})`)}`);
|
|
8459
8901
|
console.log(` ${JSON.stringify(r.record)}`);
|
|
8460
8902
|
}
|
|
8461
8903
|
console.log(`
|
|
@@ -8465,7 +8907,7 @@ ${result.total} results`);
|
|
|
8465
8907
|
}
|
|
8466
8908
|
}
|
|
8467
8909
|
async function syncSqlCommand(platformModel, sql) {
|
|
8468
|
-
const { syncSqlCommand: runSyncSql } = await import("./sql-
|
|
8910
|
+
const { syncSqlCommand: runSyncSql } = await import("./sql-QIVDWTL3.js");
|
|
8469
8911
|
await runSyncSql(platformModel, sql);
|
|
8470
8912
|
}
|
|
8471
8913
|
async function syncDeleteCommand(platformModel, options) {
|
|
@@ -8543,7 +8985,7 @@ async function syncDeleteCommand(platformModel, options) {
|
|
|
8543
8985
|
async function maybeAutoMigrateLegacy(platform, models) {
|
|
8544
8986
|
const dbSize = getDatabaseSize(platform);
|
|
8545
8987
|
if (!dbSize || dbSize === "0 B") return;
|
|
8546
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
8988
|
+
const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
|
|
8547
8989
|
const backend = await getBackend2();
|
|
8548
8990
|
let memoryHasData = false;
|
|
8549
8991
|
for (const model of models) {
|
|
@@ -8559,7 +9001,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8559
9001
|
` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
|
|
8560
9002
|
`
|
|
8561
9003
|
);
|
|
8562
|
-
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-
|
|
9004
|
+
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-IJI3BTWL.js");
|
|
8563
9005
|
await memMigrateCommand3({ platform, yes: true });
|
|
8564
9006
|
return;
|
|
8565
9007
|
}
|
|
@@ -8568,7 +9010,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8568
9010
|
initialValue: true
|
|
8569
9011
|
});
|
|
8570
9012
|
if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
|
|
8571
|
-
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-
|
|
9013
|
+
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-IJI3BTWL.js");
|
|
8572
9014
|
await memMigrateCommand2({ platform, yes: true });
|
|
8573
9015
|
}
|
|
8574
9016
|
async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
@@ -8606,30 +9048,30 @@ async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
|
8606
9048
|
return;
|
|
8607
9049
|
}
|
|
8608
9050
|
console.log(`
|
|
8609
|
-
${
|
|
9051
|
+
${pc11.bold("memory.searchable \u2014 ranked suggestions")} ${pc11.dim(`(${samples.length} samples)`)}`);
|
|
8610
9052
|
if (suggestions.length === 0) {
|
|
8611
|
-
console.log(` ${
|
|
9053
|
+
console.log(` ${pc11.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.`);
|
|
8612
9054
|
return;
|
|
8613
9055
|
}
|
|
8614
9056
|
for (const s of suggestions) {
|
|
8615
9057
|
const hitPct = Math.round(s.hitRate * 100);
|
|
8616
9058
|
const noisePct = Math.round(s.noiseFraction * 100);
|
|
8617
|
-
const noiseBadge = noisePct > 0 ?
|
|
9059
|
+
const noiseBadge = noisePct > 0 ? pc11.dim(` noise=${noisePct}%`) : "";
|
|
8618
9060
|
console.log(
|
|
8619
|
-
` ${
|
|
9061
|
+
` ${pc11.green(String(s.score).padStart(5))} ${pc11.cyan(s.path.padEnd(52))}` + pc11.dim(` ${hitPct}% hit`) + pc11.dim(` avg=${s.avgLength}ch`) + noiseBadge + (s.sampleValue ? pc11.dim(`
|
|
8620
9062
|
\u2192 "${s.sampleValue.slice(0, 140)}"`) : "")
|
|
8621
9063
|
);
|
|
8622
9064
|
}
|
|
8623
9065
|
console.log(`
|
|
8624
|
-
${
|
|
8625
|
-
console.log(" " +
|
|
9066
|
+
${pc11.bold("Paste-ready:")}`);
|
|
9067
|
+
console.log(" " + pc11.cyan(`one sync init ${platform} ${model} --config '${JSON.stringify(configPatch)}'`));
|
|
8626
9068
|
console.log(`
|
|
8627
|
-
${
|
|
9069
|
+
${pc11.dim("then preview: ")}${pc11.cyan(`one sync test ${platform}/${model} --show-searchable`)}`);
|
|
8628
9070
|
}
|
|
8629
9071
|
async function syncListCommand(platform) {
|
|
8630
9072
|
const profiles = listProfiles(platform);
|
|
8631
9073
|
const state = await readSyncState();
|
|
8632
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
9074
|
+
const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
|
|
8633
9075
|
const backend = await getBackend2();
|
|
8634
9076
|
const syncs = await Promise.all(profiles.map(async (p10) => {
|
|
8635
9077
|
const modelState = state[p10.platform]?.[p10.model];
|
|
@@ -8658,10 +9100,10 @@ async function syncListCommand(platform) {
|
|
|
8658
9100
|
return;
|
|
8659
9101
|
}
|
|
8660
9102
|
for (const s of syncs) {
|
|
8661
|
-
const status = s.status === "idle" ?
|
|
8662
|
-
const legacy = s.legacyDbSize && s.legacyDbSize !== "0 B" ?
|
|
9103
|
+
const status = s.status === "idle" ? pc11.green("idle") : s.status === "syncing" ? pc11.yellow(`syncing \u2014 page ${s.pagesProcessed}`) : pc11.red("failed");
|
|
9104
|
+
const legacy = s.legacyDbSize && s.legacyDbSize !== "0 B" ? pc11.yellow(` legacy .db ${s.legacyDbSize}`) : "";
|
|
8663
9105
|
console.log(
|
|
8664
|
-
` ${
|
|
9106
|
+
` ${pc11.bold(`${s.platform}/${s.model}`.padEnd(35))} ${String(s.totalRecords).padStart(8)} records ${status} ${pc11.dim(s.lastSync ? `last: ${s.lastSync}` : "never synced")}` + legacy
|
|
8665
9107
|
);
|
|
8666
9108
|
}
|
|
8667
9109
|
}
|
|
@@ -8740,8 +9182,8 @@ async function syncScheduleAddCommand(platform, options) {
|
|
|
8740
9182
|
}
|
|
8741
9183
|
const verb = replaced ? "Replaced existing schedule" : "Scheduled sync";
|
|
8742
9184
|
outro(
|
|
8743
|
-
`${verb} ${
|
|
8744
|
-
Logs: ${
|
|
9185
|
+
`${verb} ${pc11.bold(entry.id)} \u2014 every ${pc11.bold(entry.every)} (cron: ${pc11.dim(entry.cronExpr)})
|
|
9186
|
+
Logs: ${pc11.dim(entry.logFile)}`
|
|
8745
9187
|
);
|
|
8746
9188
|
} catch (err) {
|
|
8747
9189
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -8760,14 +9202,14 @@ async function syncScheduleListCommand() {
|
|
|
8760
9202
|
}
|
|
8761
9203
|
for (const e of entries) {
|
|
8762
9204
|
const modelsStr = e.models ? ` [${e.models.join(",")}]` : "";
|
|
8763
|
-
const installed = e.cronInstalled ?
|
|
9205
|
+
const installed = e.cronInstalled ? pc11.green("\u25CF") : pc11.red("\u2717");
|
|
8764
9206
|
console.log(
|
|
8765
|
-
` ${installed} ${
|
|
9207
|
+
` ${installed} ${pc11.bold(e.id.padEnd(32))} every ${pc11.bold(e.every.padEnd(5))} ${pc11.dim(e.cronExpr.padEnd(13))}${modelsStr}`
|
|
8766
9208
|
);
|
|
8767
|
-
console.log(` ${
|
|
9209
|
+
console.log(` ${pc11.dim("cwd:")} ${e.cwd}`);
|
|
8768
9210
|
}
|
|
8769
9211
|
console.log(`
|
|
8770
|
-
${
|
|
9212
|
+
${pc11.dim("\u25CF = cron line installed \u2717 = registry drift, run `sync schedule repair <id>`")}`);
|
|
8771
9213
|
} catch (err) {
|
|
8772
9214
|
error(err instanceof Error ? err.message : String(err));
|
|
8773
9215
|
}
|
|
@@ -8791,7 +9233,7 @@ async function syncScheduleRemoveCommand(idOrPlatform, options) {
|
|
|
8791
9233
|
return;
|
|
8792
9234
|
}
|
|
8793
9235
|
for (const r of result.removed) {
|
|
8794
|
-
console.log(` ${
|
|
9236
|
+
console.log(` ${pc11.green("\u2713")} removed ${pc11.bold(r.id)} ${pc11.dim(`(${r.cwd})`)}`);
|
|
8795
9237
|
}
|
|
8796
9238
|
} catch (err) {
|
|
8797
9239
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -8809,21 +9251,21 @@ async function syncScheduleStatusCommand() {
|
|
|
8809
9251
|
return;
|
|
8810
9252
|
}
|
|
8811
9253
|
for (const s of statuses) {
|
|
8812
|
-
const driftMarker = s.drift === "ok" ?
|
|
8813
|
-
console.log(` ${driftMarker} ${
|
|
8814
|
-
console.log(` ${
|
|
8815
|
-
console.log(` ${
|
|
8816
|
-
console.log(` ${
|
|
9254
|
+
const driftMarker = s.drift === "ok" ? pc11.green("\u25CF") : s.drift === "missing-cron" ? pc11.red("\u2717 missing cron line") : pc11.yellow(`\u26A0 ${s.drift}`);
|
|
9255
|
+
console.log(` ${driftMarker} ${pc11.bold(s.entry.id)} \u2014 every ${s.entry.every} (${pc11.dim(s.entry.cronExpr)})`);
|
|
9256
|
+
console.log(` ${pc11.dim("cwd:")} ${s.entry.cwd}`);
|
|
9257
|
+
console.log(` ${pc11.dim("last run:")} ${s.lastRunAt ?? pc11.yellow("never")}`);
|
|
9258
|
+
console.log(` ${pc11.dim("log:")} ${s.entry.logFile} ${s.logExists ? pc11.dim(`(${s.logSize} bytes)`) : pc11.yellow("(empty)")}`);
|
|
8817
9259
|
if (s.logTail.length > 0) {
|
|
8818
|
-
console.log(
|
|
9260
|
+
console.log(pc11.dim(" last lines:"));
|
|
8819
9261
|
for (const line of s.logTail.slice(-3)) {
|
|
8820
|
-
console.log(
|
|
9262
|
+
console.log(pc11.dim(` ${line}`));
|
|
8821
9263
|
}
|
|
8822
9264
|
}
|
|
8823
9265
|
}
|
|
8824
9266
|
if (statuses.some((s) => s.drift !== "ok")) {
|
|
8825
9267
|
console.log(`
|
|
8826
|
-
${
|
|
9268
|
+
${pc11.yellow("Drift detected.")} Run ${pc11.bold("one sync schedule repair <id>")} to heal.`);
|
|
8827
9269
|
}
|
|
8828
9270
|
} catch (err) {
|
|
8829
9271
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -8836,7 +9278,7 @@ async function syncScheduleRepairCommand(id) {
|
|
|
8836
9278
|
json({ status: "repaired", ...healed });
|
|
8837
9279
|
return;
|
|
8838
9280
|
}
|
|
8839
|
-
outro(`Repaired ${
|
|
9281
|
+
outro(`Repaired ${pc11.bold(healed.id)}: re-installed cron line with current node/cli paths.`);
|
|
8840
9282
|
} catch (err) {
|
|
8841
9283
|
error(err instanceof Error ? err.message : String(err));
|
|
8842
9284
|
}
|
|
@@ -8905,7 +9347,7 @@ function registerSyncSubcommands(sync) {
|
|
|
8905
9347
|
await syncSqlCommand(platformModel, sql);
|
|
8906
9348
|
});
|
|
8907
9349
|
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) => {
|
|
8908
|
-
const { syncSchemaCommand } = await import("./schema-
|
|
9350
|
+
const { syncSchemaCommand } = await import("./schema-OO4WK5ND.js");
|
|
8909
9351
|
await syncSchemaCommand(platformModel);
|
|
8910
9352
|
});
|
|
8911
9353
|
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) => {
|
|
@@ -9272,16 +9714,16 @@ function projectEmbeddingApiKey(cfg) {
|
|
|
9272
9714
|
}
|
|
9273
9715
|
function redactSecrets(cfg) {
|
|
9274
9716
|
const copy = JSON.parse(JSON.stringify(cfg));
|
|
9275
|
-
for (const
|
|
9276
|
-
const val = getPath(copy,
|
|
9717
|
+
for (const path14 of SECRET_PATHS) {
|
|
9718
|
+
const val = getPath(copy, path14);
|
|
9277
9719
|
if (typeof val === "string" && val.length > 0) {
|
|
9278
|
-
setPath(copy,
|
|
9720
|
+
setPath(copy, path14, `${val.slice(0, 6)}\u2026(redacted, use --show-secrets)`);
|
|
9279
9721
|
}
|
|
9280
9722
|
}
|
|
9281
9723
|
return copy;
|
|
9282
9724
|
}
|
|
9283
|
-
function getPath(obj,
|
|
9284
|
-
const parts =
|
|
9725
|
+
function getPath(obj, path14) {
|
|
9726
|
+
const parts = path14.split(".");
|
|
9285
9727
|
let cur = obj;
|
|
9286
9728
|
for (const part of parts) {
|
|
9287
9729
|
if (cur == null || typeof cur !== "object") return void 0;
|
|
@@ -9289,8 +9731,8 @@ function getPath(obj, path13) {
|
|
|
9289
9731
|
}
|
|
9290
9732
|
return cur;
|
|
9291
9733
|
}
|
|
9292
|
-
function setPath(obj,
|
|
9293
|
-
const parts =
|
|
9734
|
+
function setPath(obj, path14, value) {
|
|
9735
|
+
const parts = path14.split(".");
|
|
9294
9736
|
let cur = obj;
|
|
9295
9737
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9296
9738
|
const part = parts[i];
|
|
@@ -9300,8 +9742,8 @@ function setPath(obj, path13, value) {
|
|
|
9300
9742
|
cur[parts[parts.length - 1]] = value;
|
|
9301
9743
|
return obj;
|
|
9302
9744
|
}
|
|
9303
|
-
function unsetPath(obj,
|
|
9304
|
-
const parts =
|
|
9745
|
+
function unsetPath(obj, path14) {
|
|
9746
|
+
const parts = path14.split(".");
|
|
9305
9747
|
let cur = obj;
|
|
9306
9748
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9307
9749
|
const part = parts[i];
|
|
@@ -9327,7 +9769,7 @@ function parseValue(raw) {
|
|
|
9327
9769
|
}
|
|
9328
9770
|
|
|
9329
9771
|
// src/commands/mem/records.ts
|
|
9330
|
-
import
|
|
9772
|
+
import pc12 from "picocolors";
|
|
9331
9773
|
async function memAddCommand(type, dataRaw, flags) {
|
|
9332
9774
|
requireMemoryInit();
|
|
9333
9775
|
const data = parseJsonArg(dataRaw, "data");
|
|
@@ -9526,7 +9968,7 @@ function summarizeRecord(r) {
|
|
|
9526
9968
|
const v = d[field];
|
|
9527
9969
|
if (typeof v === "string" && v.trim()) return v.trim().slice(0, 80);
|
|
9528
9970
|
}
|
|
9529
|
-
return
|
|
9971
|
+
return pc12.dim("(untitled)");
|
|
9530
9972
|
}
|
|
9531
9973
|
function relativeTime(iso) {
|
|
9532
9974
|
if (!iso) return "";
|
|
@@ -9589,7 +10031,7 @@ async function memFindByKeyCommand(key, secondKey, flags) {
|
|
|
9589
10031
|
});
|
|
9590
10032
|
return;
|
|
9591
10033
|
}
|
|
9592
|
-
const label = matchedKeys.map((k) =>
|
|
10034
|
+
const label = matchedKeys.map((k) => pc12.cyan(k)).join(pc12.dim(" + "));
|
|
9593
10035
|
if (records.length === 0) {
|
|
9594
10036
|
console.log(`
|
|
9595
10037
|
No records linked to ${label}.
|
|
@@ -9597,27 +10039,27 @@ async function memFindByKeyCommand(key, secondKey, flags) {
|
|
|
9597
10039
|
return;
|
|
9598
10040
|
}
|
|
9599
10041
|
console.log();
|
|
9600
|
-
console.log(` ${label} ${
|
|
10042
|
+
console.log(` ${label} ${pc12.dim("\u2014")} ${records.length}${truncated ? "+" : ""} record${records.length === 1 ? "" : "s"} across ${byType.size} type${byType.size === 1 ? "" : "s"}`);
|
|
9601
10043
|
console.log();
|
|
9602
10044
|
const typeWidth = Math.min(30, Math.max(...[...byType.keys()].map((t) => t.length)));
|
|
9603
10045
|
for (const [type, list] of byType) {
|
|
9604
|
-
console.log(` ${
|
|
10046
|
+
console.log(` ${pc12.bold(type.padEnd(typeWidth))} ${pc12.dim(`${list.length} record${list.length === 1 ? "" : "s"}`)}`);
|
|
9605
10047
|
for (const r of list.slice(0, perType)) {
|
|
9606
|
-
console.log(` ${
|
|
10048
|
+
console.log(` ${pc12.dim("\xB7")} ${summarizeRecord(r)} ${pc12.dim(relativeTime(r.updated_at))} ${pc12.dim(r.id)}`);
|
|
9607
10049
|
}
|
|
9608
10050
|
if (list.length > perType) {
|
|
9609
|
-
console.log(` ${
|
|
10051
|
+
console.log(` ${pc12.dim(`\u2026 and ${list.length - perType} more (raise --limit)`)}`);
|
|
9610
10052
|
}
|
|
9611
10053
|
}
|
|
9612
10054
|
if (truncated) {
|
|
9613
10055
|
console.log();
|
|
9614
|
-
console.log(` ${
|
|
10056
|
+
console.log(` ${pc12.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.`);
|
|
9615
10057
|
}
|
|
9616
10058
|
console.log();
|
|
9617
10059
|
}
|
|
9618
10060
|
|
|
9619
10061
|
// src/commands/mem/doctor.ts
|
|
9620
|
-
import
|
|
10062
|
+
import pc13 from "picocolors";
|
|
9621
10063
|
async function memDoctorCommand() {
|
|
9622
10064
|
const checks = [];
|
|
9623
10065
|
const cfg = getMemoryConfig();
|
|
@@ -9682,7 +10124,7 @@ async function memDoctorCommand() {
|
|
|
9682
10124
|
}
|
|
9683
10125
|
if (cfg.embedding.provider === "openai") {
|
|
9684
10126
|
try {
|
|
9685
|
-
const { embed: embed2 } = await import("./embedding-
|
|
10127
|
+
const { embed: embed2 } = await import("./embedding-OXX4OF65.js");
|
|
9686
10128
|
const result = await embed2("connectivity check");
|
|
9687
10129
|
checks.push({
|
|
9688
10130
|
name: "OpenAI embedding provider reachable",
|
|
@@ -9724,23 +10166,23 @@ function emit(checks, capInfo) {
|
|
|
9724
10166
|
return;
|
|
9725
10167
|
}
|
|
9726
10168
|
for (const c of checks) {
|
|
9727
|
-
const mark = c.ok ?
|
|
9728
|
-
const detail = c.detail ?
|
|
10169
|
+
const mark = c.ok ? pc13.green("\u2713") : pc13.red("\u2717");
|
|
10170
|
+
const detail = c.detail ? pc13.dim(` \u2014 ${c.detail}`) : "";
|
|
9729
10171
|
console.log(` ${mark} ${c.name}${detail}`);
|
|
9730
10172
|
}
|
|
9731
10173
|
if (!allOk) {
|
|
9732
|
-
console.log("\n" +
|
|
10174
|
+
console.log("\n" + pc13.yellow("Memory is not fully healthy."));
|
|
9733
10175
|
process.exitCode = 1;
|
|
9734
10176
|
} else {
|
|
9735
|
-
console.log("\n" +
|
|
10177
|
+
console.log("\n" + pc13.green("Memory is healthy."));
|
|
9736
10178
|
}
|
|
9737
10179
|
const line = semanticSearchUpgradeLine({ vectorSearchAvailable: capInfo.vectorSearchAvailable });
|
|
9738
10180
|
if (line) console.log(`
|
|
9739
|
-
${
|
|
10181
|
+
${pc13.dim(line)}`);
|
|
9740
10182
|
}
|
|
9741
10183
|
|
|
9742
10184
|
// src/commands/mem/export.ts
|
|
9743
|
-
import
|
|
10185
|
+
import fs12 from "fs";
|
|
9744
10186
|
import { once } from "events";
|
|
9745
10187
|
async function writeLine(stream, line) {
|
|
9746
10188
|
if (!stream.write(line)) {
|
|
@@ -9752,7 +10194,7 @@ async function memExportCommand(outfile) {
|
|
|
9752
10194
|
const backend = await getBackend();
|
|
9753
10195
|
const stats = await backend.stats();
|
|
9754
10196
|
const toFile = !!outfile && outfile !== "-";
|
|
9755
|
-
const stream = toFile ?
|
|
10197
|
+
const stream = toFile ? fs12.createWriteStream(outfile, "utf-8") : process.stdout;
|
|
9756
10198
|
const all = await listAllTypes(backend);
|
|
9757
10199
|
const pageSize = 500;
|
|
9758
10200
|
let written = 0;
|
|
@@ -9783,9 +10225,9 @@ async function memExportCommand(outfile) {
|
|
|
9783
10225
|
}
|
|
9784
10226
|
async function memImportCommand(file) {
|
|
9785
10227
|
requireMemoryInit();
|
|
9786
|
-
if (!
|
|
10228
|
+
if (!fs12.existsSync(file)) error(`File not found: ${file}`);
|
|
9787
10229
|
const backend = await getBackend();
|
|
9788
|
-
const raw =
|
|
10230
|
+
const raw = fs12.readFileSync(file, "utf-8");
|
|
9789
10231
|
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
9790
10232
|
let inserted = 0;
|
|
9791
10233
|
let updated = 0;
|
|
@@ -10031,7 +10473,7 @@ function registerMemoryCommands(program2) {
|
|
|
10031
10473
|
}
|
|
10032
10474
|
|
|
10033
10475
|
// src/commands/cache.ts
|
|
10034
|
-
import
|
|
10476
|
+
import pc14 from "picocolors";
|
|
10035
10477
|
async function cacheClearCommand(actionId) {
|
|
10036
10478
|
if (actionId) {
|
|
10037
10479
|
const deleted = clearEntry(actionId);
|
|
@@ -10040,9 +10482,9 @@ async function cacheClearCommand(actionId) {
|
|
|
10040
10482
|
return;
|
|
10041
10483
|
}
|
|
10042
10484
|
if (deleted) {
|
|
10043
|
-
console.log(`Cleared cache for ${
|
|
10485
|
+
console.log(`Cleared cache for ${pc14.cyan(actionId)}`);
|
|
10044
10486
|
} else {
|
|
10045
|
-
console.log(`No cache entry found for ${
|
|
10487
|
+
console.log(`No cache entry found for ${pc14.dim(actionId)}`);
|
|
10046
10488
|
}
|
|
10047
10489
|
} else {
|
|
10048
10490
|
const count = clearAll();
|
|
@@ -10079,7 +10521,7 @@ async function cacheListCommand(options) {
|
|
|
10079
10521
|
type: e.type,
|
|
10080
10522
|
key: e.entry.key,
|
|
10081
10523
|
age: formatAge(getAge(e.entry)),
|
|
10082
|
-
status: isFresh(e.entry) ?
|
|
10524
|
+
status: isFresh(e.entry) ? pc14.green("fresh") : pc14.yellow("expired")
|
|
10083
10525
|
}));
|
|
10084
10526
|
printTable(
|
|
10085
10527
|
[
|
|
@@ -10109,8 +10551,8 @@ async function cacheUpdateAllCommand() {
|
|
|
10109
10551
|
console.log("No cached entries to update");
|
|
10110
10552
|
return;
|
|
10111
10553
|
}
|
|
10112
|
-
const
|
|
10113
|
-
|
|
10554
|
+
const spinner4 = createSpinner();
|
|
10555
|
+
spinner4.start(`Updating ${entries.length} cached ${entries.length === 1 ? "entry" : "entries"}...`);
|
|
10114
10556
|
let updated = 0;
|
|
10115
10557
|
let failed = 0;
|
|
10116
10558
|
const errors = [];
|
|
@@ -10162,7 +10604,7 @@ async function cacheUpdateAllCommand() {
|
|
|
10162
10604
|
});
|
|
10163
10605
|
}
|
|
10164
10606
|
}
|
|
10165
|
-
|
|
10607
|
+
spinner4.stop(`Updated ${updated} ${updated === 1 ? "entry" : "entries"}${failed > 0 ? `, ${failed} failed` : ""}`);
|
|
10166
10608
|
if (isAgentMode()) {
|
|
10167
10609
|
json({ updated, failed, errors: errors.length > 0 ? errors : void 0 });
|
|
10168
10610
|
return;
|
|
@@ -10170,13 +10612,13 @@ async function cacheUpdateAllCommand() {
|
|
|
10170
10612
|
if (errors.length > 0) {
|
|
10171
10613
|
console.log();
|
|
10172
10614
|
for (const e of errors) {
|
|
10173
|
-
console.log(` ${
|
|
10615
|
+
console.log(` ${pc14.red("\u2717")} ${e.key}: ${pc14.dim(e.error)}`);
|
|
10174
10616
|
}
|
|
10175
10617
|
}
|
|
10176
10618
|
}
|
|
10177
10619
|
|
|
10178
10620
|
// src/commands/guide.ts
|
|
10179
|
-
import
|
|
10621
|
+
import pc15 from "picocolors";
|
|
10180
10622
|
|
|
10181
10623
|
// src/lib/guide-content.ts
|
|
10182
10624
|
var GUIDE_OVERVIEW = `# One CLI \u2014 Agent Guide
|
|
@@ -10189,6 +10631,8 @@ var GUIDE_OVERVIEW = `# One CLI \u2014 Agent Guide
|
|
|
10189
10631
|
|
|
10190
10632
|
You can also use \`one login\` / \`one logout\` to manage authentication separately (global or per-directory).
|
|
10191
10633
|
|
|
10634
|
+
Browser login opens a consent page that names the key and tags it with where the CLI runs (scope, project path, machine, OS user, CLI version, the agent harnesses you pick, and the per-install device id unless telemetry is off), so the dashboard can show every install. The terminal prints what will be sent before the browser opens. Set \`ONE_APP_URL\` (dashboard origin) and \`ONE_API_BASE\` (API origin) to run against a local stack; neither is written to config, so pair them with \`ONE_HOME\` to keep a local stack's credentials separate.
|
|
10635
|
+
|
|
10192
10636
|
### Agent-driven setup (no prompts)
|
|
10193
10637
|
To onboard a user without any terminal interaction, pass \`--auth\` to \`one init\`. This disables every prompt, auto-installs the One skill, and skips the connect-a-platform step (run \`one add <platform>\` afterwards).
|
|
10194
10638
|
|
|
@@ -11337,14 +11781,14 @@ async function guideCommand(topic = "all") {
|
|
|
11337
11781
|
json({ topic, title, content, availableTopics });
|
|
11338
11782
|
return;
|
|
11339
11783
|
}
|
|
11340
|
-
intro(
|
|
11784
|
+
intro(pc15.bgCyan(pc15.black(" One Guide ")));
|
|
11341
11785
|
console.log();
|
|
11342
11786
|
console.log(content);
|
|
11343
|
-
console.log(
|
|
11787
|
+
console.log(pc15.dim("\u2500".repeat(60)));
|
|
11344
11788
|
console.log(
|
|
11345
|
-
|
|
11789
|
+
pc15.dim("Available topics: ") + availableTopics.map((t) => pc15.cyan(t.topic)).join(", ")
|
|
11346
11790
|
);
|
|
11347
|
-
console.log(
|
|
11791
|
+
console.log(pc15.dim(`Run ${pc15.cyan("one guide <topic>")} for a specific section.`));
|
|
11348
11792
|
}
|
|
11349
11793
|
|
|
11350
11794
|
// src/lib/platform-meta.ts
|
|
@@ -11665,7 +12109,7 @@ function buildWorkflowIdeas(connections) {
|
|
|
11665
12109
|
}
|
|
11666
12110
|
|
|
11667
12111
|
// src/commands/logout.ts
|
|
11668
|
-
import
|
|
12112
|
+
import fs13 from "fs";
|
|
11669
12113
|
import * as p9 from "@clack/prompts";
|
|
11670
12114
|
function formatWhoami(config2, apiKey, pc16) {
|
|
11671
12115
|
const whoami = config2.whoami;
|
|
@@ -11679,8 +12123,10 @@ function formatWhoami(config2, apiKey, pc16) {
|
|
|
11679
12123
|
const scopeDisplay = contextParts.length > 0 ? contextParts.join(" / ") : "Personal";
|
|
11680
12124
|
lines.push(`${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
11681
12125
|
lines.push(`${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`);
|
|
12126
|
+
if (config2.apiKeyName) lines.push(`${pc16.dim("Key:")} ${config2.apiKeyName}`);
|
|
11682
12127
|
} else {
|
|
11683
|
-
|
|
12128
|
+
const keyLabel = config2.apiKeyName ?? `${apiKey.slice(0, 8)}...`;
|
|
12129
|
+
lines.push(`${pc16.dim("Key:")} ${keyLabel} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
11684
12130
|
}
|
|
11685
12131
|
return lines;
|
|
11686
12132
|
}
|
|
@@ -11698,12 +12144,12 @@ async function logoutCommand() {
|
|
|
11698
12144
|
const globalPath = getGlobalConfigPath();
|
|
11699
12145
|
const projectPath = getProjectConfigPath();
|
|
11700
12146
|
let cleared = false;
|
|
11701
|
-
if (
|
|
11702
|
-
|
|
12147
|
+
if (fs13.existsSync(projectPath)) {
|
|
12148
|
+
fs13.unlinkSync(projectPath);
|
|
11703
12149
|
cleared = true;
|
|
11704
12150
|
}
|
|
11705
|
-
if (
|
|
11706
|
-
|
|
12151
|
+
if (fs13.existsSync(globalPath)) {
|
|
12152
|
+
fs13.unlinkSync(globalPath);
|
|
11707
12153
|
cleared = true;
|
|
11708
12154
|
}
|
|
11709
12155
|
json({ status: cleared ? "logged_out" : "not_logged_in", message: cleared ? "Credentials cleared." : "No config found." });
|
|
@@ -11772,328 +12218,17 @@ async function logoutCommand() {
|
|
|
11772
12218
|
}
|
|
11773
12219
|
if (targetScope === "project" || targetScope === "both") {
|
|
11774
12220
|
const projectPath = getProjectConfigPath();
|
|
11775
|
-
if (
|
|
12221
|
+
if (fs13.existsSync(projectPath)) fs13.unlinkSync(projectPath);
|
|
11776
12222
|
}
|
|
11777
12223
|
if (targetScope === "global" || targetScope === "both") {
|
|
11778
12224
|
const globalPath = getGlobalConfigPath();
|
|
11779
|
-
if (
|
|
12225
|
+
if (fs13.existsSync(globalPath)) fs13.unlinkSync(globalPath);
|
|
11780
12226
|
}
|
|
11781
12227
|
p9.log.success("Credentials cleared.");
|
|
11782
12228
|
p9.log.info("Your API key is still active. Manage keys at app.withone.ai/settings");
|
|
11783
12229
|
p9.outro("Logged out.");
|
|
11784
12230
|
}
|
|
11785
12231
|
|
|
11786
|
-
// src/lib/analytics.ts
|
|
11787
|
-
import { createRequire as createRequire2 } from "module";
|
|
11788
|
-
import { randomUUID, createHash } from "crypto";
|
|
11789
|
-
import pc15 from "picocolors";
|
|
11790
|
-
var require3 = createRequire2(import.meta.url);
|
|
11791
|
-
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
11792
|
-
var DEFAULT_POSTHOG_KEY = "phc_a9ok4w0uxiZcVoSWOISIlin85lHMXQD3vWPaYnuRlRV";
|
|
11793
|
-
var SEND_MAX_ATTEMPTS = 3;
|
|
11794
|
-
var QUEUE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
11795
|
-
var EXIT_GRACE_MS = 300;
|
|
11796
|
-
var inFlight = /* @__PURE__ */ new Set();
|
|
11797
|
-
var pending = /* @__PURE__ */ new Set();
|
|
11798
|
-
var dispatched = /* @__PURE__ */ new Set();
|
|
11799
|
-
var delivered = /* @__PURE__ */ new Set();
|
|
11800
|
-
var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11801
|
-
function uuidFromInsertId(insertId) {
|
|
11802
|
-
if (UUID_SHAPE.test(insertId)) return insertId.toLowerCase();
|
|
11803
|
-
const h = createHash("sha1").update(`one-cli-event:${insertId}`).digest("hex");
|
|
11804
|
-
const variant = (parseInt(h[16], 16) & 3 | 8).toString(16);
|
|
11805
|
-
return `${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
11806
|
-
}
|
|
11807
|
-
function posthogHost() {
|
|
11808
|
-
return process.env.ONE_POSTHOG_HOST || DEFAULT_POSTHOG_HOST;
|
|
11809
|
-
}
|
|
11810
|
-
function posthogKey() {
|
|
11811
|
-
return process.env.ONE_POSTHOG_KEY || DEFAULT_POSTHOG_KEY;
|
|
11812
|
-
}
|
|
11813
|
-
function envName() {
|
|
11814
|
-
const key = getApiKey();
|
|
11815
|
-
return key ? getEnvFromApiKey(key) : "live";
|
|
11816
|
-
}
|
|
11817
|
-
function isOn(value) {
|
|
11818
|
-
return value === "1" || value === "true";
|
|
11819
|
-
}
|
|
11820
|
-
function debugLog(message) {
|
|
11821
|
-
if (isOn(process.env.ONE_ANALYTICS_DEBUG)) {
|
|
11822
|
-
process.stderr.write(`[analytics] ${message}
|
|
11823
|
-
`);
|
|
11824
|
-
}
|
|
11825
|
-
}
|
|
11826
|
-
function isTelemetryDisabled() {
|
|
11827
|
-
if (isOn(process.env.ONE_NO_TELEMETRY) || isOn(process.env.ONE_DISABLE_TELEMETRY)) return true;
|
|
11828
|
-
if (isOn(process.env.DO_NOT_TRACK)) return true;
|
|
11829
|
-
if (isOn(process.env.CI)) return true;
|
|
11830
|
-
if (readConfig()?.telemetry === "off") return true;
|
|
11831
|
-
return false;
|
|
11832
|
-
}
|
|
11833
|
-
function distinctId() {
|
|
11834
|
-
return getWhoAmI()?.user?.id ?? getDeviceId();
|
|
11835
|
-
}
|
|
11836
|
-
function isAuthenticated() {
|
|
11837
|
-
return !!getWhoAmI()?.user || !!getApiKey();
|
|
11838
|
-
}
|
|
11839
|
-
function baseProperties() {
|
|
11840
|
-
return {
|
|
11841
|
-
$lib: "one-cli",
|
|
11842
|
-
cli_version: cliVersion(),
|
|
11843
|
-
agent_mode: isAgentMode(),
|
|
11844
|
-
env: envName(),
|
|
11845
|
-
os: process.platform,
|
|
11846
|
-
arch: process.arch,
|
|
11847
|
-
node_version: process.versions.node,
|
|
11848
|
-
authenticated: isAuthenticated()
|
|
11849
|
-
};
|
|
11850
|
-
}
|
|
11851
|
-
function personSet() {
|
|
11852
|
-
const whoami = getWhoAmI();
|
|
11853
|
-
if (!whoami?.user) return void 0;
|
|
11854
|
-
const set = {};
|
|
11855
|
-
if (whoami.user.email) set.email = whoami.user.email;
|
|
11856
|
-
if (whoami.user.name) set.name = whoami.user.name;
|
|
11857
|
-
if (whoami.organization?.id) set.organization_id = whoami.organization.id;
|
|
11858
|
-
return Object.keys(set).length ? set : void 0;
|
|
11859
|
-
}
|
|
11860
|
-
function send(item) {
|
|
11861
|
-
const insertId = item.properties.$insert_id;
|
|
11862
|
-
if (insertId) dispatched.add(insertId);
|
|
11863
|
-
const controller = new AbortController();
|
|
11864
|
-
inFlight.add(controller);
|
|
11865
|
-
const run = (async () => {
|
|
11866
|
-
try {
|
|
11867
|
-
const res = await fetch(`${posthogHost()}/i/v0/e/`, {
|
|
11868
|
-
method: "POST",
|
|
11869
|
-
headers: { "Content-Type": "application/json" },
|
|
11870
|
-
body: JSON.stringify({
|
|
11871
|
-
api_key: posthogKey(),
|
|
11872
|
-
event: item.event,
|
|
11873
|
-
distinct_id: item.distinct_id,
|
|
11874
|
-
// PostHog's dedupe key — a re-sent copy is dropped on ingest.
|
|
11875
|
-
uuid: item.uuid ?? (insertId ? uuidFromInsertId(insertId) : void 0),
|
|
11876
|
-
properties: item.properties,
|
|
11877
|
-
timestamp: item.timestamp
|
|
11878
|
-
}),
|
|
11879
|
-
signal: controller.signal
|
|
11880
|
-
});
|
|
11881
|
-
if (res.ok && insertId) delivered.add(insertId);
|
|
11882
|
-
debugLog(`"${item.event}" -> HTTP ${res.status}${res.ok ? "" : " (retry next run)"}`);
|
|
11883
|
-
} catch (err) {
|
|
11884
|
-
debugLog(`"${item.event}" not sent: ${err instanceof Error ? err.message : String(err)} (retry next run)`);
|
|
11885
|
-
} finally {
|
|
11886
|
-
inFlight.delete(controller);
|
|
11887
|
-
}
|
|
11888
|
-
})();
|
|
11889
|
-
pending.add(run);
|
|
11890
|
-
void run.finally(() => pending.delete(run));
|
|
11891
|
-
}
|
|
11892
|
-
function capture(event, properties = {}, opts = {}) {
|
|
11893
|
-
if (isTelemetryDisabled()) {
|
|
11894
|
-
debugLog(`disabled \u2014 skipping "${event}"`);
|
|
11895
|
-
return;
|
|
11896
|
-
}
|
|
11897
|
-
const did = opts.distinctId ?? distinctId();
|
|
11898
|
-
const props = { ...baseProperties(), ...properties };
|
|
11899
|
-
if (props.$insert_id === void 0) props.$insert_id = randomUUID();
|
|
11900
|
-
const insertId = props.$insert_id;
|
|
11901
|
-
if (opts.personProfile === false) {
|
|
11902
|
-
props.$process_person_profile = false;
|
|
11903
|
-
} else if (did === distinctId()) {
|
|
11904
|
-
const set = personSet();
|
|
11905
|
-
if (set) props.$set = set;
|
|
11906
|
-
}
|
|
11907
|
-
const item = {
|
|
11908
|
-
event,
|
|
11909
|
-
distinct_id: did,
|
|
11910
|
-
properties: props,
|
|
11911
|
-
timestamp: opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
11912
|
-
uuid: uuidFromInsertId(insertId)
|
|
11913
|
-
};
|
|
11914
|
-
appendAnalyticsQueue(JSON.stringify(item));
|
|
11915
|
-
}
|
|
11916
|
-
var ROLLUP_WINDOW_MS = 5 * 60 * 1e3;
|
|
11917
|
-
var ROLLUP_MAX_BATCH = 500;
|
|
11918
|
-
function utcDay(ts) {
|
|
11919
|
-
return new Date(ts).toISOString().slice(0, 10);
|
|
11920
|
-
}
|
|
11921
|
-
var PRE_AUTH_COMMANDS = /* @__PURE__ */ new Set([
|
|
11922
|
-
"init",
|
|
11923
|
-
"login",
|
|
11924
|
-
"logout",
|
|
11925
|
-
"guide",
|
|
11926
|
-
"platforms",
|
|
11927
|
-
"onboard",
|
|
11928
|
-
"config",
|
|
11929
|
-
"update",
|
|
11930
|
-
"help"
|
|
11931
|
-
]);
|
|
11932
|
-
function shouldRecord(commandPath2) {
|
|
11933
|
-
if (isAuthenticated()) return true;
|
|
11934
|
-
return PRE_AUTH_COMMANDS.has(commandPath2.split(" ")[0]);
|
|
11935
|
-
}
|
|
11936
|
-
function recordCommand(command) {
|
|
11937
|
-
if (isTelemetryDisabled()) {
|
|
11938
|
-
writeUsageLog([]);
|
|
11939
|
-
return;
|
|
11940
|
-
}
|
|
11941
|
-
const cmdPath = commandPath(command);
|
|
11942
|
-
if (!shouldRecord(cmdPath)) return;
|
|
11943
|
-
const did = distinctId();
|
|
11944
|
-
const entry = { ts: Date.now(), command: cmdPath, agent: isAgentMode(), did };
|
|
11945
|
-
appendUsageLog(JSON.stringify(entry));
|
|
11946
|
-
const today = utcDay(entry.ts);
|
|
11947
|
-
const state = readUsageState();
|
|
11948
|
-
const firstTouch = state.lastDay !== today || state.distinctId !== did;
|
|
11949
|
-
flushUsageRollups({ force: firstTouch });
|
|
11950
|
-
if (firstTouch) writeUsageState({ lastDay: today, distinctId: did });
|
|
11951
|
-
}
|
|
11952
|
-
function flushUsageRollups(opts = {}) {
|
|
11953
|
-
if (isTelemetryDisabled()) {
|
|
11954
|
-
writeUsageLog([]);
|
|
11955
|
-
return;
|
|
11956
|
-
}
|
|
11957
|
-
const lines = claimUsageLog();
|
|
11958
|
-
if (!lines || lines.length === 0) return;
|
|
11959
|
-
const entries = [];
|
|
11960
|
-
for (const line of lines) {
|
|
11961
|
-
try {
|
|
11962
|
-
const e = JSON.parse(line);
|
|
11963
|
-
if (e && typeof e.ts === "number" && typeof e.command === "string" && typeof e.did === "string") {
|
|
11964
|
-
entries.push(e);
|
|
11965
|
-
}
|
|
11966
|
-
} catch {
|
|
11967
|
-
}
|
|
11968
|
-
}
|
|
11969
|
-
if (entries.length === 0) return;
|
|
11970
|
-
const currentDid = entries[entries.length - 1].did;
|
|
11971
|
-
const now = Date.now();
|
|
11972
|
-
const groups = /* @__PURE__ */ new Map();
|
|
11973
|
-
for (const e of entries) {
|
|
11974
|
-
const g = groups.get(e.did);
|
|
11975
|
-
if (g) g.push(e);
|
|
11976
|
-
else groups.set(e.did, [e]);
|
|
11977
|
-
}
|
|
11978
|
-
const kept = [];
|
|
11979
|
-
for (const [did, group] of groups) {
|
|
11980
|
-
const due = opts.force === true || did !== currentDid || // a superseded login's batch — flush it now
|
|
11981
|
-
group.length >= ROLLUP_MAX_BATCH || now - group[0].ts >= ROLLUP_WINDOW_MS;
|
|
11982
|
-
if (due) emitRollup(did, group);
|
|
11983
|
-
else kept.push(...group);
|
|
11984
|
-
}
|
|
11985
|
-
for (const e of kept) appendUsageLog(JSON.stringify(e));
|
|
11986
|
-
}
|
|
11987
|
-
function emitRollup(did, group) {
|
|
11988
|
-
const byCommand = {};
|
|
11989
|
-
let agentCount = 0;
|
|
11990
|
-
for (const e of group) {
|
|
11991
|
-
byCommand[e.command] = (byCommand[e.command] ?? 0) + 1;
|
|
11992
|
-
if (e.agent) agentCount += 1;
|
|
11993
|
-
}
|
|
11994
|
-
const insertId = createHash("sha1").update(`${did}|${group.map((e) => `${e.ts}:${e.command}:${e.agent ? 1 : 0}`).join("|")}`).digest("hex");
|
|
11995
|
-
capture(
|
|
11996
|
-
"CLI Usage Rollup",
|
|
11997
|
-
{
|
|
11998
|
-
command_count: group.length,
|
|
11999
|
-
by_command: byCommand,
|
|
12000
|
-
agent_count: agentCount,
|
|
12001
|
-
human_count: group.length - agentCount,
|
|
12002
|
-
window_start: new Date(group[0].ts).toISOString(),
|
|
12003
|
-
window_end: new Date(group[group.length - 1].ts).toISOString(),
|
|
12004
|
-
$insert_id: insertId
|
|
12005
|
-
},
|
|
12006
|
-
{
|
|
12007
|
-
distinctId: did,
|
|
12008
|
-
timestamp: new Date(group[group.length - 1].ts).toISOString(),
|
|
12009
|
-
// Rollups bill at the anonymous rate; the person already exists.
|
|
12010
|
-
personProfile: false
|
|
12011
|
-
}
|
|
12012
|
-
);
|
|
12013
|
-
debugLog(`rollup \u2014 ${group.length} command(s) for ${did}`);
|
|
12014
|
-
}
|
|
12015
|
-
function commandPath(command) {
|
|
12016
|
-
const parts = [];
|
|
12017
|
-
let current = command;
|
|
12018
|
-
while (current && current.name() && current.name() !== "one") {
|
|
12019
|
-
parts.unshift(current.name());
|
|
12020
|
-
current = current.parent;
|
|
12021
|
-
}
|
|
12022
|
-
return parts.join(" ") || command.name();
|
|
12023
|
-
}
|
|
12024
|
-
function drainQueue() {
|
|
12025
|
-
if (isTelemetryDisabled()) {
|
|
12026
|
-
writeAnalyticsQueue([]);
|
|
12027
|
-
return;
|
|
12028
|
-
}
|
|
12029
|
-
const now = Date.now();
|
|
12030
|
-
const kept = [];
|
|
12031
|
-
let changed = false;
|
|
12032
|
-
for (const line of readAnalyticsQueue()) {
|
|
12033
|
-
let item;
|
|
12034
|
-
try {
|
|
12035
|
-
item = JSON.parse(line);
|
|
12036
|
-
} catch {
|
|
12037
|
-
changed = true;
|
|
12038
|
-
continue;
|
|
12039
|
-
}
|
|
12040
|
-
const insertId = item?.properties?.$insert_id;
|
|
12041
|
-
if (!insertId) {
|
|
12042
|
-
changed = true;
|
|
12043
|
-
continue;
|
|
12044
|
-
}
|
|
12045
|
-
const age = now - Date.parse(item.timestamp);
|
|
12046
|
-
const attempts = item.attempts ?? 0;
|
|
12047
|
-
if (!(age < QUEUE_MAX_AGE_MS) || attempts >= SEND_MAX_ATTEMPTS) {
|
|
12048
|
-
debugLog(`"${item.event}" dropped (${attempts} attempts, ${Math.round(age / 6e4)} min old)`);
|
|
12049
|
-
changed = true;
|
|
12050
|
-
continue;
|
|
12051
|
-
}
|
|
12052
|
-
if (dispatched.has(insertId)) {
|
|
12053
|
-
kept.push(line);
|
|
12054
|
-
continue;
|
|
12055
|
-
}
|
|
12056
|
-
item.attempts = attempts + 1;
|
|
12057
|
-
if (!item.uuid) item.uuid = uuidFromInsertId(insertId);
|
|
12058
|
-
kept.push(JSON.stringify(item));
|
|
12059
|
-
changed = true;
|
|
12060
|
-
send(item);
|
|
12061
|
-
}
|
|
12062
|
-
if (changed) writeAnalyticsQueue(kept);
|
|
12063
|
-
}
|
|
12064
|
-
async function flush() {
|
|
12065
|
-
if (pending.size > 0) {
|
|
12066
|
-
await Promise.race([
|
|
12067
|
-
Promise.allSettled([...pending]),
|
|
12068
|
-
new Promise((resolve) => setTimeout(resolve, EXIT_GRACE_MS))
|
|
12069
|
-
]);
|
|
12070
|
-
}
|
|
12071
|
-
for (const controller of inFlight) controller.abort();
|
|
12072
|
-
const remaining = readAnalyticsQueue().filter((line) => {
|
|
12073
|
-
try {
|
|
12074
|
-
const item = JSON.parse(line);
|
|
12075
|
-
const id = item.properties?.$insert_id;
|
|
12076
|
-
if (!id || delivered.has(id)) return false;
|
|
12077
|
-
return (item.attempts ?? 0) < SEND_MAX_ATTEMPTS;
|
|
12078
|
-
} catch {
|
|
12079
|
-
return false;
|
|
12080
|
-
}
|
|
12081
|
-
});
|
|
12082
|
-
writeAnalyticsQueue(remaining);
|
|
12083
|
-
dispatched.clear();
|
|
12084
|
-
delivered.clear();
|
|
12085
|
-
}
|
|
12086
|
-
function maybeShowTelemetryNotice() {
|
|
12087
|
-
if (isTelemetryDisabled() || isAgentMode()) return;
|
|
12088
|
-
if (telemetryNoticeShown()) return;
|
|
12089
|
-
markTelemetryNoticeShown();
|
|
12090
|
-
process.stderr.write(
|
|
12091
|
-
pc15.dim(
|
|
12092
|
-
"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"
|
|
12093
|
-
)
|
|
12094
|
-
);
|
|
12095
|
-
}
|
|
12096
|
-
|
|
12097
12232
|
// src/cli.ts
|
|
12098
12233
|
silenceWarningsInAgentMode();
|
|
12099
12234
|
var require4 = createRequire3(import.meta.url);
|
|
@@ -12102,7 +12237,7 @@ var program = new Command();
|
|
|
12102
12237
|
program.name("one").option("--agent", "Machine-readable JSON output (no colors, spinners, or prompts)").description(`One CLI \u2014 Connect AI agents to 600+ platforms through one interface.
|
|
12103
12238
|
|
|
12104
12239
|
Setup:
|
|
12105
|
-
one login Authenticate via browser
|
|
12240
|
+
one login Authenticate via browser; the consent page records where this CLI is installed
|
|
12106
12241
|
one logout Clear local credentials
|
|
12107
12242
|
one init Set up API key + skill (add --auth browser for no-prompt agent setup)
|
|
12108
12243
|
one add <platform> Connect a platform via OAuth (e.g. gmail, slack, shopify)
|
|
@@ -12312,8 +12447,8 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12312
12447
|
return;
|
|
12313
12448
|
}
|
|
12314
12449
|
}
|
|
12315
|
-
const
|
|
12316
|
-
|
|
12450
|
+
const fs15 = await import("fs");
|
|
12451
|
+
fs15.unlinkSync(globalPath);
|
|
12317
12452
|
if (isAgentMode()) {
|
|
12318
12453
|
json({ deleted: true, scope: "global" });
|
|
12319
12454
|
} else {
|
|
@@ -12330,15 +12465,15 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12330
12465
|
}
|
|
12331
12466
|
return;
|
|
12332
12467
|
}
|
|
12333
|
-
const
|
|
12334
|
-
const configContent =
|
|
12335
|
-
|
|
12468
|
+
const fs14 = await import("fs");
|
|
12469
|
+
const configContent = fs14.readFileSync(resolved.path, "utf-8");
|
|
12470
|
+
fs14.unlinkSync(resolved.path);
|
|
12336
12471
|
const next = resolveConfig();
|
|
12337
|
-
|
|
12338
|
-
|
|
12472
|
+
fs14.mkdirSync(path13.dirname(resolved.path), { recursive: true });
|
|
12473
|
+
fs14.writeFileSync(resolved.path, configContent);
|
|
12339
12474
|
let fallbackLabel;
|
|
12340
12475
|
if (next.scope === "project") {
|
|
12341
|
-
fallbackLabel = `parent project config (${
|
|
12476
|
+
fallbackLabel = `parent project config (${path13.basename(next.projectRoot)})`;
|
|
12342
12477
|
} else if (next.scope === "global") {
|
|
12343
12478
|
fallbackLabel = "global config";
|
|
12344
12479
|
} else {
|
|
@@ -12347,7 +12482,7 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12347
12482
|
if (!isAgentMode()) {
|
|
12348
12483
|
const p10 = await import("@clack/prompts");
|
|
12349
12484
|
const confirmed = await p10.confirm({
|
|
12350
|
-
message: `Delete project config for ${
|
|
12485
|
+
message: `Delete project config for ${path13.basename(resolved.projectRoot)}? Will fall back to ${fallbackLabel}.`,
|
|
12351
12486
|
initialValue: false
|
|
12352
12487
|
});
|
|
12353
12488
|
if (p10.isCancel(confirmed) || !confirmed) {
|
|
@@ -12355,9 +12490,9 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12355
12490
|
return;
|
|
12356
12491
|
}
|
|
12357
12492
|
}
|
|
12358
|
-
|
|
12493
|
+
fs14.unlinkSync(resolved.path);
|
|
12359
12494
|
try {
|
|
12360
|
-
|
|
12495
|
+
fs14.rmdirSync(path13.dirname(resolved.path));
|
|
12361
12496
|
} catch {
|
|
12362
12497
|
}
|
|
12363
12498
|
if (isAgentMode()) {
|
|
@@ -12507,6 +12642,7 @@ program.command("whoami").description("Show the user, organization, and project
|
|
|
12507
12642
|
const resolved = resolveConfig();
|
|
12508
12643
|
const configScope = resolved.scope ?? "global";
|
|
12509
12644
|
const apiBase = getApiBase();
|
|
12645
|
+
const keyName = resolved.config?.apiKey === apiKey ? resolved.config.apiKeyName : void 0;
|
|
12510
12646
|
if (isAgentMode()) {
|
|
12511
12647
|
json({
|
|
12512
12648
|
user: whoami.user,
|
|
@@ -12514,7 +12650,8 @@ program.command("whoami").description("Show the user, organization, and project
|
|
|
12514
12650
|
project: whoami.project,
|
|
12515
12651
|
env,
|
|
12516
12652
|
configScope,
|
|
12517
|
-
apiBase
|
|
12653
|
+
apiBase,
|
|
12654
|
+
keyName
|
|
12518
12655
|
});
|
|
12519
12656
|
return;
|
|
12520
12657
|
}
|
|
@@ -12528,6 +12665,7 @@ program.command("whoami").description("Show the user, organization, and project
|
|
|
12528
12665
|
console.log();
|
|
12529
12666
|
console.log(` ${pc16.bold(scopeDisplay)} ${pc16.dim("\xB7")} ${envLabel}`);
|
|
12530
12667
|
console.log(` ${whoami.user.name} ${pc16.dim(`(${whoami.user.email})`)}`);
|
|
12668
|
+
if (keyName) console.log(` ${pc16.dim("Key:")} ${keyName}`);
|
|
12531
12669
|
if (whoami.organization) console.log(` ${pc16.dim("Org:")} ${whoami.organization.name} ${pc16.dim(`(${whoami.organization.id})`)}`);
|
|
12532
12670
|
if (whoami.project) console.log(` ${pc16.dim("Project:")} ${whoami.project.name} ${pc16.dim(`(${whoami.project.id})`)}`);
|
|
12533
12671
|
console.log();
|