getprismo 0.1.37 → 0.1.39
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 +79 -6
- package/lib/prismo-dev/cli.js +14 -4
- package/lib/prismo-dev/cloud-sync.js +25 -13
- package/lib/prismo-dev/connector.js +11 -2
- package/lib/prismo-dev/help.js +13 -8
- package/package.json +1 -1
package/lib/prismo-dev/agent.js
CHANGED
|
@@ -174,13 +174,32 @@ module.exports = function createAgent(deps) {
|
|
|
174
174
|
return url;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
async function reportProgress(config, actionId, step, detail, options = {}) {
|
|
178
|
+
const endpoint = options.progressEndpoint || `${apiBase(config)}/v1/dev/workspace/actions/${actionId}/progress`;
|
|
179
|
+
try {
|
|
180
|
+
await requestJson("POST", endpoint, config.token, {
|
|
181
|
+
step,
|
|
182
|
+
detail: detail || null,
|
|
183
|
+
timestamp: new Date().toISOString(),
|
|
184
|
+
}, options.timeoutMs || 5000);
|
|
185
|
+
} catch (_) {}
|
|
186
|
+
}
|
|
187
|
+
|
|
177
188
|
async function executeAction(action, rootDir, options = {}) {
|
|
178
189
|
const root = repoRoot(path.resolve(rootDir || process.cwd()), action);
|
|
179
190
|
const parsed = parseCommand(action.command);
|
|
180
191
|
const startedAt = new Date().toISOString();
|
|
192
|
+
const config = options._config || null;
|
|
193
|
+
const progress = config ? (step, detail) => reportProgress(config, action.id, step, detail, options) : async () => {};
|
|
181
194
|
|
|
182
195
|
if (parsed.command === "doctor" || action.actionType === "doctor") {
|
|
196
|
+
await progress("scanning", "Scanning repo for context issues");
|
|
183
197
|
const result = runDoctor(root, { limit: options.limit || 3, applySuggestions: true, json: true });
|
|
198
|
+
const score = result.after?.score ?? result.scan?.score ?? null;
|
|
199
|
+
const issueCount = result.scan?.issues?.length || 0;
|
|
200
|
+
const generatedFiles = result.generatedFiles || result.optimize?.generatedFiles || [];
|
|
201
|
+
if (issueCount > 0) await progress("fixing", `Found ${issueCount} issue${issueCount === 1 ? "" : "s"}, applying fixes`);
|
|
202
|
+
await progress("done", `Score: ${score}/100, generated ${generatedFiles.length} file${generatedFiles.length === 1 ? "" : "s"}`);
|
|
184
203
|
return {
|
|
185
204
|
status: "completed",
|
|
186
205
|
statusMessage: "Doctor completed and applied safe ignore/context fixes.",
|
|
@@ -188,14 +207,16 @@ module.exports = function createAgent(deps) {
|
|
|
188
207
|
command: "doctor",
|
|
189
208
|
startedAt,
|
|
190
209
|
completedAt: new Date().toISOString(),
|
|
191
|
-
score
|
|
192
|
-
generatedFiles
|
|
210
|
+
score,
|
|
211
|
+
generatedFiles,
|
|
193
212
|
},
|
|
194
213
|
};
|
|
195
214
|
}
|
|
196
215
|
|
|
197
216
|
if (parsed.command === "sync" || action.actionType === "sync") {
|
|
217
|
+
await progress("syncing", "Syncing local telemetry to workspace");
|
|
198
218
|
const result = await runSync(root, { limit: options.limit || 20 });
|
|
219
|
+
await progress("done", result.synced ? "Sync completed" : "Sync failed");
|
|
199
220
|
return {
|
|
200
221
|
status: result.synced ? "completed" : "failed",
|
|
201
222
|
statusMessage: result.synced ? "Sync completed." : "Sync could not run because this machine is not connected.",
|
|
@@ -211,6 +232,7 @@ module.exports = function createAgent(deps) {
|
|
|
211
232
|
}
|
|
212
233
|
|
|
213
234
|
if (parsed.command === "guard" || action.actionType === "guard") {
|
|
235
|
+
await progress("guarding", "Running guardrail snapshot across sessions");
|
|
214
236
|
const result = await runGuard(root, {
|
|
215
237
|
tool: "all",
|
|
216
238
|
limit: options.limit || 5,
|
|
@@ -218,6 +240,8 @@ module.exports = function createAgent(deps) {
|
|
|
218
240
|
noSync: false,
|
|
219
241
|
watch: false,
|
|
220
242
|
});
|
|
243
|
+
const eventCount = result.events?.length || 0;
|
|
244
|
+
await progress("done", `Guard complete, ${eventCount} event${eventCount === 1 ? "" : "s"} recorded`);
|
|
221
245
|
return {
|
|
222
246
|
status: "completed",
|
|
223
247
|
statusMessage: "Guard snapshot completed. Start agent watch mode for continuous protection.",
|
|
@@ -226,14 +250,17 @@ module.exports = function createAgent(deps) {
|
|
|
226
250
|
startedAt,
|
|
227
251
|
completedAt: new Date().toISOString(),
|
|
228
252
|
guardRunning: Boolean(result.guardRunning),
|
|
229
|
-
events:
|
|
253
|
+
events: eventCount,
|
|
230
254
|
},
|
|
231
255
|
};
|
|
232
256
|
}
|
|
233
257
|
|
|
234
258
|
if (parsed.command === "context" || parsed.command === "optimize" || action.actionType === "context") {
|
|
235
259
|
const scope = parsed.args.find((arg) => !arg.startsWith("-")) || null;
|
|
260
|
+
await progress("generating", `Generating context pack${scope ? ` for ${scope}` : ""}`);
|
|
236
261
|
const result = runOptimize(root, { scope });
|
|
262
|
+
const generatedFiles = result.generatedFiles || [];
|
|
263
|
+
await progress("done", `Generated ${generatedFiles.length} file${generatedFiles.length === 1 ? "" : "s"}`);
|
|
237
264
|
return {
|
|
238
265
|
status: "completed",
|
|
239
266
|
statusMessage: "Context pack generated.",
|
|
@@ -242,7 +269,7 @@ module.exports = function createAgent(deps) {
|
|
|
242
269
|
startedAt,
|
|
243
270
|
completedAt: new Date().toISOString(),
|
|
244
271
|
scope,
|
|
245
|
-
generatedFiles
|
|
272
|
+
generatedFiles,
|
|
246
273
|
},
|
|
247
274
|
};
|
|
248
275
|
}
|
|
@@ -250,13 +277,16 @@ module.exports = function createAgent(deps) {
|
|
|
250
277
|
if (parsed.command === "shield" || action.actionType === "shield") {
|
|
251
278
|
const commandArgs = parseShieldArgs(parsed.args);
|
|
252
279
|
if (!commandArgs) {
|
|
280
|
+
await progress("rejected", "Command not on safe allowlist");
|
|
253
281
|
return {
|
|
254
282
|
status: "failed",
|
|
255
283
|
statusMessage: "Shield action was rejected because the command is not on the safe allowlist.",
|
|
256
284
|
result: { command: "shield", rejected: true, reason: "unsafe-shield-command" },
|
|
257
285
|
};
|
|
258
286
|
}
|
|
287
|
+
await progress("shielding", `Running shielded command: ${commandArgs.join(" ")}`);
|
|
259
288
|
const result = runShield(root, commandArgs);
|
|
289
|
+
await progress("done", result.exitCode === 0 ? "Command completed" : "Command failed");
|
|
260
290
|
return {
|
|
261
291
|
status: result.exitCode === 0 ? "completed" : "failed",
|
|
262
292
|
statusMessage: result.exitCode === 0 ? "Shielded command completed." : "Shielded command exited with an error.",
|
|
@@ -336,11 +366,29 @@ module.exports = function createAgent(deps) {
|
|
|
336
366
|
status: "running",
|
|
337
367
|
statusMessage: "Running locally through PrismoDev agent.",
|
|
338
368
|
}, options);
|
|
339
|
-
const result = await executeAction(action, rootDir, options);
|
|
369
|
+
const result = await executeAction(action, rootDir, { ...options, _config: config });
|
|
340
370
|
await updateAction(config, action.id, result, options);
|
|
341
371
|
results.push({ id: action.id, label: action.label, ...result });
|
|
342
372
|
}
|
|
343
373
|
|
|
374
|
+
let syncResult = null;
|
|
375
|
+
if (options.syncTelemetry) {
|
|
376
|
+
try {
|
|
377
|
+
const result = await runSync(rootDir, { limit: options.syncLimit || 20 });
|
|
378
|
+
syncResult = {
|
|
379
|
+
synced: Boolean(result.synced),
|
|
380
|
+
sessions: Number(result.aggregate?.sessions || 0),
|
|
381
|
+
estimatedWastedTokens: Number(result.aggregate?.estimatedWastedTokens || 0),
|
|
382
|
+
wastePercent: Number(result.aggregate?.wastePercent || 0),
|
|
383
|
+
};
|
|
384
|
+
} catch (error) {
|
|
385
|
+
syncResult = {
|
|
386
|
+
synced: false,
|
|
387
|
+
error: error && error.message ? error.message : String(error),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
344
392
|
return {
|
|
345
393
|
schemaVersion: 1,
|
|
346
394
|
command: "agent",
|
|
@@ -352,6 +400,7 @@ module.exports = function createAgent(deps) {
|
|
|
352
400
|
actionsFailed: results.filter((item) => item.status === "failed").length,
|
|
353
401
|
actionsObserved: results.filter((item) => item.status === "observed" || item.status === "pending_approval").length,
|
|
354
402
|
autoDetect: autoDetectResult,
|
|
403
|
+
sync: syncResult,
|
|
355
404
|
results,
|
|
356
405
|
privacy: {
|
|
357
406
|
rawPrompts: false,
|
|
@@ -400,6 +449,16 @@ module.exports = function createAgent(deps) {
|
|
|
400
449
|
lines.push(` - ${f.message}`);
|
|
401
450
|
});
|
|
402
451
|
}
|
|
452
|
+
if (result.sync) {
|
|
453
|
+
lines.push("");
|
|
454
|
+
lines.push("Sync");
|
|
455
|
+
if (result.sync.synced) {
|
|
456
|
+
lines.push(` Sessions: ${result.sync.sessions}`);
|
|
457
|
+
lines.push(` Likely wasted: ${result.sync.estimatedWastedTokens.toLocaleString()} (${result.sync.wastePercent}%)`);
|
|
458
|
+
} else {
|
|
459
|
+
lines.push(` Status: not synced${result.sync.error ? ` (${result.sync.error})` : ""}`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
403
462
|
if (result.results.length) {
|
|
404
463
|
lines.push("");
|
|
405
464
|
lines.push("Actions");
|
|
@@ -418,9 +477,13 @@ module.exports = function createAgent(deps) {
|
|
|
418
477
|
if (!options.watch) return runAgentOnce(rootDir, options);
|
|
419
478
|
|
|
420
479
|
const intervalMs = Math.max(5, Number(options.interval || 15)) * 1000;
|
|
480
|
+
const syncIntervalMs = Math.max(30, Number(options.syncInterval || 60)) * 1000;
|
|
481
|
+
const detectIntervalMs = Math.max(60, Number(options.detectInterval || 300)) * 1000;
|
|
421
482
|
let running = true;
|
|
422
483
|
let sleepResolve = null;
|
|
423
484
|
let firstRun = true;
|
|
485
|
+
let lastSyncAt = 0;
|
|
486
|
+
let lastDetectAt = 0;
|
|
424
487
|
|
|
425
488
|
if (options.open) {
|
|
426
489
|
const config = loadConfig();
|
|
@@ -445,7 +508,16 @@ module.exports = function createAgent(deps) {
|
|
|
445
508
|
process.on("SIGTERM", shutdown);
|
|
446
509
|
|
|
447
510
|
while (running) {
|
|
448
|
-
const
|
|
511
|
+
const now = Date.now();
|
|
512
|
+
const shouldSync = options.noSync !== true && (lastSyncAt === 0 || now - lastSyncAt >= syncIntervalMs);
|
|
513
|
+
if (shouldSync) lastSyncAt = now;
|
|
514
|
+
const shouldDetect = options.autoDetect !== false && (firstRun || now - lastDetectAt >= detectIntervalMs);
|
|
515
|
+
if (shouldDetect) lastDetectAt = now;
|
|
516
|
+
const runOptions = {
|
|
517
|
+
...options,
|
|
518
|
+
autoDetect: shouldDetect,
|
|
519
|
+
syncTelemetry: shouldSync,
|
|
520
|
+
};
|
|
449
521
|
firstRun = false;
|
|
450
522
|
const result = await runAgentOnce(rootDir, runOptions);
|
|
451
523
|
if (!running) break;
|
|
@@ -468,6 +540,7 @@ module.exports = function createAgent(deps) {
|
|
|
468
540
|
parseCommand,
|
|
469
541
|
renderAgentTerminal,
|
|
470
542
|
reportAutoDetect,
|
|
543
|
+
reportProgress,
|
|
471
544
|
runAgent,
|
|
472
545
|
runAgentOnce,
|
|
473
546
|
runAutoDetect,
|
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,11 +340,12 @@ 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
|
});
|
|
345
347
|
result.next = result.connector?.started
|
|
346
|
-
? [`${NPX_COMMAND} status
|
|
348
|
+
? [`${NPX_COMMAND} status`]
|
|
347
349
|
: [`${NPX_COMMAND} connector install`, `${NPX_COMMAND} status`];
|
|
348
350
|
}
|
|
349
351
|
if (result.connected && (rest.includes("--open") || !rest.includes("--no-open"))) {
|
|
@@ -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,8 @@ 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");
|
|
427
|
+
const detectIntervalIndex = rest.indexOf("--detect-interval");
|
|
422
428
|
const limitIndex = rest.indexOf("--limit");
|
|
423
429
|
const budgetIndex = rest.indexOf("--budget");
|
|
424
430
|
const modeIndex = rest.indexOf("--mode");
|
|
@@ -426,7 +432,7 @@ function createCli(deps) {
|
|
|
426
432
|
if (!AGENT_VALID_MODES.has(modeValue)) {
|
|
427
433
|
throw new Error(`Invalid agent mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
|
|
428
434
|
}
|
|
429
|
-
const positional = getPositionals(rest, new Set(["--interval", "--limit", "--budget", "--mode"]));
|
|
435
|
+
const positional = getPositionals(rest, new Set(["--interval", "--sync-interval", "--detect-interval", "--limit", "--budget", "--mode"]));
|
|
430
436
|
const target = positional[0] || process.cwd();
|
|
431
437
|
const agentOptions = {
|
|
432
438
|
json,
|
|
@@ -434,8 +440,12 @@ function createCli(deps) {
|
|
|
434
440
|
watch: rest.includes("--watch") && !rest.includes("--once"),
|
|
435
441
|
open: rest.includes("--open"),
|
|
436
442
|
autoDetect: !rest.includes("--no-detect"),
|
|
443
|
+
noSync: rest.includes("--no-sync"),
|
|
437
444
|
interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
|
|
445
|
+
syncInterval: parsePositiveInt(syncIntervalIndex >= 0 ? rest[syncIntervalIndex + 1] : null, 60),
|
|
446
|
+
detectInterval: parsePositiveInt(detectIntervalIndex >= 0 ? rest[detectIntervalIndex + 1] : null, 300),
|
|
438
447
|
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
|
|
448
|
+
syncLimit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
|
|
439
449
|
tokenBudget: parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || 600000,
|
|
440
450
|
};
|
|
441
451
|
const result = await runAgent(target, agentOptions);
|
|
@@ -405,20 +405,32 @@ module.exports = function createCloudSync(deps) {
|
|
|
405
405
|
function renderConnectTerminal(result) {
|
|
406
406
|
const lines = [];
|
|
407
407
|
lines.push("");
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
lines.push(
|
|
416
|
-
|
|
417
|
-
|
|
408
|
+
if (result.connected && result.connector?.started) {
|
|
409
|
+
lines.push("Prismo agent is running.");
|
|
410
|
+
lines.push("");
|
|
411
|
+
lines.push(`Device: ${result.device.name}`);
|
|
412
|
+
lines.push(`Mode: ${result.connector.mode || "autopilot"}`);
|
|
413
|
+
lines.push(`Poll: every ${result.connector.interval || 15}s`);
|
|
414
|
+
lines.push(`Sync: every ${result.connector.syncInterval || 60}s`);
|
|
415
|
+
lines.push("");
|
|
416
|
+
lines.push("Your agent will continuously scan, repair, and guard this repo.");
|
|
417
|
+
lines.push("Open the dashboard to see what it's doing.");
|
|
418
|
+
} else {
|
|
419
|
+
lines.push("PrismoDev Connect");
|
|
420
|
+
lines.push("");
|
|
421
|
+
lines.push(`Status: ${result.connected ? "connected" : "token needed"}`);
|
|
422
|
+
lines.push(`Config: ${result.configPath}`);
|
|
423
|
+
lines.push(`API: ${result.apiUrl}`);
|
|
424
|
+
lines.push(`Device: ${result.device.name}`);
|
|
425
|
+
if (result.connector) {
|
|
426
|
+
lines.push(`Connector: ${result.connector.started ? "started" : result.connector.installed ? "installed" : "not started"}`);
|
|
427
|
+
if (result.connector.reason) lines.push(`Note: ${result.connector.reason}`);
|
|
428
|
+
if (result.connector.error) lines.push(`Error: ${result.connector.error}`);
|
|
429
|
+
}
|
|
430
|
+
lines.push("");
|
|
431
|
+
lines.push("Next");
|
|
432
|
+
result.next.forEach((item, index) => lines.push(`${index + 1}. ${item}`));
|
|
418
433
|
}
|
|
419
|
-
lines.push("");
|
|
420
|
-
lines.push("Next");
|
|
421
|
-
result.next.forEach((item, index) => lines.push(`${index + 1}. ${item}`));
|
|
422
434
|
return lines.join("\n");
|
|
423
435
|
}
|
|
424
436
|
|
|
@@ -79,9 +79,11 @@ 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));
|
|
83
|
+
const detectInterval = Math.max(60, Number(options.detectInterval || 300));
|
|
82
84
|
const mode = options.mode || "autopilot";
|
|
83
85
|
fs.mkdirSync(connectorDir(), { recursive: true });
|
|
84
|
-
const command = `${BACKGROUND_COMMAND} agent --watch --interval ${interval} --mode ${shellEscape(mode)} ${shellEscape(root)}`;
|
|
86
|
+
const command = `${BACKGROUND_COMMAND} agent --watch --interval ${interval} --sync-interval ${syncInterval} --detect-interval ${detectInterval} --mode ${shellEscape(mode)} ${shellEscape(root)}`;
|
|
85
87
|
const contents = [
|
|
86
88
|
"#!/bin/sh",
|
|
87
89
|
"set -eu",
|
|
@@ -95,6 +97,8 @@ module.exports = function createConnector(deps) {
|
|
|
95
97
|
installedAt: new Date().toISOString(),
|
|
96
98
|
root,
|
|
97
99
|
interval,
|
|
100
|
+
syncInterval,
|
|
101
|
+
detectInterval,
|
|
98
102
|
mode,
|
|
99
103
|
command,
|
|
100
104
|
platform: process.platform,
|
|
@@ -102,7 +106,7 @@ module.exports = function createConnector(deps) {
|
|
|
102
106
|
logPath: logPath(),
|
|
103
107
|
errorLogPath: errorLogPath(),
|
|
104
108
|
});
|
|
105
|
-
return { root, interval, mode, command };
|
|
109
|
+
return { root, interval, syncInterval, detectInterval, mode, command };
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
function writePlist() {
|
|
@@ -168,6 +172,7 @@ module.exports = function createConnector(deps) {
|
|
|
168
172
|
root: runner.root,
|
|
169
173
|
mode: runner.mode,
|
|
170
174
|
interval: runner.interval,
|
|
175
|
+
syncInterval: runner.syncInterval,
|
|
171
176
|
plistPath: plistPath(),
|
|
172
177
|
statePath: statePath(),
|
|
173
178
|
runner: scriptPath(),
|
|
@@ -261,10 +266,14 @@ module.exports = function createConnector(deps) {
|
|
|
261
266
|
lines.push(`Installed: ${result.installed ? "yes" : "no"}`);
|
|
262
267
|
lines.push(`Status: ${result.online ? "online" : "idle"}`);
|
|
263
268
|
if (result.state?.root) lines.push(`Repo: ${result.state.root}`);
|
|
269
|
+
if (result.state?.interval) lines.push(`Poll: every ${result.state.interval}s`);
|
|
270
|
+
if (result.state?.syncInterval) lines.push(`Sync: every ${result.state.syncInterval}s`);
|
|
264
271
|
lines.push(`Logs: ${result.logPath}`);
|
|
265
272
|
} else if (result.action === "install") {
|
|
266
273
|
lines.push(`Status: ${result.started ? "started" : result.installed ? "installed" : "not installed"}`);
|
|
267
274
|
if (result.root) lines.push(`Repo: ${result.root}`);
|
|
275
|
+
if (result.interval) lines.push(`Poll: every ${result.interval}s`);
|
|
276
|
+
if (result.syncInterval) lines.push(`Sync: every ${result.syncInterval}s`);
|
|
268
277
|
if (result.reason) lines.push(`Note: ${result.reason}`);
|
|
269
278
|
if (result.error) lines.push(`Error: ${result.error}`);
|
|
270
279
|
} 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