@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.
- package/LICENSE +201 -0
- package/README.md +81 -0
- package/dist/build-info.json +9 -0
- package/dist/bundles/ask-core.js +396 -0
- package/dist/bundles/mcp.js +16592 -0
- package/dist/bundles/trace-core.js +263 -0
- package/dist/cli.js +828 -0
- package/dist/commands/activate.js +781 -0
- package/dist/commands/adoption.js +130 -0
- package/dist/commands/ask.js +290 -0
- package/dist/commands/context.js +114 -0
- package/dist/commands/debug.js +313 -0
- package/dist/commands/doctor.js +1021 -0
- package/dist/commands/enrich.js +427 -0
- package/dist/commands/evidence.js +229 -0
- package/dist/commands/flush.js +184 -0
- package/dist/commands/graph.js +104 -0
- package/dist/commands/init.js +272 -0
- package/dist/commands/internal-active-review.js +322 -0
- package/dist/commands/internal-auto-index.js +188 -0
- package/dist/commands/internal-capture-decisions.js +320 -0
- package/dist/commands/internal-evidence-correlate.js +239 -0
- package/dist/commands/internal-evidence-hooks.js +240 -0
- package/dist/commands/internal-evidence-inject.js +231 -0
- package/dist/commands/internal-finalize.js +221 -0
- package/dist/commands/internal-pretool-observe.js +225 -0
- package/dist/commands/internal-refresh.js +136 -0
- package/dist/commands/internal-session-nudge.js +120 -0
- package/dist/commands/internal-steer-sync.js +117 -0
- package/dist/commands/internal-turn-recap.js +140 -0
- package/dist/commands/kb.js +375 -0
- package/dist/commands/kb_add.js +681 -0
- package/dist/commands/kb_forget.js +283 -0
- package/dist/commands/kb_move.js +45 -0
- package/dist/commands/kb_pending.js +410 -0
- package/dist/commands/kb_personal.js +149 -0
- package/dist/commands/kb_promote.js +188 -0
- package/dist/commands/kb_purge.js +168 -0
- package/dist/commands/kb_reingest.js +335 -0
- package/dist/commands/kb_retime.js +170 -0
- package/dist/commands/kb_review.js +391 -0
- package/dist/commands/kb_revision.js +179 -0
- package/dist/commands/kb_show.js +385 -0
- package/dist/commands/label.js +226 -0
- package/dist/commands/login.js +295 -0
- package/dist/commands/logout.js +108 -0
- package/dist/commands/mcp-supervisor.js +93 -0
- package/dist/commands/mcp.js +227 -0
- package/dist/commands/queue-prune.js +98 -0
- package/dist/commands/review.js +358 -0
- package/dist/commands/rewire.js +124 -0
- package/dist/commands/rules.js +728 -0
- package/dist/commands/scan-context.js +67 -0
- package/dist/commands/session.js +347 -0
- package/dist/commands/stats.js +479 -0
- package/dist/commands/status.js +61 -0
- package/dist/commands/summary.js +250 -0
- package/dist/commands/turn.js +114 -0
- package/dist/commands/uninstall.js +222 -0
- package/dist/commands/whoami.js +102 -0
- package/dist/commands/workspace.js +130 -0
- package/dist/hooks-template/ce0-post-tool-use.sh +34 -0
- package/dist/hooks-template/ce0-session-start.sh +49 -0
- package/dist/hooks-template/ce0-stop.sh +29 -0
- package/dist/hooks-template/ce0-user-prompt-submit.sh +38 -0
- package/dist/hooks-template/common.sh +934 -0
- package/dist/hooks-template/event-batch-filter.jq +67 -0
- package/dist/hooks-template/flush.sh +503 -0
- package/dist/hooks-template/post-tool-use.sh +423 -0
- package/dist/hooks-template/pre-tool-use.sh +69 -0
- package/dist/hooks-template/session-start.sh +140 -0
- package/dist/hooks-template/stop.sh +308 -0
- package/dist/hooks-template/user-prompt-submit.sh +1162 -0
- package/dist/lib/activation.js +79 -0
- package/dist/lib/active-conflict-cache.js +141 -0
- package/dist/lib/active-memory.js +59 -0
- package/dist/lib/active-review-runner.js +26 -0
- package/dist/lib/agent-decision/index.js +25 -0
- package/dist/lib/agent-decision/keys.js +49 -0
- package/dist/lib/agent-decision/normalize-claude.js +183 -0
- package/dist/lib/agent-decision/types.js +21 -0
- package/dist/lib/agent-decision/validate.js +216 -0
- package/dist/lib/analytics/capture.js +96 -0
- package/dist/lib/analytics/command-event.js +267 -0
- package/dist/lib/analytics/consent.js +58 -0
- package/dist/lib/analytics/coverage-gap.js +96 -0
- package/dist/lib/analytics/envelope.js +236 -0
- package/dist/lib/analytics/event-id.js +86 -0
- package/dist/lib/analytics/evidence.js +150 -0
- package/dist/lib/analytics/followthrough.js +194 -0
- package/dist/lib/analytics/forwarder.js +109 -0
- package/dist/lib/analytics/logs.js +78 -0
- package/dist/lib/analytics/metrics.js +78 -0
- package/dist/lib/analytics/recorder.js +92 -0
- package/dist/lib/analytics/review-analytics.js +75 -0
- package/dist/lib/analytics/sequence.js +77 -0
- package/dist/lib/analytics/store.js +131 -0
- package/dist/lib/analytics/turn-recap.js +279 -0
- package/dist/lib/artifact_id.js +108 -0
- package/dist/lib/auth-breaker.js +161 -0
- package/dist/lib/auto-index.js +112 -0
- package/dist/lib/classifier.js +88 -0
- package/dist/lib/config.js +298 -0
- package/dist/lib/conflict-advisory.js +64 -0
- package/dist/lib/debug-bundle.js +520 -0
- package/dist/lib/enrichment/ingest.js +301 -0
- package/dist/lib/enrichment/plan.js +253 -0
- package/dist/lib/enrichment/protocol.js +359 -0
- package/dist/lib/enrichment/scout-brief.js +176 -0
- package/dist/lib/failure-telemetry.js +444 -0
- package/dist/lib/git.js +200 -0
- package/dist/lib/governance-cache.js +77 -0
- package/dist/lib/governed-path-cache.js +76 -0
- package/dist/lib/http.js +677 -0
- package/dist/lib/identity-envelope.js +23 -0
- package/dist/lib/kb-candidate.js +65 -0
- package/dist/lib/kb_acl.js +98 -0
- package/dist/lib/login.js +353 -0
- package/dist/lib/mcp-fetchers.js +130 -0
- package/dist/lib/mcp-restart.js +47 -0
- package/dist/lib/observability.js +805 -0
- package/dist/lib/open-url.js +33 -0
- package/dist/lib/orphan-guard.js +70 -0
- package/dist/lib/packaged.js +21 -0
- package/dist/lib/reconcile-sessions.js +171 -0
- package/dist/lib/redactor.js +89 -0
- package/dist/lib/relationship-candidate-query.js +27 -0
- package/dist/lib/render.js +611 -0
- package/dist/lib/rules/applicability.js +64 -0
- package/dist/lib/rules/attest-code-rule-version.js +47 -0
- package/dist/lib/rules/attest-notes-location.js +217 -0
- package/dist/lib/rules/attest-rule-version.js +69 -0
- package/dist/lib/rules/canonical-json.js +97 -0
- package/dist/lib/rules/ce0-emit.js +64 -0
- package/dist/lib/rules/ce0-evidence.js +281 -0
- package/dist/lib/rules/ce0-recall-sample.js +82 -0
- package/dist/lib/rules/ce0-rule.js +55 -0
- package/dist/lib/rules/ce0-sampling-bucket.js +15 -0
- package/dist/lib/rules/ce0-store.js +683 -0
- package/dist/lib/rules/ce0-telemetry-project.js +93 -0
- package/dist/lib/rules/ce0-telemetry.js +158 -0
- package/dist/lib/rules/code-rule-registry.js +17 -0
- package/dist/lib/rules/command-match.js +185 -0
- package/dist/lib/rules/consult-evidence-binding.js +27 -0
- package/dist/lib/rules/consultation-capture-adapter.js +193 -0
- package/dist/lib/rules/content-match.js +56 -0
- package/dist/lib/rules/deny-admission.js +99 -0
- package/dist/lib/rules/durable-observation.js +190 -0
- package/dist/lib/rules/enforce-notes-version.js +421 -0
- package/dist/lib/rules/evaluation-input-hash.js +126 -0
- package/dist/lib/rules/evaluator.js +108 -0
- package/dist/lib/rules/inert-rule-families.js +51 -0
- package/dist/lib/rules/input-authority-resolver.js +241 -0
- package/dist/lib/rules/interception-schema.js +170 -0
- package/dist/lib/rules/interception-store.js +267 -0
- package/dist/lib/rules/live-input-authority.js +66 -0
- package/dist/lib/rules/local-matcher.js +108 -0
- package/dist/lib/rules/local-observe.js +79 -0
- package/dist/lib/rules/local-rule-version-repo.js +214 -0
- package/dist/lib/rules/memory-requirement.js +109 -0
- package/dist/lib/rules/notes-observe.js +39 -0
- package/dist/lib/rules/notes-path.js +261 -0
- package/dist/lib/rules/notes-rule.js +75 -0
- package/dist/lib/rules/observe-adapter.js +114 -0
- package/dist/lib/rules/observed-rule-hash.js +119 -0
- package/dist/lib/rules/prompt-submit-adapter.js +132 -0
- package/dist/lib/rules/requirement-subject.js +240 -0
- package/dist/lib/rules/rule-activity.js +67 -0
- package/dist/lib/rules/rule-version-hash.js +151 -0
- package/dist/lib/rules/runtime-scope.js +55 -0
- package/dist/lib/rules/stop-adapter.js +116 -0
- package/dist/lib/rules/stop-response-snapshot.js +174 -0
- package/dist/lib/rules/types.js +10 -0
- package/dist/lib/rules/ulid.js +46 -0
- package/dist/lib/rules/version-evaluation.js +156 -0
- package/dist/lib/scanner/agent-memory.js +99 -0
- package/dist/lib/scanner/bootstrap-summary.js +87 -0
- package/dist/lib/scanner/cache.js +59 -0
- package/dist/lib/scanner/frontmatter.js +42 -0
- package/dist/lib/scanner/parse-directives.js +69 -0
- package/dist/lib/scanner/parse-structured.js +72 -0
- package/dist/lib/scanner/render.js +73 -0
- package/dist/lib/scanner/scan.js +132 -0
- package/dist/lib/scanner/score.js +38 -0
- package/dist/lib/scanner/scout-mission.js +126 -0
- package/dist/lib/scanner/types.js +7 -0
- package/dist/lib/session-scope.js +195 -0
- package/dist/lib/spool.js +355 -0
- package/dist/lib/staleness.js +100 -0
- package/dist/lib/steer-cache.js +87 -0
- package/dist/lib/tagged-reference.js +20 -0
- package/dist/lib/temporal.js +109 -0
- package/dist/lib/turn-recap-emit.js +67 -0
- package/dist/lib/unwire.js +253 -0
- package/dist/lib/update-check.js +469 -0
- package/dist/lib/update-notifier.js +217 -0
- package/dist/lib/upgrade-apply.js +643 -0
- package/dist/lib/wire.js +1087 -0
- package/dist/lib/workspace.js +96 -0
- package/dist/lib/zip.js +154 -0
- package/dist/pretool-entry.js +37 -0
- package/package.json +75 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isImmediateTerminal = isImmediateTerminal;
|
|
4
|
+
exports.parseArgs = parseArgs;
|
|
5
|
+
exports.buildTimeoutMessage = buildTimeoutMessage;
|
|
6
|
+
exports.runReview = runReview;
|
|
7
|
+
exports.parseReviewByIdArgs = parseReviewByIdArgs;
|
|
8
|
+
exports.runReviewById = runReviewById;
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const http_1 = require("../lib/http");
|
|
11
|
+
const render_1 = require("../lib/render");
|
|
12
|
+
const flush_1 = require("./flush");
|
|
13
|
+
const config_2 = require("../lib/config");
|
|
14
|
+
const internal_finalize_1 = require("./internal-finalize");
|
|
15
|
+
// `mla review` and `mla review <id>` (Wedge v6 dogfood loop, redesigned).
|
|
16
|
+
//
|
|
17
|
+
// Locked surface:
|
|
18
|
+
//
|
|
19
|
+
// mla review -> current session ONLY (CLAUDE_CODE_SESSION_ID).
|
|
20
|
+
// Leads with console URLs (workspace queues),
|
|
21
|
+
// then renders the deterministic packet. Flags:
|
|
22
|
+
// --plain, --no-flush.
|
|
23
|
+
// mla review <id> -> emit a console deep link for an id. Probes
|
|
24
|
+
// control for relationship-candidate first,
|
|
25
|
+
// then agent-review case. No flags.
|
|
26
|
+
//
|
|
27
|
+
// Removed (intentionally; do not bring back without An sign-off):
|
|
28
|
+
//
|
|
29
|
+
// mla review latest Resolved a workspace-wide "latest run" implicitly
|
|
30
|
+
// from /internal/v1/agent-runs/latest. That is
|
|
31
|
+
// implementation-driven incoherence: the right
|
|
32
|
+
// default is the session you are running INSIDE,
|
|
33
|
+
// not whatever the workspace last touched.
|
|
34
|
+
// mla review by-session <sid> Per-session escape hatch. The locked rule is
|
|
35
|
+
// "current session is the default AND the only
|
|
36
|
+
// one allowed; go to the UI to access more." A
|
|
37
|
+
// --session flag re-opens the same hole.
|
|
38
|
+
// mla cases list/show Replaced by the unified `mla review` + console
|
|
39
|
+
// URL emission. The console at /cases is the
|
|
40
|
+
// first-class surface for browsing cases.
|
|
41
|
+
//
|
|
42
|
+
// Polling contract (unchanged from the pre-redesign by-session path):
|
|
43
|
+
// status=pending -> poll up to 60s, 500ms cadence
|
|
44
|
+
// status=ready, syn=pending -> continue polling with a 30s sub-timeout
|
|
45
|
+
// status=ready, syn=ready -> STOP, render full packet
|
|
46
|
+
// status=ready, syn=failed -> STOP, render base + synth-failed footer
|
|
47
|
+
// status=failed, syn=* -> STOP, render error and doctor suggestion
|
|
48
|
+
// 60s overall timeout w/ pending -> print doctor suggestion
|
|
49
|
+
const OVERALL_TIMEOUT_MS = 60_000;
|
|
50
|
+
const SYNTH_SUBTIMEOUT_MS = 30_000;
|
|
51
|
+
const POLL_INTERVAL_MS = 500;
|
|
52
|
+
function sleep(ms) {
|
|
53
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
54
|
+
}
|
|
55
|
+
// Exported for unit tests. The poll loop must STOP rendering immediately when:
|
|
56
|
+
// - status=failed (base build blew up; render the error packet)
|
|
57
|
+
// - status=ready + synthesisStatus in {ready, failed} (LLM either succeeded or
|
|
58
|
+
// gave up; render whatever is available)
|
|
59
|
+
// - status=ready + synthesisStatus is null OR undefined (server signalled the
|
|
60
|
+
// synthesis path will never run for this packet; render the base layer).
|
|
61
|
+
// A backend response that omits synthesisStatus entirely (undefined) used to
|
|
62
|
+
// fall through every branch and trap the loop until the 60s overall timeout
|
|
63
|
+
// fired. The user got "Review not ready after 60s" for a packet that was
|
|
64
|
+
// already terminal. Treating null and undefined identically closes the trap.
|
|
65
|
+
function isImmediateTerminal(status, synthesisStatus) {
|
|
66
|
+
if (status === "failed")
|
|
67
|
+
return true;
|
|
68
|
+
if (status === "ready") {
|
|
69
|
+
if (synthesisStatus == null)
|
|
70
|
+
return true;
|
|
71
|
+
if (synthesisStatus === "ready" || synthesisStatus === "failed")
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Strict argv parser for the no-arg `mla review`. Two supported flags only.
|
|
77
|
+
//
|
|
78
|
+
// The pre-redesign parser also handled a `wantBySession` mode that allowed a
|
|
79
|
+
// session-id positional. That mode is gone because the locked design is
|
|
80
|
+
// "current session only; go to the UI for more." Re-introducing a positional
|
|
81
|
+
// here would silently re-open the deprecated `mla review by-session <sid>`
|
|
82
|
+
// path as a positional shortcut.
|
|
83
|
+
function parseArgs(argv) {
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const a of argv) {
|
|
86
|
+
if (a === "--plain") {
|
|
87
|
+
out.plain = true;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (a === "--no-flush") {
|
|
91
|
+
out.noFlush = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (a.startsWith("--")) {
|
|
95
|
+
throw new Error(`Unknown flag: ${a}. Supported flags: --plain, --no-flush`);
|
|
96
|
+
}
|
|
97
|
+
// No positionals. `mla review <id>` is a SEPARATE command routed by cli.ts
|
|
98
|
+
// before we get here. A stray positional at THIS layer means the operator
|
|
99
|
+
// tried `mla review --plain some-sid` (sid-as-trailing-positional) or the
|
|
100
|
+
// dispatcher routed wrong; either way, naming the offender is more useful
|
|
101
|
+
// than silently dropping it.
|
|
102
|
+
throw new Error(`Unexpected positional argument: ${a}. \`mla review\` takes no positional arguments; ` +
|
|
103
|
+
`use \`mla review <id>\` for a specific item.`);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
function stripAnsi(s) {
|
|
108
|
+
// eslint-disable-next-line no-control-regex
|
|
109
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
110
|
+
}
|
|
111
|
+
// Build the operator-visible timeout message. Carries the last observed
|
|
112
|
+
// status + synthesisStatus so `mla review` does not return a useless
|
|
113
|
+
// "not ready after 60s." It matters which side of the worker pipeline
|
|
114
|
+
// is hung: `pending/not_started` means the base-layer build never
|
|
115
|
+
// started (worker draining or DB writes wedged); `ready/pending` means
|
|
116
|
+
// synthesis is hung (intel reachability or token bucket exhaustion).
|
|
117
|
+
// Surfacing these in the failure message saves the operator a full
|
|
118
|
+
// `mla doctor` round-trip on every timeout.
|
|
119
|
+
function buildTimeoutMessage(lastStatus, lastSyn) {
|
|
120
|
+
return (`Review not ready after 60s (last seen: status=${lastStatus}, syn=${lastSyn}). ` +
|
|
121
|
+
"Run `mla doctor` to check worker draining and intel reachability.");
|
|
122
|
+
}
|
|
123
|
+
async function pollForPacket(opts) {
|
|
124
|
+
const start = Date.now();
|
|
125
|
+
let synthStart = null;
|
|
126
|
+
let lastStatus = "?";
|
|
127
|
+
let lastSyn = "?";
|
|
128
|
+
while (Date.now() - start < OVERALL_TIMEOUT_MS) {
|
|
129
|
+
let raw;
|
|
130
|
+
try {
|
|
131
|
+
raw = await (0, http_1.get)(opts.cfg, opts.url(), 8000);
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
const err = e;
|
|
135
|
+
if (err.status === 404) {
|
|
136
|
+
// Run exists but packet not created yet; treat as pending and keep polling.
|
|
137
|
+
await sleep(POLL_INTERVAL_MS);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
throw e;
|
|
141
|
+
}
|
|
142
|
+
if (raw.status === "pending" && raw.synthesisStatus === "not_started") {
|
|
143
|
+
lastStatus = "pending";
|
|
144
|
+
lastSyn = "not_started";
|
|
145
|
+
if (Date.now() - start < POLL_INTERVAL_MS * 2) {
|
|
146
|
+
process.stderr.write("Building deterministic review...\n");
|
|
147
|
+
}
|
|
148
|
+
await sleep(POLL_INTERVAL_MS);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const packet = raw;
|
|
152
|
+
lastStatus = packet.status;
|
|
153
|
+
lastSyn = packet.synthesisStatus ?? "n/a";
|
|
154
|
+
if (isImmediateTerminal(packet.status, packet.synthesisStatus)) {
|
|
155
|
+
return { kind: "packet", packet };
|
|
156
|
+
}
|
|
157
|
+
if (packet.status === "ready") {
|
|
158
|
+
if (packet.synthesisStatus === "pending") {
|
|
159
|
+
if (synthStart === null) {
|
|
160
|
+
synthStart = Date.now();
|
|
161
|
+
process.stderr.write("Base ready; waiting on LLM synthesis...\n");
|
|
162
|
+
}
|
|
163
|
+
if (Date.now() - synthStart >= SYNTH_SUBTIMEOUT_MS) {
|
|
164
|
+
packet.warnings = [
|
|
165
|
+
...(packet.warnings ?? []),
|
|
166
|
+
"LLM synthesis still pending; will appear on next `mla review` invocation.",
|
|
167
|
+
];
|
|
168
|
+
return { kind: "packet", packet };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (packet.synthesisStatus === "not_started") {
|
|
172
|
+
// Worker hasn't enqueued synthesis yet; keep polling.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (packet.status === "pending") {
|
|
176
|
+
// Worker is still writing base layer.
|
|
177
|
+
}
|
|
178
|
+
await sleep(POLL_INTERVAL_MS);
|
|
179
|
+
}
|
|
180
|
+
return { kind: "timeout", lastStatus, lastSyn };
|
|
181
|
+
}
|
|
182
|
+
async function autoFlushAll() {
|
|
183
|
+
// Best-effort. Failures here are non-fatal; the poll loop will tell the user
|
|
184
|
+
// what's missing through the packet shape itself.
|
|
185
|
+
try {
|
|
186
|
+
await (0, flush_1.runFlush)(["--all"], { quiet: true, hookDir: config_2.HOOKS_DIR });
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// ignore
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Header block emitted at the top of every `mla review` invocation.
|
|
193
|
+
// The locked design is "all the review operations are to be done on web UI,
|
|
194
|
+
// so we need to surface the right web UI under the right command." The
|
|
195
|
+
// terminal packet render is a convenience snapshot, NOT the review surface.
|
|
196
|
+
// Leading with URLs makes the contract obvious.
|
|
197
|
+
function consoleUrlsBlock(consoleBase) {
|
|
198
|
+
return [
|
|
199
|
+
"Review in Console:",
|
|
200
|
+
` Relationships queue: ${consoleBase}/relationships`,
|
|
201
|
+
` Cases queue: ${consoleBase}/cases`,
|
|
202
|
+
"",
|
|
203
|
+
].join("\n");
|
|
204
|
+
}
|
|
205
|
+
// Header for `mla review` when CLAUDE_CODE_SESSION_ID is unset. The CLI cannot
|
|
206
|
+
// guess which session the user means and the locked design forbids inferring
|
|
207
|
+
// one. Print the workspace URLs and exit 0 -- that still routes them to the UI,
|
|
208
|
+
// which is the locked outcome.
|
|
209
|
+
function printConsoleOnly(consoleBase) {
|
|
210
|
+
console.log(consoleUrlsBlock(consoleBase));
|
|
211
|
+
console.log("`mla review` shows the current session's review packet when run INSIDE a " +
|
|
212
|
+
"Claude Code session (CLAUDE_CODE_SESSION_ID is unset here). Open the queues " +
|
|
213
|
+
"above to review pending items.");
|
|
214
|
+
}
|
|
215
|
+
// On-demand review trigger (Phase 7 / PATCH 5 / INV-M6,
|
|
216
|
+
// notes/20260604-mla-mission-and-review-packet-rethink.md).
|
|
217
|
+
//
|
|
218
|
+
// `mla review` used to be a PASSIVE poller: the by-session packet only existed
|
|
219
|
+
// if the Claude Code Stop hook had already fired the finalize. Running review
|
|
220
|
+
// mid-session (before any clean Stop, which in practice rarely arrives) just
|
|
221
|
+
// spun to the 60s timeout. INV-M6 makes review producible by at least one
|
|
222
|
+
// non-Stop trigger, and the floor is an explicit `mla review`. So we fire the
|
|
223
|
+
// same finalize the Stop-hook path fires, ourselves, before polling.
|
|
224
|
+
//
|
|
225
|
+
// UNCONDITIONAL by design: it runs even under --no-flush. --no-flush means "skip
|
|
226
|
+
// draining the spool queues", NOT "skip producing my review"; INV-M6 makes the
|
|
227
|
+
// on-demand trigger the producing floor, not a flush side effect. Idempotent on
|
|
228
|
+
// runId server-side (rolling-snapshot), so re-firing every review is safe.
|
|
229
|
+
//
|
|
230
|
+
// Best-effort: a finalize failure (no run attached yet -> 404, transient
|
|
231
|
+
// network error) must not abort the review. We swallow it and fall through to
|
|
232
|
+
// the poll, which surfaces a missing packet exactly as it did when Stop was the
|
|
233
|
+
// only trigger.
|
|
234
|
+
async function triggerOnDemandReview(sid, cfg) {
|
|
235
|
+
try {
|
|
236
|
+
await (0, internal_finalize_1.triggerSessionFinalize)(sid, cfg);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// ignore; the poll loop reports what's missing
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// `mla review` (no args). Resolves the current session from
|
|
243
|
+
// CLAUDE_CODE_SESSION_ID and polls the by-session packet endpoint. The poll
|
|
244
|
+
// shape is exactly the previous `mla review by-session <sid>` path; the only
|
|
245
|
+
// difference is who supplies the session id.
|
|
246
|
+
async function runReview(argv) {
|
|
247
|
+
const cfg = (0, config_1.loadWorkspaceConfig)();
|
|
248
|
+
const consoleBase = (0, config_1.getConsoleUrl)(cfg);
|
|
249
|
+
const flags = parseArgs(argv);
|
|
250
|
+
const sid = process.env.CLAUDE_CODE_SESSION_ID;
|
|
251
|
+
if (!sid) {
|
|
252
|
+
printConsoleOnly(consoleBase);
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
255
|
+
if (!flags.noFlush)
|
|
256
|
+
await autoFlushAll();
|
|
257
|
+
// Fire the non-Stop finalize trigger before polling so the packet can exist
|
|
258
|
+
// even when no Stop hook ever ran for this session (INV-M6).
|
|
259
|
+
await triggerOnDemandReview(sid, cfg);
|
|
260
|
+
const result = await pollForPacket({
|
|
261
|
+
cfg,
|
|
262
|
+
url: () => `/internal/v1/review-packets/by-session/${encodeURIComponent(sid)}?workspaceId=${encodeURIComponent(cfg.workspaceId)}`,
|
|
263
|
+
});
|
|
264
|
+
// Lead every render path with the console URL block. The previous CLI buried
|
|
265
|
+
// the URL deep in the packet body (or omitted it entirely); An's lock made
|
|
266
|
+
// surfacing the right web UI under the right command the deliverable.
|
|
267
|
+
console.log(consoleUrlsBlock(consoleBase));
|
|
268
|
+
if (result.kind === "timeout") {
|
|
269
|
+
console.error(buildTimeoutMessage(result.lastStatus, result.lastSyn));
|
|
270
|
+
return 1;
|
|
271
|
+
}
|
|
272
|
+
let out = (0, render_1.renderPacket)(result.packet);
|
|
273
|
+
if (flags.plain)
|
|
274
|
+
out = stripAnsi(out);
|
|
275
|
+
console.log(out);
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
// `mla review <id>` -- emit a console deep link for an id.
|
|
279
|
+
//
|
|
280
|
+
// The locked design treats the URL as THE deliverable. We probe control to
|
|
281
|
+
// disambiguate between the two id-bearing review surfaces:
|
|
282
|
+
//
|
|
283
|
+
// 1. relationship candidate -> /relationships/<id>
|
|
284
|
+
// 2. agent-review case -> /cases/<id>
|
|
285
|
+
//
|
|
286
|
+
// Order matters: we try relationship-candidates FIRST because the volume is
|
|
287
|
+
// higher under dogfood and the URL is the dominant case. A case id that
|
|
288
|
+
// happens to also be a relationship-candidate id is impossible (cuids are
|
|
289
|
+
// unique across tables), so the ordering only affects the wasted probe on a
|
|
290
|
+
// miss, not correctness.
|
|
291
|
+
const CUID_REGEX = /^c[a-z0-9]{20,30}$/;
|
|
292
|
+
function parseReviewByIdArgs(argv) {
|
|
293
|
+
let id;
|
|
294
|
+
for (const a of argv) {
|
|
295
|
+
if (a.startsWith("--") || a.startsWith("-")) {
|
|
296
|
+
throw new Error(`Unknown flag: ${a}. \`mla review <id>\` takes no flags, only a single id positional.`);
|
|
297
|
+
}
|
|
298
|
+
if (id !== undefined) {
|
|
299
|
+
throw new Error(`Unexpected extra positional argument: ${a}. \`mla review <id>\` takes exactly one id.`);
|
|
300
|
+
}
|
|
301
|
+
id = a;
|
|
302
|
+
}
|
|
303
|
+
if (id === undefined) {
|
|
304
|
+
throw new Error("Usage: mla review <id>");
|
|
305
|
+
}
|
|
306
|
+
return { id };
|
|
307
|
+
}
|
|
308
|
+
async function existsRelationshipCandidate(cfg, id) {
|
|
309
|
+
try {
|
|
310
|
+
await (0, http_1.get)(cfg, `/internal/v1/relationship-candidates/${encodeURIComponent(id)}?workspaceId=${encodeURIComponent(cfg.workspaceId)}`, 8000);
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
catch (e) {
|
|
314
|
+
const err = e;
|
|
315
|
+
if (err.status === 404)
|
|
316
|
+
return false;
|
|
317
|
+
throw e;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function existsAgentReviewCase(cfg, id) {
|
|
321
|
+
try {
|
|
322
|
+
await (0, http_1.get)(cfg, `/internal/v1/agent-review/cases/${encodeURIComponent(id)}?workspaceId=${encodeURIComponent(cfg.workspaceId)}`, 8000);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
catch (e) {
|
|
326
|
+
const err = e;
|
|
327
|
+
if (err.status === 404)
|
|
328
|
+
return false;
|
|
329
|
+
throw e;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async function runReviewById(argv) {
|
|
333
|
+
const cfg = (0, config_1.loadWorkspaceConfig)();
|
|
334
|
+
const consoleBase = (0, config_1.getConsoleUrl)(cfg);
|
|
335
|
+
let parsed;
|
|
336
|
+
try {
|
|
337
|
+
parsed = parseReviewByIdArgs(argv);
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
console.error(e.message);
|
|
341
|
+
return 2;
|
|
342
|
+
}
|
|
343
|
+
if (!CUID_REGEX.test(parsed.id)) {
|
|
344
|
+
console.error(`Not a valid cuid: ${parsed.id}. \`mla review <id>\` accepts a relationship ` +
|
|
345
|
+
`candidate id or an agent-review case id.`);
|
|
346
|
+
return 2;
|
|
347
|
+
}
|
|
348
|
+
if (await existsRelationshipCandidate(cfg, parsed.id)) {
|
|
349
|
+
console.log(`${consoleBase}/relationships/${parsed.id}`);
|
|
350
|
+
return 0;
|
|
351
|
+
}
|
|
352
|
+
if (await existsAgentReviewCase(cfg, parsed.id)) {
|
|
353
|
+
console.log(`${consoleBase}/cases/${parsed.id}`);
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
console.error(`Unknown id ${parsed.id} (not a relationship candidate or agent-review case in this workspace).`);
|
|
357
|
+
return 1;
|
|
358
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseRewireArgs = parseRewireArgs;
|
|
4
|
+
exports.runRewire = runRewire;
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const wire_1 = require("../lib/wire");
|
|
7
|
+
// `mla rewire` (Wedge v6 init/rewire split).
|
|
8
|
+
//
|
|
9
|
+
// Idempotent local re-wiring. Does everything `mla init` does EXCEPT
|
|
10
|
+
// write credentials -- so it can be safely chained off `pnpm build` or
|
|
11
|
+
// suggested by `mla doctor` when hook drift is detected, without
|
|
12
|
+
// forcing the operator to dig up their control token.
|
|
13
|
+
//
|
|
14
|
+
// Contract:
|
|
15
|
+
// - Refuses to run if cli-config.json does not exist. Tells the
|
|
16
|
+
// operator to run `mla init` first.
|
|
17
|
+
// - Re-resolves mlaPath (the binary may have moved across upgrades)
|
|
18
|
+
// and re-writes the cli-config.json with the new path. Credentials
|
|
19
|
+
// and URLs are preserved byte-for-byte.
|
|
20
|
+
// - Re-copies hook scripts to ~/.meetless/hooks/.
|
|
21
|
+
// - Re-registers hook entries in ~/.claude/settings.json (idempotent;
|
|
22
|
+
// existing entries are detected by exact command-path match).
|
|
23
|
+
// - Re-installs the /mla skill.
|
|
24
|
+
// - Re-checks `flock` and auto-installs on macOS unless --no-install-flock.
|
|
25
|
+
//
|
|
26
|
+
// Flags:
|
|
27
|
+
// --no-post-tool-use skip post-tool-use.sh install (Bash capture opt-out)
|
|
28
|
+
// --no-install-flock skip auto-install of flock (macOS)
|
|
29
|
+
// --no-mcp skip registering the Meetless MCP server in ~/.claude.json
|
|
30
|
+
// --skill-only only re-install the /mla skill
|
|
31
|
+
//
|
|
32
|
+
// Exit codes:
|
|
33
|
+
// 0 fully ready
|
|
34
|
+
// 1 wrote everything but flock missing (hook pipeline will no-op until fixed)
|
|
35
|
+
// 2 bad flags / no config
|
|
36
|
+
const BOOLEAN_FLAGS = new Set([
|
|
37
|
+
"--no-post-tool-use",
|
|
38
|
+
"--no-install-flock",
|
|
39
|
+
"--no-mcp",
|
|
40
|
+
"--skill-only",
|
|
41
|
+
]);
|
|
42
|
+
// Strict argv parser. `mla rewire` takes only boolean flags; any
|
|
43
|
+
// value-shaped flag, short flag, or positional is rejected loudly so
|
|
44
|
+
// operators don't accidentally pass a `--control-token` here expecting
|
|
45
|
+
// it to be honored (it's not -- use `mla init` for that).
|
|
46
|
+
function parseRewireArgs(argv) {
|
|
47
|
+
const out = {};
|
|
48
|
+
for (const a of argv) {
|
|
49
|
+
if (BOOLEAN_FLAGS.has(a)) {
|
|
50
|
+
if (a === "--no-post-tool-use")
|
|
51
|
+
out.noPostToolUse = true;
|
|
52
|
+
else if (a === "--no-install-flock")
|
|
53
|
+
out.noInstallFlock = true;
|
|
54
|
+
else if (a === "--no-mcp")
|
|
55
|
+
out.noMcp = true;
|
|
56
|
+
else if (a === "--skill-only")
|
|
57
|
+
out.skillOnly = true;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (a.startsWith("--") || a.startsWith("-")) {
|
|
61
|
+
throw new Error(`Unknown flag: ${a}. \`mla rewire\` takes only boolean flags: ${[...BOOLEAN_FLAGS].sort().join(", ")}. ` +
|
|
62
|
+
`To change credentials or URLs, run \`mla init\` instead.`);
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Unexpected positional argument: ${a}. \`mla rewire\` takes no positional arguments.`);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
async function runRewire(argv) {
|
|
69
|
+
let flags;
|
|
70
|
+
try {
|
|
71
|
+
flags = parseRewireArgs(argv);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
console.error(e.message);
|
|
75
|
+
return 2;
|
|
76
|
+
}
|
|
77
|
+
if (flags.skillOnly) {
|
|
78
|
+
const res = (0, wire_1.runWire)({ skillOnly: true });
|
|
79
|
+
(0, wire_1.printWireResult)(res, { skillOnly: true });
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
if (!(0, config_1.configExists)()) {
|
|
83
|
+
console.error(`cli-config.json not found at ${config_1.CFG_PATH}. ` +
|
|
84
|
+
`\`mla rewire\` only refreshes the local wiring of an existing install; ` +
|
|
85
|
+
`run \`mla init --control-token <token>\` first.`);
|
|
86
|
+
return 2;
|
|
87
|
+
}
|
|
88
|
+
let cfg;
|
|
89
|
+
try {
|
|
90
|
+
cfg = (0, config_1.readConfig)();
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
console.error(`cli-config.json at ${config_1.CFG_PATH} is unreadable: ${e.message}. ` +
|
|
94
|
+
`Run \`mla init --control-token <token>\` to re-create it.`);
|
|
95
|
+
return 2;
|
|
96
|
+
}
|
|
97
|
+
// Re-resolve mlaPath so a moved binary (e.g. pnpm link to a new
|
|
98
|
+
// dist/) gets re-pinned. Credentials and URLs come from the existing
|
|
99
|
+
// config unchanged.
|
|
100
|
+
const refreshed = { ...cfg, mlaPath: (0, wire_1.resolveMlaPath)() };
|
|
101
|
+
(0, config_1.writeConfig)(refreshed);
|
|
102
|
+
// Project rules (a repo's CLAUDE.md) are `mla init`'s job: an operator
|
|
103
|
+
// explicitly opting a repo into consult-governed-memory-first onboarding
|
|
104
|
+
// hygiene. rewire
|
|
105
|
+
// is a frequent, cwd-sensitive refresh of *local wiring* (hooks, skill,
|
|
106
|
+
// flock, cli-config.json), so it must never mutate whatever repo the cwd
|
|
107
|
+
// happens to sit in. Re-run `mla init` in a repo to refresh its block.
|
|
108
|
+
const wire = (0, wire_1.runWire)({
|
|
109
|
+
noPostToolUse: !!flags.noPostToolUse,
|
|
110
|
+
noInstallFlock: !!flags.noInstallFlock,
|
|
111
|
+
noProjectRules: true,
|
|
112
|
+
noMcp: !!flags.noMcp,
|
|
113
|
+
});
|
|
114
|
+
console.log(`Refreshed ${config_1.CFG_PATH}`);
|
|
115
|
+
console.log(` controlUrl: ${refreshed.controlUrl}`);
|
|
116
|
+
// workspaceId is DEPRECATED as a config field (T1.1, folder = workspace): it is
|
|
117
|
+
// intentionally unpopulated and resolved from the nearest `.meetless.json`
|
|
118
|
+
// marker instead, so printing it here only ever showed a misleading `undefined`.
|
|
119
|
+
console.log(` intelUrl: ${refreshed.intelUrl}`);
|
|
120
|
+
console.log(` mlaPath: ${refreshed.mlaPath}`);
|
|
121
|
+
(0, wire_1.printWireResult)(wire);
|
|
122
|
+
console.log("Next: mla doctor");
|
|
123
|
+
return wire.flock?.ok ? 0 : 1;
|
|
124
|
+
}
|