@meetless/mla 0.1.5 → 0.1.6

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.
Files changed (41) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/cli.js +31 -5
  3. package/dist/commands/activate.js +39 -18
  4. package/dist/commands/agent-memory.js +333 -0
  5. package/dist/commands/enrich.js +211 -2
  6. package/dist/commands/internal-auto-index.js +64 -1
  7. package/dist/commands/internal-pretool-observe.js +86 -1
  8. package/dist/commands/internal-redact-capture.js +130 -0
  9. package/dist/commands/pilot.js +385 -0
  10. package/dist/lib/agent-memory-capture/binding.js +115 -0
  11. package/dist/lib/agent-memory-capture/classify.js +68 -0
  12. package/dist/lib/agent-memory-capture/collector.js +69 -0
  13. package/dist/lib/agent-memory-capture/containment.js +74 -0
  14. package/dist/lib/agent-memory-capture/ledger.js +43 -0
  15. package/dist/lib/agent-memory-capture/live-collector.js +148 -0
  16. package/dist/lib/agent-memory-capture/live-ledger.js +45 -0
  17. package/dist/lib/agent-memory-capture/live-pipeline.js +344 -0
  18. package/dist/lib/agent-memory-capture/lock.js +98 -0
  19. package/dist/lib/agent-memory-capture/paths.js +47 -0
  20. package/dist/lib/agent-memory-capture/pipeline.js +222 -0
  21. package/dist/lib/agent-memory-capture/report.js +131 -0
  22. package/dist/lib/agent-memory-capture/types.js +14 -0
  23. package/dist/lib/agent-memory-capture/upsert-client.js +104 -0
  24. package/dist/lib/analytics/enforcement-classify.js +65 -0
  25. package/dist/lib/analytics/enforcement-incident.js +83 -0
  26. package/dist/lib/analytics/envelope.js +55 -1
  27. package/dist/lib/analytics/pilot.js +313 -0
  28. package/dist/lib/enrichment/ingest.js +98 -13
  29. package/dist/lib/enrichment/materialize-rules.js +81 -0
  30. package/dist/lib/enrichment/plan.js +72 -15
  31. package/dist/lib/enrichment/protocol.js +85 -5
  32. package/dist/lib/enrichment/scout-brief.js +35 -6
  33. package/dist/lib/redactor.js +104 -1
  34. package/dist/lib/scanner/agent-memory.js +55 -4
  35. package/dist/lib/scanner/managed-rules.js +0 -0
  36. package/dist/lib/scanner/scan.js +52 -1
  37. package/dist/lib/scanner/score.js +41 -3
  38. package/dist/lib/scanner/scout-mission.js +9 -7
  39. package/dist/lib/upgrade-apply.js +30 -0
  40. package/dist/lib/wire.js +2 -0
  41. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "0.1.5",
3
- "sha": "a984add",
2
+ "version": "0.1.6",
3
+ "sha": "5434c09",
4
4
  "branch": "HEAD",
5
5
  "dirty": false,
6
- "builtAt": "2026-06-27T18:44:27.928Z",
6
+ "builtAt": "2026-06-27T19:14:26.079Z",
7
7
  "sentryDsn": "",
8
8
  "updatePublicKey": ""
9
9
  }
package/dist/cli.js CHANGED
@@ -65,6 +65,7 @@ const internal_evidence_hooks_1 = require("./commands/internal-evidence-hooks");
65
65
  const internal_steer_sync_1 = require("./commands/internal-steer-sync");
66
66
  const internal_capture_decisions_1 = require("./commands/internal-capture-decisions");
67
67
  const internal_pretool_observe_1 = require("./commands/internal-pretool-observe");
68
+ const internal_redact_capture_1 = require("./commands/internal-redact-capture");
68
69
  const internal_turn_recap_1 = require("./commands/internal-turn-recap");
69
70
  const internal_refresh_1 = require("./commands/internal-refresh");
70
71
  const internal_session_nudge_1 = require("./commands/internal-session-nudge");
@@ -73,11 +74,13 @@ const upgrade_apply_1 = require("./lib/upgrade-apply");
73
74
  const wire_1 = require("./lib/wire");
74
75
  const scan_context_1 = require("./commands/scan-context");
75
76
  const kb_1 = require("./commands/kb");
77
+ const agent_memory_1 = require("./commands/agent-memory");
76
78
  const enrich_1 = require("./commands/enrich");
77
79
  const graph_1 = require("./commands/graph");
78
80
  const summary_1 = require("./commands/summary");
79
81
  const label_1 = require("./commands/label");
80
82
  const stats_1 = require("./commands/stats");
83
+ const pilot_1 = require("./commands/pilot");
81
84
  const turn_1 = require("./commands/turn");
82
85
  const ask_1 = require("./commands/ask");
83
86
  const session_1 = require("./commands/session");
@@ -95,7 +98,7 @@ const rules_1 = require("./commands/rules");
95
98
  // Commands:
96
99
  // mla init [flags]
97
100
  // mla rewire [flags]
98
- // mla activate [--name <name>] [--note <text>] [--here|--create|--repair] [--bootstrap <fast|agentic|full>]
101
+ // mla activate [--name <name>] [--note <text>] [--here|--create|--repair] [--bootstrap <fast|agentic>]
99
102
  // mla deactivate [--yes] [--from-root|--marker <path>]
100
103
  // mla mute | mla unmute
101
104
  // mla review [--plain] [--no-flush]
@@ -154,11 +157,12 @@ usage:
154
157
  mla activate --repair
155
158
  (re-check the existing binding's membership + connectivity;
156
159
  never mints a new id)
157
- mla activate --bootstrap <fast|agentic|full>
160
+ mla activate --bootstrap <fast|agentic>
158
161
  (bootstrap tier for the activation preview: fast (default) shows
159
- the deterministic review bundle; agentic ALSO emits a deep-read
160
- scout mission to hand a coding agent; full adds the temporal
161
- legacy-note graph (not built yet, falls back to agentic))
162
+ the deterministic review bundle. agentic is DEPRECATED: it still
163
+ emits a static deep-read scout mission, but the consolidated
164
+ agent-driven onboarding is /mla onboard. The old full tier was
165
+ removed; --bootstrap full now errors with a migration note.)
162
166
  mla deactivate [--yes] [--from-root|--marker <path>]
163
167
  (REMOVE this folder's workspace binding: deletes the nearest
164
168
  .meetless.json. Confirms first (--yes to skip); from a subdir
@@ -260,6 +264,11 @@ usage:
260
264
  (usefulness-first dashboard from local events.jsonl: evidence
261
265
  followthrough, contradictions caught, coverage gaps. default
262
266
  window 30d. \`evidence\` is the focused adoption join below.)
267
+ mla pilot <feedback|report|export|sample-check> ...
268
+ (pilot value signal: record one explicit verdict at a natural
269
+ point (feedback), score the four hypotheses (report), dump the
270
+ raw pilot subset (export), or consult the 1-in-N injection
271
+ sampling gate (sample-check). Local events.jsonl; no dashboard.)
263
272
  mla turn [N] [--session <sid>] [--json]
264
273
  (per-turn assist recap: did mla run this turn and did it help?
265
274
  no N recaps the latest completed turn of the current session;
@@ -488,6 +497,14 @@ async function dispatch(argv) {
488
497
  return (0, ask_1.runAsk)(argv.slice(1));
489
498
  case "kb":
490
499
  return (0, kb_1.runKb)(argv.slice(1));
500
+ // `mla agent-memory <enable|disable|status|scan|report>`: operator surface for
501
+ // the agent-memory capture pipeline (notes/20260626-agent-memory-auto-capture-
502
+ // proposal.md). Phase 1 is DRY-RUN ONLY: `scan` observes/classifies/secret-scans
503
+ // project-type Claude auto-memory files and records metadata-only decisions
504
+ // locally; it uploads nothing. Live ingestion is blocked upstream by the missing
505
+ // cross-revision claim-grain idempotency and is intentionally not wired.
506
+ case "agent-memory":
507
+ return (0, agent_memory_1.runAgentMemory)(argv.slice(1));
491
508
  // `mla enrich`: agent-orchestrated onboarding enrichment. `enrich plan` scans the
492
509
  // repo into an immutable run record + prints the plan the agent reads; `enrich
493
510
  // ingest` validates + persists the scouts' candidates born PENDING. The agent
@@ -508,6 +525,13 @@ async function dispatch(argv) {
508
525
  return (0, label_1.runLabel)(argv.slice(1));
509
526
  case "stats":
510
527
  return (0, stats_1.runStats)(argv.slice(1));
528
+ // `mla pilot` is the pilot value-signal surface (memo §6 Phase 3): record one
529
+ // explicit human verdict at a natural point (`feedback`), fold local events into
530
+ // the four hypotheses (`report`), dump the raw pilot subset (`export`), or consult
531
+ // the deterministic occasional-injection sampling gate (`sample-check`). No
532
+ // dashboard, no server -- it reads/writes the same local events.jsonl.
533
+ case "pilot":
534
+ return (0, pilot_1.runPilot)(argv.slice(1));
511
535
  // `mla turn [N]` is the per-turn analog of `mla stats`; `mla stats --turn`
512
536
  // routes to the SAME runTurn handler (one implementation, two entry points).
513
537
  case "turn":
@@ -572,6 +596,8 @@ async function dispatch(argv) {
572
596
  return (0, internal_capture_decisions_1.runCaptureDecisions)(rest);
573
597
  if (sub === "pretool-observe")
574
598
  return (0, internal_pretool_observe_1.runInternalPretoolObserve)(rest);
599
+ if (sub === "redact-capture")
600
+ return (0, internal_redact_capture_1.runInternalRedactCapture)(rest);
575
601
  if (sub === "turn-recap")
576
602
  return (0, internal_turn_recap_1.runInternalTurnRecap)(rest);
577
603
  if (sub === "refresh")
@@ -37,7 +37,8 @@ exports.renderActivationCard = void 0;
37
37
  exports.parseActivateArgs = parseActivateArgs;
38
38
  exports.resolveBootstrapTier = resolveBootstrapTier;
39
39
  exports.bootstrapTierEmitsMission = bootstrapTierEmitsMission;
40
- exports.bootstrapTierIsDeepNotYet = bootstrapTierIsDeepNotYet;
40
+ exports.bootstrapTierIsDeprecated = bootstrapTierIsDeprecated;
41
+ exports.agenticDeprecationNote = agenticDeprecationNote;
41
42
  exports.writeActivationMarker = writeActivationMarker;
42
43
  exports.clearDeactivateSentinel = clearDeactivateSentinel;
43
44
  exports.removeStaleGitignoreEntry = removeStaleGitignoreEntry;
@@ -59,7 +60,7 @@ Object.defineProperty(exports, "renderActivationCard", { enumerable: true, get:
59
60
  const scout_mission_1 = require("../lib/scanner/scout-mission");
60
61
  const scan_context_1 = require("./scan-context");
61
62
  const workspace_1 = require("../lib/workspace");
62
- const BOOTSTRAP_TIERS = ["fast", "agentic", "full"];
63
+ const BOOTSTRAP_TIERS = ["fast", "agentic"];
63
64
  const VALUE_FLAGS = new Set(["--name", "--note", "--bootstrap"]);
64
65
  const BOOLEAN_FLAGS = new Set(["--here", "--create", "--repair"]);
65
66
  function parseActivateArgs(argv) {
@@ -76,6 +77,15 @@ function parseActivateArgs(argv) {
76
77
  else if (a === "--note")
77
78
  out.note = v;
78
79
  else if (a === "--bootstrap") {
80
+ // The removed `full` tier gets a migration message, never a silent fallback
81
+ // to a shallower tier (Phase 2: "never silently fall back from a named-but-
82
+ // unbuilt tier").
83
+ if (v === "full") {
84
+ throw new Error("The `full` bootstrap tier was removed: its temporal legacy-note graph was " +
85
+ "never built. The deep, agent-driven read now lives in `/mla onboard` " +
86
+ "(two read-only scouts; candidates land born PENDING for you to review). " +
87
+ "Use `--bootstrap fast` (default) or run `/mla onboard` inside a session.");
88
+ }
79
89
  if (!BOOTSTRAP_TIERS.includes(v)) {
80
90
  throw new Error(`Invalid value for --bootstrap: ${v}. Supported tiers: ${BOOTSTRAP_TIERS.join(", ")}.`);
81
91
  }
@@ -103,17 +113,27 @@ function parseActivateArgs(argv) {
103
113
  function resolveBootstrapTier(flags) {
104
114
  return flags.bootstrap ?? "fast";
105
115
  }
106
- // Whether a tier emits the agentic scout mission after the review bundle. Only the
107
- // deterministic `fast` tier stays silent; `agentic` and `full` both invite the
108
- // deep read.
116
+ // Whether a tier emits the static scout mission after the review bundle. Only the
117
+ // deterministic `fast` tier stays silent; the deprecated `agentic` tier still emits
118
+ // the deep-read mission for back-compat.
109
119
  function bootstrapTierEmitsMission(tier) {
110
120
  return tier !== "fast";
111
121
  }
112
- // Whether a tier asks for the deep temporal scan that is not built in this lane
113
- // yet. Only `full` does; the activation tail uses this to print an honest "not yet,
114
- // running agentic instead" note rather than silently under-delivering.
115
- function bootstrapTierIsDeepNotYet(tier) {
116
- return tier === "full";
122
+ // Whether a tier is deprecated. `agentic` is kept working but steered toward the
123
+ // consolidated `/mla onboard` flow; the activation tail prints the steer below it.
124
+ function bootstrapTierIsDeprecated(tier) {
125
+ return tier === "agentic";
126
+ }
127
+ // Pure steer printed above the static `agentic` mission, pointing at the consolidated
128
+ // `/mla onboard` flow. Exported so the writing-style + content guards can assert it
129
+ // without driving the whole activation tail.
130
+ function agenticDeprecationNote() {
131
+ return [
132
+ "`--bootstrap agentic` is deprecated. The richer, agent-driven onboarding is",
133
+ "`/mla onboard`: two read-only scouts read your docs and git history and surface",
134
+ "candidates born PENDING for you to review (the static mission below is a copy/paste",
135
+ "fallback for shells without a Claude Code session).",
136
+ ].join("\n");
117
137
  }
118
138
  // Pure marker writer (no console output). Writes a `.meetless.json` into `cwd`
119
139
  // unless one already exists and `force` is not set. Returns whether a NEW marker
@@ -481,6 +501,9 @@ function onboardRecommendation(opts) {
481
501
  " history. They surface constraints, decisions, conventions, boundaries, and",
482
502
  " deprecations as candidates born PENDING for you to review; nothing is accepted",
483
503
  " automatically. You can run it now or any time later.",
504
+ " First run only: the scout agents were just installed, and Claude Code loads",
505
+ " agents at session start. If `/mla onboard` reports a scout agent is not found,",
506
+ " restart Claude Code (or open a new session) and run it again.",
484
507
  ].join("\n");
485
508
  }
486
509
  // Shared tail for the provision/bind paths: clear any per-session OFF sentinel,
@@ -508,18 +531,16 @@ function finishActivate(cwd, tier, recommendOnboard = false) {
508
531
  const result = (0, scan_context_1.rescanAndCache)({ cwd, workspaceId: scanWorkspaceId });
509
532
  console.log("");
510
533
  console.log((0, bootstrap_summary_1.renderBootstrapSummary)(result));
511
- // Deeper tiers invite the agentic scout to read the messy Tier-2 docs the
512
- // deterministic pass could only count. `full` additionally asks for the
513
- // temporal legacy-note graph, which is the canonical agent's lane and not
514
- // built here, so we say so plainly and fall back to the agentic mission.
534
+ // The deprecated `agentic` tier still prints the static scout mission for the
535
+ // messy Tier-2 docs the deterministic pass could only count, but steers the
536
+ // operator to the consolidated `/mla onboard` flow first (Phase 2).
515
537
  if (bootstrapTierEmitsMission(tier)) {
516
- if (bootstrapTierIsDeepNotYet(tier)) {
538
+ if (bootstrapTierIsDeprecated(tier)) {
517
539
  console.log("");
518
- console.log("The `full` tier (temporal legacy-note graph) is not built yet; it depends on the");
519
- console.log("coordination graph. Running the agentic tier below, the deepest available now.");
540
+ console.log(agenticDeprecationNote());
520
541
  }
521
542
  console.log("");
522
- console.log("Agentic scout mission (hand this to a coding agent):");
543
+ console.log("Static scout mission (hand this to a coding agent):");
523
544
  console.log("");
524
545
  console.log((0, scout_mission_1.renderManualScoutMission)(result));
525
546
  }
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAgentMemory = runAgentMemory;
4
+ // src/commands/agent-memory.ts
5
+ //
6
+ // `mla agent-memory <enable|disable|status|scan|push|report>`: the operator
7
+ // surface for the agent-memory capture pipeline
8
+ // (notes/20260626-agent-memory-auto-capture-proposal.md).
9
+ //
10
+ // `scan` is the Phase 1 DRY-RUN: it observes, classifies, secret-scans
11
+ // (observe-only: signals are recorded, nothing is blocked), and records
12
+ // metadata-only decisions locally; it uploads NOTHING.
13
+ //
14
+ // `push` is the Phase 2A LIVE pass: it uploads changed project-type memory
15
+ // revisions to the governed KB (born PENDING, non-grounding), withholding any
16
+ // file carrying a known credential format (SECRET-1). It is DEFAULT OFF behind
17
+ // MEETLESS_AGENT_MEMORY_LIVE and refuses without --yes. The same collector also
18
+ // runs (gated identically) from the Stop auto-index worker. Phase 2A keeps
19
+ // claim extraction OFF; Phase 2B turns it on and is what the missing
20
+ // cross-revision claim-grain idempotency (DERIVED-IDEMPOTENCY-1) gates.
21
+ //
22
+ // Consent (CONSENT-1) is explicit and per-directory: `enable` shows the resolved
23
+ // directory, the target workspace, and exactly what capture does, and refuses to
24
+ // persist a binding without `--yes`.
25
+ const node_fs_1 = require("node:fs");
26
+ const agent_memory_1 = require("../lib/scanner/agent-memory");
27
+ const workspace_1 = require("../lib/workspace");
28
+ const binding_1 = require("../lib/agent-memory-capture/binding");
29
+ const collector_1 = require("../lib/agent-memory-capture/collector");
30
+ const live_collector_1 = require("../lib/agent-memory-capture/live-collector");
31
+ const ledger_1 = require("../lib/agent-memory-capture/ledger");
32
+ const live_ledger_1 = require("../lib/agent-memory-capture/live-ledger");
33
+ const report_1 = require("../lib/agent-memory-capture/report");
34
+ function parseArgs(argv) {
35
+ const out = { sub: null, dir: null, workspace: null, yes: false, json: false };
36
+ for (let i = 0; i < argv.length; i++) {
37
+ const a = argv[i];
38
+ if (a === "--dir") {
39
+ out.dir = argv[++i] ?? null;
40
+ continue;
41
+ }
42
+ if (a === "--workspace") {
43
+ out.workspace = argv[++i] ?? null;
44
+ continue;
45
+ }
46
+ if (a === "--yes" || a === "-y") {
47
+ out.yes = true;
48
+ continue;
49
+ }
50
+ if (a === "--json") {
51
+ out.json = true;
52
+ continue;
53
+ }
54
+ if (a.startsWith("-")) {
55
+ throw new Error(`Unknown flag: ${a}`);
56
+ }
57
+ if (out.sub === null) {
58
+ out.sub = a;
59
+ continue;
60
+ }
61
+ throw new Error(`Unexpected argument: ${a}`);
62
+ }
63
+ return out;
64
+ }
65
+ function nowIso() {
66
+ return new Date().toISOString();
67
+ }
68
+ // Resolve the directory to operate on: --dir override, else the Claude
69
+ // auto-memory dir for the current project cwd.
70
+ function resolveDir(dir) {
71
+ return dir && dir.trim() ? dir.trim() : (0, agent_memory_1.agentMemoryDir)(process.cwd());
72
+ }
73
+ const CONSENT_LINES = [
74
+ "This enables LOCAL DRY-RUN capture only (Phase 1).",
75
+ "mla will observe project-type memory files in this directory, hash and",
76
+ "secret-scan them, and record metadata-only decisions to a local log.",
77
+ "Nothing is uploaded in this phase.",
78
+ "",
79
+ "Secret patterns are recorded as observations only here; they do not block",
80
+ "anything, because nothing leaves the machine. Pre-upload credential",
81
+ "blocking arrives with remote capture (Phase 2B), not in this phase.",
82
+ "Raw memory notes never ground any agent answer.",
83
+ ];
84
+ function runEnable(args) {
85
+ const dir = resolveDir(args.dir);
86
+ let workspaceId;
87
+ if (args.workspace && args.workspace.trim()) {
88
+ workspaceId = args.workspace.trim();
89
+ }
90
+ else {
91
+ try {
92
+ workspaceId = (0, workspace_1.resolveWorkspaceContext)().workspaceId;
93
+ }
94
+ catch {
95
+ console.error("No activated workspace found. Run this inside an activated repo or pass --workspace <id>.");
96
+ return 2;
97
+ }
98
+ }
99
+ const canonical = (0, binding_1.canonicalizeDir)(dir);
100
+ if (!canonical) {
101
+ console.error(`Memory directory does not resolve: ${dir}`);
102
+ console.error("Pass an existing directory with --dir, or activate Claude memory first.");
103
+ return 2;
104
+ }
105
+ if (!args.yes) {
106
+ console.log(`Directory: ${canonical}`);
107
+ console.log(`Workspace: ${workspaceId}`);
108
+ console.log("");
109
+ for (const l of CONSENT_LINES)
110
+ console.log(l);
111
+ console.log("");
112
+ console.log("Re-run with --yes to consent and enable dry-run capture.");
113
+ return 0;
114
+ }
115
+ const outcome = (0, binding_1.enableBinding)(canonical, workspaceId, nowIso());
116
+ if (!outcome.ok) {
117
+ if (outcome.reason === "workspace-conflict") {
118
+ console.error(`This directory is already bound to workspace ${outcome.conflictWorkspaceId}. ` +
119
+ "One memory directory binds exactly one workspace (MEMORY-WORKSPACE-1). " +
120
+ "Disable the existing binding first.");
121
+ return 2;
122
+ }
123
+ console.error(`Memory directory does not resolve: ${dir}`);
124
+ return 2;
125
+ }
126
+ const b = outcome.binding;
127
+ console.log(`${outcome.reactivated ? "Reactivated" : "Enabled"} dry-run capture for ${b.memoryDir}`);
128
+ console.log(`Binding: ${b.bindingId} -> workspace ${b.workspaceId}`);
129
+ console.log("Run `mla agent-memory scan` to record a dry-run pass (uploads nothing).");
130
+ return 0;
131
+ }
132
+ function runDisable(args) {
133
+ const dir = resolveDir(args.dir);
134
+ const canonical = (0, binding_1.canonicalizeDir)(dir) ?? dir;
135
+ const b = (0, binding_1.disableBinding)(canonical);
136
+ if (!b) {
137
+ console.error(`No capture binding found for ${canonical}`);
138
+ return 1;
139
+ }
140
+ console.log(`Disabled capture for ${b.memoryDir} (binding ${b.bindingId} preserved).`);
141
+ return 0;
142
+ }
143
+ // Derive the live ledger's counts for one binding: how many paths the SERVER has
144
+ // acked (uploaded), how many are currently WITHHELD by the credential denylist
145
+ // (blocked), and the total tracked. The live ledger stores acks/blocks, not
146
+ // outcomes, so these are computed from the entry shape.
147
+ function liveLedgerCounts(bindingId) {
148
+ const entries = Object.values((0, live_ledger_1.readLiveLedger)(bindingId).entries);
149
+ let uploaded = 0;
150
+ let blocked = 0;
151
+ for (const e of entries) {
152
+ if (e.lastUploadedHash)
153
+ uploaded++;
154
+ if (e.blockedHash)
155
+ blocked++;
156
+ }
157
+ return { tracked: entries.length, uploaded, blocked };
158
+ }
159
+ function runStatus(args) {
160
+ const bindings = (0, binding_1.listBindings)();
161
+ if (args.json) {
162
+ const rows = bindings.map((b) => ({
163
+ ...b,
164
+ ledgerEntries: Object.keys((0, ledger_1.readLedger)(b.bindingId).entries).length,
165
+ live: liveLedgerCounts(b.bindingId),
166
+ }));
167
+ console.log(JSON.stringify({ liveCaptureEnabled: (0, live_collector_1.liveCaptureEnabled)(), bindings: rows }, null, 2));
168
+ return 0;
169
+ }
170
+ if (bindings.length === 0) {
171
+ console.log("No agent-memory capture bindings. Run `mla agent-memory enable` to create one.");
172
+ return 0;
173
+ }
174
+ console.log(`Live capture: ${(0, live_collector_1.liveCaptureEnabled)() ? "ENABLED" : "off (default)"}`);
175
+ for (const b of bindings) {
176
+ const entries = Object.keys((0, ledger_1.readLedger)(b.bindingId).entries).length;
177
+ const live = liveLedgerCounts(b.bindingId);
178
+ console.log(`${b.enabled ? "[enabled] " : "[disabled]"} ${b.memoryDir}`);
179
+ console.log(` binding ${b.bindingId}`);
180
+ console.log(` workspace ${b.workspaceId}`);
181
+ console.log(` consented ${b.consentedAt}`);
182
+ console.log(` tracked ${entries} file(s) in dry-run ledger`);
183
+ console.log(` live ${live.tracked} tracked, ${live.uploaded} uploaded, ${live.blocked} blocked`);
184
+ }
185
+ return 0;
186
+ }
187
+ function tally(records) {
188
+ const t = {};
189
+ for (const r of records)
190
+ t[r.decision] = (t[r.decision] ?? 0) + 1;
191
+ return t;
192
+ }
193
+ function runScan(args) {
194
+ const results = (0, collector_1.runDryRunCollector)({ nowIso: nowIso() });
195
+ if (args.json) {
196
+ console.log(JSON.stringify({ results }, null, 2));
197
+ return 0;
198
+ }
199
+ if (results.length === 0) {
200
+ console.log("No enabled bindings. Run `mla agent-memory enable` first.");
201
+ return 0;
202
+ }
203
+ for (const r of results) {
204
+ if (!r.locked) {
205
+ console.log(`${r.bindingId}: skipped (another collector holds the lock)`);
206
+ continue;
207
+ }
208
+ const s = r.summary;
209
+ if (!s) {
210
+ console.log(`${r.bindingId}: no summary`);
211
+ continue;
212
+ }
213
+ const t = tally(s.records);
214
+ const parts = Object.entries(t).map(([k, v]) => `${k}=${v}`).join(" ");
215
+ console.log(`${s.memoryDir} [scan ${s.scanComplete ? "complete" : "PARTIAL"}] ${parts || "(no files)"}`);
216
+ console.log(` appended ${r.appended} actionable decision(s) to the dry-run log`);
217
+ }
218
+ return 0;
219
+ }
220
+ function liveTally(records) {
221
+ const t = {};
222
+ for (const r of records)
223
+ t[r.outcome] = (t[r.outcome] ?? 0) + 1;
224
+ return t;
225
+ }
226
+ // `push`: the Phase 2A LIVE upload pass. DEFAULT OFF (MEETLESS_AGENT_MEMORY_LIVE)
227
+ // and refuses without --yes. Shares the exact collector + gates the Stop worker
228
+ // uses, so a manual push and an automatic Stop pass behave identically.
229
+ async function runPush(args) {
230
+ if (!(0, live_collector_1.liveCaptureEnabled)()) {
231
+ console.error("Live agent-memory capture is OFF (the default).");
232
+ console.error("");
233
+ console.error("When enabled, this uploads changed project-type memory revisions to the");
234
+ console.error("governed KB as born-PENDING sources. They never ground any agent answer");
235
+ console.error("until a human accepts a derived claim. A pre-upload credential denylist");
236
+ console.error("withholds any file carrying a known credential format.");
237
+ console.error("");
238
+ console.error("To enable, set MEETLESS_AGENT_MEMORY_LIVE=1 and re-run with --yes:");
239
+ console.error(" MEETLESS_AGENT_MEMORY_LIVE=1 mla agent-memory push --yes");
240
+ return 0;
241
+ }
242
+ if (!args.yes) {
243
+ console.log("Live capture is ENABLED.");
244
+ console.log("This will UPLOAD changed project-type memory files from every enabled binding");
245
+ console.log("to the governed KB (born PENDING, non-grounding). Files carrying a known");
246
+ console.log("credential format are withheld. Re-run with --yes to upload.");
247
+ return 0;
248
+ }
249
+ const results = await (0, live_collector_1.runLiveCollector)({ nowIso: nowIso() });
250
+ if (args.json) {
251
+ console.log(JSON.stringify({ results }, null, 2));
252
+ return 0;
253
+ }
254
+ if (results.length === 0) {
255
+ console.log("No live upload performed (no enabled bindings, or no resolvable actor identity).");
256
+ return 0;
257
+ }
258
+ for (const r of results) {
259
+ if (!r.locked) {
260
+ console.log(`${r.bindingId}: skipped (another collector holds the lock)`);
261
+ continue;
262
+ }
263
+ const s = r.summary;
264
+ if (!s) {
265
+ console.log(`${r.bindingId}: no summary`);
266
+ continue;
267
+ }
268
+ const t = liveTally(s.records);
269
+ const parts = Object.entries(t)
270
+ .map(([k, v]) => `${k}=${v}`)
271
+ .join(" ");
272
+ console.log(`${s.memoryDir} [scan ${s.scanComplete ? "complete" : "PARTIAL"}] ${parts || "(no files)"}`);
273
+ console.log(` appended ${r.appended} actionable outcome(s) to the live log`);
274
+ }
275
+ return 0;
276
+ }
277
+ function runReport(args) {
278
+ const dir = resolveDir(args.dir);
279
+ if (!(0, node_fs_1.existsSync)(dir) || !(0, node_fs_1.statSync)(dir).isDirectory()) {
280
+ console.error(`Not a directory: ${dir}`);
281
+ return 2;
282
+ }
283
+ const report = (0, report_1.analyzeCorpus)(dir);
284
+ if (args.json) {
285
+ console.log(JSON.stringify(report, null, 2));
286
+ return 0;
287
+ }
288
+ console.log(`Corpus: ${report.memoryDir}`);
289
+ console.log(`Total .md files: ${report.totalMdFiles}`);
290
+ console.log(`By type: ${JSON.stringify(report.byType)}`);
291
+ console.log(`Size bytes: min=${report.sizeBytes.min} median=${report.sizeBytes.median} ` +
292
+ `p90=${report.sizeBytes.p90} max=${report.sizeBytes.max}`);
293
+ console.log(`Project files with a secret signal (observe-only): ${report.secretSignalFiles.length}`);
294
+ for (const b of report.secretSignalFiles) {
295
+ console.log(` ${b.file}: ${b.ruleIds.join(", ")}`);
296
+ }
297
+ console.log(`Phase 2B credential-denylist probe (known fixtures caught): ${report.credentialProbePass ? "PASS" : "FAIL"}`);
298
+ if (report.credentialProbeMisses.length > 0) {
299
+ console.log(` UNDETECTED known credential token(s) in: ${report.credentialProbeMisses.join(", ")}`);
300
+ }
301
+ console.log("");
302
+ console.log("Manual gates (not auto-measured):");
303
+ for (const g of report.manualGates)
304
+ console.log(` - ${g}`);
305
+ return 0;
306
+ }
307
+ async function runAgentMemory(argv) {
308
+ let args;
309
+ try {
310
+ args = parseArgs(argv);
311
+ }
312
+ catch (e) {
313
+ console.error(e.message);
314
+ return 2;
315
+ }
316
+ switch (args.sub) {
317
+ case "enable":
318
+ return runEnable(args);
319
+ case "disable":
320
+ return runDisable(args);
321
+ case "status":
322
+ return runStatus(args);
323
+ case "scan":
324
+ return runScan(args);
325
+ case "push":
326
+ return runPush(args);
327
+ case "report":
328
+ return runReport(args);
329
+ default:
330
+ console.error("Usage: mla agent-memory <enable|disable|status|scan|push|report> [--dir <path>] [--workspace <id>] [--yes] [--json]");
331
+ return 2;
332
+ }
333
+ }