@productbrain/mcp 0.0.1-beta.65 → 0.0.1-beta.67
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/{chunk-UWILSX73.js → chunk-TH5AUVVM.js} +310 -148
- package/dist/chunk-TH5AUVVM.js.map +1 -0
- package/dist/{chunk-VBKAAFR6.js → chunk-YARRUQBW.js} +329 -292
- package/dist/chunk-YARRUQBW.js.map +1 -0
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{smart-capture-EGTUM4XP.js → smart-capture-Q64ZXK65.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-UWILSX73.js.map +0 -1
- package/dist/chunk-VBKAAFR6.js.map +0 -1
- /package/dist/{smart-capture-EGTUM4XP.js.map → smart-capture-Q64ZXK65.js.map} +0 -0
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
registerSmartCaptureTools,
|
|
32
32
|
requireActiveSession,
|
|
33
33
|
requireWriteAccess,
|
|
34
|
+
resolveCollection,
|
|
34
35
|
runWithToolContext,
|
|
35
36
|
setSessionOriented,
|
|
36
37
|
startAgentSession,
|
|
@@ -42,7 +43,7 @@ import {
|
|
|
42
43
|
unknownAction,
|
|
43
44
|
validationResult,
|
|
44
45
|
withEnvelope
|
|
45
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-TH5AUVVM.js";
|
|
46
47
|
import {
|
|
47
48
|
trackKnowledgeGap,
|
|
48
49
|
trackQualityCheck,
|
|
@@ -237,7 +238,7 @@ ${formatted}` }],
|
|
|
237
238
|
},
|
|
238
239
|
withEnvelope(async ({ entryId }) => {
|
|
239
240
|
requireWriteAccess();
|
|
240
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
241
|
+
const { runContradictionCheck } = await import("./smart-capture-Q64ZXK65.js");
|
|
241
242
|
const entry = await mcpQuery("chain.getEntry", { entryId });
|
|
242
243
|
if (!entry) {
|
|
243
244
|
return notFoundResult(entryId, `Entry '${entryId}' not found. Try search to find the right ID.`);
|
|
@@ -364,14 +365,15 @@ function sanitizeEntryData(data) {
|
|
|
364
365
|
);
|
|
365
366
|
return Object.keys(filtered).length > 0 ? filtered : void 0;
|
|
366
367
|
}
|
|
367
|
-
var ENTRIES_ACTIONS = ["list", "get", "batch", "search"];
|
|
368
|
+
var ENTRIES_ACTIONS = ["list", "get", "batch", "search", "move"];
|
|
368
369
|
var entriesSchema = z2.object({
|
|
369
370
|
action: z2.enum(ENTRIES_ACTIONS).describe(
|
|
370
|
-
"'list': browse entries with filters. 'get': fetch one entry by ID. 'batch': fetch multiple entries. 'search': full-text search."
|
|
371
|
+
"'list': browse entries with filters. 'get': fetch one entry by ID. 'batch': fetch multiple entries. 'search': full-text search. 'move': move entry to a different collection."
|
|
371
372
|
),
|
|
372
|
-
entryId: z2.string().optional().describe("Entry ID for get action, e.g. '
|
|
373
|
+
entryId: z2.string().optional().describe("Entry ID for get/move action, e.g. 'DEC-42', 'BR-001'"),
|
|
373
374
|
entryIds: z2.array(z2.string()).min(1).max(20).optional().describe("Entry IDs for batch action, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
|
|
374
375
|
collection: z2.string().optional().describe("Collection slug for list/search, e.g. 'glossary', 'tracking-events', 'business-rules'"),
|
|
376
|
+
toCollection: z2.string().optional().describe("Target collection slug for move action, e.g. 'decisions', 'architecture'"),
|
|
375
377
|
status: z2.string().optional().describe("Filter: draft | active | deprecated | archived"),
|
|
376
378
|
tag: z2.string().optional().describe("Filter by internal tag for list"),
|
|
377
379
|
label: z2.string().optional().describe("Filter by label slug for list \u2014 matches entries across all collections"),
|
|
@@ -426,14 +428,14 @@ function registerEntriesTools(server) {
|
|
|
426
428
|
"entries",
|
|
427
429
|
{
|
|
428
430
|
title: "Entries",
|
|
429
|
-
description: 'Read entries from the Chain. One tool for all entry reading.\n\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n\nUse `entries action=get entryId="..."` to fetch one. Use `entries action=search query="..."` to discover.',
|
|
431
|
+
description: 'Read entries from the Chain. One tool for all entry reading.\n\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n- **move**: Move an entry to a different collection. Use when classifier misrouted or user wants to reclassify.\n\nUse `entries action=get entryId="..."` to fetch one. Use `entries action=search query="..."` to discover.',
|
|
430
432
|
inputSchema: entriesSchema,
|
|
431
|
-
annotations: {
|
|
433
|
+
annotations: { idempotentHint: false, openWorldHint: false }
|
|
432
434
|
},
|
|
433
435
|
withEnvelope(async (args) => {
|
|
434
436
|
const parsed = parseOrFail(entriesSchema, args);
|
|
435
437
|
if (!parsed.ok) return parsed.result;
|
|
436
|
-
const { action, entryId, entryIds, collection, status, tag, label, query } = parsed.data;
|
|
438
|
+
const { action, entryId, entryIds, collection, toCollection, status, tag, label, query } = parsed.data;
|
|
437
439
|
return runWithToolContext({ tool: "entries", action }, async () => {
|
|
438
440
|
if (action === "get") {
|
|
439
441
|
if (!entryId) {
|
|
@@ -456,6 +458,11 @@ function registerEntriesTools(server) {
|
|
|
456
458
|
if (action === "list") {
|
|
457
459
|
return handleList(collection, status, tag, label);
|
|
458
460
|
}
|
|
461
|
+
if (action === "move") {
|
|
462
|
+
if (!entryId) return validationResult("entryId is required when action is 'move'.");
|
|
463
|
+
if (!toCollection) return validationResult("toCollection is required when action is 'move'.");
|
|
464
|
+
return handleMove(entryId, toCollection);
|
|
465
|
+
}
|
|
459
466
|
return unknownAction(action, ENTRIES_ACTIONS);
|
|
460
467
|
});
|
|
461
468
|
})
|
|
@@ -657,6 +664,41 @@ ${formatted}` }],
|
|
|
657
664
|
structuredContent: success(`Found ${total} entries${scope}.`, { entries: structuredEntries, total })
|
|
658
665
|
};
|
|
659
666
|
}
|
|
667
|
+
async function handleMove(entryId, toCollection) {
|
|
668
|
+
try {
|
|
669
|
+
const result = await mcpMutation("chain.moveToCollection", { entryId, toCollectionSlug: toCollection });
|
|
670
|
+
const lines = [
|
|
671
|
+
`## Move Result`,
|
|
672
|
+
"",
|
|
673
|
+
`Moved **${result.entryId}** from \`${result.fromCollection}\` \u2192 \`${result.toCollection}\``
|
|
674
|
+
];
|
|
675
|
+
if (result.workflowStatusReset) {
|
|
676
|
+
lines.push(``, `\u26A0\uFE0F Workflow status \`${result.previousWorkflowStatus}\` was reset (incompatible with target collection).`);
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
680
|
+
structuredContent: success(
|
|
681
|
+
`Moved ${result.entryId} from ${result.fromCollection} to ${result.toCollection}.`,
|
|
682
|
+
result,
|
|
683
|
+
[
|
|
684
|
+
{ tool: "entries", description: "View updated entry", parameters: { action: "get", entryId } },
|
|
685
|
+
{ tool: "quality", description: "Re-check quality", parameters: { action: "check", entryId } }
|
|
686
|
+
]
|
|
687
|
+
)
|
|
688
|
+
};
|
|
689
|
+
} catch (error) {
|
|
690
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
691
|
+
const isNotFound = msg.includes("not found");
|
|
692
|
+
if (isNotFound) return notFoundResult(entryId, `Could not move entry: ${msg}`);
|
|
693
|
+
return failureResult(
|
|
694
|
+
`Could not move **${entryId}** to \`${toCollection}\`: ${msg}`,
|
|
695
|
+
"MOVE_FAILED",
|
|
696
|
+
msg,
|
|
697
|
+
"Check the entry ID and target collection slug, then retry.",
|
|
698
|
+
[{ tool: "entries", description: "Search for entry", parameters: { action: "search", query: entryId } }]
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
660
702
|
async function handleSearch(server, query, collection, status) {
|
|
661
703
|
const scope = collection ? ` in \`${collection}\`` : "";
|
|
662
704
|
await server.sendLoggingMessage({
|
|
@@ -3053,7 +3095,7 @@ If any facilitate call fails:
|
|
|
3053
3095
|
label: "De-risk \u2014 Rabbit Holes & No-Gos",
|
|
3054
3096
|
type: "open",
|
|
3055
3097
|
instruction: "What could go wrong? What are we NOT building? Walk through the solution slowly and find the risks.",
|
|
3056
|
-
facilitatorGuidance: "**Investigate first.** Read the investigationBrief. Spawn sub-agents to search the codebase for fragile code, tight coupling, missing tests, performance-sensitive paths, and external dependencies near the affected modules. Propose risks with evidence: 'I found that X module has no tests and is tightly coupled to Y \u2014 this is a rabbit hole.' Every confirmed risk MUST be captured with its own respond call: `facilitate action=respond betEntryId='...' dimension='risks' source='user_reaction' userInput='...' capture={type:'risk', name:'Risk Name', description:'What could go wrong', theme:'implementation'}`. Each becomes a tensions entry linked to the bet via constrains. Push for mitigations \u2014 every risk needs a patch or explicit acceptance. Then declare no-gos: 'Based on what I've seen, I'd suggest these no-gos.' Every no-go MUST use capture: `facilitate action=respond betEntryId='...' dimension='boundaries' source='user_reaction' userInput='...' capture={type:'noGo', name:'No-Go Title', description:'Why we are not doing this'}`. Without the `capture` parameter on each call, the item is NOT saved \u2014 you will get a WARNING. When risks score 6+ and boundaries score 4+, present Shape Go gate: 'Is this buildable within the appetite?'",
|
|
3098
|
+
facilitatorGuidance: "**Investigate first.** Read the investigationBrief. Spawn sub-agents to search the codebase for fragile code, tight coupling, missing tests, performance-sensitive paths, and external dependencies near the affected modules. Propose risks with evidence: 'I found that X module has no tests and is tightly coupled to Y \u2014 this is a rabbit hole.' Every confirmed risk MUST be captured with its own respond call: `facilitate action=respond betEntryId='...' dimension='risks' source='user_reaction' userInput='...' capture={type:'risk', name:'Risk Name', description:'What could go wrong', theme:'implementation'}`. Each becomes a tensions entry linked to the bet via constrains. Push for mitigations \u2014 every risk needs a patch or explicit acceptance. Then declare no-gos: 'Based on what I've seen, I'd suggest these no-gos.' Every no-go MUST use capture: `facilitate action=respond betEntryId='...' dimension='boundaries' source='user_reaction' userInput='...' capture={type:'noGo', name:'No-Go Title', description:'Why we are not doing this'}`. Without the `capture` parameter on each call, the item is NOT saved \u2014 you will get a WARNING. **Counter-Metric Mandate (STD-19):** If the derisking references any quantitative gates or metrics (accuracy targets, performance budgets, adoption thresholds), stress-test them: 'What's the denominator? What gets excluded? What counter-metric would expose a false positive?' A metric gate that can be gamed by abstaining or cherry-picking the population is not a gate \u2014 name the compound metric that can't be gamed. When risks score 6+ and boundaries score 4+, present Shape Go gate: 'Is this buildable within the appetite?'",
|
|
3057
3099
|
questions: [
|
|
3058
3100
|
{
|
|
3059
3101
|
id: "shape-go",
|
|
@@ -3079,7 +3121,7 @@ If any facilitate call fails:
|
|
|
3079
3121
|
label: "Validate & Build Contract",
|
|
3080
3122
|
type: "synthesis",
|
|
3081
3123
|
instruction: "Check completeness. Generate the build contract. Review the full scorecard.",
|
|
3082
|
-
facilitatorGuidance: "Call `facilitate action=score` to get the full scorecard. Present it as a table. Check: does the response include a buildContract? If captureReady is true, it should. Verify the 5 core ingredients: Problem, Appetite, Solution elements, Rabbit Holes, No-Gos. For Big Batch: also verify Architecture, narrative hook, and value-flow annotations. Present the build contract. Ask: 'Anything to adjust before we capture to the Chain?'",
|
|
3124
|
+
facilitatorGuidance: "Call `facilitate action=score` to get the full scorecard. Present it as a table. Check: does the response include a buildContract? If captureReady is true, it should. Verify the 5 core ingredients: Problem, Appetite, Solution elements, Rabbit Holes, No-Gos. For Big Batch: also verify Architecture, narrative hook, and value-flow annotations. **Counter-Metric Mandate (STD-19):** If the scorecard or build contract contains metrics or gates, verify each has a denominator, a coverage rate, and a counter-metric. Flag any gate that can be satisfied by abstaining or excluding the hard cases. Present the build contract. Ask: 'Anything to adjust before we capture to the Chain?'",
|
|
3083
3125
|
outputSchema: {
|
|
3084
3126
|
field: "validation",
|
|
3085
3127
|
description: "Completeness check result and build contract",
|
|
@@ -3166,6 +3208,7 @@ var IMPLEMENTATION_REVIEW_WORKFLOW_DESCRIPTOR = {
|
|
|
3166
3208
|
## Review scope (CRITICAL)
|
|
3167
3209
|
|
|
3168
3210
|
- **Default scope is this conversation only.** Only the work discussed or produced in this conversation is in scope. Do not review or touch files, BETs, or work outside that scope unless the user explicitly expands it (e.g. "also review the auth module").
|
|
3211
|
+
- **Every file touched must be explicit.** Scope is not complete until you have listed every file that was touched (created, modified, or deleted) in the work under review. Use git status/diff and conversation context to enumerate them. The review then assesses holistic coherence: does this set of changes fit our system, bring us closer to our vision, and make our code and architecture cleaner?
|
|
3169
3212
|
- **Infer scope first.** Use conversation context, git status/diff, and recent edits to determine which BET, feature, or files are in scope. Call orient/start and \`context action=gather\` with the inferred scope; do not ask the user to pick what to review unless it's ambiguous.
|
|
3170
3213
|
- **Ask only to clarify boundaries.** If scope is ambiguous after inference, ask a single, focused question to clarify (e.g. "Should this review include only the changes we just made, or the whole feature?"). Do not ask open-ended "what should we review?" or "which work area?" unless inference failed.
|
|
3171
3214
|
- **State scope explicitly in Round 01.** After orient and context gather, state in one sentence what is in scope (e.g. "Scope: changes in this conversation for BET-72" or "Scope: files X, Y and BET-72"). Confirm only if the user might reasonably expect something else.
|
|
@@ -3200,11 +3243,11 @@ When reviewing test results: (a) test staleness \u2014 code changed, test not up
|
|
|
3200
3243
|
num: "01",
|
|
3201
3244
|
label: "Orient & Scope",
|
|
3202
3245
|
type: "open",
|
|
3203
|
-
instruction: "Apply the Review scope rules: infer scope from this conversation, git diff, and recent edits (default = work in this conversation only). Call orient or start, then context action=gather for the inferred BET/feature. State scope in one explicit sentence. Only ask the participant if scope is ambiguous.",
|
|
3204
|
-
facilitatorGuidance: "Infer scope from conversation context, git status/diff, and recent edits \u2014 default is work in this conversation only. Call orient or start to load governance and active bets. Use context action=gather task='implementation review for [inferred-BET-or-feature]' to load related entries. State scope explicitly in one sentence (e.g. 'Scope: changes in this conversation for BET-72'). Present: stated scope, relevant BETs/DECs/BRs, and any stale entries orient surfaces. Ask the participant only if scope is ambiguous (e.g. 'Only the files we changed, or the whole feature?').",
|
|
3246
|
+
instruction: "Apply the Review scope rules: infer scope from this conversation, git diff, and recent edits (default = work in this conversation only). Enumerate every file touched (created, modified, deleted). Call orient or start, then context action=gather for the inferred BET/feature. State scope in one explicit sentence and list all files in scope. Only ask the participant if scope is ambiguous. The review will assess: holistic coherence with our system, whether this brings us closer to our vision, and whether it makes our code and architecture cleaner.",
|
|
3247
|
+
facilitatorGuidance: "Infer scope from conversation context, git status/diff, and recent edits \u2014 default is work in this conversation only. List every file touched (created, modified, or deleted) in the work under review; scope is not complete without this list. Call orient or start to load governance and active bets. Use context action=gather task='implementation review for [inferred-BET-or-feature]' to load related entries. State scope explicitly in one sentence (e.g. 'Scope: changes in this conversation for BET-72'). Present: stated scope, the full list of files touched, relevant BETs/DECs/BRs, and any stale entries orient surfaces. Frame the review: we will assess holistic coherence with our system, whether this brings us closer to our vision, and whether it makes our code and architecture cleaner. Ask the participant only if scope is ambiguous (e.g. 'Only the files we changed, or the whole feature?').",
|
|
3205
3248
|
outputSchema: {
|
|
3206
3249
|
field: "scope",
|
|
3207
|
-
description: "Explicit scope statement
|
|
3250
|
+
description: "Explicit scope statement, every file touched, BET/feature IDs and related Chain context",
|
|
3208
3251
|
format: "structured"
|
|
3209
3252
|
},
|
|
3210
3253
|
maxDurationHint: "3 min"
|
|
@@ -3229,7 +3272,7 @@ When reviewing test results: (a) test staleness \u2014 code changed, test not up
|
|
|
3229
3272
|
label: "Code & Test Honesty",
|
|
3230
3273
|
type: "open",
|
|
3231
3274
|
instruction: "Spawn sub-agents to review implementation and tests for the stated scope only. Did we meet high standards? Are tests validating real behavior or did we edit them just to pass?",
|
|
3232
|
-
facilitatorGuidance: "Restrict all review to the scope stated in Round 01 (by default, work in this conversation only). Spawn 1\u20132 sub-agents in parallel: (1) explore agent \u2014 code review, architecture boundaries, type-safety for scoped files only. (2) generalPurpose agent \u2014 test review for scoped code: are tests asserting real behavior or were they edited to pass? Pass the scope (files/BET) explicitly to sub-agents so they do not touch other work. Use Context7 (query-docs) for relevant testing and framework best practices if needed. Classify any test failures: staleness, regression, or flaky. Synthesize: implementation grade, test honesty verdict, refactoring suggestions (within scope only).",
|
|
3275
|
+
facilitatorGuidance: "Restrict all review to the scope stated in Round 01 (by default, work in this conversation only). Spawn 1\u20132 sub-agents in parallel: (1) explore agent \u2014 code review, architecture boundaries, type-safety for scoped files only. (2) generalPurpose agent \u2014 test review for scoped code: are tests asserting real behavior or were they edited to pass? Pass the scope (files/BET) explicitly to sub-agents so they do not touch other work. Use Context7 (query-docs) for relevant testing and framework best practices if needed. Classify any test failures: staleness, regression, or flaky. **Counter-Metric Mandate (STD-19):** When reporting test coverage, accuracy, or any quantitative result, include the denominator, what was excluded, and at least one counter-metric. Never report accuracy without recall. Never report pass rate without coverage. Synthesize: implementation grade, test honesty verdict, refactoring suggestions (within scope only).",
|
|
3233
3276
|
outputSchema: {
|
|
3234
3277
|
field: "codeAndTests",
|
|
3235
3278
|
description: "Implementation grade, test honesty, refactor suggestions",
|
|
@@ -3256,8 +3299,8 @@ When reviewing test results: (a) test staleness \u2014 code changed, test not up
|
|
|
3256
3299
|
num: "05",
|
|
3257
3300
|
label: "Synthesis & Sign-Off",
|
|
3258
3301
|
type: "commit",
|
|
3259
|
-
instruction: "Summarize the review. Refactoring needed? Ship or conditional? End with BET/chain IDs.",
|
|
3260
|
-
facilitatorGuidance: "Present the full synthesis: standards pass/fail, code grade, test honesty, chain validation. Recommend: ship, ship with conditions, or do not ship. CRITICAL: The output MUST end with one sentence: 'BET/feature IDs reviewed: [IDs]. [One-line summary].' Example: 'BET-xxx, STD-xxx reviewed. Conditional ship \u2014 fix [specific issues] and add [missing tests].'",
|
|
3302
|
+
instruction: "Summarize the review. Answer: Does this bring us closer to our vision and make our code and architecture cleaner? Refactoring needed? Ship or conditional? End with BET/chain IDs.",
|
|
3303
|
+
facilitatorGuidance: "Present the full synthesis: standards pass/fail, code grade, test honesty, chain validation. Explicitly answer: Does this bring us closer to our vision and make our code and architecture cleaner? **Counter-Metric Mandate (STD-19):** For EVERY quantitative result you present, you MUST include: (1) the denominator \u2014 what is the total population measured, (2) the coverage/abstention rate \u2014 what was excluded, (3) at least one counter-metric that tells the opposite story (recall vs precision, error rate vs success rate), (4) the 'student exam' reframe \u2014 score on the full exam, not just questions answered. **Red-team your own synthesis:** Before presenting, ask yourself: 'What's the worst honest interpretation of these numbers? What metric looks good but hides a real problem? What would a skeptic challenge?' Present that alongside the headline. Recommend: ship, ship with conditions, or do not ship. CRITICAL: The output MUST end with one sentence: 'BET/feature IDs reviewed: [IDs]. [One-line summary].' Example: 'BET-xxx, STD-xxx reviewed. Conditional ship \u2014 fix [specific issues] and add [missing tests].'",
|
|
3261
3304
|
outputSchema: {
|
|
3262
3305
|
field: "synthesis",
|
|
3263
3306
|
description: "Full review synthesis with BET/chain IDs",
|
|
@@ -3852,6 +3895,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
3852
3895
|
runId
|
|
3853
3896
|
);
|
|
3854
3897
|
}
|
|
3898
|
+
const resolvedSummaryCapture = summaryCapture;
|
|
3855
3899
|
const existingRun = await mcpQuery(
|
|
3856
3900
|
"chainwork.getLatestWorkflowRun",
|
|
3857
3901
|
{
|
|
@@ -3865,6 +3909,15 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
3865
3909
|
);
|
|
3866
3910
|
}
|
|
3867
3911
|
try {
|
|
3912
|
+
let resolvedCollectionSlug;
|
|
3913
|
+
if (resolvedSummaryCapture.routing.mode === "classifier") {
|
|
3914
|
+
const classifyName = summaryName ?? wf.name;
|
|
3915
|
+
const classifyDesc = summaryDescription ?? outputPreview;
|
|
3916
|
+
const resolved = await resolveCollection({ name: classifyName, description: classifyDesc });
|
|
3917
|
+
if (resolved && resolved.tier !== "low") {
|
|
3918
|
+
resolvedCollectionSlug = resolved.collection;
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3868
3921
|
const result = await mcpMutation("chainwork.finalizeWorkflowRun", {
|
|
3869
3922
|
agentSessionId,
|
|
3870
3923
|
workflowId: wf.id,
|
|
@@ -3882,22 +3935,23 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
3882
3935
|
finalRoundId: roundId,
|
|
3883
3936
|
finalOutput: normalizedOutput,
|
|
3884
3937
|
summaryCapture: {
|
|
3885
|
-
routing:
|
|
3938
|
+
routing: resolvedSummaryCapture.routing.mode === "fixed" ? {
|
|
3886
3939
|
mode: "fixed",
|
|
3887
|
-
collection:
|
|
3940
|
+
collection: resolvedSummaryCapture.routing.collection
|
|
3888
3941
|
} : {
|
|
3889
3942
|
mode: "classifier"
|
|
3890
3943
|
},
|
|
3891
|
-
nameTemplate:
|
|
3892
|
-
descriptionField:
|
|
3893
|
-
descriptionSource:
|
|
3944
|
+
nameTemplate: resolvedSummaryCapture.nameTemplate,
|
|
3945
|
+
descriptionField: resolvedSummaryCapture.descriptionField,
|
|
3946
|
+
descriptionSource: resolvedSummaryCapture.descriptionSource
|
|
3894
3947
|
},
|
|
3895
3948
|
summaryDescription,
|
|
3896
|
-
summaryName
|
|
3949
|
+
summaryName,
|
|
3950
|
+
resolvedCollectionSlug
|
|
3897
3951
|
});
|
|
3898
3952
|
lines.push(
|
|
3899
3953
|
result.summary.created ? `**Draft Created**: \`${result.summary.entryId}\`` : `**Draft Already Exists**: \`${result.summary.entryId}\``,
|
|
3900
|
-
`Collection: \`${result.summary.collection ?? (
|
|
3954
|
+
`Collection: \`${result.summary.collection ?? (resolvedSummaryCapture.routing.mode === "fixed" ? resolvedSummaryCapture.routing.collection : "classifier-routed")}\``,
|
|
3901
3955
|
`Name: ${result.summary.name}`,
|
|
3902
3956
|
"",
|
|
3903
3957
|
`The summary is captured as a draft. Use \`commit-entry entryId="${result.summary.entryId}"\` to promote it to the Chain.`,
|
|
@@ -3911,7 +3965,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
3911
3965
|
entryId: result.summary.entryId,
|
|
3912
3966
|
workflowId,
|
|
3913
3967
|
roundId,
|
|
3914
|
-
collection: result.summary.collection ?? (
|
|
3968
|
+
collection: result.summary.collection ?? (resolvedSummaryCapture.routing.mode === "fixed" ? resolvedSummaryCapture.routing.collection : null),
|
|
3915
3969
|
isFinal: true,
|
|
3916
3970
|
runId: result.runId,
|
|
3917
3971
|
created: result.summary.created
|
|
@@ -3937,8 +3991,8 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
3937
3991
|
"",
|
|
3938
3992
|
`The workflow output is preserved in this conversation. `,
|
|
3939
3993
|
`You can manually create the entry later using \`capture\` with:`,
|
|
3940
|
-
`- Collection: \`${
|
|
3941
|
-
`- Name: ${summaryName ??
|
|
3994
|
+
`- Collection: \`${resolvedSummaryCapture.routing.mode === "fixed" ? resolvedSummaryCapture.routing.collection : "classifier-routed"}\``,
|
|
3995
|
+
`- Name: ${summaryName ?? resolvedSummaryCapture.nameTemplate}`,
|
|
3942
3996
|
`- Description: ${summaryDescription ?? outputPreview}`
|
|
3943
3997
|
);
|
|
3944
3998
|
return {
|
|
@@ -5489,11 +5543,12 @@ async function processCaptures(opts) {
|
|
|
5489
5543
|
const entriesCreated = [];
|
|
5490
5544
|
let relationsCreated = 0;
|
|
5491
5545
|
const capAgentId = getAgentSessionId();
|
|
5492
|
-
const
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5546
|
+
const CAPTURE_DEFAULTS = {
|
|
5547
|
+
features: { dataField: "description", relationType: "part_of" },
|
|
5548
|
+
tensions: { dataField: "description", relationType: "constrains" },
|
|
5549
|
+
decisions: { dataField: "rationale", relationType: "informs" }
|
|
5496
5550
|
};
|
|
5551
|
+
const FALLBACK_DEFAULTS = { dataField: "description", relationType: "related_to" };
|
|
5497
5552
|
let runningBetData = { ...betData };
|
|
5498
5553
|
for (const item of captureItems) {
|
|
5499
5554
|
if (item.type === "noGo") {
|
|
@@ -5517,17 +5572,28 @@ async function processCaptures(opts) {
|
|
|
5517
5572
|
}
|
|
5518
5573
|
continue;
|
|
5519
5574
|
}
|
|
5520
|
-
const
|
|
5521
|
-
|
|
5575
|
+
const resolved = await resolveCollection({
|
|
5576
|
+
name: item.name,
|
|
5577
|
+
description: item.description,
|
|
5578
|
+
typeHint: item.type
|
|
5579
|
+
});
|
|
5580
|
+
if (!resolved) {
|
|
5581
|
+
captureErrors.push({
|
|
5582
|
+
operation: "classify",
|
|
5583
|
+
detail: `Could not resolve collection for ${item.type} "${item.name}" \u2014 skipped.`
|
|
5584
|
+
});
|
|
5585
|
+
continue;
|
|
5586
|
+
}
|
|
5587
|
+
const { dataField, relationType } = CAPTURE_DEFAULTS[resolved.collection] ?? FALLBACK_DEFAULTS;
|
|
5522
5588
|
let capturedEntryId = null;
|
|
5523
5589
|
try {
|
|
5524
5590
|
const result = await mcpMutation(
|
|
5525
5591
|
"chain.createEntry",
|
|
5526
5592
|
{
|
|
5527
|
-
collectionSlug:
|
|
5593
|
+
collectionSlug: resolved.collection,
|
|
5528
5594
|
name: item.name,
|
|
5529
5595
|
status: "draft",
|
|
5530
|
-
data: { [
|
|
5596
|
+
data: { [dataField]: item.description },
|
|
5531
5597
|
createdBy: capAgentId ? `agent:${capAgentId}` : "facilitate",
|
|
5532
5598
|
sessionId: capAgentId ?? void 0
|
|
5533
5599
|
}
|
|
@@ -5539,9 +5605,9 @@ async function processCaptures(opts) {
|
|
|
5539
5605
|
if (msg.includes("Duplicate entry") || msg.includes("already exists")) {
|
|
5540
5606
|
const fallback = await findAndLinkExisting(
|
|
5541
5607
|
item.name,
|
|
5542
|
-
|
|
5608
|
+
resolved.collection,
|
|
5543
5609
|
betEntryId,
|
|
5544
|
-
|
|
5610
|
+
relationType,
|
|
5545
5611
|
capAgentId
|
|
5546
5612
|
);
|
|
5547
5613
|
if (fallback) {
|
|
@@ -5550,7 +5616,7 @@ async function processCaptures(opts) {
|
|
|
5550
5616
|
if (fallback.linked) relationsCreated++;
|
|
5551
5617
|
captureErrors.push({
|
|
5552
5618
|
operation: "info",
|
|
5553
|
-
detail: `Linked existing ${
|
|
5619
|
+
detail: `Linked existing ${resolved.collection} entry \`${fallback.entryId}\` instead of creating duplicate.`
|
|
5554
5620
|
});
|
|
5555
5621
|
} else {
|
|
5556
5622
|
captureErrors.push({ operation: "capture", detail: `${item.type}: ${msg}` });
|
|
@@ -5564,7 +5630,7 @@ async function processCaptures(opts) {
|
|
|
5564
5630
|
await mcpMutation("chain.createEntryRelation", {
|
|
5565
5631
|
fromEntryId: capturedEntryId,
|
|
5566
5632
|
toEntryId: betEntryId,
|
|
5567
|
-
type:
|
|
5633
|
+
type: relationType,
|
|
5568
5634
|
sessionId: capAgentId ?? void 0
|
|
5569
5635
|
});
|
|
5570
5636
|
relationsCreated++;
|
|
@@ -5573,7 +5639,7 @@ async function processCaptures(opts) {
|
|
|
5573
5639
|
if (!msg.includes("already exists") && !msg.includes("Duplicate")) {
|
|
5574
5640
|
captureErrors.push({
|
|
5575
5641
|
operation: "relation",
|
|
5576
|
-
detail: `${
|
|
5642
|
+
detail: `${relationType} from ${capturedEntryId} to ${betEntryId}: ${msg}`
|
|
5577
5643
|
});
|
|
5578
5644
|
}
|
|
5579
5645
|
}
|
|
@@ -6272,7 +6338,7 @@ async function handleCommitConstellation(args) {
|
|
|
6272
6338
|
}
|
|
6273
6339
|
let contradictionWarnings = [];
|
|
6274
6340
|
try {
|
|
6275
|
-
const { runContradictionCheck } = await import("./smart-capture-
|
|
6341
|
+
const { runContradictionCheck } = await import("./smart-capture-Q64ZXK65.js");
|
|
6276
6342
|
const descField = betData.problem ?? betData.description ?? "";
|
|
6277
6343
|
contradictionWarnings = await runContradictionCheck(
|
|
6278
6344
|
betEntry.name ?? betId,
|
|
@@ -6974,13 +7040,14 @@ function buildAlignmentCheckLines(result) {
|
|
|
6974
7040
|
lines.push("");
|
|
6975
7041
|
return lines;
|
|
6976
7042
|
}
|
|
6977
|
-
var
|
|
7043
|
+
var CORE_PROTOCOL_BASE = [
|
|
6978
7044
|
'**Search before proposing.** Before suggesting new features, architecture, or changes, search the Chain: `entries action=search query="<relevant terms>"`. Build on what exists.',
|
|
6979
7045
|
"**Reference by ID.** When discussing a topic that has Chain entries, cite them by entry ID (e.g. `DEC-50`, `PRI-3`). This keeps conversations grounded in shared knowledge.",
|
|
6980
7046
|
"**Check scope.** If the proposed work doesn't fall under an active bet, stop and say so. Do not design implementation for out-of-scope work without explicit user go-ahead.",
|
|
6981
|
-
`**Capture continuously.** When a decision, tension, insight, or new term surfaces during work, capture it as a draft immediately. Don't defer to "later."
|
|
6982
|
-
"**Validate against governance.** Before proposing any solution, check it against the Workspace Governance directives below. If your proposal conflicts with a principle, standard, or business rule \u2014 stop, name the conflict, and get explicit user confirmation before proceeding."
|
|
7047
|
+
`**Capture continuously.** When a decision, tension, insight, or new term surfaces during work, capture it as a draft immediately. Don't defer to "later."`
|
|
6983
7048
|
];
|
|
7049
|
+
var RULE5_WITH_GOVERNANCE = "**Validate against governance.** Before proposing any solution, check it against the Workspace Governance directives below. If your proposal conflicts with a principle, standard, or business rule \u2014 stop, name the conflict, and get explicit user confirmation before proceeding.";
|
|
7050
|
+
var RULE5_COMPACT = '**Validate against governance.** Before proposing or building anything, call `orient task="<your task>"` to load relevant governance. If your proposal conflicts with a principle, standard, or business rule \u2014 stop, name the conflict, and get explicit user confirmation.';
|
|
6984
7051
|
var MAX_ENTRIES_NO_TASK = 3;
|
|
6985
7052
|
var MAX_ENTRIES_WITH_TASK = 5;
|
|
6986
7053
|
function extractKeywords(text) {
|
|
@@ -6997,16 +7064,18 @@ function formatGovernanceEntry(entry) {
|
|
|
6997
7064
|
}
|
|
6998
7065
|
function buildOperatingProtocol(governanceOrStandards, task) {
|
|
6999
7066
|
const governance = Array.isArray(governanceOrStandards) ? { standards: governanceOrStandards } : governanceOrStandards ?? {};
|
|
7067
|
+
const { principles = [], standards = [], businessRules = [] } = governance;
|
|
7068
|
+
const hasGovernance = principles.length > 0 || standards.length > 0 || businessRules.length > 0;
|
|
7069
|
+
const rule5 = hasGovernance ? RULE5_WITH_GOVERNANCE : RULE5_COMPACT;
|
|
7070
|
+
const protocol = [...CORE_PROTOCOL_BASE, rule5];
|
|
7000
7071
|
const lines = [
|
|
7001
7072
|
"## Operating Protocol",
|
|
7002
7073
|
"_How to work in this workspace. Follow these before and during every task._",
|
|
7003
7074
|
""
|
|
7004
7075
|
];
|
|
7005
|
-
for (let i = 0; i <
|
|
7006
|
-
lines.push(`${i + 1}. ${
|
|
7076
|
+
for (let i = 0; i < protocol.length; i++) {
|
|
7077
|
+
lines.push(`${i + 1}. ${protocol[i]}`);
|
|
7007
7078
|
}
|
|
7008
|
-
const { principles = [], standards = [], businessRules = [] } = governance;
|
|
7009
|
-
const hasGovernance = principles.length > 0 || standards.length > 0 || businessRules.length > 0;
|
|
7010
7079
|
if (hasGovernance) {
|
|
7011
7080
|
lines.push("");
|
|
7012
7081
|
lines.push("### Workspace governance directives");
|
|
@@ -7592,98 +7661,92 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
7592
7661
|
try {
|
|
7593
7662
|
const betEntries = await mcpQuery("chain.listEntries", { collectionSlug: "bets" });
|
|
7594
7663
|
activeBets = (betEntries ?? []).filter((e) => e.status === "active" && e.data?.horizon === "now").slice(0, 8);
|
|
7664
|
+
} catch {
|
|
7665
|
+
}
|
|
7666
|
+
if (task) {
|
|
7595
7667
|
if (activeBets.length > 0) {
|
|
7596
7668
|
lines.push("");
|
|
7597
7669
|
lines.push("## Active bets \u2014 current scope");
|
|
7598
|
-
lines.push("
|
|
7670
|
+
lines.push("_Work outside these bets requires explicit user confirmation._");
|
|
7599
7671
|
lines.push("");
|
|
7600
7672
|
for (const e of activeBets) {
|
|
7601
7673
|
lines.push(`- \`${e.entryId ?? e.name}\` ${e.name}`);
|
|
7602
7674
|
}
|
|
7603
7675
|
lines.push("");
|
|
7604
7676
|
}
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7677
|
+
let wsPrinciples = [];
|
|
7678
|
+
let wsStandards = [];
|
|
7679
|
+
let wsBusinessRules = [];
|
|
7680
|
+
try {
|
|
7681
|
+
for (const slug of ["principles", "standards", "business-rules"]) {
|
|
7682
|
+
const entries = await mcpQuery("chain.listEntries", { collectionSlug: slug });
|
|
7683
|
+
const active = (entries ?? []).filter((e) => e.status === "active");
|
|
7684
|
+
if (slug === "principles") wsPrinciples = active;
|
|
7685
|
+
if (slug === "standards") wsStandards = active;
|
|
7686
|
+
if (slug === "business-rules") wsBusinessRules = active;
|
|
7687
|
+
}
|
|
7688
|
+
} catch {
|
|
7689
|
+
}
|
|
7690
|
+
const mapGovEntry = (e) => ({
|
|
7691
|
+
entryId: e.entryId,
|
|
7692
|
+
name: e.name,
|
|
7693
|
+
description: typeof e.data?.description === "string" ? e.data.description : typeof e.description === "string" ? e.description : void 0
|
|
7694
|
+
});
|
|
7695
|
+
lines.push(...buildOperatingProtocol({
|
|
7696
|
+
principles: wsPrinciples.map(mapGovEntry),
|
|
7697
|
+
standards: wsStandards.map(mapGovEntry),
|
|
7698
|
+
businessRules: wsBusinessRules.map(mapGovEntry)
|
|
7699
|
+
}, task));
|
|
7700
|
+
const plannedWork = await queryPlannedWork();
|
|
7701
|
+
if (hasPlannedWork(plannedWork)) {
|
|
7702
|
+
lines.push("");
|
|
7703
|
+
lines.push(...buildPlannedWorkSection(plannedWork, priorSessions, recoveryBlock));
|
|
7704
|
+
} else if (recoveryBlock) {
|
|
7705
|
+
lines.push("");
|
|
7706
|
+
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
7707
|
+
}
|
|
7708
|
+
try {
|
|
7709
|
+
const allEntries = await mcpQuery("chain.listEntries", {});
|
|
7710
|
+
const committed = (allEntries ?? []).filter(
|
|
7711
|
+
(e) => e.status === "active" && !e.seededByPlatform
|
|
7712
|
+
);
|
|
7713
|
+
const committedCollections = new Set(committed.map((e) => e.collectionId ?? e.collection));
|
|
7714
|
+
if (committed.length >= 10 && committedCollections.size >= 3) {
|
|
7715
|
+
lines.push("");
|
|
7716
|
+
lines.push(`_${committed.length} entries across ${committedCollections.size} collections on the Chain._`);
|
|
7717
|
+
}
|
|
7718
|
+
} catch {
|
|
7617
7719
|
}
|
|
7618
|
-
} catch {
|
|
7619
|
-
}
|
|
7620
|
-
const mapGovEntry = (e) => ({
|
|
7621
|
-
entryId: e.entryId,
|
|
7622
|
-
name: e.name,
|
|
7623
|
-
description: typeof e.data?.description === "string" ? e.data.description : typeof e.description === "string" ? e.description : void 0
|
|
7624
|
-
});
|
|
7625
|
-
lines.push(...buildOperatingProtocol({
|
|
7626
|
-
principles: wsPrinciples.map(mapGovEntry),
|
|
7627
|
-
standards: wsStandards.map(mapGovEntry),
|
|
7628
|
-
businessRules: wsBusinessRules.map(mapGovEntry)
|
|
7629
|
-
}, task));
|
|
7630
|
-
const plannedWork = await queryPlannedWork();
|
|
7631
|
-
if (hasPlannedWork(plannedWork)) {
|
|
7632
7720
|
lines.push("");
|
|
7633
|
-
lines.push(
|
|
7721
|
+
lines.push(`Working on: **${task}**`);
|
|
7722
|
+
lines.push("");
|
|
7634
7723
|
} else {
|
|
7635
|
-
|
|
7724
|
+
if (activeBets.length > 0) {
|
|
7725
|
+
lines.push("");
|
|
7726
|
+
lines.push("## Active bets \u2014 current scope");
|
|
7727
|
+
lines.push("_Work outside these bets requires explicit user confirmation._");
|
|
7728
|
+
lines.push("");
|
|
7729
|
+
for (const e of activeBets) {
|
|
7730
|
+
lines.push(`- \`${e.entryId ?? e.name}\` ${e.name}`);
|
|
7731
|
+
}
|
|
7732
|
+
lines.push("");
|
|
7733
|
+
}
|
|
7734
|
+
lines.push(...buildOperatingProtocol());
|
|
7636
7735
|
if (priorSessions.length > 0 && !recoveryBlock) {
|
|
7637
7736
|
const last = priorSessions[0];
|
|
7638
|
-
const date = new Date(last.startedAt).toISOString().split("T")[0];
|
|
7737
|
+
const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
|
|
7639
7738
|
const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
|
|
7640
7739
|
const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
|
|
7641
|
-
|
|
7642
|
-
}
|
|
7643
|
-
if (readiness?.gaps?.length > 0) {
|
|
7644
|
-
briefingItems.push(`**${readiness.gaps.length} gap${readiness.gaps.length === 1 ? "" : "s"}** remaining`);
|
|
7645
|
-
}
|
|
7646
|
-
if (briefingItems.length > 0) {
|
|
7647
|
-
lines.push("");
|
|
7648
|
-
lines.push("## Briefing");
|
|
7649
|
-
for (const item of briefingItems) {
|
|
7650
|
-
lines.push(`- ${item}`);
|
|
7651
|
-
}
|
|
7740
|
+
lines.push(`_Last session (${date}): ${created} created, ${modified} modified._`);
|
|
7652
7741
|
lines.push("");
|
|
7653
7742
|
}
|
|
7654
7743
|
if (recoveryBlock) {
|
|
7655
7744
|
lines.push("");
|
|
7656
7745
|
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
7657
7746
|
}
|
|
7747
|
+
lines.push("**What are you working on?** Tell me and I'll load relevant governance and context.");
|
|
7748
|
+
lines.push("");
|
|
7658
7749
|
}
|
|
7659
|
-
try {
|
|
7660
|
-
const allEntries = await mcpQuery("chain.listEntries", {});
|
|
7661
|
-
const committed = (allEntries ?? []).filter(
|
|
7662
|
-
(e) => e.status === "active" && !e.seededByPlatform
|
|
7663
|
-
);
|
|
7664
|
-
const committedCollections = new Set(committed.map((e) => e.collectionId ?? e.collection));
|
|
7665
|
-
if (committed.length >= 10 && committedCollections.size >= 3) {
|
|
7666
|
-
lines.push("");
|
|
7667
|
-
lines.push("## Your workspace is activated");
|
|
7668
|
-
lines.push(
|
|
7669
|
-
`**${committed.length} entries** across **${committedCollections.size} collections** \u2014 your knowledge graph is alive.`
|
|
7670
|
-
);
|
|
7671
|
-
lines.push("");
|
|
7672
|
-
lines.push(
|
|
7673
|
-
`**Try it:** Ask me anything about your product \u2014 architecture, decisions, tensions \u2014 and I'll pull context from the graph.`
|
|
7674
|
-
);
|
|
7675
|
-
lines.push("");
|
|
7676
|
-
if (wsCtx.workspaceSlug) {
|
|
7677
|
-
lines.push(`**View in Studio:** \`/w/${wsCtx.workspaceSlug}/studio\``);
|
|
7678
|
-
lines.push("");
|
|
7679
|
-
}
|
|
7680
|
-
lines.push("_Tip: Ask me to suggest connections between entries to unlock deeper context._");
|
|
7681
|
-
lines.push("");
|
|
7682
|
-
}
|
|
7683
|
-
} catch {
|
|
7684
|
-
}
|
|
7685
|
-
lines.push("What would you like to work on?");
|
|
7686
|
-
lines.push("");
|
|
7687
7750
|
}
|
|
7688
7751
|
if (errors.length > 0) {
|
|
7689
7752
|
lines.push("## Errors");
|
|
@@ -9409,6 +9472,7 @@ var CALL_CATEGORIES = {
|
|
|
9409
9472
|
"chain.searchEntries": "search",
|
|
9410
9473
|
"chain.createEntry": "write",
|
|
9411
9474
|
"chain.updateEntry": "write",
|
|
9475
|
+
"chain.moveToCollection": "write",
|
|
9412
9476
|
"chain.createEntryRelation": "write",
|
|
9413
9477
|
"chain.applyLabel": "label",
|
|
9414
9478
|
"chain.removeLabel": "label",
|
|
@@ -10042,23 +10106,27 @@ function registerHealthTools(server) {
|
|
|
10042
10106
|
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
10043
10107
|
} else if (priorSessions.length > 0) {
|
|
10044
10108
|
const last = priorSessions[0];
|
|
10045
|
-
const date = new Date(last.startedAt).toISOString().split("T")[0];
|
|
10109
|
+
const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
|
|
10046
10110
|
const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
|
|
10047
10111
|
const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
|
|
10048
10112
|
lines.push(`Last session (${date}): ${created} created, ${modified} modified`);
|
|
10049
10113
|
}
|
|
10050
10114
|
if (orientEntries) {
|
|
10051
|
-
const mapGovernanceEntry = (e) => ({
|
|
10052
|
-
entryId: e.entryId,
|
|
10053
|
-
name: e.name,
|
|
10054
|
-
description: typeof e.preview === "string" ? e.preview : void 0
|
|
10055
|
-
});
|
|
10056
10115
|
lines.push("");
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10116
|
+
if (task) {
|
|
10117
|
+
const mapGovernanceEntry = (e) => ({
|
|
10118
|
+
entryId: e.entryId,
|
|
10119
|
+
name: e.name,
|
|
10120
|
+
description: typeof e.preview === "string" ? e.preview : void 0
|
|
10121
|
+
});
|
|
10122
|
+
lines.push(...buildOperatingProtocol({
|
|
10123
|
+
principles: (orientEntries.principles ?? []).map(mapGovernanceEntry),
|
|
10124
|
+
standards: (orientEntries.standards ?? []).map(mapGovernanceEntry),
|
|
10125
|
+
businessRules: (orientEntries.businessRules ?? []).map(mapGovernanceEntry)
|
|
10126
|
+
}, task));
|
|
10127
|
+
} else {
|
|
10128
|
+
lines.push(...buildOperatingProtocol());
|
|
10129
|
+
}
|
|
10062
10130
|
}
|
|
10063
10131
|
if (agentSessionId) {
|
|
10064
10132
|
try {
|
|
@@ -10118,195 +10186,164 @@ function registerHealthTools(server) {
|
|
|
10118
10186
|
lines.push("_Use `collections action=create` to add it, or ask me to propose collections for your domain._");
|
|
10119
10187
|
lines.push("");
|
|
10120
10188
|
} else if (readiness) {
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
if (sc.productAreaCount != null && sc.productAreaCount > 0) {
|
|
10129
|
-
lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
|
|
10130
|
-
}
|
|
10131
|
-
const betLine = sc.currentBet ? `**Current bet:** ${sc.currentBet}. ${sc.activeBetCount} active bet(s).` : "No active bets.";
|
|
10132
|
-
lines.push(`${betLine} ${sc.activeTensionCount} open tension(s).`);
|
|
10133
|
-
lines.push("");
|
|
10134
|
-
}
|
|
10135
|
-
if (orientEntries?.continuingFrom && orientEntries.continuingFrom.length > 0) {
|
|
10136
|
-
lines.push("## Continuing from");
|
|
10137
|
-
lines.push("_Prior-session entries most relevant to your task._");
|
|
10138
|
-
lines.push("");
|
|
10139
|
-
for (const e of orientEntries.continuingFrom) {
|
|
10140
|
-
const id = e.entryId ?? e.name;
|
|
10141
|
-
const type = e.canonicalKey ?? "generic";
|
|
10142
|
-
const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
|
|
10143
|
-
lines.push(`- \`${id}\` (score ${e.score}) [${type}]${coll} \u2014 ${e.name}`);
|
|
10144
|
-
if (e.reasoning) lines.push(` _${e.reasoning}_`);
|
|
10145
|
-
}
|
|
10146
|
-
lines.push("");
|
|
10147
|
-
}
|
|
10148
|
-
if (orientEntries?.lastSessionTouched && orientEntries.lastSessionTouched.length > 0) {
|
|
10149
|
-
lines.push("## Last session touched");
|
|
10150
|
-
lines.push("_Entries created or modified in your most recent session._");
|
|
10151
|
-
lines.push("");
|
|
10152
|
-
for (const e of orientEntries.lastSessionTouched) {
|
|
10153
|
-
const id = e.entryId ?? e.name;
|
|
10154
|
-
const type = e.canonicalKey ?? "generic";
|
|
10155
|
-
const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
|
|
10156
|
-
lines.push(`- \`${id}\` [${type}]${coll} \u2014 ${e.name}`);
|
|
10157
|
-
}
|
|
10158
|
-
lines.push("");
|
|
10159
|
-
}
|
|
10160
|
-
if (orientEntries?.taskContext && orientEntries.taskContext.context.length > 0) {
|
|
10161
|
-
const tc = orientEntries.taskContext;
|
|
10162
|
-
lines.push("## Task Context");
|
|
10163
|
-
lines.push(`_Task-scoped entries (${tc.confidence} confidence, ${tc.totalFound} relevant)`);
|
|
10189
|
+
const fmt = (e) => {
|
|
10190
|
+
const type = e.canonicalKey ?? "generic";
|
|
10191
|
+
const stratum = e.stratum ?? "?";
|
|
10192
|
+
return `- \`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}`;
|
|
10193
|
+
};
|
|
10194
|
+
if (task) {
|
|
10195
|
+
lines.push(`**Brain stage: ${orientStage}.** Working on: **${task}**`);
|
|
10164
10196
|
lines.push("");
|
|
10165
|
-
|
|
10166
|
-
const
|
|
10167
|
-
|
|
10168
|
-
|
|
10197
|
+
if (orientEntries?.strategicContext) {
|
|
10198
|
+
const sc = orientEntries.strategicContext;
|
|
10199
|
+
lines.push("## Strategic Context");
|
|
10200
|
+
if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
|
|
10201
|
+
if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
|
|
10202
|
+
if (sc.productAreaCount != null && sc.productAreaCount > 0) {
|
|
10203
|
+
lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
|
|
10204
|
+
}
|
|
10205
|
+
const betLine = sc.currentBet ? `**Current bet:** ${sc.currentBet}. ${sc.activeBetCount} active bet(s).` : "No active bets.";
|
|
10206
|
+
lines.push(`${betLine} ${sc.activeTensionCount} open tension(s).`);
|
|
10207
|
+
lines.push("");
|
|
10169
10208
|
}
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
const result = runAlignmentCheck(
|
|
10174
|
-
task,
|
|
10175
|
-
orientEntries.activeBets ?? [],
|
|
10176
|
-
orientEntries.taskContext?.context
|
|
10177
|
-
);
|
|
10178
|
-
lines.push(...buildAlignmentCheckLines(result));
|
|
10179
|
-
}
|
|
10180
|
-
if (orientEntries) {
|
|
10181
|
-
const fmt = (e) => {
|
|
10182
|
-
const type = e.canonicalKey ?? "generic";
|
|
10183
|
-
const stratum = e.stratum ?? "?";
|
|
10184
|
-
return `- \`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}`;
|
|
10185
|
-
};
|
|
10186
|
-
if (orientEntries.activeBets?.length > 0) {
|
|
10187
|
-
lines.push("## Active bets \u2014 current scope");
|
|
10188
|
-
lines.push("_These define what you're building now. Work outside these bets requires explicit user confirmation before designing._");
|
|
10209
|
+
if (orientEntries?.continuingFrom && orientEntries.continuingFrom.length > 0) {
|
|
10210
|
+
lines.push("## Continuing from");
|
|
10211
|
+
lines.push("_Prior-session entries most relevant to your task._");
|
|
10189
10212
|
lines.push("");
|
|
10190
|
-
for (const e of orientEntries.
|
|
10191
|
-
|
|
10192
|
-
const
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
return `\`${t.entryId ?? t.name}\` (${t.name}${meta ? `, ${meta}` : ""})`;
|
|
10197
|
-
});
|
|
10198
|
-
lines.push(` Tensions: ${tensionLines.join("; ")}`);
|
|
10199
|
-
} else {
|
|
10200
|
-
lines.push(` Tensions: No linked tensions`);
|
|
10201
|
-
}
|
|
10213
|
+
for (const e of orientEntries.continuingFrom) {
|
|
10214
|
+
const id = e.entryId ?? e.name;
|
|
10215
|
+
const type = e.canonicalKey ?? "generic";
|
|
10216
|
+
const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
|
|
10217
|
+
lines.push(`- \`${id}\` (score ${e.score}) [${type}]${coll} \u2014 ${e.name}`);
|
|
10218
|
+
if (e.reasoning) lines.push(` _${e.reasoning}_`);
|
|
10202
10219
|
}
|
|
10203
10220
|
lines.push("");
|
|
10204
10221
|
}
|
|
10205
|
-
if (orientEntries.
|
|
10206
|
-
lines.push("##
|
|
10207
|
-
|
|
10222
|
+
if (orientEntries?.lastSessionTouched && orientEntries.lastSessionTouched.length > 0) {
|
|
10223
|
+
lines.push("## Last session touched");
|
|
10224
|
+
lines.push("_Entries created or modified in your most recent session._");
|
|
10208
10225
|
lines.push("");
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10226
|
+
for (const e of orientEntries.lastSessionTouched) {
|
|
10227
|
+
const id = e.entryId ?? e.name;
|
|
10228
|
+
const type = e.canonicalKey ?? "generic";
|
|
10229
|
+
const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
|
|
10230
|
+
lines.push(`- \`${id}\` [${type}]${coll} \u2014 ${e.name}`);
|
|
10231
|
+
}
|
|
10213
10232
|
lines.push("");
|
|
10214
10233
|
}
|
|
10215
|
-
if (orientEntries.
|
|
10216
|
-
|
|
10217
|
-
|
|
10234
|
+
if (orientEntries?.taskContext && orientEntries.taskContext.context.length > 0) {
|
|
10235
|
+
const tc = orientEntries.taskContext;
|
|
10236
|
+
lines.push("## Task Context");
|
|
10237
|
+
lines.push(`_Task-scoped entries (${tc.confidence} confidence, ${tc.totalFound} relevant)`);
|
|
10218
10238
|
lines.push("");
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10239
|
+
for (const e of tc.context) {
|
|
10240
|
+
const id = e.entryId ?? e.name;
|
|
10241
|
+
const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
|
|
10242
|
+
lines.push(`- \`${id}\` (score ${e.score})${coll}${e.name !== id ? ` \u2014 ${e.name}` : ""}`);
|
|
10243
|
+
}
|
|
10224
10244
|
lines.push("");
|
|
10225
10245
|
}
|
|
10226
|
-
if (orientEntries
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10246
|
+
if (orientEntries) {
|
|
10247
|
+
const result = runAlignmentCheck(
|
|
10248
|
+
task,
|
|
10249
|
+
orientEntries.activeBets ?? [],
|
|
10250
|
+
orientEntries.taskContext?.context
|
|
10251
|
+
);
|
|
10252
|
+
lines.push(...buildAlignmentCheckLines(result));
|
|
10253
|
+
}
|
|
10254
|
+
if (orientEntries) {
|
|
10255
|
+
if (orientEntries.activeBets?.length > 0) {
|
|
10256
|
+
lines.push("## Active bets \u2014 current scope");
|
|
10257
|
+
lines.push("_Work outside these bets requires explicit user confirmation._");
|
|
10258
|
+
lines.push("");
|
|
10259
|
+
for (const e of orientEntries.activeBets) {
|
|
10260
|
+
lines.push(fmt(e));
|
|
10261
|
+
const tensions = e.linkedTensions;
|
|
10262
|
+
if (tensions?.length) {
|
|
10263
|
+
const tensionLines = tensions.map((t) => {
|
|
10264
|
+
const meta = [t.severity, t.priority].filter(Boolean).join(", ");
|
|
10265
|
+
return `\`${t.entryId ?? t.name}\` (${t.name}${meta ? `, ${meta}` : ""})`;
|
|
10266
|
+
});
|
|
10267
|
+
lines.push(` Tensions: ${tensionLines.join("; ")}`);
|
|
10268
|
+
}
|
|
10269
|
+
}
|
|
10270
|
+
lines.push("");
|
|
10271
|
+
}
|
|
10272
|
+
if (orientEntries.activeGoals?.length > 0) {
|
|
10273
|
+
lines.push("## Active goals");
|
|
10274
|
+
orientEntries.activeGoals.forEach((e) => lines.push(fmt(e)));
|
|
10275
|
+
lines.push("");
|
|
10276
|
+
}
|
|
10277
|
+
if (orientEntries.recentDecisions?.length > 0) {
|
|
10278
|
+
lines.push("## Recent decisions");
|
|
10279
|
+
orientEntries.recentDecisions.forEach((e) => lines.push(fmt(e)));
|
|
10280
|
+
lines.push("");
|
|
10281
|
+
}
|
|
10282
|
+
if (orientEntries.recentlySuperseded?.length > 0) {
|
|
10283
|
+
lines.push("## Recently superseded");
|
|
10284
|
+
orientEntries.recentlySuperseded.forEach((e) => lines.push(fmt(e)));
|
|
10285
|
+
lines.push("");
|
|
10286
|
+
}
|
|
10287
|
+
if (orientEntries.staleEntries?.length > 0) {
|
|
10288
|
+
lines.push("## Needs confirmation");
|
|
10289
|
+
lines.push(`_Domain stratum entries not confirmed in ${orientEntries.stalenessThresholdDays} days._`);
|
|
10290
|
+
orientEntries.staleEntries.forEach((e) => lines.push(fmt(e)));
|
|
10291
|
+
lines.push("");
|
|
10292
|
+
}
|
|
10293
|
+
if (orientEntries.architectureNotes?.length > 0) {
|
|
10294
|
+
lines.push("## Architecture notes");
|
|
10295
|
+
orientEntries.architectureNotes.forEach((e) => lines.push(fmt(e)));
|
|
10296
|
+
lines.push("");
|
|
10297
|
+
}
|
|
10298
|
+
const mapGovernanceEntry = (e) => ({
|
|
10299
|
+
entryId: e.entryId,
|
|
10300
|
+
name: e.name,
|
|
10301
|
+
description: typeof e.preview === "string" ? e.preview : void 0
|
|
10302
|
+
});
|
|
10303
|
+
lines.push(...buildOperatingProtocol({
|
|
10304
|
+
principles: (orientEntries.principles ?? []).map(mapGovernanceEntry),
|
|
10305
|
+
standards: (orientEntries.standards ?? []).map(mapGovernanceEntry),
|
|
10306
|
+
businessRules: (orientEntries.businessRules ?? []).map(mapGovernanceEntry)
|
|
10307
|
+
}, task));
|
|
10308
|
+
}
|
|
10309
|
+
let allEntries = [];
|
|
10310
|
+
try {
|
|
10311
|
+
allEntries = await mcpQuery("chain.listEntries", {}) ?? [];
|
|
10312
|
+
} catch {
|
|
10313
|
+
}
|
|
10314
|
+
const plannedWork = buildPlannedWork(allEntries);
|
|
10315
|
+
if (hasPlannedWork(plannedWork)) {
|
|
10316
|
+
lines.push(...buildPlannedWorkSection(plannedWork, priorSessions, recoveryBlock));
|
|
10317
|
+
} else if (recoveryBlock) {
|
|
10318
|
+
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
10230
10319
|
}
|
|
10231
|
-
const mapGovernanceEntry = (e) => ({
|
|
10232
|
-
entryId: e.entryId,
|
|
10233
|
-
name: e.name,
|
|
10234
|
-
description: typeof e.preview === "string" ? e.preview : void 0
|
|
10235
|
-
});
|
|
10236
|
-
lines.push(...buildOperatingProtocol({
|
|
10237
|
-
principles: (orientEntries.principles ?? []).map(mapGovernanceEntry),
|
|
10238
|
-
standards: (orientEntries.standards ?? []).map(mapGovernanceEntry),
|
|
10239
|
-
businessRules: (orientEntries.businessRules ?? []).map(mapGovernanceEntry)
|
|
10240
|
-
}, task));
|
|
10241
|
-
}
|
|
10242
|
-
let allEntries = [];
|
|
10243
|
-
try {
|
|
10244
|
-
allEntries = await mcpQuery("chain.listEntries", {}) ?? [];
|
|
10245
|
-
} catch {
|
|
10246
|
-
}
|
|
10247
|
-
const plannedWork = buildPlannedWork(allEntries);
|
|
10248
|
-
if (hasPlannedWork(plannedWork)) {
|
|
10249
|
-
lines.push(...buildPlannedWorkSection(plannedWork, priorSessions, recoveryBlock));
|
|
10250
10320
|
} else {
|
|
10251
|
-
|
|
10321
|
+
lines.push(`**Brain stage: ${orientStage}.**`);
|
|
10322
|
+
lines.push("");
|
|
10323
|
+
if (orientEntries?.activeBets?.length) {
|
|
10324
|
+
lines.push("## Active bets \u2014 current scope");
|
|
10325
|
+
lines.push("_Work outside these bets requires explicit user confirmation._");
|
|
10326
|
+
lines.push("");
|
|
10327
|
+
for (const e of orientEntries.activeBets) {
|
|
10328
|
+
lines.push(fmt(e));
|
|
10329
|
+
}
|
|
10330
|
+
lines.push("");
|
|
10331
|
+
}
|
|
10332
|
+
lines.push(...buildOperatingProtocol());
|
|
10252
10333
|
if (priorSessions.length > 0 && !recoveryBlock) {
|
|
10253
10334
|
const last = priorSessions[0];
|
|
10254
|
-
const date = new Date(last.startedAt).toISOString().split("T")[0];
|
|
10335
|
+
const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
|
|
10255
10336
|
const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
|
|
10256
10337
|
const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
|
|
10257
|
-
|
|
10258
|
-
}
|
|
10259
|
-
if (readiness.gaps?.length > 0) {
|
|
10260
|
-
briefingItems.push(`**${readiness.gaps.length} gap${readiness.gaps.length === 1 ? "" : "s"}** remaining`);
|
|
10261
|
-
}
|
|
10262
|
-
if (briefingItems.length > 0) {
|
|
10263
|
-
lines.push("## Briefing");
|
|
10264
|
-
for (const item of briefingItems) {
|
|
10265
|
-
lines.push(`- ${item}`);
|
|
10266
|
-
}
|
|
10338
|
+
lines.push(`_Last session (${date}): ${created} created, ${modified} modified._`);
|
|
10267
10339
|
lines.push("");
|
|
10268
10340
|
}
|
|
10269
10341
|
if (recoveryBlock) {
|
|
10270
|
-
lines.push("");
|
|
10271
10342
|
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
10272
10343
|
}
|
|
10273
|
-
|
|
10274
|
-
const activeEntries = allEntries.filter((e) => e.status === "active");
|
|
10275
|
-
if (activeEntries.length > 0) {
|
|
10276
|
-
const orgHealth = computeOrganisationHealth(activeEntries);
|
|
10277
|
-
if (orgHealth.disagreements > 0) {
|
|
10278
|
-
lines.push("## Organisation Health");
|
|
10279
|
-
lines.push(...formatOrgHealthLines(orgHealth, 3));
|
|
10280
|
-
lines.push("");
|
|
10281
|
-
}
|
|
10282
|
-
}
|
|
10283
|
-
const epistemicEntries = activeEntries.filter(
|
|
10284
|
-
(e) => e.collectionSlug === "insights" || e.collectionSlug === "assumptions"
|
|
10285
|
-
);
|
|
10286
|
-
if (epistemicEntries.length > 0) {
|
|
10287
|
-
let validated = 0;
|
|
10288
|
-
let evidenced = 0;
|
|
10289
|
-
let hypotheses = 0;
|
|
10290
|
-
let untested = 0;
|
|
10291
|
-
for (const e of epistemicEntries) {
|
|
10292
|
-
const ws = e.workflowStatus;
|
|
10293
|
-
if (ws === "validated") validated++;
|
|
10294
|
-
else if (ws === "evidenced") evidenced++;
|
|
10295
|
-
else if (ws === "testing") evidenced++;
|
|
10296
|
-
else if (ws === "invalidated") validated++;
|
|
10297
|
-
else if (e.collectionSlug === "assumptions") untested++;
|
|
10298
|
-
else hypotheses++;
|
|
10299
|
-
}
|
|
10300
|
-
const parts = [];
|
|
10301
|
-
if (validated > 0) parts.push(`${validated} validated`);
|
|
10302
|
-
if (evidenced > 0) parts.push(`${evidenced} evidenced`);
|
|
10303
|
-
if (hypotheses > 0) parts.push(`${hypotheses} hypotheses`);
|
|
10304
|
-
if (untested > 0) parts.push(`${untested} untested`);
|
|
10305
|
-
lines.push(`**Epistemic health:** ${parts.join(" \xB7 ")} _(${epistemicEntries.length} claim-carrying entries)_`);
|
|
10344
|
+
lines.push("**What are you working on?** Tell me and I'll load relevant governance and context.");
|
|
10306
10345
|
lines.push("");
|
|
10307
10346
|
}
|
|
10308
|
-
lines.push("What would you like to work on?");
|
|
10309
|
-
lines.push("");
|
|
10310
10347
|
}
|
|
10311
10348
|
if (errors.length > 0) {
|
|
10312
10349
|
lines.push("## Errors");
|
|
@@ -11704,4 +11741,4 @@ export {
|
|
|
11704
11741
|
SERVER_VERSION,
|
|
11705
11742
|
createProductBrainServer
|
|
11706
11743
|
};
|
|
11707
|
-
//# sourceMappingURL=chunk-
|
|
11744
|
+
//# sourceMappingURL=chunk-YARRUQBW.js.map
|