getprismo 0.1.37 → 0.1.38
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/lib/prismo-dev/agent.js +39 -1
- package/lib/prismo-dev/cli.js +11 -3
- package/lib/prismo-dev/connector.js +9 -2
- package/lib/prismo-dev/help.js +13 -8
- package/package.json +1 -1
package/lib/prismo-dev/agent.js
CHANGED
|
@@ -341,6 +341,24 @@ module.exports = function createAgent(deps) {
|
|
|
341
341
|
results.push({ id: action.id, label: action.label, ...result });
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
+
let syncResult = null;
|
|
345
|
+
if (options.syncTelemetry) {
|
|
346
|
+
try {
|
|
347
|
+
const result = await runSync(rootDir, { limit: options.syncLimit || 20 });
|
|
348
|
+
syncResult = {
|
|
349
|
+
synced: Boolean(result.synced),
|
|
350
|
+
sessions: Number(result.aggregate?.sessions || 0),
|
|
351
|
+
estimatedWastedTokens: Number(result.aggregate?.estimatedWastedTokens || 0),
|
|
352
|
+
wastePercent: Number(result.aggregate?.wastePercent || 0),
|
|
353
|
+
};
|
|
354
|
+
} catch (error) {
|
|
355
|
+
syncResult = {
|
|
356
|
+
synced: false,
|
|
357
|
+
error: error && error.message ? error.message : String(error),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
344
362
|
return {
|
|
345
363
|
schemaVersion: 1,
|
|
346
364
|
command: "agent",
|
|
@@ -352,6 +370,7 @@ module.exports = function createAgent(deps) {
|
|
|
352
370
|
actionsFailed: results.filter((item) => item.status === "failed").length,
|
|
353
371
|
actionsObserved: results.filter((item) => item.status === "observed" || item.status === "pending_approval").length,
|
|
354
372
|
autoDetect: autoDetectResult,
|
|
373
|
+
sync: syncResult,
|
|
355
374
|
results,
|
|
356
375
|
privacy: {
|
|
357
376
|
rawPrompts: false,
|
|
@@ -400,6 +419,16 @@ module.exports = function createAgent(deps) {
|
|
|
400
419
|
lines.push(` - ${f.message}`);
|
|
401
420
|
});
|
|
402
421
|
}
|
|
422
|
+
if (result.sync) {
|
|
423
|
+
lines.push("");
|
|
424
|
+
lines.push("Sync");
|
|
425
|
+
if (result.sync.synced) {
|
|
426
|
+
lines.push(` Sessions: ${result.sync.sessions}`);
|
|
427
|
+
lines.push(` Likely wasted: ${result.sync.estimatedWastedTokens.toLocaleString()} (${result.sync.wastePercent}%)`);
|
|
428
|
+
} else {
|
|
429
|
+
lines.push(` Status: not synced${result.sync.error ? ` (${result.sync.error})` : ""}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
403
432
|
if (result.results.length) {
|
|
404
433
|
lines.push("");
|
|
405
434
|
lines.push("Actions");
|
|
@@ -418,9 +447,11 @@ module.exports = function createAgent(deps) {
|
|
|
418
447
|
if (!options.watch) return runAgentOnce(rootDir, options);
|
|
419
448
|
|
|
420
449
|
const intervalMs = Math.max(5, Number(options.interval || 15)) * 1000;
|
|
450
|
+
const syncIntervalMs = Math.max(30, Number(options.syncInterval || 60)) * 1000;
|
|
421
451
|
let running = true;
|
|
422
452
|
let sleepResolve = null;
|
|
423
453
|
let firstRun = true;
|
|
454
|
+
let lastSyncAt = 0;
|
|
424
455
|
|
|
425
456
|
if (options.open) {
|
|
426
457
|
const config = loadConfig();
|
|
@@ -445,7 +476,14 @@ module.exports = function createAgent(deps) {
|
|
|
445
476
|
process.on("SIGTERM", shutdown);
|
|
446
477
|
|
|
447
478
|
while (running) {
|
|
448
|
-
const
|
|
479
|
+
const now = Date.now();
|
|
480
|
+
const shouldSync = options.noSync !== true && (lastSyncAt === 0 || now - lastSyncAt >= syncIntervalMs);
|
|
481
|
+
if (shouldSync) lastSyncAt = now;
|
|
482
|
+
const runOptions = {
|
|
483
|
+
...options,
|
|
484
|
+
autoDetect: firstRun && options.autoDetect !== false,
|
|
485
|
+
syncTelemetry: shouldSync,
|
|
486
|
+
};
|
|
449
487
|
firstRun = false;
|
|
450
488
|
const result = await runAgentOnce(rootDir, runOptions);
|
|
451
489
|
if (!running) break;
|
package/lib/prismo-dev/cli.js
CHANGED
|
@@ -321,12 +321,13 @@ function createCli(deps) {
|
|
|
321
321
|
const deviceIndex = rest.indexOf("--device");
|
|
322
322
|
const limitIndex = rest.indexOf("--limit");
|
|
323
323
|
const intervalIndex = rest.indexOf("--interval");
|
|
324
|
+
const syncIntervalIndex = rest.indexOf("--sync-interval");
|
|
324
325
|
const modeIndex = rest.indexOf("--mode");
|
|
325
326
|
const modeValue = modeIndex >= 0 ? rest[modeIndex + 1] : "autopilot";
|
|
326
327
|
if (!AGENT_VALID_MODES.has(modeValue)) {
|
|
327
328
|
throw new Error(`Invalid connector mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
|
|
328
329
|
}
|
|
329
|
-
const positional = getPositionals(rest, new Set(["--token", "--api-url", "--org", "--user", "--device", "--limit", "--interval", "--mode"]));
|
|
330
|
+
const positional = getPositionals(rest, new Set(["--token", "--api-url", "--org", "--user", "--device", "--limit", "--interval", "--sync-interval", "--mode"]));
|
|
330
331
|
const target = positional[0] || process.cwd();
|
|
331
332
|
const result = runConnect({
|
|
332
333
|
token: tokenIndex >= 0 ? rest[tokenIndex + 1] : null,
|
|
@@ -339,6 +340,7 @@ function createCli(deps) {
|
|
|
339
340
|
if (result.connected && !rest.includes("--no-agent") && runConnectorInstall) {
|
|
340
341
|
result.connector = runConnectorInstall(target, {
|
|
341
342
|
interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
|
|
343
|
+
syncInterval: parsePositiveInt(syncIntervalIndex >= 0 ? rest[syncIntervalIndex + 1] : null, 60),
|
|
342
344
|
mode: modeValue,
|
|
343
345
|
dryRun: rest.includes("--dry-run"),
|
|
344
346
|
});
|
|
@@ -357,18 +359,20 @@ function createCli(deps) {
|
|
|
357
359
|
if (command === "connector") {
|
|
358
360
|
const json = rest.includes("--json");
|
|
359
361
|
const intervalIndex = rest.indexOf("--interval");
|
|
362
|
+
const syncIntervalIndex = rest.indexOf("--sync-interval");
|
|
360
363
|
const modeIndex = rest.indexOf("--mode");
|
|
361
364
|
const modeValue = modeIndex >= 0 ? rest[modeIndex + 1] : "autopilot";
|
|
362
365
|
if (!AGENT_VALID_MODES.has(modeValue)) {
|
|
363
366
|
throw new Error(`Invalid connector mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
|
|
364
367
|
}
|
|
365
|
-
const positional = getPositionals(rest, new Set(["--interval", "--mode"]));
|
|
368
|
+
const positional = getPositionals(rest, new Set(["--interval", "--sync-interval", "--mode"]));
|
|
366
369
|
const action = ["install", "start", "stop", "status", "uninstall"].includes(positional[0]) ? positional[0] : "status";
|
|
367
370
|
const target = ["install"].includes(action) ? positional[1] || process.cwd() : positional[0] || process.cwd();
|
|
368
371
|
let result;
|
|
369
372
|
if (action === "install") {
|
|
370
373
|
result = runConnectorInstall(target, {
|
|
371
374
|
interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
|
|
375
|
+
syncInterval: parsePositiveInt(syncIntervalIndex >= 0 ? rest[syncIntervalIndex + 1] : null, 60),
|
|
372
376
|
mode: modeValue,
|
|
373
377
|
dryRun: rest.includes("--dry-run"),
|
|
374
378
|
});
|
|
@@ -419,6 +423,7 @@ function createCli(deps) {
|
|
|
419
423
|
if (command === "agent") {
|
|
420
424
|
const json = rest.includes("--json");
|
|
421
425
|
const intervalIndex = rest.indexOf("--interval");
|
|
426
|
+
const syncIntervalIndex = rest.indexOf("--sync-interval");
|
|
422
427
|
const limitIndex = rest.indexOf("--limit");
|
|
423
428
|
const budgetIndex = rest.indexOf("--budget");
|
|
424
429
|
const modeIndex = rest.indexOf("--mode");
|
|
@@ -426,7 +431,7 @@ function createCli(deps) {
|
|
|
426
431
|
if (!AGENT_VALID_MODES.has(modeValue)) {
|
|
427
432
|
throw new Error(`Invalid agent mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
|
|
428
433
|
}
|
|
429
|
-
const positional = getPositionals(rest, new Set(["--interval", "--limit", "--budget", "--mode"]));
|
|
434
|
+
const positional = getPositionals(rest, new Set(["--interval", "--sync-interval", "--limit", "--budget", "--mode"]));
|
|
430
435
|
const target = positional[0] || process.cwd();
|
|
431
436
|
const agentOptions = {
|
|
432
437
|
json,
|
|
@@ -434,8 +439,11 @@ function createCli(deps) {
|
|
|
434
439
|
watch: rest.includes("--watch") && !rest.includes("--once"),
|
|
435
440
|
open: rest.includes("--open"),
|
|
436
441
|
autoDetect: !rest.includes("--no-detect"),
|
|
442
|
+
noSync: rest.includes("--no-sync"),
|
|
437
443
|
interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
|
|
444
|
+
syncInterval: parsePositiveInt(syncIntervalIndex >= 0 ? rest[syncIntervalIndex + 1] : null, 60),
|
|
438
445
|
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
446
|
+
syncLimit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
439
447
|
tokenBudget: parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || 600000,
|
|
440
448
|
};
|
|
441
449
|
const result = await runAgent(target, agentOptions);
|
|
@@ -79,9 +79,10 @@ module.exports = function createConnector(deps) {
|
|
|
79
79
|
function writeRunner(rootDir, options = {}) {
|
|
80
80
|
const root = path.resolve(rootDir || process.cwd());
|
|
81
81
|
const interval = Math.max(5, Number(options.interval || 15));
|
|
82
|
+
const syncInterval = Math.max(30, Number(options.syncInterval || 60));
|
|
82
83
|
const mode = options.mode || "autopilot";
|
|
83
84
|
fs.mkdirSync(connectorDir(), { recursive: true });
|
|
84
|
-
const command = `${BACKGROUND_COMMAND} agent --watch --interval ${interval} --mode ${shellEscape(mode)} ${shellEscape(root)}`;
|
|
85
|
+
const command = `${BACKGROUND_COMMAND} agent --watch --interval ${interval} --sync-interval ${syncInterval} --mode ${shellEscape(mode)} ${shellEscape(root)}`;
|
|
85
86
|
const contents = [
|
|
86
87
|
"#!/bin/sh",
|
|
87
88
|
"set -eu",
|
|
@@ -95,6 +96,7 @@ module.exports = function createConnector(deps) {
|
|
|
95
96
|
installedAt: new Date().toISOString(),
|
|
96
97
|
root,
|
|
97
98
|
interval,
|
|
99
|
+
syncInterval,
|
|
98
100
|
mode,
|
|
99
101
|
command,
|
|
100
102
|
platform: process.platform,
|
|
@@ -102,7 +104,7 @@ module.exports = function createConnector(deps) {
|
|
|
102
104
|
logPath: logPath(),
|
|
103
105
|
errorLogPath: errorLogPath(),
|
|
104
106
|
});
|
|
105
|
-
return { root, interval, mode, command };
|
|
107
|
+
return { root, interval, syncInterval, mode, command };
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
function writePlist() {
|
|
@@ -168,6 +170,7 @@ module.exports = function createConnector(deps) {
|
|
|
168
170
|
root: runner.root,
|
|
169
171
|
mode: runner.mode,
|
|
170
172
|
interval: runner.interval,
|
|
173
|
+
syncInterval: runner.syncInterval,
|
|
171
174
|
plistPath: plistPath(),
|
|
172
175
|
statePath: statePath(),
|
|
173
176
|
runner: scriptPath(),
|
|
@@ -261,10 +264,14 @@ module.exports = function createConnector(deps) {
|
|
|
261
264
|
lines.push(`Installed: ${result.installed ? "yes" : "no"}`);
|
|
262
265
|
lines.push(`Status: ${result.online ? "online" : "idle"}`);
|
|
263
266
|
if (result.state?.root) lines.push(`Repo: ${result.state.root}`);
|
|
267
|
+
if (result.state?.interval) lines.push(`Poll: every ${result.state.interval}s`);
|
|
268
|
+
if (result.state?.syncInterval) lines.push(`Sync: every ${result.state.syncInterval}s`);
|
|
264
269
|
lines.push(`Logs: ${result.logPath}`);
|
|
265
270
|
} else if (result.action === "install") {
|
|
266
271
|
lines.push(`Status: ${result.started ? "started" : result.installed ? "installed" : "not installed"}`);
|
|
267
272
|
if (result.root) lines.push(`Repo: ${result.root}`);
|
|
273
|
+
if (result.interval) lines.push(`Poll: every ${result.interval}s`);
|
|
274
|
+
if (result.syncInterval) lines.push(`Sync: every ${result.syncInterval}s`);
|
|
268
275
|
if (result.reason) lines.push(`Note: ${result.reason}`);
|
|
269
276
|
if (result.error) lines.push(`Error: ${result.error}`);
|
|
270
277
|
} else if (result.action === "start") {
|
package/lib/prismo-dev/help.js
CHANGED
|
@@ -13,11 +13,11 @@ Usage:
|
|
|
13
13
|
prismo mcp [path]
|
|
14
14
|
prismo mcp doctor [--json] [path]
|
|
15
15
|
prismo connect [--json] [--token TOKEN] [--api-url URL] [--org ORG] [--user USER] [--device NAME]
|
|
16
|
-
prismo connector [status|install|start|stop|uninstall] [--json] [--interval N] [--mode observe|suggest|autopilot] [path]
|
|
16
|
+
prismo connector [status|install|start|stop|uninstall] [--json] [--interval N] [--sync-interval N] [--mode observe|suggest|autopilot] [path]
|
|
17
17
|
prismo sync [--json] [--dry-run] [--watch] [--interval N] [--limit N] [--tool all|codex|claude|cursor] [path]
|
|
18
18
|
prismo status [--json]
|
|
19
19
|
prismo disconnect [--json]
|
|
20
|
-
prismo agent [--json] [--once] [--watch] [--interval N] [--limit N] [--mode MODE] [path]
|
|
20
|
+
prismo agent [--json] [--once] [--watch] [--interval N] [--sync-interval N] [--limit N] [--mode MODE] [path]
|
|
21
21
|
prismo setup [--json] [--proxy-url URL] [path]
|
|
22
22
|
prismo scan [--fix] [--ci] [--json] [--usage] [--optimizer-fit] [--report-card] [--simple] [--no-report] [path]
|
|
23
23
|
prismo optimize [scope] [--json] [path]
|
|
@@ -79,6 +79,7 @@ Options:
|
|
|
79
79
|
--firewall Generate cc timeline-derived firewall suggestion files.
|
|
80
80
|
--task TASK Name the task for timeline-derived firewall suggestions.
|
|
81
81
|
--interval N Refresh interval in seconds for watch mode.
|
|
82
|
+
--sync-interval N Telemetry sync interval in seconds for the background connector.
|
|
82
83
|
--dry-run Preview doctor/fix actions without writing files.
|
|
83
84
|
--apply-ignores-only Only create/suggest AI ignore files in doctor mode.
|
|
84
85
|
--apply-suggestions Append missing recommended ignore rules with backups.
|
|
@@ -409,7 +410,7 @@ Output:
|
|
|
409
410
|
|
|
410
411
|
Usage:
|
|
411
412
|
prismo connect [--json] [--token TOKEN] [--api-url URL] [--org ORG] [--user USER] [--device NAME]
|
|
412
|
-
prismo connector [status|install|start|stop|uninstall] [--json] [--interval N] [--mode observe|suggest|autopilot] [path]
|
|
413
|
+
prismo connector [status|install|start|stop|uninstall] [--json] [--interval N] [--sync-interval N] [--mode observe|suggest|autopilot] [path]
|
|
413
414
|
prismo sync [--json] [--dry-run] [--watch] [--interval N] [--limit N] [--tool all|codex|claude|cursor] [path]
|
|
414
415
|
prismo status [--json]
|
|
415
416
|
prismo disconnect [--json]
|
|
@@ -420,6 +421,7 @@ Examples:
|
|
|
420
421
|
prismo connect --token <token> --no-agent
|
|
421
422
|
prismo connector status
|
|
422
423
|
prismo connector install
|
|
424
|
+
prismo connector install --sync-interval 120
|
|
423
425
|
prismo sync --dry-run
|
|
424
426
|
prismo sync
|
|
425
427
|
prismo sync --watch --interval 60
|
|
@@ -428,7 +430,7 @@ Examples:
|
|
|
428
430
|
|
|
429
431
|
Output:
|
|
430
432
|
connect stores a local PrismoDev device connection in ~/.prismo/config.json and starts the background workspace connector by default.
|
|
431
|
-
connector keeps Prismo Workspace online so repairs queued in the dashboard run locally without copy/paste commands.
|
|
433
|
+
connector keeps Prismo Workspace online so repairs queued in the dashboard run locally without copy/paste commands, and continuously syncs aggregate telemetry on a controlled interval.
|
|
432
434
|
sync reads local Codex, Claude Code, and Cursor session logs, builds aggregate agent-efficiency telemetry, and sends it to Prismo.
|
|
433
435
|
sync --watch keeps running so a local service manager can keep the Waste Scanner dashboard fresh.
|
|
434
436
|
Sync does not upload prompts, source code, file contents, stdout, stderr, or full command logs.`,
|
|
@@ -436,7 +438,7 @@ Output:
|
|
|
436
438
|
|
|
437
439
|
Usage:
|
|
438
440
|
prismo connector status [--json]
|
|
439
|
-
prismo connector install [--json] [--interval N] [--mode observe|suggest|autopilot] [path]
|
|
441
|
+
prismo connector install [--json] [--interval N] [--sync-interval N] [--mode observe|suggest|autopilot] [path]
|
|
440
442
|
prismo connector start [--json]
|
|
441
443
|
prismo connector stop [--json]
|
|
442
444
|
prismo connector uninstall [--json]
|
|
@@ -450,13 +452,14 @@ Examples:
|
|
|
450
452
|
prismo connector status
|
|
451
453
|
prismo connector install
|
|
452
454
|
prismo connector install --mode suggest --interval 30
|
|
455
|
+
prismo connector install --sync-interval 120
|
|
453
456
|
prismo connector stop
|
|
454
457
|
prismo connector uninstall
|
|
455
458
|
|
|
456
459
|
Output:
|
|
457
460
|
Installs and manages the local Prismo Workspace connector.
|
|
458
461
|
On macOS this creates a LaunchAgent so Prismo stays online after the terminal closes.
|
|
459
|
-
The connector claims safe repairs queued from Prismo Cloud, runs them locally, and reports status back.
|
|
462
|
+
The connector claims safe repairs queued from Prismo Cloud, runs them locally, continuously syncs aggregate telemetry, and reports status back.
|
|
460
463
|
It does not upload prompts, source code, file contents, stdout, stderr, or full command logs.`,
|
|
461
464
|
sync: `PrismoDev Sync
|
|
462
465
|
|
|
@@ -489,7 +492,7 @@ Output:
|
|
|
489
492
|
agent: `PrismoDev Agent
|
|
490
493
|
|
|
491
494
|
Usage:
|
|
492
|
-
prismo agent [--json] [--once] [--watch] [--open] [--no-detect] [--interval N] [--limit N] [--mode MODE] [path]
|
|
495
|
+
prismo agent [--json] [--once] [--watch] [--open] [--no-detect] [--no-sync] [--interval N] [--sync-interval N] [--limit N] [--mode MODE] [path]
|
|
493
496
|
|
|
494
497
|
Modes:
|
|
495
498
|
observe Watch and report actions without executing. No changes made.
|
|
@@ -499,6 +502,7 @@ Modes:
|
|
|
499
502
|
Examples:
|
|
500
503
|
prismo agent --once
|
|
501
504
|
prismo agent --watch --interval 15
|
|
505
|
+
prismo agent --watch --sync-interval 120
|
|
502
506
|
prismo agent --watch --mode observe
|
|
503
507
|
prismo agent --watch --mode suggest
|
|
504
508
|
prismo agent --watch --open
|
|
@@ -507,12 +511,13 @@ Examples:
|
|
|
507
511
|
Options:
|
|
508
512
|
--open Open the Prismo workspace in the browser on start.
|
|
509
513
|
--no-detect Skip the initial auto-detect scan on first poll.
|
|
514
|
+
--no-sync Keep watch mode from continuously syncing aggregate telemetry.
|
|
510
515
|
|
|
511
516
|
Output:
|
|
512
517
|
On first poll, the agent proactively runs doctor to detect context issues.
|
|
513
518
|
In autopilot mode it auto-fixes safe issues. In suggest mode it reports them as pending_approval in the workspace.
|
|
514
519
|
Claims safe workspace actions queued from Prismo Cloud, runs them locally, and reports status back.
|
|
515
|
-
Sends heartbeat to Prismo Cloud on each poll so the dashboard
|
|
520
|
+
Sends heartbeat to Prismo Cloud on each poll and syncs aggregate telemetry on a controlled interval so the dashboard stays fresh.
|
|
516
521
|
Handles SIGINT/SIGTERM gracefully and marks the agent offline before exiting.
|
|
517
522
|
Supported actions are doctor, sync, guard, context/optimize, and shield with a conservative command allowlist.
|
|
518
523
|
Agent does not upload prompts, source code, file contents, stdout, stderr, or full command logs.`,
|
package/package.json
CHANGED