getprismo 0.1.38 → 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.
@@ -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: result.after?.score ?? result.scan?.score ?? null,
192
- generatedFiles: result.generatedFiles || result.optimize?.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: result.events?.length || 0,
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: result.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,7 +366,7 @@ 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
  }
@@ -448,10 +478,12 @@ module.exports = function createAgent(deps) {
448
478
 
449
479
  const intervalMs = Math.max(5, Number(options.interval || 15)) * 1000;
450
480
  const syncIntervalMs = Math.max(30, Number(options.syncInterval || 60)) * 1000;
481
+ const detectIntervalMs = Math.max(60, Number(options.detectInterval || 300)) * 1000;
451
482
  let running = true;
452
483
  let sleepResolve = null;
453
484
  let firstRun = true;
454
485
  let lastSyncAt = 0;
486
+ let lastDetectAt = 0;
455
487
 
456
488
  if (options.open) {
457
489
  const config = loadConfig();
@@ -479,9 +511,11 @@ module.exports = function createAgent(deps) {
479
511
  const now = Date.now();
480
512
  const shouldSync = options.noSync !== true && (lastSyncAt === 0 || now - lastSyncAt >= syncIntervalMs);
481
513
  if (shouldSync) lastSyncAt = now;
514
+ const shouldDetect = options.autoDetect !== false && (firstRun || now - lastDetectAt >= detectIntervalMs);
515
+ if (shouldDetect) lastDetectAt = now;
482
516
  const runOptions = {
483
517
  ...options,
484
- autoDetect: firstRun && options.autoDetect !== false,
518
+ autoDetect: shouldDetect,
485
519
  syncTelemetry: shouldSync,
486
520
  };
487
521
  firstRun = false;
@@ -506,6 +540,7 @@ module.exports = function createAgent(deps) {
506
540
  parseCommand,
507
541
  renderAgentTerminal,
508
542
  reportAutoDetect,
543
+ reportProgress,
509
544
  runAgent,
510
545
  runAgentOnce,
511
546
  runAutoDetect,
@@ -345,7 +345,7 @@ function createCli(deps) {
345
345
  dryRun: rest.includes("--dry-run"),
346
346
  });
347
347
  result.next = result.connector?.started
348
- ? [`${NPX_COMMAND} status`, "Refresh Prismo Workspace"]
348
+ ? [`${NPX_COMMAND} status`]
349
349
  : [`${NPX_COMMAND} connector install`, `${NPX_COMMAND} status`];
350
350
  }
351
351
  if (result.connected && (rest.includes("--open") || !rest.includes("--no-open"))) {
@@ -424,6 +424,7 @@ function createCli(deps) {
424
424
  const json = rest.includes("--json");
425
425
  const intervalIndex = rest.indexOf("--interval");
426
426
  const syncIntervalIndex = rest.indexOf("--sync-interval");
427
+ const detectIntervalIndex = rest.indexOf("--detect-interval");
427
428
  const limitIndex = rest.indexOf("--limit");
428
429
  const budgetIndex = rest.indexOf("--budget");
429
430
  const modeIndex = rest.indexOf("--mode");
@@ -431,7 +432,7 @@ function createCli(deps) {
431
432
  if (!AGENT_VALID_MODES.has(modeValue)) {
432
433
  throw new Error(`Invalid agent mode: ${modeValue}. Valid modes: observe, suggest, autopilot`);
433
434
  }
434
- const positional = getPositionals(rest, new Set(["--interval", "--sync-interval", "--limit", "--budget", "--mode"]));
435
+ const positional = getPositionals(rest, new Set(["--interval", "--sync-interval", "--detect-interval", "--limit", "--budget", "--mode"]));
435
436
  const target = positional[0] || process.cwd();
436
437
  const agentOptions = {
437
438
  json,
@@ -442,6 +443,7 @@ function createCli(deps) {
442
443
  noSync: rest.includes("--no-sync"),
443
444
  interval: parsePositiveInt(intervalIndex >= 0 ? rest[intervalIndex + 1] : null, 15),
444
445
  syncInterval: parsePositiveInt(syncIntervalIndex >= 0 ? rest[syncIntervalIndex + 1] : null, 60),
446
+ detectInterval: parsePositiveInt(detectIntervalIndex >= 0 ? rest[detectIntervalIndex + 1] : null, 300),
445
447
  limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 5),
446
448
  syncLimit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 20),
447
449
  tokenBudget: parseTokenBudget(budgetIndex >= 0 ? rest[budgetIndex + 1] : null) || 600000,
@@ -405,20 +405,32 @@ module.exports = function createCloudSync(deps) {
405
405
  function renderConnectTerminal(result) {
406
406
  const lines = [];
407
407
  lines.push("");
408
- lines.push("PrismoDev Connect");
409
- lines.push("");
410
- lines.push(`Status: ${result.connected ? "connected" : "token needed"}`);
411
- lines.push(`Config: ${result.configPath}`);
412
- lines.push(`API: ${result.apiUrl}`);
413
- lines.push(`Device: ${result.device.name}`);
414
- if (result.connector) {
415
- lines.push(`Connector: ${result.connector.started ? "started" : result.connector.installed ? "installed" : "not started"}`);
416
- if (result.connector.reason) lines.push(`Connector note: ${result.connector.reason}`);
417
- if (result.connector.error) lines.push(`Connector error: ${result.connector.error}`);
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
 
@@ -80,9 +80,10 @@ module.exports = function createConnector(deps) {
80
80
  const root = path.resolve(rootDir || process.cwd());
81
81
  const interval = Math.max(5, Number(options.interval || 15));
82
82
  const syncInterval = Math.max(30, Number(options.syncInterval || 60));
83
+ const detectInterval = Math.max(60, Number(options.detectInterval || 300));
83
84
  const mode = options.mode || "autopilot";
84
85
  fs.mkdirSync(connectorDir(), { recursive: true });
85
- const command = `${BACKGROUND_COMMAND} agent --watch --interval ${interval} --sync-interval ${syncInterval} --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)}`;
86
87
  const contents = [
87
88
  "#!/bin/sh",
88
89
  "set -eu",
@@ -97,6 +98,7 @@ module.exports = function createConnector(deps) {
97
98
  root,
98
99
  interval,
99
100
  syncInterval,
101
+ detectInterval,
100
102
  mode,
101
103
  command,
102
104
  platform: process.platform,
@@ -104,7 +106,7 @@ module.exports = function createConnector(deps) {
104
106
  logPath: logPath(),
105
107
  errorLogPath: errorLogPath(),
106
108
  });
107
- return { root, interval, syncInterval, mode, command };
109
+ return { root, interval, syncInterval, detectInterval, mode, command };
108
110
  }
109
111
 
110
112
  function writePlist() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getprismo",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "description": "Local AI coding workflow scanner for Codex, Claude Code, Cursor, and token-waste diagnostics.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/shanirsh/prismodev#readme",