@remnic/core 9.3.688 → 9.3.690
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/dist/access-boundary.d.ts +5 -4
- package/dist/access-boundary.js +12 -11
- package/dist/access-cli.js +90 -26
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +4 -3
- package/dist/access-http.js +15 -14
- package/dist/access-mcp.d.ts +11 -3
- package/dist/access-mcp.js +14 -13
- package/dist/access-operations.d.ts +11 -5
- package/dist/access-operations.js +15 -12
- package/dist/{access-service-DmCHJ4cH.d.ts → access-service-Dujr3MTm.d.ts} +62 -2
- package/dist/access-service.d.ts +4 -3
- package/dist/access-service.js +11 -10
- package/dist/access-surface-catalog.d.ts +4 -3
- package/dist/access-surface-catalog.js +2 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/bootstrap.d.ts +3 -2
- package/dist/briefing.d.ts +1 -0
- package/dist/briefing.js +3 -2
- package/dist/buffer.d.ts +1 -0
- package/dist/{catalog-COqWZlZ6.d.ts → catalog-CKPtJ114.d.ts} +1 -1
- package/dist/causal-consolidation.js +4 -3
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-B4XVLHJA.js → chunk-2N6UNJSX.js} +2 -2
- package/dist/{chunk-NN7QYW5W.js → chunk-46URPRE6.js} +2 -2
- package/dist/chunk-46URPRE6.js.map +1 -0
- package/dist/{chunk-4N3TFFPH.js → chunk-54PVJDO5.js} +2 -2
- package/dist/{chunk-PH3HOKYW.js → chunk-67MMWC74.js} +2 -2
- package/dist/{chunk-STOEE37X.js → chunk-BKAMHZYR.js} +2 -2
- package/dist/{chunk-B43NZNMG.js → chunk-CE6CBRCV.js} +432 -2240
- package/dist/chunk-CE6CBRCV.js.map +1 -0
- package/dist/{chunk-RVYD6LR3.js → chunk-CP2NZQLT.js} +15 -4
- package/dist/chunk-CP2NZQLT.js.map +1 -0
- package/dist/{chunk-BLIWOONZ.js → chunk-CUNTLEJP.js} +4 -12
- package/dist/chunk-CUNTLEJP.js.map +1 -0
- package/dist/{chunk-2SJCWLQD.js → chunk-CWE74HRG.js} +3 -3
- package/dist/{chunk-VX6OBUDW.js → chunk-GR77Z2BM.js} +2 -2
- package/dist/{chunk-CTOQEZSN.js → chunk-LXIEXSHU.js} +2 -2
- package/dist/{chunk-KFBOZYME.js → chunk-NSVXK7M5.js} +33 -4
- package/dist/chunk-NSVXK7M5.js.map +1 -0
- package/dist/{chunk-473JIN2U.js → chunk-OMKUJTVJ.js} +37 -5
- package/dist/chunk-OMKUJTVJ.js.map +1 -0
- package/dist/{chunk-GS55WYRL.js → chunk-PHZKALOE.js} +2 -2
- package/dist/{chunk-6O6A6YUO.js → chunk-RGNEARXW.js} +3 -3
- package/dist/{chunk-4FE2K57M.js → chunk-RTFAZOIR.js} +2 -2
- package/dist/{chunk-UTYBJR7M.js → chunk-SB6CQTKP.js} +2 -2
- package/dist/chunk-SVOZFLIQ.js +16 -0
- package/dist/chunk-SVOZFLIQ.js.map +1 -0
- package/dist/{chunk-2KAYTPPT.js → chunk-TYF3D4MS.js} +5 -5
- package/dist/{chunk-WIHPNY65.js → chunk-UD5OKH4J.js} +2 -2
- package/dist/{chunk-QANVLERJ.js → chunk-UPIBE2DK.js} +2 -2
- package/dist/{chunk-CCWHPGT4.js → chunk-WROKD3XC.js} +45 -30
- package/dist/chunk-WROKD3XC.js.map +1 -0
- package/dist/{chunk-ZPTISBQU.js → chunk-X5J3JZR3.js} +7 -7
- package/dist/{chunk-OV4D5T7V.js → chunk-X7RLU5CR.js} +2 -2
- package/dist/{chunk-S2OU5DZY.js → chunk-XKUKJIOY.js} +30 -7
- package/dist/chunk-XKUKJIOY.js.map +1 -0
- package/dist/{chunk-FUCUR2OZ.js → chunk-Z7KILAOU.js} +603 -9
- package/dist/chunk-Z7KILAOU.js.map +1 -0
- package/dist/chunk-ZU7N3S6V.js +2190 -0
- package/dist/chunk-ZU7N3S6V.js.map +1 -0
- package/dist/{chunk-DCWIQFNA.js → chunk-ZUDM75KG.js} +4 -4
- package/dist/{cli-D8nZ2MPH.d.ts → cli-BkDp6WNi.d.ts} +2 -2
- package/dist/cli.d.ts +5 -4
- package/dist/cli.js +32 -30
- package/dist/compounding/engine.d.ts +1 -0
- package/dist/compounding/engine.js +3 -2
- package/dist/connectors/codex-materialize-runner.js +3 -2
- package/dist/connectors/index.js +3 -2
- package/dist/consolidation-provenance-check.d.ts +1 -0
- package/dist/consolidation-undo.d.ts +1 -0
- package/dist/contradiction/index.d.ts +1 -0
- package/dist/conversation-index/backend.js +2 -2
- package/dist/entity-retrieval.d.ts +1 -0
- package/dist/entity-retrieval.js +3 -2
- package/dist/explicit-capture.d.ts +3 -2
- package/dist/index.d.ts +6 -5
- package/dist/index.js +47 -44
- package/dist/index.js.map +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +5 -5
- package/dist/maintenance/memory-governance.js +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +4 -3
- package/dist/mcp-memory-inspector-app.d.ts +4 -3
- package/dist/memory-worth-outcomes.d.ts +1 -0
- package/dist/namespaces/migrate.d.ts +2 -1
- package/dist/namespaces/migrate.js +10 -9
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +2 -1
- package/dist/namespaces/storage.js +3 -2
- package/dist/operator-toolkit.d.ts +1 -0
- package/dist/operator-toolkit.js +13 -11
- package/dist/{orchestrator-CA6ouzBn.d.ts → orchestrator-B7ixmUkP.d.ts} +145 -1
- package/dist/orchestrator.d.ts +3 -2
- package/dist/orchestrator.js +22 -20
- package/dist/recall-pipeline-stages.d.ts +167 -0
- package/dist/recall-pipeline-stages.js +61 -0
- package/dist/recall-pipeline-stages.js.map +1 -0
- package/dist/schemas.d.ts +10 -10
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +9 -9
- package/dist/semantic-consolidation.js +4 -3
- package/dist/semantic-rule-promotion.js +3 -2
- package/dist/semantic-rule-verifier.js +3 -2
- package/dist/storage.d.ts +3 -27
- package/dist/storage.js +5 -3
- package/dist/structured-attributes.d.ts +29 -0
- package/dist/structured-attributes.js +8 -0
- package/dist/structured-attributes.js.map +1 -0
- package/dist/temporal-supersession.d.ts +1 -0
- package/dist/tier-migration.d.ts +1 -0
- package/dist/verified-recall.js +3 -2
- package/package.json +2 -2
- package/src/access-boundary.ts +2 -1
- package/src/access-cli.test.ts +40 -0
- package/src/access-cli.ts +90 -2
- package/src/access-http.ts +35 -6
- package/src/access-mcp.ts +34 -0
- package/src/access-operations.ts +45 -0
- package/src/access-service.ts +60 -0
- package/src/access-surface-catalog.test.ts +1 -1
- package/src/access-surface-catalog.ts +2 -0
- package/src/cli.ts +18 -0
- package/src/coding/architecture-card.test.ts +544 -0
- package/src/coding/architecture-card.ts +687 -0
- package/src/coding/architecture-surfaces.test.ts +579 -0
- package/src/coding/architecture-surfaces.ts +457 -0
- package/src/maintenance/namespace-maintenance-fanout.test.ts +595 -0
- package/src/maintenance/namespace-maintenance-fanout.ts +318 -0
- package/src/maintenance/namespace-planner.ts +74 -16
- package/src/operator-toolkit.ts +25 -0
- package/src/orchestrator.ts +144 -0
- package/src/recall-pipeline-stages.test.ts +269 -0
- package/src/recall-pipeline-stages.ts +294 -0
- package/src/storage.ts +6 -20
- package/src/structured-attributes.ts +39 -0
- package/dist/chunk-473JIN2U.js.map +0 -1
- package/dist/chunk-B43NZNMG.js.map +0 -1
- package/dist/chunk-BLIWOONZ.js.map +0 -1
- package/dist/chunk-CCWHPGT4.js.map +0 -1
- package/dist/chunk-FUCUR2OZ.js.map +0 -1
- package/dist/chunk-KFBOZYME.js.map +0 -1
- package/dist/chunk-NN7QYW5W.js.map +0 -1
- package/dist/chunk-RVYD6LR3.js.map +0 -1
- package/dist/chunk-S2OU5DZY.js.map +0 -1
- /package/dist/{chunk-B4XVLHJA.js.map → chunk-2N6UNJSX.js.map} +0 -0
- /package/dist/{chunk-4N3TFFPH.js.map → chunk-54PVJDO5.js.map} +0 -0
- /package/dist/{chunk-PH3HOKYW.js.map → chunk-67MMWC74.js.map} +0 -0
- /package/dist/{chunk-STOEE37X.js.map → chunk-BKAMHZYR.js.map} +0 -0
- /package/dist/{chunk-2SJCWLQD.js.map → chunk-CWE74HRG.js.map} +0 -0
- /package/dist/{chunk-VX6OBUDW.js.map → chunk-GR77Z2BM.js.map} +0 -0
- /package/dist/{chunk-CTOQEZSN.js.map → chunk-LXIEXSHU.js.map} +0 -0
- /package/dist/{chunk-GS55WYRL.js.map → chunk-PHZKALOE.js.map} +0 -0
- /package/dist/{chunk-6O6A6YUO.js.map → chunk-RGNEARXW.js.map} +0 -0
- /package/dist/{chunk-4FE2K57M.js.map → chunk-RTFAZOIR.js.map} +0 -0
- /package/dist/{chunk-UTYBJR7M.js.map → chunk-SB6CQTKP.js.map} +0 -0
- /package/dist/{chunk-2KAYTPPT.js.map → chunk-TYF3D4MS.js.map} +0 -0
- /package/dist/{chunk-WIHPNY65.js.map → chunk-UD5OKH4J.js.map} +0 -0
- /package/dist/{chunk-QANVLERJ.js.map → chunk-UPIBE2DK.js.map} +0 -0
- /package/dist/{chunk-ZPTISBQU.js.map → chunk-X5J3JZR3.js.map} +0 -0
- /package/dist/{chunk-OV4D5T7V.js.map → chunk-X7RLU5CR.js.map} +0 -0
- /package/dist/{chunk-DCWIQFNA.js.map → chunk-ZUDM75KG.js.map} +0 -0
package/src/access-cli.test.ts
CHANGED
|
@@ -522,3 +522,43 @@ test("access-cli rejects adjacent option-looking values", async () => {
|
|
|
522
522
|
|
|
523
523
|
assert.match(output, /missing required option: --content/);
|
|
524
524
|
});
|
|
525
|
+
|
|
526
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
527
|
+
// architecture command — wired through the boundary operation (#1548 PR3)
|
|
528
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
529
|
+
|
|
530
|
+
test("access-cli architecture is a known command (unknown options rejected, not unsupported-command)", async () => {
|
|
531
|
+
const output = await captureRunCliFailure(["architecture", "--typo", "x"]);
|
|
532
|
+
assert.match(output, /unknown option: --typo/);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
test("access-cli architecture accepts its documented value options", async () => {
|
|
536
|
+
// Valid option spellings parse cleanly; the invocation only fails once it
|
|
537
|
+
// reaches the runtime (no OpenClaw config here), proving the options were
|
|
538
|
+
// accepted by parseArgs rather than rejected as unknown.
|
|
539
|
+
const output = await captureRunCliFailure([
|
|
540
|
+
"architecture",
|
|
541
|
+
"--subcommand",
|
|
542
|
+
"get",
|
|
543
|
+
"--session-key",
|
|
544
|
+
"s1",
|
|
545
|
+
"--namespace",
|
|
546
|
+
"ns",
|
|
547
|
+
"--project-tag",
|
|
548
|
+
"myproj",
|
|
549
|
+
]);
|
|
550
|
+
assert.doesNotMatch(output, /unknown option/);
|
|
551
|
+
assert.doesNotMatch(output, /unsupported command/);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("access-cli usage lists the architecture command and its options", async () => {
|
|
555
|
+
const output = await captureRunCliFailure(["architecture", "--typo"]);
|
|
556
|
+
assert.match(output, /engram-access architecture \[options\]/);
|
|
557
|
+
assert.match(output, /Architecture options:/);
|
|
558
|
+
assert.match(output, /--subcommand <get\|refresh>/);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
test("access-cli still rejects truly unknown commands as unsupported", async () => {
|
|
562
|
+
const output = await captureRunCliFailure(["bogus-command"]);
|
|
563
|
+
assert.match(output, /unsupported command/);
|
|
564
|
+
});
|
package/src/access-cli.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { projectTagProjectId } from "./coding/coding-namespace.js";
|
|
|
15
15
|
|
|
16
16
|
const OPENCLAW_REMNIC_PLUGIN_IDS = ["openclaw-remnic", "openclaw-engram"] as const;
|
|
17
17
|
|
|
18
|
-
type CommandName = "browse" | "store" | "decision";
|
|
18
|
+
type CommandName = "browse" | "store" | "decision" | "architecture";
|
|
19
19
|
|
|
20
20
|
type ParsedArgs = {
|
|
21
21
|
command: CommandName;
|
|
@@ -137,6 +137,7 @@ function usage(): string {
|
|
|
137
137
|
" engram-access browse [options]",
|
|
138
138
|
" engram-access store [options]",
|
|
139
139
|
" engram-access decision [options]",
|
|
140
|
+
" engram-access architecture [options]",
|
|
140
141
|
"",
|
|
141
142
|
"Browse options:",
|
|
142
143
|
" --namespace <name>",
|
|
@@ -176,6 +177,14 @@ function usage(): string {
|
|
|
176
177
|
" --entity-ref <ref> (repeatable)",
|
|
177
178
|
" --project-tag <tag> (attach coding context for this invocation)",
|
|
178
179
|
" --supersedes-id <id> (alias for --id on supersede)",
|
|
180
|
+
"",
|
|
181
|
+
"Architecture options:",
|
|
182
|
+
" --subcommand <get|refresh>",
|
|
183
|
+
" --namespace <name>",
|
|
184
|
+
" --session-key <key>",
|
|
185
|
+
" --principal <principal>",
|
|
186
|
+
" --project-tag <tag> (attach coding context for this invocation)",
|
|
187
|
+
" --repo-root <path> (repo to scan for refresh; defaults to the current directory)",
|
|
179
188
|
].join("\n");
|
|
180
189
|
}
|
|
181
190
|
|
|
@@ -228,6 +237,17 @@ const COMMAND_SPECS: Record<CommandName, CommandSpec> = {
|
|
|
228
237
|
]),
|
|
229
238
|
flagOptions: new Set(),
|
|
230
239
|
},
|
|
240
|
+
architecture: {
|
|
241
|
+
valueOptions: new Set([
|
|
242
|
+
"subcommand",
|
|
243
|
+
"namespace",
|
|
244
|
+
"session-key",
|
|
245
|
+
"principal",
|
|
246
|
+
"project-tag",
|
|
247
|
+
"repo-root",
|
|
248
|
+
]),
|
|
249
|
+
flagOptions: new Set(),
|
|
250
|
+
},
|
|
231
251
|
};
|
|
232
252
|
const BROWSE_SORT_VALUES = Object.freeze([
|
|
233
253
|
"updated_desc",
|
|
@@ -238,9 +258,19 @@ const BROWSE_SORT_VALUES = Object.freeze([
|
|
|
238
258
|
|
|
239
259
|
type BrowseSort = (typeof BROWSE_SORT_VALUES)[number];
|
|
240
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Type guard for {@link CommandName}. Enumerating the union (rather than a
|
|
263
|
+
* bare `value in COMMAND_SPECS`) is what lets TypeScript NARROW the string
|
|
264
|
+
* to `CommandName` — the `in` operator alone yields TS2322 on the
|
|
265
|
+
* `command: commandRaw` assignment below (codex review P2).
|
|
266
|
+
*/
|
|
267
|
+
function isCommandName(value: string): value is CommandName {
|
|
268
|
+
return value === "browse" || value === "store" || value === "decision" || value === "architecture";
|
|
269
|
+
}
|
|
270
|
+
|
|
241
271
|
function parseArgs(argv: string[]): ParsedArgs {
|
|
242
272
|
const [commandRaw, ...rest] = argv;
|
|
243
|
-
if (commandRaw
|
|
273
|
+
if (!isCommandName(commandRaw)) {
|
|
244
274
|
throw new UsageError("unsupported-command");
|
|
245
275
|
}
|
|
246
276
|
const spec = COMMAND_SPECS[commandRaw];
|
|
@@ -552,6 +582,60 @@ async function runDecision(args: ParsedArgs, preferredId?: string): Promise<void
|
|
|
552
582
|
console.log(JSON.stringify(output.result, null, 2));
|
|
553
583
|
}
|
|
554
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Architecture-card surface (issue #1548 Track A PR 3). Dispatches through
|
|
587
|
+
* the same `coding_architecture` operation as the MCP tool and HTTP route —
|
|
588
|
+
* one validation boundary, three transports.
|
|
589
|
+
*/
|
|
590
|
+
async function runArchitecture(args: ParsedArgs, preferredId?: string): Promise<void> {
|
|
591
|
+
const subcommand = requireOption(args, "subcommand");
|
|
592
|
+
const { config, service } = buildRuntime(preferredId);
|
|
593
|
+
// Same coding-context attachment as runDecision (review P2): the CLI's
|
|
594
|
+
// fresh Orchestrator has an empty session coding-context map, so attach
|
|
595
|
+
// a context BEFORE dispatching when --project-tag + --session-key are
|
|
596
|
+
// given, so the gate passes and writes resolve to the right namespace.
|
|
597
|
+
const projectTag = getLastOption(args, "project-tag");
|
|
598
|
+
const sessionKey = getLastOption(args, "session-key");
|
|
599
|
+
if (sessionKey && sessionKey.trim().length > 0) {
|
|
600
|
+
// refresh scans codingContext.rootPath, so it must be a REAL checkout
|
|
601
|
+
// path. Default to the CWD (or an explicit --repo-root) so a one-shot
|
|
602
|
+
// CLI refresh scans the caller's repo, not a non-existent tag path.
|
|
603
|
+
const repoRoot = expandOptionalPath(getLastOption(args, "repo-root")) ?? process.cwd();
|
|
604
|
+
// --project-tag supplies the context id (namespace); when absent, derive
|
|
605
|
+
// a default from the repo-root basename so refresh works with just
|
|
606
|
+
// --session-key + --repo-root (codex review).
|
|
607
|
+
const projectId =
|
|
608
|
+
projectTag && projectTag.trim().length > 0
|
|
609
|
+
? projectTagProjectId(projectTag.trim())
|
|
610
|
+
: projectTagProjectId(path.basename(repoRoot));
|
|
611
|
+
service.setCodingContext({
|
|
612
|
+
sessionKey,
|
|
613
|
+
codingContext: {
|
|
614
|
+
projectId,
|
|
615
|
+
branch: null,
|
|
616
|
+
rootPath: repoRoot,
|
|
617
|
+
defaultBranch: null,
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
const op = getOperation("coding_architecture");
|
|
622
|
+
if (!op) {
|
|
623
|
+
throw new Error("access-boundary: operation not registered: coding_architecture");
|
|
624
|
+
}
|
|
625
|
+
const output = (await op.run(
|
|
626
|
+
{
|
|
627
|
+
subcommand,
|
|
628
|
+
namespace: getLastOption(args, "namespace"),
|
|
629
|
+
sessionKey,
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
service,
|
|
633
|
+
authenticatedPrincipal: getLastOption(args, "principal") ?? config.agentAccessHttp.principal,
|
|
634
|
+
},
|
|
635
|
+
)) as { result: unknown };
|
|
636
|
+
console.log(JSON.stringify(output.result, null, 2));
|
|
637
|
+
}
|
|
638
|
+
|
|
555
639
|
export async function main(
|
|
556
640
|
argv: string[] = process.argv.slice(2),
|
|
557
641
|
options: AccessCliOptions = {},
|
|
@@ -565,6 +649,10 @@ export async function main(
|
|
|
565
649
|
await runDecision(args, options.preferredId);
|
|
566
650
|
return;
|
|
567
651
|
}
|
|
652
|
+
if (args.command === "architecture") {
|
|
653
|
+
await runArchitecture(args, options.preferredId);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
568
656
|
await runStore(args, options.preferredId);
|
|
569
657
|
}
|
|
570
658
|
|
package/src/access-http.ts
CHANGED
|
@@ -316,6 +316,7 @@ export class EngramAccessHttpServer {
|
|
|
316
316
|
citationsAutoDetect: options.citationsAutoDetect,
|
|
317
317
|
emitLegacyTools: options.emitLegacyTools,
|
|
318
318
|
codingDecisionVisible: this.service.decisionRecordSurfaceVisible,
|
|
319
|
+
architectureCardVisible: this.service.architectureCardSurfaceVisible,
|
|
319
320
|
});
|
|
320
321
|
}
|
|
321
322
|
|
|
@@ -1361,6 +1362,30 @@ export class EngramAccessHttpServer {
|
|
|
1361
1362
|
return;
|
|
1362
1363
|
}
|
|
1363
1364
|
|
|
1365
|
+
if (req.method === "POST" && pathname === "/engram/v1/coding/architecture") {
|
|
1366
|
+
// Migrated through the access boundary (issue #1525/#1548 PR3):
|
|
1367
|
+
// refresh persists the card, so it is gated by the 30/min write quota;
|
|
1368
|
+
// get is a pure read and stays uncounted.
|
|
1369
|
+
const body = await this.readJsonBody(req);
|
|
1370
|
+
const isWriteSubcommand = body.subcommand === "refresh";
|
|
1371
|
+
if (isWriteSubcommand) {
|
|
1372
|
+
this.ensureWriteRateLimitAvailable();
|
|
1373
|
+
}
|
|
1374
|
+
const op = getOperation("coding_architecture");
|
|
1375
|
+
if (!op) {
|
|
1376
|
+
throw new EngramAccessInputError("access-boundary: operation not registered: coding_architecture");
|
|
1377
|
+
}
|
|
1378
|
+
const output = (await op.run(body, {
|
|
1379
|
+
service: this.service,
|
|
1380
|
+
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1381
|
+
})) as { result: unknown };
|
|
1382
|
+
if (isWriteSubcommand) {
|
|
1383
|
+
this.recordWriteRateLimitHit();
|
|
1384
|
+
}
|
|
1385
|
+
this.respondJson(res, 200, output.result);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1364
1389
|
if (req.method === "POST" && pathname === "/engram/v1/suggestions") {
|
|
1365
1390
|
const body = await this.readValidatedBody(req, "suggestionSubmit");
|
|
1366
1391
|
const request = {
|
|
@@ -2213,13 +2238,16 @@ export class EngramAccessHttpServer {
|
|
|
2213
2238
|
typeof toolArgs === "object" &&
|
|
2214
2239
|
!Array.isArray(toolArgs) &&
|
|
2215
2240
|
(toolArgs as { dryRun?: unknown }).dryRun === true;
|
|
2241
|
+
const toolArgsSubcommand =
|
|
2242
|
+
toolArgs !== null && typeof toolArgs === "object" && !Array.isArray(toolArgs) && "subcommand" in toolArgs
|
|
2243
|
+
? toolArgs.subcommand
|
|
2244
|
+
: undefined;
|
|
2216
2245
|
const codingDecisionWrite =
|
|
2217
2246
|
(toolName === "engram.coding_decision" || toolName === "remnic.coding_decision") &&
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
(toolArgs as { subcommand?: unknown }).subcommand === "supersede");
|
|
2247
|
+
(toolArgsSubcommand === "record" || toolArgsSubcommand === "supersede");
|
|
2248
|
+
const codingArchitectureWrite =
|
|
2249
|
+
(toolName === "engram.coding_architecture" || toolName === "remnic.coding_architecture") &&
|
|
2250
|
+
toolArgsSubcommand === "refresh";
|
|
2223
2251
|
const isMcpWrite =
|
|
2224
2252
|
request.method === "tools/call" &&
|
|
2225
2253
|
(
|
|
@@ -2248,7 +2276,8 @@ export class EngramAccessHttpServer {
|
|
|
2248
2276
|
toolName === "remnic.memory_action_apply"
|
|
2249
2277
|
)
|
|
2250
2278
|
) ||
|
|
2251
|
-
codingDecisionWrite
|
|
2279
|
+
codingDecisionWrite ||
|
|
2280
|
+
codingArchitectureWrite
|
|
2252
2281
|
);
|
|
2253
2282
|
if (isMcpWrite) {
|
|
2254
2283
|
this.ensureWriteRateLimitAvailable();
|
package/src/access-mcp.ts
CHANGED
|
@@ -110,6 +110,7 @@ const MCP_MIGRATED_OPERATIONS: Readonly<Record<string, OperationName>> = {
|
|
|
110
110
|
"engram.memory_search": "memory_search",
|
|
111
111
|
"engram.memory_store": "memory_store",
|
|
112
112
|
"engram.coding_decision": "coding_decision",
|
|
113
|
+
"engram.coding_architecture": "coding_architecture",
|
|
113
114
|
};
|
|
114
115
|
|
|
115
116
|
function resolveChatGptInspectorRecallSessionKey(
|
|
@@ -324,6 +325,12 @@ export class EngramMcpServer {
|
|
|
324
325
|
* pre-feature.
|
|
325
326
|
*/
|
|
326
327
|
private readonly codingDecisionVisible: boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Whether the `coding_architecture` tool should appear in `tools/list`.
|
|
330
|
+
* Gated on `codingKnowledge.enabled && codingKnowledge.architectureCard`
|
|
331
|
+
* (issue #1548 Track A PR 3, rule 39).
|
|
332
|
+
*/
|
|
333
|
+
private readonly architectureCardVisible: boolean;
|
|
327
334
|
|
|
328
335
|
constructor(
|
|
329
336
|
private readonly service: EngramAccessService,
|
|
@@ -333,12 +340,14 @@ export class EngramMcpServer {
|
|
|
333
340
|
citationsAutoDetect?: boolean;
|
|
334
341
|
emitLegacyTools?: boolean;
|
|
335
342
|
codingDecisionVisible?: boolean;
|
|
343
|
+
architectureCardVisible?: boolean;
|
|
336
344
|
} = {},
|
|
337
345
|
) {
|
|
338
346
|
this.citationsEnabled = options.citationsEnabled === true;
|
|
339
347
|
this.citationsAutoDetect = options.citationsAutoDetect !== false;
|
|
340
348
|
this.emitLegacyTools = options.emitLegacyTools !== false;
|
|
341
349
|
this.codingDecisionVisible = options.codingDecisionVisible === true;
|
|
350
|
+
this.architectureCardVisible = options.architectureCardVisible === true;
|
|
342
351
|
this.authenticatedPrincipal =
|
|
343
352
|
options.principal?.trim() ||
|
|
344
353
|
readEnvVar("OPENCLAW_ENGRAM_ACCESS_PRINCIPAL")?.trim() ||
|
|
@@ -1999,6 +2008,31 @@ export class EngramMcpServer {
|
|
|
1999
2008
|
);
|
|
2000
2009
|
this.tools = [...this.tools, ...codingDecisionTools];
|
|
2001
2010
|
}
|
|
2011
|
+
if (this.architectureCardVisible) {
|
|
2012
|
+
const architectureTools = withToolAliases(
|
|
2013
|
+
{
|
|
2014
|
+
name: "engram.coding_architecture",
|
|
2015
|
+
description:
|
|
2016
|
+
"Get or refresh the architecture card for the session's coding namespace (issue #1548 Track A PR 3). Subcommands: get, refresh.",
|
|
2017
|
+
inputSchema: {
|
|
2018
|
+
type: "object",
|
|
2019
|
+
properties: {
|
|
2020
|
+
subcommand: {
|
|
2021
|
+
type: "string",
|
|
2022
|
+
enum: ["get", "refresh"],
|
|
2023
|
+
description: "Which architecture-card operation to run.",
|
|
2024
|
+
},
|
|
2025
|
+
sessionKey: { type: "string", description: "Session identifier whose coding context scopes the operation." },
|
|
2026
|
+
namespace: { type: "string", description: "Optional explicit namespace (overrides coding-context overlay)." },
|
|
2027
|
+
},
|
|
2028
|
+
required: ["subcommand"],
|
|
2029
|
+
additionalProperties: false,
|
|
2030
|
+
},
|
|
2031
|
+
},
|
|
2032
|
+
this.emitLegacyTools,
|
|
2033
|
+
);
|
|
2034
|
+
this.tools = [...this.tools, ...architectureTools];
|
|
2035
|
+
}
|
|
2002
2036
|
}
|
|
2003
2037
|
|
|
2004
2038
|
/** Get clientInfo for a specific MCP session. Returns undefined for non-MCP requests. */
|
package/src/access-operations.ts
CHANGED
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
type DecisionSurfaceRequest,
|
|
26
26
|
type DecisionSurfaceResponse,
|
|
27
27
|
} from "./coding/decision-surfaces.js";
|
|
28
|
+
import {
|
|
29
|
+
type ArchitectureSurfaceRequest,
|
|
30
|
+
type ArchitectureSurfaceResponse,
|
|
31
|
+
} from "./coding/architecture-surfaces.js";
|
|
28
32
|
|
|
29
33
|
// ---------------------------------------------------------------------------
|
|
30
34
|
// memory_get — fetch one memory by id
|
|
@@ -206,6 +210,46 @@ export const codingDecisionOperation = defineOperation<
|
|
|
206
210
|
},
|
|
207
211
|
});
|
|
208
212
|
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// coding_architecture — architecture-card surfaces (issue #1548 Track A PR 3)
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
const codingArchitectureSchema = z.preprocess(
|
|
218
|
+
(data) => {
|
|
219
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
220
|
+
const obj = data as Record<string, unknown>;
|
|
221
|
+
const cleaned: Record<string, unknown> = {};
|
|
222
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
223
|
+
if (value !== null) cleaned[key] = value;
|
|
224
|
+
}
|
|
225
|
+
return cleaned;
|
|
226
|
+
}
|
|
227
|
+
return data;
|
|
228
|
+
},
|
|
229
|
+
z.object({
|
|
230
|
+
subcommand: z.enum(["get", "refresh"]),
|
|
231
|
+
sessionKey: z.string().optional(),
|
|
232
|
+
namespace: z.string().optional(),
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
export type CodingArchitectureInput = ArchitectureSurfaceRequest;
|
|
237
|
+
export type CodingArchitectureOutput = { result: ArchitectureSurfaceResponse };
|
|
238
|
+
|
|
239
|
+
export const codingArchitectureOperation = defineOperation<
|
|
240
|
+
CodingArchitectureInput,
|
|
241
|
+
CodingArchitectureOutput
|
|
242
|
+
>({
|
|
243
|
+
name: "coding_architecture",
|
|
244
|
+
description:
|
|
245
|
+
"Get or refresh the architecture card for the session's coding namespace (issue #1548 Track A PR 3).",
|
|
246
|
+
schema: codingArchitectureSchema as z.ZodType<CodingArchitectureInput>,
|
|
247
|
+
handler: async (input, ctx) => {
|
|
248
|
+
const result = await ctx.service.codingArchitecture(input, ctx.authenticatedPrincipal);
|
|
249
|
+
return { result };
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
209
253
|
// ---------------------------------------------------------------------------
|
|
210
254
|
// Surface registration map — what each transport calls the pilot ops
|
|
211
255
|
// ---------------------------------------------------------------------------
|
|
@@ -220,4 +264,5 @@ export const REGISTERED_OPERATIONS = [
|
|
|
220
264
|
memorySearchOperation.spec.name,
|
|
221
265
|
memoryStoreOperation.spec.name,
|
|
222
266
|
codingDecisionOperation.spec.name,
|
|
267
|
+
codingArchitectureOperation.spec.name,
|
|
223
268
|
] as const;
|
package/src/access-service.ts
CHANGED
|
@@ -19,6 +19,16 @@ import {
|
|
|
19
19
|
type DecisionSurfaceRequest,
|
|
20
20
|
type DecisionSurfaceResponse,
|
|
21
21
|
} from "./coding/decision-surfaces.js";
|
|
22
|
+
import {
|
|
23
|
+
handleCodingArchitecture,
|
|
24
|
+
type ArchitectureSurfaceRequest,
|
|
25
|
+
type ArchitectureSurfaceResponse,
|
|
26
|
+
type ArchitectureSurfaceStorage,
|
|
27
|
+
createArchitectureVersioningHook,
|
|
28
|
+
ARCHITECTURE_CARD_TAG,
|
|
29
|
+
} from "./coding/architecture-surfaces.js";
|
|
30
|
+
import { buildArchitectureCard, createArchitectureCardSummariser } from "./coding/architecture-card.js";
|
|
31
|
+
import { createVersion } from "./page-versioning.js";
|
|
22
32
|
import { WorkStorage } from "./work/storage.js";
|
|
23
33
|
import {
|
|
24
34
|
exportWorkBoardMarkdown,
|
|
@@ -4485,6 +4495,56 @@ export class EngramAccessService {
|
|
|
4485
4495
|
});
|
|
4486
4496
|
}
|
|
4487
4497
|
|
|
4498
|
+
/** Whether the coding_architecture tool should appear in tools/list (rule 39). */
|
|
4499
|
+
get architectureCardSurfaceVisible(): boolean {
|
|
4500
|
+
return this.orchestrator.config.codingKnowledge?.enabled === true
|
|
4501
|
+
&& this.orchestrator.config.codingKnowledge?.architectureCard === true;
|
|
4502
|
+
}
|
|
4503
|
+
/**
|
|
4504
|
+
* Thin delegate — handler logic in coding/architecture-surfaces.ts (#1548 PR3).
|
|
4505
|
+
* All three surfaces (MCP/HTTP/CLI) arrive here via the boundary operation.
|
|
4506
|
+
* Namespace resolution uses the SAME coding-scoped path as decision records.
|
|
4507
|
+
*/
|
|
4508
|
+
async codingArchitecture(
|
|
4509
|
+
request: ArchitectureSurfaceRequest,
|
|
4510
|
+
authenticatedPrincipal?: string,
|
|
4511
|
+
): Promise<ArchitectureSurfaceResponse> {
|
|
4512
|
+
const resolvedConfig = this.orchestrator.config;
|
|
4513
|
+
return handleCodingArchitecture(request, {
|
|
4514
|
+
codingKnowledge: this.orchestrator.config.codingKnowledge,
|
|
4515
|
+
getCodingContext: (sk) => this.orchestrator.getCodingContextForSession(sk),
|
|
4516
|
+
resolveStorage: async (req) => {
|
|
4517
|
+
const isWrite = req.subcommand === "refresh";
|
|
4518
|
+
const ns = isWrite
|
|
4519
|
+
? await this.resolveCodingScopedWriteNamespace({
|
|
4520
|
+
namespace: req.namespace,
|
|
4521
|
+
sessionKey: req.sessionKey,
|
|
4522
|
+
authenticatedPrincipal,
|
|
4523
|
+
})
|
|
4524
|
+
: await this.resolveCodingScopedReadableNamespace({
|
|
4525
|
+
namespace: req.namespace,
|
|
4526
|
+
sessionKey: req.sessionKey,
|
|
4527
|
+
authenticatedPrincipal,
|
|
4528
|
+
});
|
|
4529
|
+
const storage = await this.orchestrator.getStorage(ns);
|
|
4530
|
+
return Object.assign(storage, { namespace: ns }) as ArchitectureSurfaceStorage;
|
|
4531
|
+
},
|
|
4532
|
+
buildCard: async (repoRoot) => buildArchitectureCard(repoRoot, {
|
|
4533
|
+
llmSummary: this.orchestrator.config.codingKnowledge?.architectureCardLlmSummary === true,
|
|
4534
|
+
summariser: createArchitectureCardSummariser(this.fallbackLlmRef ?? this.localLlmRef),
|
|
4535
|
+
}),
|
|
4536
|
+
versioning: createArchitectureVersioningHook(
|
|
4537
|
+
resolvedConfig.versioningEnabled === true,
|
|
4538
|
+
resolvedConfig.versioningMaxPerPage,
|
|
4539
|
+
resolvedConfig.versioningSidecarDir,
|
|
4540
|
+
resolvedConfig.memoryDir,
|
|
4541
|
+
(p) => nodeFs.readFile(p, "utf-8"),
|
|
4542
|
+
createVersion,
|
|
4543
|
+
),
|
|
4544
|
+
throwInputError: (msg) => { throw new EngramAccessInputError(msg); },
|
|
4545
|
+
});
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4488
4548
|
async memoryBrowse(
|
|
4489
4549
|
request: EngramAccessMemoryBrowseRequest = {},
|
|
4490
4550
|
): Promise<EngramAccessMemoryBrowseResponse> {
|
|
@@ -67,7 +67,7 @@ function shortToolName(advertised: string): string {
|
|
|
67
67
|
/** Spin up a server with emitLegacyTools=true and read the deduped short names. */
|
|
68
68
|
async function liveMcpToolShortNames(): Promise<ReadonlySet<string>> {
|
|
69
69
|
const stub = { briefingEnabled: true } as unknown as EngramAccessService;
|
|
70
|
-
const server = new EngramMcpServer(stub, { emitLegacyTools: true, codingDecisionVisible: true });
|
|
70
|
+
const server = new EngramMcpServer(stub, { emitLegacyTools: true, codingDecisionVisible: true, architectureCardVisible: true });
|
|
71
71
|
const response = await server.handleRequest({ jsonrpc: "2.0", id: 1, method: "tools/list" });
|
|
72
72
|
const result = (response as { result?: { tools?: Array<{ name: string }> } }).result;
|
|
73
73
|
const names = new Set<string>();
|
|
@@ -73,6 +73,7 @@ export const MCP_TOOLS: readonly McpToolEntry[] = [
|
|
|
73
73
|
{ tool: "memory_timeline", operation: null },
|
|
74
74
|
{ tool: "memory_store", operation: "memory_store" },
|
|
75
75
|
{ tool: "coding_decision", operation: "coding_decision" },
|
|
76
|
+
{ tool: "coding_architecture", operation: "coding_architecture" },
|
|
76
77
|
{ tool: "suggestion_submit", operation: null },
|
|
77
78
|
{ tool: "entity_get", operation: null },
|
|
78
79
|
{ tool: "review_queue_list", operation: null },
|
|
@@ -170,6 +171,7 @@ export const HTTP_ROUTES: readonly HttpRouteEntry[] = [
|
|
|
170
171
|
{ method: "GET", pathname: "/engram/v1/lcm/status", operation: null },
|
|
171
172
|
{ method: "POST", pathname: "/engram/v1/memories", operation: "memory_store" },
|
|
172
173
|
{ method: "POST", pathname: "/engram/v1/coding/decisions", operation: "coding_decision" },
|
|
174
|
+
{ method: "POST", pathname: "/engram/v1/coding/architecture", operation: "coding_architecture" },
|
|
173
175
|
{ method: "POST", pathname: "/engram/v1/suggestions", operation: null },
|
|
174
176
|
{ method: "GET", pathname: "/engram/v1/memories", operation: null },
|
|
175
177
|
{ method: "GET", pathname: "/engram/v1/memories/:id", operation: "memory_get" },
|
package/src/cli.ts
CHANGED
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
} from "./maintenance/rebuild-memory-projection.js";
|
|
58
58
|
import { rebuildObservations } from "./maintenance/rebuild-observations.js";
|
|
59
59
|
import { migrateObservations } from "./maintenance/migrate-observations.js";
|
|
60
|
+
import { formatNamespaceMaintenanceHealthText } from "./maintenance/namespace-maintenance-fanout.js";
|
|
60
61
|
import {
|
|
61
62
|
listNamespaces,
|
|
62
63
|
runNamespaceMigration,
|
|
@@ -2801,6 +2802,7 @@ export async function runAccessMcpServeCliCommand(
|
|
|
2801
2802
|
principal: options.principal,
|
|
2802
2803
|
emitLegacyTools: options.emitLegacyTools,
|
|
2803
2804
|
codingDecisionVisible: service.decisionRecordSurfaceVisible,
|
|
2805
|
+
architectureCardVisible: service.architectureCardSurfaceVisible,
|
|
2804
2806
|
});
|
|
2805
2807
|
await server.runStdio(options.stdin ?? process.stdin, options.stdout ?? process.stdout);
|
|
2806
2808
|
return { ok: true };
|
|
@@ -4292,6 +4294,22 @@ export function registerCli(
|
|
|
4292
4294
|
}
|
|
4293
4295
|
});
|
|
4294
4296
|
|
|
4297
|
+
namespacesCmd
|
|
4298
|
+
.command("maintenance")
|
|
4299
|
+
.description(
|
|
4300
|
+
"Show per-namespace maintenance status (issue #1500). Reports which namespaces were maintained, skipped, or failed for each standard job.",
|
|
4301
|
+
)
|
|
4302
|
+
.option("--json", "Emit machine-readable JSON only")
|
|
4303
|
+
.action(async (...args: unknown[]) => {
|
|
4304
|
+
const options = (args[0] ?? {}) as Record<string, unknown>;
|
|
4305
|
+
const summary = await orchestrator.readNamespaceMaintenanceHealth();
|
|
4306
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
4307
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
4308
|
+
} else {
|
|
4309
|
+
console.log(formatNamespaceMaintenanceHealthText(summary));
|
|
4310
|
+
}
|
|
4311
|
+
});
|
|
4312
|
+
|
|
4295
4313
|
cmd
|
|
4296
4314
|
.command("export")
|
|
4297
4315
|
.description("Export Remnic memory to JSON, Markdown bundle, or SQLite")
|