@meetless/mla 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.
Files changed (202) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +81 -0
  3. package/dist/build-info.json +9 -0
  4. package/dist/bundles/ask-core.js +396 -0
  5. package/dist/bundles/mcp.js +16592 -0
  6. package/dist/bundles/trace-core.js +263 -0
  7. package/dist/cli.js +828 -0
  8. package/dist/commands/activate.js +781 -0
  9. package/dist/commands/adoption.js +130 -0
  10. package/dist/commands/ask.js +290 -0
  11. package/dist/commands/context.js +114 -0
  12. package/dist/commands/debug.js +313 -0
  13. package/dist/commands/doctor.js +1021 -0
  14. package/dist/commands/enrich.js +427 -0
  15. package/dist/commands/evidence.js +229 -0
  16. package/dist/commands/flush.js +184 -0
  17. package/dist/commands/graph.js +104 -0
  18. package/dist/commands/init.js +272 -0
  19. package/dist/commands/internal-active-review.js +322 -0
  20. package/dist/commands/internal-auto-index.js +188 -0
  21. package/dist/commands/internal-capture-decisions.js +320 -0
  22. package/dist/commands/internal-evidence-correlate.js +239 -0
  23. package/dist/commands/internal-evidence-hooks.js +240 -0
  24. package/dist/commands/internal-evidence-inject.js +231 -0
  25. package/dist/commands/internal-finalize.js +221 -0
  26. package/dist/commands/internal-pretool-observe.js +225 -0
  27. package/dist/commands/internal-refresh.js +136 -0
  28. package/dist/commands/internal-session-nudge.js +120 -0
  29. package/dist/commands/internal-steer-sync.js +117 -0
  30. package/dist/commands/internal-turn-recap.js +140 -0
  31. package/dist/commands/kb.js +375 -0
  32. package/dist/commands/kb_add.js +681 -0
  33. package/dist/commands/kb_forget.js +283 -0
  34. package/dist/commands/kb_move.js +45 -0
  35. package/dist/commands/kb_pending.js +410 -0
  36. package/dist/commands/kb_personal.js +149 -0
  37. package/dist/commands/kb_promote.js +188 -0
  38. package/dist/commands/kb_purge.js +168 -0
  39. package/dist/commands/kb_reingest.js +335 -0
  40. package/dist/commands/kb_retime.js +170 -0
  41. package/dist/commands/kb_review.js +391 -0
  42. package/dist/commands/kb_revision.js +179 -0
  43. package/dist/commands/kb_show.js +385 -0
  44. package/dist/commands/label.js +226 -0
  45. package/dist/commands/login.js +295 -0
  46. package/dist/commands/logout.js +108 -0
  47. package/dist/commands/mcp-supervisor.js +93 -0
  48. package/dist/commands/mcp.js +227 -0
  49. package/dist/commands/queue-prune.js +98 -0
  50. package/dist/commands/review.js +358 -0
  51. package/dist/commands/rewire.js +124 -0
  52. package/dist/commands/rules.js +728 -0
  53. package/dist/commands/scan-context.js +67 -0
  54. package/dist/commands/session.js +347 -0
  55. package/dist/commands/stats.js +479 -0
  56. package/dist/commands/status.js +61 -0
  57. package/dist/commands/summary.js +250 -0
  58. package/dist/commands/turn.js +114 -0
  59. package/dist/commands/uninstall.js +222 -0
  60. package/dist/commands/whoami.js +102 -0
  61. package/dist/commands/workspace.js +130 -0
  62. package/dist/hooks-template/ce0-post-tool-use.sh +34 -0
  63. package/dist/hooks-template/ce0-session-start.sh +49 -0
  64. package/dist/hooks-template/ce0-stop.sh +29 -0
  65. package/dist/hooks-template/ce0-user-prompt-submit.sh +38 -0
  66. package/dist/hooks-template/common.sh +934 -0
  67. package/dist/hooks-template/event-batch-filter.jq +67 -0
  68. package/dist/hooks-template/flush.sh +503 -0
  69. package/dist/hooks-template/post-tool-use.sh +423 -0
  70. package/dist/hooks-template/pre-tool-use.sh +69 -0
  71. package/dist/hooks-template/session-start.sh +140 -0
  72. package/dist/hooks-template/stop.sh +308 -0
  73. package/dist/hooks-template/user-prompt-submit.sh +1162 -0
  74. package/dist/lib/activation.js +79 -0
  75. package/dist/lib/active-conflict-cache.js +141 -0
  76. package/dist/lib/active-memory.js +59 -0
  77. package/dist/lib/active-review-runner.js +26 -0
  78. package/dist/lib/agent-decision/index.js +25 -0
  79. package/dist/lib/agent-decision/keys.js +49 -0
  80. package/dist/lib/agent-decision/normalize-claude.js +183 -0
  81. package/dist/lib/agent-decision/types.js +21 -0
  82. package/dist/lib/agent-decision/validate.js +216 -0
  83. package/dist/lib/analytics/capture.js +96 -0
  84. package/dist/lib/analytics/command-event.js +267 -0
  85. package/dist/lib/analytics/consent.js +58 -0
  86. package/dist/lib/analytics/coverage-gap.js +96 -0
  87. package/dist/lib/analytics/envelope.js +236 -0
  88. package/dist/lib/analytics/event-id.js +86 -0
  89. package/dist/lib/analytics/evidence.js +150 -0
  90. package/dist/lib/analytics/followthrough.js +194 -0
  91. package/dist/lib/analytics/forwarder.js +109 -0
  92. package/dist/lib/analytics/logs.js +78 -0
  93. package/dist/lib/analytics/metrics.js +78 -0
  94. package/dist/lib/analytics/recorder.js +92 -0
  95. package/dist/lib/analytics/review-analytics.js +75 -0
  96. package/dist/lib/analytics/sequence.js +77 -0
  97. package/dist/lib/analytics/store.js +131 -0
  98. package/dist/lib/analytics/turn-recap.js +279 -0
  99. package/dist/lib/artifact_id.js +108 -0
  100. package/dist/lib/auth-breaker.js +161 -0
  101. package/dist/lib/auto-index.js +112 -0
  102. package/dist/lib/classifier.js +88 -0
  103. package/dist/lib/config.js +298 -0
  104. package/dist/lib/conflict-advisory.js +64 -0
  105. package/dist/lib/debug-bundle.js +520 -0
  106. package/dist/lib/enrichment/ingest.js +301 -0
  107. package/dist/lib/enrichment/plan.js +253 -0
  108. package/dist/lib/enrichment/protocol.js +359 -0
  109. package/dist/lib/enrichment/scout-brief.js +176 -0
  110. package/dist/lib/failure-telemetry.js +444 -0
  111. package/dist/lib/git.js +200 -0
  112. package/dist/lib/governance-cache.js +77 -0
  113. package/dist/lib/governed-path-cache.js +76 -0
  114. package/dist/lib/http.js +677 -0
  115. package/dist/lib/identity-envelope.js +23 -0
  116. package/dist/lib/kb-candidate.js +65 -0
  117. package/dist/lib/kb_acl.js +98 -0
  118. package/dist/lib/login.js +353 -0
  119. package/dist/lib/mcp-fetchers.js +130 -0
  120. package/dist/lib/mcp-restart.js +47 -0
  121. package/dist/lib/observability.js +805 -0
  122. package/dist/lib/open-url.js +33 -0
  123. package/dist/lib/orphan-guard.js +70 -0
  124. package/dist/lib/packaged.js +21 -0
  125. package/dist/lib/reconcile-sessions.js +171 -0
  126. package/dist/lib/redactor.js +89 -0
  127. package/dist/lib/relationship-candidate-query.js +27 -0
  128. package/dist/lib/render.js +611 -0
  129. package/dist/lib/rules/applicability.js +64 -0
  130. package/dist/lib/rules/attest-code-rule-version.js +47 -0
  131. package/dist/lib/rules/attest-notes-location.js +217 -0
  132. package/dist/lib/rules/attest-rule-version.js +69 -0
  133. package/dist/lib/rules/canonical-json.js +97 -0
  134. package/dist/lib/rules/ce0-emit.js +64 -0
  135. package/dist/lib/rules/ce0-evidence.js +281 -0
  136. package/dist/lib/rules/ce0-recall-sample.js +82 -0
  137. package/dist/lib/rules/ce0-rule.js +55 -0
  138. package/dist/lib/rules/ce0-sampling-bucket.js +15 -0
  139. package/dist/lib/rules/ce0-store.js +683 -0
  140. package/dist/lib/rules/ce0-telemetry-project.js +93 -0
  141. package/dist/lib/rules/ce0-telemetry.js +158 -0
  142. package/dist/lib/rules/code-rule-registry.js +17 -0
  143. package/dist/lib/rules/command-match.js +185 -0
  144. package/dist/lib/rules/consult-evidence-binding.js +27 -0
  145. package/dist/lib/rules/consultation-capture-adapter.js +193 -0
  146. package/dist/lib/rules/content-match.js +56 -0
  147. package/dist/lib/rules/deny-admission.js +99 -0
  148. package/dist/lib/rules/durable-observation.js +190 -0
  149. package/dist/lib/rules/enforce-notes-version.js +421 -0
  150. package/dist/lib/rules/evaluation-input-hash.js +126 -0
  151. package/dist/lib/rules/evaluator.js +108 -0
  152. package/dist/lib/rules/inert-rule-families.js +51 -0
  153. package/dist/lib/rules/input-authority-resolver.js +241 -0
  154. package/dist/lib/rules/interception-schema.js +170 -0
  155. package/dist/lib/rules/interception-store.js +267 -0
  156. package/dist/lib/rules/live-input-authority.js +66 -0
  157. package/dist/lib/rules/local-matcher.js +108 -0
  158. package/dist/lib/rules/local-observe.js +79 -0
  159. package/dist/lib/rules/local-rule-version-repo.js +214 -0
  160. package/dist/lib/rules/memory-requirement.js +109 -0
  161. package/dist/lib/rules/notes-observe.js +39 -0
  162. package/dist/lib/rules/notes-path.js +261 -0
  163. package/dist/lib/rules/notes-rule.js +75 -0
  164. package/dist/lib/rules/observe-adapter.js +114 -0
  165. package/dist/lib/rules/observed-rule-hash.js +119 -0
  166. package/dist/lib/rules/prompt-submit-adapter.js +132 -0
  167. package/dist/lib/rules/requirement-subject.js +240 -0
  168. package/dist/lib/rules/rule-activity.js +67 -0
  169. package/dist/lib/rules/rule-version-hash.js +151 -0
  170. package/dist/lib/rules/runtime-scope.js +55 -0
  171. package/dist/lib/rules/stop-adapter.js +116 -0
  172. package/dist/lib/rules/stop-response-snapshot.js +174 -0
  173. package/dist/lib/rules/types.js +10 -0
  174. package/dist/lib/rules/ulid.js +46 -0
  175. package/dist/lib/rules/version-evaluation.js +156 -0
  176. package/dist/lib/scanner/agent-memory.js +99 -0
  177. package/dist/lib/scanner/bootstrap-summary.js +87 -0
  178. package/dist/lib/scanner/cache.js +59 -0
  179. package/dist/lib/scanner/frontmatter.js +42 -0
  180. package/dist/lib/scanner/parse-directives.js +69 -0
  181. package/dist/lib/scanner/parse-structured.js +72 -0
  182. package/dist/lib/scanner/render.js +73 -0
  183. package/dist/lib/scanner/scan.js +132 -0
  184. package/dist/lib/scanner/score.js +38 -0
  185. package/dist/lib/scanner/scout-mission.js +126 -0
  186. package/dist/lib/scanner/types.js +7 -0
  187. package/dist/lib/session-scope.js +195 -0
  188. package/dist/lib/spool.js +355 -0
  189. package/dist/lib/staleness.js +100 -0
  190. package/dist/lib/steer-cache.js +87 -0
  191. package/dist/lib/tagged-reference.js +20 -0
  192. package/dist/lib/temporal.js +109 -0
  193. package/dist/lib/turn-recap-emit.js +67 -0
  194. package/dist/lib/unwire.js +253 -0
  195. package/dist/lib/update-check.js +469 -0
  196. package/dist/lib/update-notifier.js +217 -0
  197. package/dist/lib/upgrade-apply.js +643 -0
  198. package/dist/lib/wire.js +1087 -0
  199. package/dist/lib/workspace.js +96 -0
  200. package/dist/lib/zip.js +154 -0
  201. package/dist/pretool-entry.js +37 -0
  202. package/package.json +75 -0
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCP_RESTART_WINDOW_MS = exports.MCP_RESTART_MAX = void 0;
4
+ exports.runMcpSupervisor = runMcpSupervisor;
5
+ const child_process_1 = require("child_process");
6
+ const mcp_restart_1 = require("../lib/mcp-restart");
7
+ const orphan_guard_1 = require("../lib/orphan-guard");
8
+ // The supervising parent for `mla mcp` (see lib/mcp-restart.ts for the why).
9
+ // This process is intentionally dumb: it holds the client's stdio pipe open and
10
+ // keeps a single `mla mcp --child` worker alive under it. The worker serves the
11
+ // MCP protocol; when it detects a newer build on disk and goes idle it exits
12
+ // with MCP_RESTART_EXIT_CODE, and we respawn it on the fresh dist. Because the
13
+ // parent never closes fd 0/1, the MCP client never sees a disconnect across a
14
+ // reload. Every other worker exit (0 clean disconnect via stdin EOF, 1/2 error)
15
+ // is final and we propagate it.
16
+ // Storm cap: tolerate this many reloads inside the window before giving up, so a
17
+ // pathological loop (e.g. a build-info `builtAt` that is perpetually "newer" due
18
+ // to clock skew) degrades to the old manual-restart behaviour instead of
19
+ // respawning without bound. Legitimate dev rebuilds are far rarer than this.
20
+ exports.MCP_RESTART_MAX = 5;
21
+ exports.MCP_RESTART_WINDOW_MS = 60_000;
22
+ // Re-spawn the SAME mla binary as `mla mcp --child`, inheriting our stdio so the
23
+ // worker reads/writes the exact pipe the client connected to us on. process.exit
24
+ // in the worker (the reload signal) closes only the worker's dup'd fds; ours stay
25
+ // open, so the client's connection survives the swap. `onChild` is handed a
26
+ // killer so the supervisor can SIGTERM this worker if the supervisor itself is
27
+ // told to stop (otherwise a TERM to the supervisor would orphan the worker).
28
+ function defaultSpawnChild(childArgv, onChild) {
29
+ return new Promise((resolve) => {
30
+ const child = (0, child_process_1.spawn)(process.execPath, [process.argv[1], "mcp", "--child", ...childArgv], { stdio: "inherit", env: process.env });
31
+ onChild?.(() => {
32
+ try {
33
+ child.kill("SIGTERM");
34
+ }
35
+ catch {
36
+ // already gone; nothing to reap.
37
+ }
38
+ });
39
+ child.on("exit", (code, signal) => resolve(typeof code === "number" ? code : signal ? 1 : 0));
40
+ child.on("error", () => resolve(1));
41
+ });
42
+ }
43
+ // Wire the supervisor's own teardown to the current worker by delegating to the
44
+ // SAME guard the worker uses (lib/orphan-guard.ts), so the supervisor gets both
45
+ // backstops, not just signal handling:
46
+ // - SIGTERM/SIGINT/SIGHUP: kill the worker first (onTerminate), then exit 143
47
+ // (the standard "terminated by SIGTERM" code) so the chain collapses cleanly
48
+ // instead of leaving the worker blocked on a stdin whose EOF never comes.
49
+ // - parent-death watchdog: if the supervisor is orphaned (ppid -> 1) while its
50
+ // worker is still alive beneath it, the worker's ppid is the still-running
51
+ // supervisor (NOT 1), so the worker's own watchdog never fires. The
52
+ // supervisor's does: it kills the worker (onTerminate) and exits 0. That
53
+ // orphaned-supervisor case was the MAJORITY of the measured leak (148 vs 61
54
+ // workers), so the watchdog has to live here too, not just at the leaf.
55
+ // The 'exit' listener is a belt-and-suspenders reap for any OTHER exit path (the
56
+ // guard wires only signals + the watchdog); kill is synchronous, so it is safe
57
+ // to call from inside an 'exit' handler.
58
+ function defaultInstallTeardown(killCurrent) {
59
+ (0, orphan_guard_1.installOrphanGuard)({ onTerminate: killCurrent, signalExitCode: 143 });
60
+ process.on("exit", () => killCurrent());
61
+ }
62
+ async function runMcpSupervisor(argv, deps = {}) {
63
+ const spawnChild = deps.spawnChild ?? defaultSpawnChild;
64
+ const errorLog = deps.errorLog ?? ((m) => console.error(m));
65
+ const now = deps.now ?? Date.now;
66
+ const installTeardown = deps.installTeardown ?? defaultInstallTeardown;
67
+ // The killer for whichever worker is live right now. Reset to a no-op the
68
+ // instant a worker exits, so a signal that races the worker's death (or the
69
+ // gap between reload-respawns) never double-kills or targets a dead pid. The
70
+ // teardown handlers below close over this slot, not over any one worker.
71
+ let killCurrentChild = () => { };
72
+ installTeardown(() => killCurrentChild());
73
+ const restarts = [];
74
+ for (;;) {
75
+ const code = await spawnChild(argv, (kill) => {
76
+ killCurrentChild = kill;
77
+ });
78
+ killCurrentChild = () => { };
79
+ if (code !== mcp_restart_1.MCP_RESTART_EXIT_CODE)
80
+ return code;
81
+ const t = now();
82
+ restarts.push(t);
83
+ const recent = restarts.filter((ts) => t - ts < exports.MCP_RESTART_WINDOW_MS);
84
+ if (recent.length > exports.MCP_RESTART_MAX) {
85
+ errorLog(`Meetless MCP: ${recent.length} reloads within ` +
86
+ `${Math.round(exports.MCP_RESTART_WINDOW_MS / 1000)}s; giving up to avoid a ` +
87
+ `restart storm. Restart your editor to recover.`);
88
+ return code;
89
+ }
90
+ errorLog("Meetless MCP: a newer build is on disk; reloading the server " +
91
+ "(no editor restart needed).");
92
+ }
93
+ }
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runMcp = runMcp;
37
+ const path = __importStar(require("path"));
38
+ const config_1 = require("../lib/config");
39
+ const workspace_1 = require("../lib/workspace");
40
+ const mcp_fetchers_1 = require("../lib/mcp-fetchers");
41
+ const staleness_1 = require("../lib/staleness");
42
+ const mcp_restart_1 = require("../lib/mcp-restart");
43
+ const orphan_guard_1 = require("../lib/orphan-guard");
44
+ const packaged_1 = require("../lib/packaged");
45
+ // @meetless/mcp is ESM-only; `mla` compiles to CommonJS. It ships as a CJS
46
+ // bundle (scripts/bundle-esm.js -> dist/bundles/mcp.js) so the CLI loads it with
47
+ // a plain require(), which the pkg V8 snapshot supports. A true import() does
48
+ // NOT work inside the snapshot (no ESM dynamic-import callback) and would die
49
+ // with "A dynamic import callback was not specified". The Function constructor
50
+ // below preserves a TRUE runtime import() for the dev fallback only (ts-node
51
+ // `pnpm dev`, no built dist), where tsc must not downlevel it to require() of an
52
+ // ESM package.
53
+ const trueDynamicImport = new Function("u", "return import(u)");
54
+ // dist/commands/mcp.js -> dist -> dist/bundles/mcp.js
55
+ function mcpBundlePath() {
56
+ return path.resolve(__dirname, "..", "bundles", "mcp.js");
57
+ }
58
+ // Prefer the bundled CJS (require() works in the binary). Fall back to the ESM
59
+ // source via a true import() for dev (ts-node), where no dist/bundles exists.
60
+ // The fallback never runs inside the binary, where a true import() would throw;
61
+ // there a require failure surfaces as-is. Only fall through on a genuine
62
+ // "module not found"; a real load error inside the bundle must surface.
63
+ async function loadAndServe(deps) {
64
+ let mod;
65
+ try {
66
+ mod = require(mcpBundlePath());
67
+ }
68
+ catch (e) {
69
+ if ((0, packaged_1.isPackagedBinary)())
70
+ throw e;
71
+ const code = e?.code;
72
+ if (code !== "MODULE_NOT_FOUND" && code !== "ERR_MODULE_NOT_FOUND")
73
+ throw e;
74
+ mod = (await trueDynamicImport("@meetless/mcp"));
75
+ }
76
+ return mod.runStdioServer(deps);
77
+ }
78
+ // A spawned MCP server is a daemon: it cannot `cd`, and its launch cwd is
79
+ // whatever the client chose, which may sit outside the activated repo. So
80
+ // `mla mcp` must NOT blindly trust process.cwd() for marker resolution. Derive
81
+ // the start dir from an explicit client signal instead, in priority order:
82
+ // 1. an injected startDir (tests, and a future `mla mcp --dir <path>`),
83
+ // 2. MEETLESS_PROJECT_DIR (client-agnostic: any MCP client can pin the repo
84
+ // in its server `env` block),
85
+ // 3. CLAUDE_PROJECT_DIR (Claude Code sets this to the project root for
86
+ // every stdio server it spawns, so CC users get zero-config resolution).
87
+ // Falling through to undefined lets resolveWorkspaceContext default to
88
+ // process.cwd(), which is correct for an interactive `mla mcp` launch.
89
+ function resolveStartDir(env, explicit) {
90
+ return (explicit ?? env.MEETLESS_PROJECT_DIR ?? env.CLAUDE_PROJECT_DIR ?? undefined);
91
+ }
92
+ // notesRoot powers ONLY the INDEX.md canonical matcher, which degrades to
93
+ // retrieval when absent, so an imperfect guess is non-fatal. Honor an explicit
94
+ // override, else derive the standalone notes repo as a sibling of the marker
95
+ // repo (projects/<x>/notes for the dogfood layout).
96
+ function resolveNotesRoot(env, ctx) {
97
+ if (env.MEETLESS_NOTES_ROOT)
98
+ return env.MEETLESS_NOTES_ROOT;
99
+ return path.resolve(ctx.markerDir, "..", "notes");
100
+ }
101
+ function notActivatedStatus() {
102
+ return {
103
+ state: "inactive",
104
+ reason: "not-activated",
105
+ message: "Meetless is installed but inactive in this repository. No Meetless context is being injected.",
106
+ action: { command: "mla activate" },
107
+ };
108
+ }
109
+ function notAuthenticatedStatus() {
110
+ return {
111
+ state: "inactive",
112
+ reason: "not-authenticated",
113
+ message: "Meetless is not logged in, so it is inactive here. No Meetless context is being injected.",
114
+ action: { command: "mla login" },
115
+ };
116
+ }
117
+ function invalidActivationStatus() {
118
+ return {
119
+ state: "inactive",
120
+ reason: "invalid-activation",
121
+ message: "Meetless activation is incomplete in this repository. Run `mla doctor`, then rerun `mla activate` to repair it.",
122
+ action: { command: "mla doctor" },
123
+ };
124
+ }
125
+ // Boot a connected-but-inactive (status-only) server for a KNOWN dormant state.
126
+ // The handshake completes (green in Claude Code), only the status tool is
127
+ // advertised, and no backend is touched. One stderr breadcrumb is written for
128
+ // Claude Code's MCP log so a connected-but-inactive server reads as intentional,
129
+ // not a crash; it is a plain log line, not a TTY branch.
130
+ async function serveInactive(status, startServer, installGuard, err) {
131
+ err(`meetless mcp: inactive (${status.reason}); run \`${status.action.command}\` to enable.`);
132
+ installGuard();
133
+ try {
134
+ await startServer({ mode: "inactive", status });
135
+ return 0;
136
+ }
137
+ catch (e) {
138
+ err(`meetless mcp server exited with an error: ${e.message}`);
139
+ return 1;
140
+ }
141
+ }
142
+ async function runMcp(argv, deps = {}) {
143
+ const readCfg = deps.readConfig ?? config_1.readConfig;
144
+ const resolveWs = deps.resolveWorkspaceContext ?? workspace_1.resolveWorkspaceContext;
145
+ const makeControlFetch = deps.makeControlFetch ?? mcp_fetchers_1.makeControlFetchFromCli;
146
+ const makeIntelFetch = deps.makeIntelFetch ?? mcp_fetchers_1.makeIntelFetchFromCli;
147
+ const makeIntelAsk = deps.makeIntelAsk ?? mcp_fetchers_1.makeIntelAskFromCli;
148
+ const makeStaleCheck = deps.makeStaleCheck ?? staleness_1.makeMcpStaleCheck;
149
+ const startServer = deps.startServer ?? loadAndServe;
150
+ const installGuard = deps.installOrphanGuard ?? orphan_guard_1.installOrphanGuard;
151
+ const env = deps.env ?? process.env;
152
+ const err = deps.errorLog ?? ((m) => console.error(m));
153
+ const exit = deps.exit ?? ((code) => process.exit(code));
154
+ let cfg;
155
+ try {
156
+ cfg = readCfg();
157
+ }
158
+ catch (e) {
159
+ err(e.message);
160
+ return 2;
161
+ }
162
+ // `none` is terminal for credentials but no longer fatal for the server: boot
163
+ // a status-only server so Claude Code shows a CONNECTED (not red) server that
164
+ // can explain it needs `mla login`.
165
+ if (cfg.auth.mode === "none") {
166
+ return serveInactive(notAuthenticatedStatus(), startServer, installGuard, err);
167
+ }
168
+ let ctx;
169
+ try {
170
+ ctx = resolveWs(resolveStartDir(env, deps.startDir));
171
+ }
172
+ catch (e) {
173
+ // Known-inactive states: serve a green, status-only server instead of dying
174
+ // red. Distinguish a missing activation (`mla activate`) from a present but
175
+ // broken marker (`mla doctor` to repair).
176
+ if (e instanceof workspace_1.NotActivatedError) {
177
+ return serveInactive(notActivatedStatus(), startServer, installGuard, err);
178
+ }
179
+ if (e instanceof workspace_1.MarkerMissingWorkspaceIdError) {
180
+ return serveInactive(invalidActivationStatus(), startServer, installGuard, err);
181
+ }
182
+ // An unanticipated resolution failure stays fatal (red): we cannot truthfully
183
+ // describe a state we did not expect.
184
+ err(e.message);
185
+ return 2;
186
+ }
187
+ const serverDeps = {
188
+ mode: "active",
189
+ // Closures bind the SAME cfg object, so http.ts's in-place token rotation
190
+ // (refreshUserToken) stays visible to every later control / intel call.
191
+ controlFetch: makeControlFetch(cfg),
192
+ intelFetch: makeIntelFetch(cfg),
193
+ intelAsk: makeIntelAsk(cfg),
194
+ defaultWorkspaceId: ctx.workspaceId,
195
+ notesRoot: resolveNotesRoot(env, ctx),
196
+ // Identity is the audited human under user-token; shared-key has none.
197
+ operatorUserId: cfg.auth.mode === "user-token" ? cfg.auth.user.id : null,
198
+ agentRuntime: env.MEETLESS_AGENT_RUNTIME || null,
199
+ // Snapshot the build identity now, at spawn; the probe compares against the
200
+ // on-disk build on every later tool call.
201
+ staleCheck: makeStaleCheck(),
202
+ // Only a supervised child can be respawned, so only it self-heals. A bare /
203
+ // kill-switched run has no parent to come back to, so it leaves this null and
204
+ // relies on the inline staleCheck warning instead.
205
+ onStaleRestart: (0, mcp_restart_1.isMcpChild)(argv, env)
206
+ ? () => exit(mcp_restart_1.MCP_RESTART_EXIT_CODE)
207
+ : null,
208
+ };
209
+ // Install the worker's death backstops just before serving. The server below
210
+ // resolves ONLY on stdin EOF; if the client dies without closing the pipe the
211
+ // process would otherwise block forever (reparented to pid 1). Signal handlers
212
+ // + a parent-death watchdog reap it. Applies to BOTH the supervised --child
213
+ // worker and a bare / kill-switched single-process run: in the bare case our
214
+ // direct parent is the client, so its death also flips ppid to 1 and we exit.
215
+ installGuard();
216
+ try {
217
+ // Long-lived: in production this resolves only when the MCP client
218
+ // disconnects (stdin EOF). The entrypoint's process.exit therefore fires
219
+ // after the server is done, never tearing it down mid-session.
220
+ await startServer(serverDeps);
221
+ return 0;
222
+ }
223
+ catch (e) {
224
+ err(`meetless mcp server exited with an error: ${e.message}`);
225
+ return 1;
226
+ }
227
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runQueuePrune = runQueuePrune;
4
+ const spool_1 = require("../lib/spool");
5
+ function parseArgs(argv) {
6
+ const out = {
7
+ yes: false,
8
+ dryRun: false,
9
+ flush: true,
10
+ maxAgeHours: null,
11
+ session: undefined,
12
+ error: null,
13
+ };
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const a = argv[i];
16
+ if (a === "--yes" || a === "-y")
17
+ out.yes = true;
18
+ else if (a === "--dry-run")
19
+ out.dryRun = true;
20
+ else if (a === "--no-flush")
21
+ out.flush = false;
22
+ else if (a === "--max-age-hours") {
23
+ const v = Number(argv[++i]);
24
+ if (!Number.isFinite(v) || v < 0) {
25
+ out.error = `--max-age-hours expects a non-negative number, got: ${argv[i] ?? "(missing)"}`;
26
+ return out;
27
+ }
28
+ out.maxAgeHours = v;
29
+ }
30
+ else if (a === "--session") {
31
+ out.session = argv[++i];
32
+ if (!out.session) {
33
+ out.error = "--session expects a session id";
34
+ return out;
35
+ }
36
+ }
37
+ else {
38
+ out.error = `Unknown flag: ${a}`;
39
+ return out;
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+ function fmtBytes(n) {
45
+ if (n < 1024)
46
+ return `${n}B`;
47
+ if (n < 1024 * 1024)
48
+ return `${(n / 1024).toFixed(1)}K`;
49
+ return `${(n / (1024 * 1024)).toFixed(1)}M`;
50
+ }
51
+ function fmtAge(sec) {
52
+ if (sec === null)
53
+ return "n/a";
54
+ if (sec < 3600)
55
+ return `${Math.round(sec / 60)}m`;
56
+ if (sec < 86_400)
57
+ return `${(sec / 3600).toFixed(1)}h`;
58
+ return `${(sec / 86_400).toFixed(1)}d`;
59
+ }
60
+ async function runQueuePrune(argv, opts = {}) {
61
+ const a = parseArgs(argv);
62
+ if (a.error) {
63
+ console.error(a.error);
64
+ return 2;
65
+ }
66
+ const maxAgeSec = a.maxAgeHours != null ? Math.round(a.maxAgeHours * 3600) : undefined;
67
+ const plan = (0, spool_1.planQueuePrune)({
68
+ maxAgeSec,
69
+ sessionId: a.session,
70
+ queueDir: opts.queueDir,
71
+ now: opts.now,
72
+ });
73
+ if (plan.candidates.length === 0) {
74
+ console.log(`Nothing to prune (${plan.skippedFresh} session(s) too fresh to be litter).`);
75
+ return 0;
76
+ }
77
+ console.log(`Prune plan: ${plan.candidates.length} dead session(s), ${plan.totalFiles} files, ` +
78
+ `${plan.totalUnflushedEvents} un-flushed event(s), ${fmtBytes(plan.totalBytes)}, ` +
79
+ `oldest ${fmtAge(plan.oldestAgeSec)}.`);
80
+ for (const c of plan.candidates.slice(0, 20)) {
81
+ console.log(` ${c.sessionId} ${c.files.length} files ${c.unflushedEvents} ev ${fmtAge(c.ageSec)}`);
82
+ }
83
+ if (plan.candidates.length > 20) {
84
+ console.log(` ... and ${plan.candidates.length - 20} more`);
85
+ }
86
+ if (!a.yes || a.dryRun) {
87
+ console.log(`\nDry run (no files removed). Re-run with --yes to prune` +
88
+ (a.flush ? "; un-flushed events are flushed best-effort first" : "") +
89
+ `.`);
90
+ return 0;
91
+ }
92
+ const res = (0, spool_1.executeQueuePrune)(plan, { hookDir: opts.hookDir, flush: a.flush });
93
+ console.log(`Pruned ${res.prunedSessions.length} session(s): removed ${res.removedFiles} files` +
94
+ (res.flushedSessions ? `, flushed ${res.flushedSessions} before prune` : "") +
95
+ (res.discardedEvents ? `, discarded ${res.discardedEvents} undeliverable event(s)` : "") +
96
+ `.`);
97
+ return 0;
98
+ }