runtrim 0.1.3 → 0.1.4

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 CHANGED
@@ -90,8 +90,8 @@ npm run runtrim -- start
90
90
  - blocks unsafe mega-runs and suggests split-safe follow-ups
91
91
  - generates guarded prompts with explicit stop rules
92
92
  - monitors changed files during execution
93
- - checks output quality and missing proof after edits
94
- - stores local run memory in `.runtrim/`
93
+ - reviews changed files, risk flags, verification debt, and next safe action after edits
94
+ - shows current project memory, latest run state, and continuation guidance in `.runtrim/`
95
95
 
96
96
  ## Core commands
97
97
 
@@ -32,7 +32,7 @@ import { execa as execa3 } from "execa";
32
32
  // package.json
33
33
  var package_default = {
34
34
  name: "runtrim",
35
- version: "0.1.2",
35
+ version: "0.1.3",
36
36
  description: "CLI guard layer that scopes AI coding runs before they waste tokens.",
37
37
  license: "MIT",
38
38
  author: "RunTrim",
@@ -3420,6 +3420,77 @@ function parseMemorySection2(memory, title) {
3420
3420
  function dedupeFiles(files) {
3421
3421
  return [...new Set(files.filter(Boolean).map((f) => f.replace(/\\/g, "/")))];
3422
3422
  }
3423
+ var HIGH_RISK_PATH_KEYWORDS = [
3424
+ "auth",
3425
+ "login",
3426
+ "signup",
3427
+ "session",
3428
+ "jwt",
3429
+ "middleware",
3430
+ "proxy",
3431
+ "billing",
3432
+ "payment",
3433
+ "stripe",
3434
+ "dodo",
3435
+ "checkout",
3436
+ "webhook",
3437
+ "database",
3438
+ "schema",
3439
+ "migration",
3440
+ "supabase",
3441
+ "env",
3442
+ "secret",
3443
+ "token",
3444
+ "admin",
3445
+ "permission",
3446
+ "security",
3447
+ "package.json",
3448
+ "package-lock.json",
3449
+ "pnpm-lock.yaml",
3450
+ "yarn.lock"
3451
+ ];
3452
+ function inferMaxFilesFromScope(scope, fallback) {
3453
+ var _a2, _b;
3454
+ const text = scope.join(" ").toLowerCase();
3455
+ const n = Number.parseInt((_b = (_a2 = text.match(/maximum\s+(\d+)\s+files/)) == null ? void 0 : _a2[1]) != null ? _b : "", 10);
3456
+ if (Number.isFinite(n) && n > 0) return n;
3457
+ return Math.max(1, fallback || 5);
3458
+ }
3459
+ function collectProtectedSystems(run, config, audit) {
3460
+ var _a2, _b, _c, _d, _e, _f;
3461
+ const values = /* @__PURE__ */ new Set();
3462
+ const add = (v) => {
3463
+ const x = v.trim().toLowerCase();
3464
+ if (!x) return;
3465
+ values.add(x);
3466
+ };
3467
+ for (const a of (_a2 = config.sensitiveAreas) != null ? _a2 : []) add(a);
3468
+ for (const a of (_b = audit == null ? void 0 : audit.protectedAreas) != null ? _b : []) add(a);
3469
+ for (const s of (_d = (_c = run == null ? void 0 : run.contract.contract) == null ? void 0 : _c.sensitiveScope) != null ? _d : []) add(s);
3470
+ for (const s of (_f = (_e = run == null ? void 0 : run.contract.contract) == null ? void 0 : _e.forbiddenScope) != null ? _f : []) add(s);
3471
+ const mapped = /* @__PURE__ */ new Set();
3472
+ for (const raw of values) {
3473
+ if (raw.includes("auth")) mapped.add("auth");
3474
+ if (raw.includes("middleware") || raw.includes("proxy")) mapped.add("middleware");
3475
+ if (raw.includes("database") || raw.includes("schema") || raw.includes("migration")) mapped.add("database");
3476
+ if (raw.includes("env") || raw.includes("secret")) mapped.add("env/secrets");
3477
+ if (raw.includes("billing")) mapped.add("billing");
3478
+ if (raw.includes("payment") || raw.includes("stripe") || raw.includes("dodo")) mapped.add("payments");
3479
+ if (raw.includes("webhook")) mapped.add("webhooks");
3480
+ if (raw.includes("package") || raw.includes("lock")) mapped.add("package/config changes");
3481
+ }
3482
+ const ordered = [
3483
+ "auth",
3484
+ "middleware",
3485
+ "database",
3486
+ "env/secrets",
3487
+ "billing",
3488
+ "payments",
3489
+ "webhooks",
3490
+ "package/config changes"
3491
+ ];
3492
+ return ordered.filter((x) => mapped.has(x));
3493
+ }
3423
3494
  var CONTINUATION_REASONS = [
3424
3495
  "usage_limit",
3425
3496
  "credits_exhausted",
@@ -4649,95 +4720,32 @@ program.command("go <task>").description("Daily shortcut: initialize if needed,
4649
4720
  console.log(chalk.white("Run `runtrim --help` for panel, check, memory and continuation commands."));
4650
4721
  console.log("");
4651
4722
  });
4652
- program.command("check").description("Check the latest run and evaluate agent output").action(async () => {
4653
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
4723
+ program.command("check").description("Check the latest run and evaluate agent output").option("--json", "Print machine-readable check summary").action(async (options) => {
4724
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
4654
4725
  const cwd = process.cwd();
4655
4726
  console.log("");
4656
4727
  console.log(BOLD("RunTrim") + DIM(" check"));
4657
4728
  console.log("");
4658
4729
  const run = loadLatestRun(cwd);
4659
4730
  if (!run) {
4660
- console.log(chalk.yellow(' No runs found. Run: runtrim guard "your task"'));
4661
- console.log("");
4662
- return;
4663
- }
4664
- if (run.evaluation) {
4665
- const { recheck } = await prompts({
4666
- type: "confirm",
4667
- name: "recheck",
4668
- message: "Latest run already has an evaluation. Re-check now?",
4669
- initial: false
4670
- });
4671
- if (!recheck) {
4672
- console.log(DIM(" Skipped. Existing evaluation retained."));
4673
- console.log("");
4674
- return;
4675
- }
4676
- }
4677
- console.log(DIM(" Latest run: ") + chalk.white(truncate(run.task, 55)));
4678
- console.log(DIM(" Guarded at: ") + chalk.white(formatDate(run.createdAt)));
4679
- console.log("");
4680
- if (run.status === "blocked" || run.status === "split_required") {
4681
- const evaluationBase2 = evaluateAgentOutput(null, [], {
4682
- task: run.task,
4683
- relevantScope: (_b = (_a2 = run.contract.contract) == null ? void 0 : _a2.relevantScope) != null ? _b : [],
4684
- sensitiveScope: (_d = (_c = run.contract.contract) == null ? void 0 : _c.sensitiveScope) != null ? _d : [],
4685
- forbiddenScope: (_f = (_e = run.contract.contract) == null ? void 0 : _e.forbiddenScope) != null ? _f : [],
4686
- runStatus: run.status
4687
- });
4688
- const evaluation2 = __spreadProps(__spreadValues({}, evaluationBase2), {
4689
- nextPrompt: evaluationBase2.nextGuardedPrompt,
4690
- nextSafePrompt: evaluationBase2.nextGuardedPrompt,
4691
- nextSafeAction: evaluationBase2.nextSafeAction,
4692
- memorySummary: evaluationBase2.memorySummary,
4693
- evaluatedAt: evaluationBase2.evaluatedAt
4694
- });
4695
- updateRun(run.id, { evaluation: evaluation2, status: "checked" }, cwd);
4696
- const latestAfterUpdate2 = loadLatestRun(cwd);
4697
- if (latestAfterUpdate2) {
4698
- writeMemoryFromRuns(latestAfterUpdate2, loadAllRuns(cwd), loadConfig(cwd), cwd);
4699
- }
4700
- await copyToClipboardSafe(evaluation2.nextPrompt);
4701
- console.log(chalk.yellow(" Latest run was blocked. Start with the recommended split audit task."));
4702
- console.log("");
4703
- console.log(DIM(" Next safe prompt:"));
4704
- for (const line of evaluation2.nextPrompt.split("\n")) console.log(DIM(" " + line));
4705
- console.log("");
4706
- console.log(ACCENT.bold(" Next prompt copied to clipboard."));
4731
+ console.log(chalk.yellow(' No runs found. Start with: runtrim go "your task"'));
4707
4732
  console.log("");
4708
4733
  return;
4709
4734
  }
4710
- const diffSpinner = oraFactory({ text: "Reading git diff...", color: "yellow" }).start();
4711
- const changedFiles = await getGitDiff(cwd);
4712
- diffSpinner.stop();
4713
- if (changedFiles.length > 0) {
4714
- console.log(DIM(" Changed files (" + changedFiles.length + "):"));
4715
- for (const f of changedFiles) console.log(DIM(" " + f));
4716
- console.log("");
4717
- } else {
4718
- console.log(DIM(" No git changes detected since last commit."));
4719
- console.log("");
4720
- }
4721
- const { pasteOutput } = await prompts({
4722
- type: "confirm",
4723
- name: "pasteOutput",
4724
- message: "Evaluate agent output? (paste output or skip)",
4725
- initial: true
4735
+ const config = configExists(cwd) ? loadConfig(cwd) : DEFAULT_CONFIG;
4736
+ const changedFiles = dedupeFiles(await getGitDiff(cwd));
4737
+ const maxFiles = inferMaxFilesFromScope((_b = (_a2 = run.contract.contract) == null ? void 0 : _a2.relevantScope) != null ? _b : [], config.maxFilesPerRun);
4738
+ const scope = evaluateWatchState({
4739
+ changedFiles,
4740
+ run,
4741
+ maxFilesPerRun: maxFiles,
4742
+ strict: false
4726
4743
  });
4727
- let agentOutput = null;
4728
- if (pasteOutput) {
4729
- const { output } = await prompts({
4730
- type: "text",
4731
- name: "output",
4732
- message: "Paste agent output:"
4733
- });
4734
- agentOutput = output != null ? output : null;
4735
- }
4736
- const evaluationBase = evaluateAgentOutput(agentOutput, changedFiles, {
4744
+ const evaluationBase = evaluateAgentOutput(null, changedFiles, {
4737
4745
  task: run.task,
4738
- relevantScope: (_h = (_g = run.contract.contract) == null ? void 0 : _g.relevantScope) != null ? _h : [],
4739
- sensitiveScope: (_j = (_i = run.contract.contract) == null ? void 0 : _i.sensitiveScope) != null ? _j : [],
4740
- forbiddenScope: (_l = (_k = run.contract.contract) == null ? void 0 : _k.forbiddenScope) != null ? _l : [],
4746
+ relevantScope: (_d = (_c = run.contract.contract) == null ? void 0 : _c.relevantScope) != null ? _d : [],
4747
+ sensitiveScope: (_f = (_e = run.contract.contract) == null ? void 0 : _e.sensitiveScope) != null ? _f : [],
4748
+ forbiddenScope: (_h = (_g = run.contract.contract) == null ? void 0 : _g.forbiddenScope) != null ? _h : [],
4741
4749
  runStatus: run.status
4742
4750
  });
4743
4751
  const evaluation = __spreadProps(__spreadValues({}, evaluationBase), {
@@ -4747,66 +4755,131 @@ program.command("check").description("Check the latest run and evaluate agent ou
4747
4755
  memorySummary: evaluationBase.memorySummary,
4748
4756
  evaluatedAt: evaluationBase.evaluatedAt
4749
4757
  });
4750
- updateRun(run.id, { evaluation, status: "checked" }, cwd);
4751
- const latestAfterUpdate = loadLatestRun(cwd);
4752
- if (latestAfterUpdate) {
4753
- writeMemoryFromRuns(latestAfterUpdate, loadAllRuns(cwd), loadConfig(cwd), cwd);
4758
+ const lowerChanged = changedFiles.map((f) => f.toLowerCase());
4759
+ const riskFlags = /* @__PURE__ */ new Set();
4760
+ for (const file of lowerChanged) {
4761
+ for (const kw of HIGH_RISK_PATH_KEYWORDS) {
4762
+ if (file.includes(kw)) {
4763
+ riskFlags.add(`High-risk path touched: ${kw}`);
4764
+ break;
4765
+ }
4766
+ }
4754
4767
  }
4755
- const statusColors2 = {
4756
- passed: chalk.green,
4757
- partial: chalk.yellow,
4758
- needs_verification: chalk.hex("#FF8C00"),
4759
- no_changes_detected: chalk.hex("#FF8C00"),
4760
- drift_detected: chalk.red,
4761
- blocked: chalk.red
4762
- };
4763
- const driftColors = {
4764
- none: chalk.green,
4765
- low: chalk.yellow,
4766
- medium: chalk.hex("#FF8C00"),
4767
- high: chalk.red
4768
+ if (scope.forbiddenFiles.length > 0) riskFlags.add("Forbidden scope changed");
4769
+ if (scope.sensitiveFiles.length > 0) riskFlags.add("Sensitive scope changed");
4770
+ if (scope.outOfScopeFiles.length > 0) riskFlags.add("Potential outside-scope changes detected");
4771
+ if (changedFiles.length > maxFiles) riskFlags.add(`File count exceeded scope limit (${maxFiles})`);
4772
+ const verificationDebt = /* @__PURE__ */ new Set();
4773
+ if (run.status === "guarded") verificationDebt.add("Run is still guarded and not checked.");
4774
+ if (changedFiles.length > 0 && !run.evaluation) verificationDebt.add("Changed files exist but no post-run check was recorded.");
4775
+ if (scope.sensitiveFiles.length > 0) verificationDebt.add("Sensitive files changed. Review and verify before continuing.");
4776
+ if (scope.forbiddenFiles.length > 0) verificationDebt.add("Forbidden files changed. Manual containment required.");
4777
+ if (changedFiles.length > maxFiles) verificationDebt.add("Too many files changed for one scoped run. Split the task.");
4778
+ if (lowerChanged.some((f) => /(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$/.test(f))) {
4779
+ verificationDebt.add("Lockfile changed. Confirm dependency intent.");
4780
+ }
4781
+ if (lowerChanged.some((f) => /(migration|migrations|schema|database)/.test(f))) {
4782
+ verificationDebt.add("Database or migration-related changes need explicit verification.");
4783
+ }
4784
+ if (lowerChanged.some((f) => /(middleware|auth|login|session|jwt|payment|billing|stripe|webhook)/.test(f))) {
4785
+ verificationDebt.add("Auth, middleware, payment, or webhook surface changed. Run focused verification.");
4786
+ }
4787
+ if (scope.outOfScopeFiles.length > 0) {
4788
+ verificationDebt.add("Some changed files appear outside declared relevant scope.");
4789
+ }
4790
+ for (const item of (_j = (_i = run.evaluation) == null ? void 0 : _i.missingProofItems) != null ? _j : []) verificationDebt.add(item);
4791
+ let nextSafeAction = "Run is ready to continue.";
4792
+ if (scope.forbiddenFiles.length > 0) {
4793
+ nextSafeAction = "Stop and inspect forbidden files before continuing.";
4794
+ } else if (scope.sensitiveFiles.length > 0) {
4795
+ nextSafeAction = "Review sensitive changes, then run tests before continuing.";
4796
+ } else if (changedFiles.length > maxFiles) {
4797
+ nextSafeAction = "Stop scope drift and split the task.";
4798
+ } else if (changedFiles.length === 0) {
4799
+ nextSafeAction = "No local changes detected. Continue or prepare the next run.";
4800
+ } else if (verificationDebt.size > 0) {
4801
+ nextSafeAction = "Resolve verification debt, then run runtrim check again.";
4802
+ }
4803
+ evaluation.nextSafeAction = nextSafeAction;
4804
+ evaluation.nextPrompt = evaluation.nextGuardedPrompt;
4805
+ evaluation.nextSafePrompt = evaluation.nextGuardedPrompt;
4806
+ const checkSummary = {
4807
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
4808
+ changedFilesCount: changedFiles.length,
4809
+ allowedCount: scope.relevantFiles.length,
4810
+ sensitiveCount: scope.sensitiveFiles.length,
4811
+ forbiddenCount: scope.forbiddenFiles.length,
4812
+ outsideScopeCount: scope.outOfScopeFiles.length,
4813
+ verificationDebt: [...verificationDebt],
4814
+ riskFlags: [...riskFlags],
4815
+ nextSafeAction
4768
4816
  };
4769
- const statusColor = (_m = statusColors2[evaluation.status]) != null ? _m : chalk.white;
4770
- const driftColor = (_n = driftColors[evaluation.scopeDriftRisk]) != null ? _n : chalk.white;
4771
- console.log("");
4772
- console.log(DIM(" " + SECTION));
4773
- console.log(DIM(" EVALUATION"));
4774
- console.log(DIM(" " + SECTION));
4775
- console.log("");
4776
- console.log(DIM(" Status ") + statusColor(formatStatus(evaluation.status).toUpperCase()));
4777
- console.log(DIM(" Contract score ") + chalk.white(formatScore(evaluation.contractScore)));
4778
- console.log(DIM(" Scope drift ") + driftColor(evaluation.scopeDriftRisk.toUpperCase()));
4779
- console.log(DIM(" Next action ") + chalk.white(evaluation.nextSafeAction));
4780
- console.log("");
4781
- if (evaluation.driftedFiles.length > 0) {
4782
- console.log(chalk.red(" Drifted files:"));
4783
- for (const f of evaluation.driftedFiles) console.log(chalk.red(" x " + f));
4784
- console.log("");
4817
+ updateRun(run.id, { evaluation, checkSummary, status: "checked" }, cwd);
4818
+ const latestAfterUpdate = loadLatestRun(cwd);
4819
+ if (latestAfterUpdate && configExists(cwd)) {
4820
+ writeMemoryFromRuns(latestAfterUpdate, loadAllRuns(cwd), loadConfig(cwd), cwd);
4785
4821
  }
4786
- if (evaluation.outOfScopeFiles.length > 0) {
4787
- console.log(chalk.yellow(" Out-of-scope files:"));
4788
- for (const f of evaluation.outOfScopeFiles) console.log(DIM(" - " + f));
4822
+ if (options.json) {
4823
+ console.log(
4824
+ JSON.stringify(
4825
+ {
4826
+ runId: run.id,
4827
+ task: run.task,
4828
+ scopeResult: {
4829
+ allowedChanges: checkSummary.allowedCount,
4830
+ sensitiveChanges: checkSummary.sensitiveCount,
4831
+ forbiddenChanges: checkSummary.forbiddenCount,
4832
+ outsideScope: checkSummary.outsideScopeCount
4833
+ },
4834
+ verificationDebt: checkSummary.verificationDebt,
4835
+ riskFlags: checkSummary.riskFlags,
4836
+ changedFiles,
4837
+ nextSafeAction: checkSummary.nextSafeAction,
4838
+ checkedAt: checkSummary.checkedAt
4839
+ },
4840
+ null,
4841
+ 2
4842
+ )
4843
+ );
4789
4844
  console.log("");
4845
+ return;
4790
4846
  }
4791
- if (evaluation.missingProofItems.length > 0) {
4792
- console.log(chalk.yellow(" Missing:"));
4793
- for (const item of evaluation.missingProofItems) console.log(DIM(" - " + item));
4794
- console.log("");
4847
+ const changedPreview = changedFiles.slice(0, 8);
4848
+ const extraCount = Math.max(0, changedFiles.length - changedPreview.length);
4849
+ console.log(BOLD("Run"));
4850
+ console.log(chalk.white(((_k = run.task) == null ? void 0 : _k.trim()) ? truncate(run.task, 68) : "Latest run"));
4851
+ console.log("");
4852
+ console.log(BOLD("Scope result"));
4853
+ console.log(chalk.white(`- Allowed changes: ${checkSummary.allowedCount}`));
4854
+ console.log(chalk.white(`- Sensitive changes: ${checkSummary.sensitiveCount}`));
4855
+ console.log(chalk.white(`- Forbidden changes: ${checkSummary.forbiddenCount}`));
4856
+ console.log(chalk.white(`- Outside scope: ${checkSummary.outsideScopeCount}`));
4857
+ console.log("");
4858
+ console.log(BOLD("Verification debt"));
4859
+ if (checkSummary.verificationDebt.length === 0) {
4860
+ console.log(chalk.white("No verification debt recorded."));
4861
+ } else {
4862
+ for (const item of checkSummary.verificationDebt) console.log(chalk.white(`- ${item}`));
4795
4863
  }
4796
- console.log(DIM(" " + SECTION));
4797
- console.log(DIM(" NEXT GUARDED PROMPT"));
4798
- console.log(DIM(" " + SECTION));
4799
4864
  console.log("");
4800
- for (const line of evaluation.nextPrompt.split("\n")) {
4801
- console.log(DIM(" " + line));
4865
+ console.log(BOLD("Risk flags"));
4866
+ if (checkSummary.riskFlags.length === 0) {
4867
+ console.log(chalk.white("No high-risk flags detected."));
4868
+ } else {
4869
+ for (const flag of checkSummary.riskFlags) console.log(chalk.white(`- ${flag}`));
4802
4870
  }
4803
4871
  console.log("");
4804
- try {
4805
- await clipboard.write(evaluation.nextPrompt);
4806
- console.log(ACCENT.bold(" Next prompt copied to clipboard."));
4807
- } catch (e) {
4872
+ console.log(BOLD("Changed files"));
4873
+ if (changedFiles.length === 0) {
4874
+ console.log(chalk.white("No local changed files detected."));
4875
+ } else {
4876
+ for (const file of changedPreview) console.log(chalk.white(`- ${file}`));
4877
+ if (extraCount > 0) console.log(chalk.white(`+${extraCount} more`));
4808
4878
  }
4809
4879
  console.log("");
4880
+ console.log(BOLD("Next safe action"));
4881
+ console.log(chalk.white(checkSummary.nextSafeAction));
4882
+ console.log("");
4810
4883
  });
4811
4884
  program.command("sync").description("Sync local RunTrim metadata to dashboard").action(async () => {
4812
4885
  var _a2, _b;
@@ -5029,23 +5102,25 @@ program.command("panel").description("Open local RunTrim browser panel").option(
5029
5102
  cwd
5030
5103
  });
5031
5104
  });
5032
- program.command("memory").description("Show project memory and latest next safe prompt").option("--prompt", "Print only latest next safe prompt").action(async (options) => {
5033
- var _a2, _b, _c, _d, _e, _f, _g;
5105
+ program.command("memory").description("Show project memory and latest next safe prompt").option("--prompt", "Print only latest next safe prompt").option("--full", "Print full memory markdown").action(async (options) => {
5106
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
5034
5107
  const cwd = process.cwd();
5035
5108
  console.log("");
5036
5109
  console.log(BOLD("RunTrim") + DIM(" memory"));
5037
5110
  console.log("");
5111
+ const config = configExists(cwd) ? loadConfig(cwd) : DEFAULT_CONFIG;
5112
+ const audit = (_a2 = loadProjectAudit(cwd)) != null ? _a2 : performBaselineProjectAudit(cwd, null);
5113
+ const memoryPath = path9.join(getConfigDir(cwd), "memory.md");
5038
5114
  const latestRun = loadLatestRun(cwd);
5039
5115
  if (!latestRun) {
5040
- const config = configExists(cwd) ? loadConfig(cwd) : DEFAULT_CONFIG;
5041
- const audit = (_a2 = loadProjectAudit(cwd)) != null ? _a2 : performBaselineProjectAudit(cwd, null);
5042
- const memoryPath = path9.join(getConfigDir(cwd), "memory.md");
5043
5116
  let memory2 = readMemory(cwd);
5044
5117
  if (!memory2) {
5118
+ const memoryDir = path9.dirname(memoryPath);
5119
+ if (!fs9.existsSync(memoryDir)) fs9.mkdirSync(memoryDir, { recursive: true });
5045
5120
  memory2 = buildBaselineMemoryMarkdown(audit);
5046
5121
  fs9.writeFileSync(memoryPath, memory2, "utf-8");
5047
5122
  }
5048
- const baselinePrompt = 'runtrim prepare "describe your next AI coding task"';
5123
+ const baselinePrompt = 'runtrim go "your task"';
5049
5124
  if (options.prompt) {
5050
5125
  console.log(baselinePrompt);
5051
5126
  await copyToClipboardSafe(baselinePrompt);
@@ -5054,9 +5129,37 @@ program.command("memory").description("Show project memory and latest next safe
5054
5129
  console.log("");
5055
5130
  return;
5056
5131
  }
5057
- console.log(memory2);
5058
- await copyToClipboardSafe(baselinePrompt);
5059
- console.log(ACCENT.bold(" Project memory loaded. Latest next safe prompt copied."));
5132
+ if (options.full) {
5133
+ console.log(memory2);
5134
+ console.log("");
5135
+ }
5136
+ console.log(BOLD("Project"));
5137
+ console.log(chalk.white(audit.projectName || cwd));
5138
+ console.log("");
5139
+ console.log(BOLD("Current state"));
5140
+ console.log(chalk.white("No runs recorded yet."));
5141
+ console.log("");
5142
+ console.log(BOLD("Latest run"));
5143
+ console.log(chalk.white("- Task: none"));
5144
+ console.log(chalk.white("- Status: baseline"));
5145
+ console.log(chalk.white("- Proof: needs check"));
5146
+ console.log(chalk.white(`- Next: ${baselinePrompt}`));
5147
+ console.log("");
5148
+ console.log(BOLD("Protected systems"));
5149
+ const protectedSystems2 = collectProtectedSystems(null, config, audit);
5150
+ console.log(chalk.white((protectedSystems2.length ? protectedSystems2 : ["auth", "middleware", "database", "env/secrets", "billing", "webhooks", "migrations"]).join(", ")));
5151
+ console.log("");
5152
+ console.log(BOLD("Recent context"));
5153
+ console.log(chalk.white("No recent memory items yet."));
5154
+ console.log("");
5155
+ console.log(BOLD("Continuation"));
5156
+ console.log(chalk.white("No continuation prompt yet. Run `runtrim continue --reason usage_limit` when context runs out."));
5157
+ console.log("");
5158
+ console.log(BOLD("Useful commands"));
5159
+ console.log(chalk.white('- runtrim go "your task"'));
5160
+ console.log(chalk.white("- runtrim panel --monitor"));
5161
+ console.log(chalk.white("- runtrim check"));
5162
+ console.log(chalk.white("- runtrim continue --reason usage_limit"));
5060
5163
  console.log("");
5061
5164
  if (config.baselineInitialized !== true) {
5062
5165
  config.baselineInitialized = true;
@@ -5065,7 +5168,8 @@ program.command("memory").description("Show project memory and latest next safe
5065
5168
  }
5066
5169
  return;
5067
5170
  }
5068
- const memory = writeMemoryFromRuns(latestRun, loadAllRuns(cwd), loadConfig(cwd), cwd);
5171
+ const allRuns = loadAllRuns(cwd);
5172
+ const memory = writeMemoryFromRuns(latestRun, allRuns, config, cwd);
5069
5173
  const latestPrompt = (_g = (_f = (_d = (_b = latestRun == null ? void 0 : latestRun.evaluation) == null ? void 0 : _b.nextPrompt) != null ? _d : (_c = latestRun == null ? void 0 : latestRun.evaluation) == null ? void 0 : _c.nextSafePrompt) != null ? _f : (_e = latestRun == null ? void 0 : latestRun.evaluation) == null ? void 0 : _e.nextGuardedPrompt) != null ? _g : "";
5070
5174
  if (options.prompt) {
5071
5175
  if (!latestPrompt) {
@@ -5080,14 +5184,64 @@ program.command("memory").description("Show project memory and latest next safe
5080
5184
  console.log("");
5081
5185
  return;
5082
5186
  }
5083
- console.log(memory);
5187
+ if (options.full) {
5188
+ console.log(memory);
5189
+ console.log("");
5190
+ }
5191
+ const status = (_i = (_h = latestRun.evaluation) == null ? void 0 : _h.status) != null ? _i : latestRun.status;
5192
+ const checkSummary = latestRun.checkSummary;
5193
+ const protectedSystems = collectProtectedSystems(latestRun, config, audit);
5194
+ const recent = allRuns.slice(0, 3).map((r) => {
5195
+ var _a3, _b2;
5196
+ const s = (_b2 = (_a3 = r.evaluation) == null ? void 0 : _a3.status) != null ? _b2 : r.status;
5197
+ return `- ${truncate(r.task, 56)} (${s})`;
5198
+ });
5199
+ const nextAction = (_l = (_k = checkSummary == null ? void 0 : checkSummary.nextSafeAction) != null ? _k : (_j = latestRun.evaluation) == null ? void 0 : _j.nextSafeAction) != null ? _l : "runtrim check";
5200
+ const proofState = checkSummary ? checkSummary.verificationDebt.length > 0 ? "verification debt" : "checked" : latestRun.evaluation ? latestRun.evaluation.missingProofItems.length > 0 ? "verification debt" : "checked" : "needs check";
5201
+ console.log(BOLD("Project"));
5202
+ console.log(chalk.white(audit.projectName || cwd));
5203
+ console.log("");
5204
+ console.log(BOLD("Current state"));
5205
+ console.log(chalk.white(((_m = latestRun.evaluation) == null ? void 0 : _m.memorySummary) || `Latest run is ${status}.`));
5206
+ console.log("");
5207
+ console.log(BOLD("Latest run"));
5208
+ console.log(chalk.white(`- Task: ${truncate(latestRun.task, 72)}`));
5209
+ console.log(chalk.white(`- Status: ${status}`));
5210
+ console.log(chalk.white(`- Proof: ${proofState}`));
5211
+ console.log(chalk.white(`- Next: ${nextAction}`));
5212
+ console.log("");
5213
+ console.log(BOLD("Protected systems"));
5214
+ console.log(chalk.white((protectedSystems.length ? protectedSystems : ["auth", "middleware", "database", "env/secrets", "billing", "webhooks", "migrations"]).join(", ")));
5215
+ console.log("");
5216
+ console.log(BOLD("Recent context"));
5217
+ if (recent.length > 0) {
5218
+ for (const line of recent) console.log(chalk.white(line));
5219
+ } else {
5220
+ console.log(chalk.white("No recent memory items yet."));
5221
+ }
5222
+ console.log("");
5223
+ console.log(BOLD("Continuation"));
5084
5224
  if (latestPrompt) {
5225
+ const compact = latestPrompt.replace(/\s+/g, " ").trim();
5226
+ const isDrift = /scope drift detected/i.test(compact);
5227
+ if (isDrift) {
5228
+ console.log(chalk.white("Scope drift detected. Run `runtrim check` before continuing."));
5229
+ } else if (compact.length > 160) {
5230
+ console.log(chalk.white(truncate(compact, 160)));
5231
+ } else {
5232
+ console.log(chalk.white(compact));
5233
+ }
5085
5234
  await copyToClipboardSafe(latestPrompt);
5086
- console.log(ACCENT.bold(" Project memory loaded. Latest next safe prompt copied."));
5087
5235
  } else {
5088
- console.log(DIM(" Project memory loaded."));
5236
+ console.log(chalk.white("No continuation prompt yet. Run `runtrim continue --reason usage_limit` when context runs out."));
5089
5237
  }
5090
5238
  console.log("");
5239
+ console.log(BOLD("Useful commands"));
5240
+ console.log(chalk.white('- runtrim go "your task"'));
5241
+ console.log(chalk.white("- runtrim panel --monitor"));
5242
+ console.log(chalk.white("- runtrim check"));
5243
+ console.log(chalk.white("- runtrim continue --reason usage_limit"));
5244
+ console.log("");
5091
5245
  });
5092
5246
  program.command("continue").description("Create a safe continuation prompt from latest RunTrim state").option("--reason <reason>", "Continuation reason").option("--agent <agent>", "Target agent hint").option("--print", "Print the full continuation prompt").option("--open", "Open continuation prompt in editor").option("--editor <editor>", "Editor command (code, cursor, or custom)").action(async (options) => {
5093
5247
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runtrim",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "CLI guard layer that scopes AI coding runs before they waste tokens.",
5
5
  "license": "MIT",
6
6
  "author": "RunTrim",