@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,322 @@
|
|
|
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.parseArgs = parseArgs;
|
|
37
|
+
exports.renderAdvisoryText = renderAdvisoryText;
|
|
38
|
+
exports.runInternalActiveReview = runInternalActiveReview;
|
|
39
|
+
const fs_1 = require("fs");
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const config_1 = require("../lib/config");
|
|
42
|
+
const active_memory_1 = require("../lib/active-memory");
|
|
43
|
+
const http_1 = require("../lib/http");
|
|
44
|
+
const active_review_runner_1 = require("../lib/active-review-runner");
|
|
45
|
+
const tagged_reference_1 = require("../lib/tagged-reference");
|
|
46
|
+
// `mla _internal active-review --session <sid>` (Phase 1, Active Review).
|
|
47
|
+
//
|
|
48
|
+
// Fired by the UserPromptSubmit hook's Layer 3 AFTER the turn counter advances.
|
|
49
|
+
// It reviews the PRIOR turn's produced docs (the Active Memory store the
|
|
50
|
+
// PostToolUse hook appends to ~/.meetless/logs/kb-knowledge.jsonl) for conflict
|
|
51
|
+
// with the workspace's approved knowledge and prints an advisory the hook
|
|
52
|
+
// injects as additionalContext. Two contracts mirror the runner:
|
|
53
|
+
// - dry-run only (no persistence; the detect call is always dryRun:true).
|
|
54
|
+
// - advise-never-block (P6): this command NEVER throws past the dispatcher and
|
|
55
|
+
// NEVER exits non-zero on a review miss; a failure prints an empty advisory
|
|
56
|
+
// and exits 0 so the hook simply injects nothing.
|
|
57
|
+
//
|
|
58
|
+
// Hermetic test seam: when MEETLESS_ACTIVE_REVIEW_STUB_DETECT is set (non-empty)
|
|
59
|
+
// the intel client is a stub that returns that parsed JSON instead of making a
|
|
60
|
+
// real HTTP call, so the hook test stays offline. Otherwise the real client
|
|
61
|
+
// POSTs to intel /internal/v1/active-review/detect.
|
|
62
|
+
//
|
|
63
|
+
// A3 (Phase 2): on top of the Phase 1 conflict advisories, this command also
|
|
64
|
+
// renders supersession/contradiction advisories for the docs the user NAMED this
|
|
65
|
+
// session (the tagged_reference captures the UserPromptSubmit hook appends). The
|
|
66
|
+
// pure engine (tagged-reference.ts) joins those paths against APPROVED relation
|
|
67
|
+
// facts; the facts come from control's relationship-candidates list endpoint
|
|
68
|
+
// (statusId=ACCEPTED, posture=LIVE), the same read kb pending uses. Its hermetic
|
|
69
|
+
// seam is MEETLESS_TAGGED_FACTS_STUB (parsed as a KbRelationFact[] JSON). The
|
|
70
|
+
// supersession fetch is best-effort and advise-never-block (P6): any failure
|
|
71
|
+
// degrades to an empty fact list, so the supersession advisory simply does not
|
|
72
|
+
// render; the join engages the moment approved facts exist for a named doc.
|
|
73
|
+
// The store the PostToolUse hook appends to. Path + filename are byte-identical
|
|
74
|
+
// to common.sh LOG_DIR/kb-knowledge.jsonl so both sides resolve the same file
|
|
75
|
+
// under MEETLESS_HOME.
|
|
76
|
+
function activeMemoryStorePath() {
|
|
77
|
+
return path.join(config_1.HOME, "logs", "kb-knowledge.jsonl");
|
|
78
|
+
}
|
|
79
|
+
// TTL + cap for the read-time reduction. 48h matches the Active Memory store's
|
|
80
|
+
// own dedup/TTL intent; 100 is a generous per-review cap (a single turn produces
|
|
81
|
+
// only a handful of docs).
|
|
82
|
+
const TTL_HOURS = 48;
|
|
83
|
+
const MAX_RECORDS = 100;
|
|
84
|
+
// V1 confidence floor for the conflict-advisory policy. A detection below this
|
|
85
|
+
// is a weak signal and produces no advisory (the policy logs but does not flag).
|
|
86
|
+
const MIN_CONFIDENCE = 0.6;
|
|
87
|
+
// Stub client: returns the operator-supplied detect response verbatim. Used by
|
|
88
|
+
// the hook test so it never touches the network. The stub JSON is the same shape
|
|
89
|
+
// the real endpoint returns ({ detections, persisted }).
|
|
90
|
+
function stubIntelClient(stubJson) {
|
|
91
|
+
return {
|
|
92
|
+
detect: async () => {
|
|
93
|
+
const parsed = JSON.parse(stubJson);
|
|
94
|
+
return { detections: parsed.detections ?? [], persisted: parsed.persisted ?? false };
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// Read the produced doc's CURRENT on-disk content so the in-process detector has
|
|
99
|
+
// real text to score against the owner's approved corpus. Mirrors the Zone 2
|
|
100
|
+
// auto-index eligibility (auto-index.ts selectIndexTargets): only a produced_doc
|
|
101
|
+
// that carries a repoRoot is resolvable. A tagged_reference is a doc the user
|
|
102
|
+
// NAMED (handled by the A3 supersession join, not detect), and a record without a
|
|
103
|
+
// repoRoot predates Phase A and cannot be located on disk. The absolute repoRoot
|
|
104
|
+
// is LOCAL-only and never leaves the machine: we join it with the RELATIVE
|
|
105
|
+
// canonicalPath, read the file, and put only the CONTENT on the wire. Best-effort
|
|
106
|
+
// (P6): an ineligible record or an unreadable file (moved/deleted since capture)
|
|
107
|
+
// yields an empty body, which the detect endpoint skips as a no-op, so a review
|
|
108
|
+
// can never throw on a vanished doc.
|
|
109
|
+
function readCandidateBody(rec) {
|
|
110
|
+
if (rec.kind !== "produced_doc")
|
|
111
|
+
return "";
|
|
112
|
+
const root = (rec.repoRoot || "").trim();
|
|
113
|
+
if (!root)
|
|
114
|
+
return "";
|
|
115
|
+
try {
|
|
116
|
+
return (0, fs_1.readFileSync)(path.join(root, rec.canonicalPath), "utf8");
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Real client: POST the dry-run review request to intel. Carries the env-pinned
|
|
123
|
+
// workspace AND the owner so the detection scope is built server-side, never a
|
|
124
|
+
// parameter the caller widens.
|
|
125
|
+
function realIntelClient(cfg) {
|
|
126
|
+
return {
|
|
127
|
+
detect: async (req) => {
|
|
128
|
+
// INV-DETECTION-OWNER-SCOPED: the endpoint builds an owner-scoped corpus,
|
|
129
|
+
// so ownerUserId is required. Without a configured actor we cannot name an
|
|
130
|
+
// owner; throw so the runner's P6 catch degrades to an empty advisory
|
|
131
|
+
// rather than POSTing a request the endpoint validates away as a 422
|
|
132
|
+
// (which would degrade silently and look like "no conflicts").
|
|
133
|
+
const ownerUserId = (cfg.actorUserId || "").trim();
|
|
134
|
+
if (!ownerUserId) {
|
|
135
|
+
throw new Error("active-review detect requires actorUserId (owner scope)");
|
|
136
|
+
}
|
|
137
|
+
// Map each metadata-only Active Memory record to the endpoint's candidate
|
|
138
|
+
// wire shape (ActiveReviewCandidate {canonicalPath, body, kind}). The Zone 1
|
|
139
|
+
// spool captures metadata only (contentHash, no doc body, by privacy
|
|
140
|
+
// design), so at review time we read the produced doc's CURRENT content from
|
|
141
|
+
// disk (readCandidateBody: repoRoot-resolved, LOCAL-only, best-effort) and
|
|
142
|
+
// send THAT as body, which the in-process detector embeds and scores against
|
|
143
|
+
// the owner-scoped corpus. Sending the raw record would 422 (no `body`) and
|
|
144
|
+
// leak internal field names onto the wire.
|
|
145
|
+
const candidates = req.candidates.map((c) => ({
|
|
146
|
+
canonicalPath: c.canonicalPath,
|
|
147
|
+
body: readCandidateBody(c),
|
|
148
|
+
kind: c.kind,
|
|
149
|
+
}));
|
|
150
|
+
return (0, http_1.intelPost)(cfg, "/internal/v1/active-review/detect", { workspaceId: cfg.workspaceId, ownerUserId, dryRun: req.dryRun, candidates }, 8000);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// Stub client: returns the operator-supplied facts verbatim (MEETLESS_TAGGED_FACTS_STUB,
|
|
155
|
+
// parsed as a KbRelationFact[] JSON). Used by tests so the merge runs offline.
|
|
156
|
+
function stubTaggedFactsClient(stubJson) {
|
|
157
|
+
return {
|
|
158
|
+
fetch: async () => {
|
|
159
|
+
const parsed = JSON.parse(stubJson);
|
|
160
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// Real client: read APPROVED relation facts (statusId=ACCEPTED, posture=LIVE) for
|
|
165
|
+
// each referenced doc from control's relationship-candidates list endpoint, the
|
|
166
|
+
// same read kb pending uses (GET /internal/v1/relationship-candidates). We query
|
|
167
|
+
// per path by notePath, keep only conflict relations (SUPERSEDED_BY / CONTRADICTS),
|
|
168
|
+
// and map each row into a KbRelationFact whose fromPath is the doc the user named
|
|
169
|
+
// and whose toKbId/toPath is the row's target artifact. Best-effort: any error on
|
|
170
|
+
// any path is swallowed and yields no facts for it, so the supersession advisory
|
|
171
|
+
// degrades to empty rather than throwing (P6). Only the ACCEPTED/LIVE filter is
|
|
172
|
+
// trusted; the pure engine re-checks posture/status so an unapproved row can never
|
|
173
|
+
// leak even if the server filter were ever loosened.
|
|
174
|
+
//
|
|
175
|
+
// Config is loaded LAZILY, inside fetch and only if there is at least one path to
|
|
176
|
+
// resolve, via the supplied getter. The Phase 1 path must never pay a config load
|
|
177
|
+
// (or its possible throw) when the A3 path has nothing to do; loading eagerly here
|
|
178
|
+
// would couple a config failure to the unrelated conflict advisory.
|
|
179
|
+
function realTaggedFactsClient(getCfg) {
|
|
180
|
+
return {
|
|
181
|
+
fetch: async (referencedPaths) => {
|
|
182
|
+
if (referencedPaths.length === 0)
|
|
183
|
+
return [];
|
|
184
|
+
const cfg = getCfg();
|
|
185
|
+
const facts = [];
|
|
186
|
+
for (const p of referencedPaths) {
|
|
187
|
+
try {
|
|
188
|
+
const qs = new URLSearchParams();
|
|
189
|
+
qs.set("workspaceId", cfg.workspaceId);
|
|
190
|
+
qs.set("statusId", "ACCEPTED");
|
|
191
|
+
qs.set("posture", "LIVE");
|
|
192
|
+
qs.set("limit", "20");
|
|
193
|
+
if (p.includes(":"))
|
|
194
|
+
qs.set("artifactId", p);
|
|
195
|
+
else
|
|
196
|
+
qs.set("notePath", p);
|
|
197
|
+
const res = await (0, http_1.get)(cfg, `/internal/v1/relationship-candidates?${qs.toString()}`, 8000);
|
|
198
|
+
for (const row of res.items ?? []) {
|
|
199
|
+
const relationType = row.relationTypeId ?? "";
|
|
200
|
+
if (relationType !== "SUPERSEDED_BY" && relationType !== "CONTRADICTS")
|
|
201
|
+
continue;
|
|
202
|
+
const toId = row.targetArtifactId ?? "";
|
|
203
|
+
if (!toId)
|
|
204
|
+
continue;
|
|
205
|
+
facts.push({
|
|
206
|
+
fromPath: p,
|
|
207
|
+
relationType,
|
|
208
|
+
toPath: toId,
|
|
209
|
+
toKbId: toId,
|
|
210
|
+
posture: row.postureId ?? "LIVE",
|
|
211
|
+
status: row.statusId ?? "ACCEPTED",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// best-effort: this path contributes no facts; never a throw (P6).
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return facts;
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Strict argv parsing: `mla _internal active-review --session <sid>`. The
|
|
224
|
+
// --session flag is optional (absent reviews every record in the store); any
|
|
225
|
+
// other flag is rejected so a hook template typo surfaces loudly rather than
|
|
226
|
+
// silently binding the wrong value.
|
|
227
|
+
function parseArgs(argv) {
|
|
228
|
+
let sessionId = null;
|
|
229
|
+
for (let i = 0; i < argv.length; i++) {
|
|
230
|
+
const a = argv[i];
|
|
231
|
+
if (a === "--session") {
|
|
232
|
+
sessionId = argv[i + 1] ?? null;
|
|
233
|
+
i++;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (a.startsWith("-")) {
|
|
237
|
+
throw new Error(`Unknown flag: ${a}. \`mla _internal active-review\` takes only [--session <sid>].`);
|
|
238
|
+
}
|
|
239
|
+
throw new Error(`Unexpected positional argument: ${a}. \`mla _internal active-review\` takes only [--session <sid>].`);
|
|
240
|
+
}
|
|
241
|
+
return { sessionId };
|
|
242
|
+
}
|
|
243
|
+
// Render the advisory text the hook injects: one terse line per cited doc naming
|
|
244
|
+
// the candidate path, the conflict relation, the cited id, and the cited quote.
|
|
245
|
+
// Plain text (no markdown headers); multiple advisories are newline-joined.
|
|
246
|
+
function renderAdvisoryText(advisories) {
|
|
247
|
+
if (advisories.length === 0)
|
|
248
|
+
return "";
|
|
249
|
+
return advisories
|
|
250
|
+
.map((a) => `Active Review: ${a.candidatePath} may ${a.relationType} approved ${a.citedKbId} ("${a.citedQuote}").`)
|
|
251
|
+
.join("\n");
|
|
252
|
+
}
|
|
253
|
+
async function runInternalActiveReview(argv) {
|
|
254
|
+
let sessionId;
|
|
255
|
+
try {
|
|
256
|
+
({ sessionId } = parseArgs(argv));
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
console.error(e.message);
|
|
260
|
+
return 2;
|
|
261
|
+
}
|
|
262
|
+
// advise-never-block (P6): from here on, every failure path prints an empty
|
|
263
|
+
// advisory and exits 0 so the hook injects nothing rather than the turn seeing
|
|
264
|
+
// a non-zero review.
|
|
265
|
+
try {
|
|
266
|
+
const records = (0, active_memory_1.reduceActiveMemory)(activeMemoryStorePath(), {
|
|
267
|
+
nowMs: Date.now(),
|
|
268
|
+
ttlHours: TTL_HOURS,
|
|
269
|
+
maxRecords: MAX_RECORDS,
|
|
270
|
+
});
|
|
271
|
+
const scoped = sessionId ? records.filter((r) => r.sessionId === sessionId) : records;
|
|
272
|
+
// Build the clients. The stub paths are hermetic and need NO config (the hook
|
|
273
|
+
// test has only intelUrl, no control credentials), so read the stub env BEFORE
|
|
274
|
+
// any loadWorkspaceConfig(): only the real HTTP clients require a valid config.
|
|
275
|
+
// Config is loaded at most once and shared by both real clients.
|
|
276
|
+
const detectStub = process.env.MEETLESS_ACTIVE_REVIEW_STUB_DETECT;
|
|
277
|
+
const factsStub = process.env.MEETLESS_TAGGED_FACTS_STUB;
|
|
278
|
+
let cfg = null;
|
|
279
|
+
const ensureCfg = () => {
|
|
280
|
+
if (cfg === null)
|
|
281
|
+
cfg = (0, config_1.loadWorkspaceConfig)();
|
|
282
|
+
return cfg;
|
|
283
|
+
};
|
|
284
|
+
const intel = detectStub && detectStub.length > 0 ? stubIntelClient(detectStub) : realIntelClient(ensureCfg());
|
|
285
|
+
// The real facts client takes the lazy getter, not a resolved config, so config
|
|
286
|
+
// loads only inside its fetch (and only when there are referenced paths). This
|
|
287
|
+
// keeps the Phase 1 path (detect stub set, no facts stub) from ever paying a
|
|
288
|
+
// config load: a config failure must not couple into the conflict advisory.
|
|
289
|
+
const facts = factsStub && factsStub.length > 0 ? stubTaggedFactsClient(factsStub) : realTaggedFactsClient(ensureCfg);
|
|
290
|
+
// Phase 1: conflict advisories over the prior turn's produced docs.
|
|
291
|
+
const result = await (0, active_review_runner_1.runActiveReview)({ records: scoped, intel, minConfidence: MIN_CONFIDENCE });
|
|
292
|
+
// A3 (Phase 2): supersession/contradiction advisories over the docs the user
|
|
293
|
+
// NAMED this session (the tagged_reference captures). The pure engine joins
|
|
294
|
+
// those paths against approved (LIVE/ACCEPTED) relation facts; the fetch is
|
|
295
|
+
// best-effort (P6: a fetch failure swallows to no supersession advisory, never
|
|
296
|
+
// a throw). The supersession lines ride AFTER the Phase 1 conflict lines.
|
|
297
|
+
const referencedPaths = Array.from(new Set(scoped.filter((r) => r.kind === "tagged_reference").map((r) => r.canonicalPath)));
|
|
298
|
+
let supersessionLines = [];
|
|
299
|
+
if (referencedPaths.length > 0) {
|
|
300
|
+
try {
|
|
301
|
+
const relationFacts = await facts.fetch(referencedPaths);
|
|
302
|
+
supersessionLines = (0, tagged_reference_1.supersessionAdvisory)(referencedPaths, relationFacts).map((a) => a.message);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// best-effort: no supersession advisory on any fetch/join failure (P6).
|
|
306
|
+
supersessionLines = [];
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const advisoryText = [renderAdvisoryText(result.advisories), ...supersessionLines]
|
|
310
|
+
.filter((s) => s.length > 0)
|
|
311
|
+
.join("\n");
|
|
312
|
+
console.log(JSON.stringify({ advisoryText, advisories: result.advisories }));
|
|
313
|
+
return 0;
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
// Any unexpected error (missing config, etc.) is silent: print an empty
|
|
317
|
+
// advisory and exit 0. Active Review is best-effort; it must never break the
|
|
318
|
+
// turn it rides on.
|
|
319
|
+
console.log(JSON.stringify({ advisoryText: "", advisories: [] }));
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
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.parseArgs = parseArgs;
|
|
37
|
+
exports.runInternalAutoIndex = runInternalAutoIndex;
|
|
38
|
+
// tools/meetless-agent/src/commands/internal-auto-index.ts
|
|
39
|
+
// `mla _internal auto-index --session <sid>` (Zone 2 auto-index loop).
|
|
40
|
+
//
|
|
41
|
+
// Fired detached from the Stop hook (spawn_auto_index). It reads this session's
|
|
42
|
+
// produced-doc captures from the Zone 1 Active Review spool and indexes each into
|
|
43
|
+
// the owner's Personal KB as a SHADOW / agent_distilled doc via the idempotent
|
|
44
|
+
// `mla kb add` path. SHADOW never grounds anyone (INV-GROUNDING-APPROVED), so this
|
|
45
|
+
// auto-ingest cannot pollute retrieval; the explicit human gate moves to
|
|
46
|
+
// `mla kb promote` (SHADOW -> LIVE), which is unchanged.
|
|
47
|
+
//
|
|
48
|
+
// advise-never-block (P6): every failure path is swallowed; the command prints a
|
|
49
|
+
// JSON summary and exits 0 (except a strict argv parse error -> 2, and an
|
|
50
|
+
// owner-check denial -> 3). It runs off the session's hot path and must never
|
|
51
|
+
// disturb the session it rides on; the denial halt only stops THIS detached
|
|
52
|
+
// batch, never the session.
|
|
53
|
+
//
|
|
54
|
+
// Owner-denial halt (fix B3): a non-OWNER actor used to fail-soft once PER DOC
|
|
55
|
+
// (154 denial lines in the incident) because runKbAdd swallows KbOwnerCheckError
|
|
56
|
+
// into stderr + exit 2, invisible to this loop. The denial is run-fatal, not
|
|
57
|
+
// doc-local: the same actor is denied for every doc. So the run halts on the
|
|
58
|
+
// first denial with ONE message. The OWNER-only gate itself (kb_acl.ts + the
|
|
59
|
+
// control-side check) is locked design and is NOT touched here.
|
|
60
|
+
// See notes/20260605-mla-auto-index-loop-implementation-plan.md.
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const path = __importStar(require("path"));
|
|
63
|
+
const config_1 = require("../lib/config");
|
|
64
|
+
const active_memory_1 = require("../lib/active-memory");
|
|
65
|
+
const auto_index_1 = require("../lib/auto-index");
|
|
66
|
+
const kb_acl_1 = require("../lib/kb_acl");
|
|
67
|
+
const kb_add_1 = require("./kb_add");
|
|
68
|
+
function activeMemoryStorePath() {
|
|
69
|
+
return path.join(config_1.HOME, "logs", "kb-knowledge.jsonl");
|
|
70
|
+
}
|
|
71
|
+
// Mirror the Active Review reader's window so the two zones see the same record set.
|
|
72
|
+
const TTL_HOURS = 48;
|
|
73
|
+
const MAX_RECORDS = 100;
|
|
74
|
+
function parseArgs(argv) {
|
|
75
|
+
let sessionId = null;
|
|
76
|
+
for (let i = 0; i < argv.length; i++) {
|
|
77
|
+
const a = argv[i];
|
|
78
|
+
if (a === "--session") {
|
|
79
|
+
sessionId = argv[i + 1] ?? null;
|
|
80
|
+
i++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (a.startsWith("-")) {
|
|
84
|
+
throw new Error(`Unknown flag: ${a}. \`mla _internal auto-index\` takes only [--session <sid>].`);
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Unexpected positional argument: ${a}. \`mla _internal auto-index\` takes only [--session <sid>].`);
|
|
87
|
+
}
|
|
88
|
+
return { sessionId };
|
|
89
|
+
}
|
|
90
|
+
// runKbAdd converts KbOwnerCheckError into stderr + exit 2 before it reaches
|
|
91
|
+
// this loop, so a thrown denial only arrives from injected add fns or future
|
|
92
|
+
// boundary changes. Match the class, the name (survives module-duplication
|
|
93
|
+
// boundaries), or the stable message prefix kb_acl.ts stamps on every denial.
|
|
94
|
+
function isOwnerDenial(e) {
|
|
95
|
+
if (e instanceof kb_acl_1.KbOwnerCheckError)
|
|
96
|
+
return true;
|
|
97
|
+
const err = e;
|
|
98
|
+
if (err && err.name === "KbOwnerCheckError")
|
|
99
|
+
return true;
|
|
100
|
+
return Boolean(err && typeof err.message === "string" && err.message.includes("KB owner check failed"));
|
|
101
|
+
}
|
|
102
|
+
function haltOnOwnerDenial(e, summary) {
|
|
103
|
+
const detail = e instanceof Error && e.message ? e.message : String(e);
|
|
104
|
+
// One clear line for the whole run instead of one denial per doc. The
|
|
105
|
+
// kb_acl message already names the actor, its role, and the OWNER
|
|
106
|
+
// requirement.
|
|
107
|
+
console.error(`auto-index halted: owner-check denial; remaining docs not attempted. ${detail}`);
|
|
108
|
+
console.log(JSON.stringify({ ...summary, halted: "owner_check_denied" }));
|
|
109
|
+
return 3;
|
|
110
|
+
}
|
|
111
|
+
async function runInternalAutoIndex(argv, deps = {}) {
|
|
112
|
+
let sessionId;
|
|
113
|
+
try {
|
|
114
|
+
({ sessionId } = parseArgs(argv));
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
console.error(e.message);
|
|
118
|
+
return 2;
|
|
119
|
+
}
|
|
120
|
+
const add = deps.add ?? kb_add_1.runKbAdd;
|
|
121
|
+
const storePath = deps.storePath ?? activeMemoryStorePath();
|
|
122
|
+
const verifyOwner = deps.verifyOwner ??
|
|
123
|
+
(deps.add ? null : async (ws) => (0, kb_acl_1.verifyKbActorIsOwner)((0, config_1.readKbConfig)(ws)));
|
|
124
|
+
try {
|
|
125
|
+
// Scope to this session BEFORE dedup: the content-keyed dedup identity omits
|
|
126
|
+
// sessionId, so a post-reduce filter could drop this session's doc in favor of
|
|
127
|
+
// an identical-content record from another session. sessionId === null (no flag)
|
|
128
|
+
// reduces the whole spool, matching the active-review reader's window.
|
|
129
|
+
const records = (0, active_memory_1.reduceActiveMemory)(storePath, {
|
|
130
|
+
nowMs: Date.now(),
|
|
131
|
+
ttlHours: TTL_HOURS,
|
|
132
|
+
maxRecords: MAX_RECORDS,
|
|
133
|
+
...(sessionId ? { sessionId } : {}),
|
|
134
|
+
});
|
|
135
|
+
const targets = (0, auto_index_1.selectIndexTargets)(records);
|
|
136
|
+
let indexed = 0;
|
|
137
|
+
let skipped = 0;
|
|
138
|
+
let failed = 0;
|
|
139
|
+
const verifiedWorkspaces = new Set();
|
|
140
|
+
for (const t of targets) {
|
|
141
|
+
if (!fs.existsSync(t.absPath)) {
|
|
142
|
+
skipped++;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
// Owner-gate preflight, once per workspace: runKbAdd would swallow a
|
|
146
|
+
// denial into exit 2 per doc; checking here lets a denial halt the
|
|
147
|
+
// whole run before the spam starts. Non-denial preflight failures
|
|
148
|
+
// (missing config, control unreachable) stay fail-soft and let the add
|
|
149
|
+
// surface its own per-doc outcome.
|
|
150
|
+
if (verifyOwner && !verifiedWorkspaces.has(t.workspaceId)) {
|
|
151
|
+
try {
|
|
152
|
+
await verifyOwner(t.workspaceId);
|
|
153
|
+
verifiedWorkspaces.add(t.workspaceId);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
if (isOwnerDenial(e)) {
|
|
157
|
+
return haltOnOwnerDenial(e, { indexed, skipped, failed, total: targets.length });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
// Pass this run's raw session UUID (from `--session`, kept raw for spool
|
|
163
|
+
// scoping above) so the add carries `--agent-session` to the intel route.
|
|
164
|
+
// buildKbAddArgv canonicalizes it; null/invalid simply omits the flag.
|
|
165
|
+
const code = await add((0, auto_index_1.buildKbAddArgv)(t, sessionId));
|
|
166
|
+
if (code === 0)
|
|
167
|
+
indexed++;
|
|
168
|
+
else
|
|
169
|
+
failed++;
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
if (isOwnerDenial(e)) {
|
|
173
|
+
// Run-fatal, not doc-local: the same denial would repeat for every
|
|
174
|
+
// remaining doc.
|
|
175
|
+
return haltOnOwnerDenial(e, { indexed, skipped, failed, total: targets.length });
|
|
176
|
+
}
|
|
177
|
+
failed++; // fail-soft: one bad add never aborts the batch.
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
console.log(JSON.stringify({ indexed, skipped, failed, total: targets.length }));
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Any unexpected error (unreadable store, etc.) degrades to a quiet no-op.
|
|
185
|
+
console.log(JSON.stringify({ indexed: 0, skipped: 0, failed: 0, total: 0 }));
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
}
|