@productbrain/mcp 0.0.1-beta.9562 → 0.0.1-beta.9574
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-QJ6KOXG6.js → chunk-O6HEYDXJ.js} +64 -64
- package/dist/chunk-O6HEYDXJ.js.map +1 -0
- package/dist/{chunk-J2ZAJCHH.js → chunk-WD2HD54Z.js} +3 -3
- package/dist/{chunk-J2ZAJCHH.js.map → chunk-WD2HD54Z.js.map} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{setup-5E7IYWVN.js → setup-5RIC5CZM.js} +3 -3
- package/dist/{setup-5E7IYWVN.js.map → setup-5RIC5CZM.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-QJ6KOXG6.js.map +0 -1
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
trackQualityVerdict,
|
|
44
44
|
trackSessionCaptureRate,
|
|
45
45
|
trackZeroCaptureAuditFired
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-WD2HD54Z.js";
|
|
47
47
|
|
|
48
48
|
// src/server.ts
|
|
49
49
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -101,8 +101,8 @@ function notFound(id, hint) {
|
|
|
101
101
|
return failure(
|
|
102
102
|
"NOT_FOUND",
|
|
103
103
|
`Entry '${id}' not found.`,
|
|
104
|
-
hint ?? "Use
|
|
105
|
-
[{ tool: "
|
|
104
|
+
hint ?? "Use context action=search to find the correct ID.",
|
|
105
|
+
[{ tool: "context", description: "Search entries", parameters: { action: "search", query: id } }]
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
function validationError(message) {
|
|
@@ -392,7 +392,7 @@ var TOOL_NAME_MIGRATIONS = /* @__PURE__ */ new Map([
|
|
|
392
392
|
["list-entries", 'context action="list"'],
|
|
393
393
|
["get-entry", 'context action="get"'],
|
|
394
394
|
["batch-get", 'context action="batch"'],
|
|
395
|
-
["search", '
|
|
395
|
+
["search", 'context action="search"'],
|
|
396
396
|
["relate-entries", 'relations action="create"'],
|
|
397
397
|
["batch-relate", 'relations action="batch-create"'],
|
|
398
398
|
["find-related", 'relations action="find"'],
|
|
@@ -639,7 +639,7 @@ ${msg}
|
|
|
639
639
|
"CAPTURE_OUTCOME_UNKNOWN",
|
|
640
640
|
msg,
|
|
641
641
|
recovery,
|
|
642
|
-
[{ tool: "
|
|
642
|
+
[{ tool: "context", description: "Search for the entry before retrying", parameters: { action: "search", query: name } }],
|
|
643
643
|
{
|
|
644
644
|
// Structured so a caller can branch on this without parsing prose — the
|
|
645
645
|
// reconciliation signal TEN-1126 says the capture path never had.
|
|
@@ -2001,7 +2001,7 @@ Use \`context action=get\` to inspect the existing entry, or \`entries action=up
|
|
|
2001
2001
|
if (isBetOrGoal && !hasStrategyLink) {
|
|
2002
2002
|
lines.push("");
|
|
2003
2003
|
lines.push(
|
|
2004
|
-
`**Strategy link:** This ${isWorkPackageOrBetCapture ? "work package" : "goal"} doesn't connect to any strategy entry. Consider linking before accepting. Find one with \`
|
|
2004
|
+
`**Strategy link:** This ${isWorkPackageOrBetCapture ? "work package" : "goal"} doesn't connect to any strategy entry. Consider linking before accepting. Find one with \`context action=search\` and link it with \`relations action=create\`.`
|
|
2005
2005
|
);
|
|
2006
2006
|
await recordSessionActivity({ strategyLinkWarnedForEntryId: internalId });
|
|
2007
2007
|
}
|
|
@@ -2025,13 +2025,13 @@ Use \`context action=get\` to inspect the existing entry, or \`entries action=up
|
|
|
2025
2025
|
lines.push("## Next Steps");
|
|
2026
2026
|
const eid = finalEntryId || "(check entry ID)";
|
|
2027
2027
|
if (finalStatus === "committed") {
|
|
2028
|
-
lines.push(`1. **Connect it:** find related entries with \`
|
|
2028
|
+
lines.push(`1. **Connect it:** find related entries with \`context action=search\`, then \`relations action=create from="${eid}" to="<ID>" type="<verb>"\``);
|
|
2029
2029
|
if (hasQualityGaps) {
|
|
2030
2030
|
lines.push(`2. **Improve quality:** \`entries action=update entryId="${eid}"\` \u2014 fill missing fields`);
|
|
2031
2031
|
}
|
|
2032
2032
|
} else {
|
|
2033
2033
|
if (userLinkResults.length === 0) {
|
|
2034
|
-
lines.push(`1. **Connect it:** find related entries with \`
|
|
2034
|
+
lines.push(`1. **Connect it:** find related entries with \`context action=search\`, then \`relations action=create from="${eid}" to="<ID>" type="<verb>"\``);
|
|
2035
2035
|
}
|
|
2036
2036
|
lines.push(`${userLinkResults.length === 0 ? "2" : "1"}. **Review the possibility:** Keep this visible draft while it is an alternative. Accept only when commitment is intended and your role is authorized. Types reserved for human acceptance require human ratification. An audit advisory is not a reason to accept it.`);
|
|
2037
2037
|
if (hasQualityGaps) {
|
|
@@ -3145,7 +3145,7 @@ ${recovery}`,
|
|
|
3145
3145
|
"MOVE_FAILED",
|
|
3146
3146
|
msg,
|
|
3147
3147
|
"Check the entry ID and target collection slug, then retry.",
|
|
3148
|
-
[{ tool: "
|
|
3148
|
+
[{ tool: "context", description: "Search for entry", parameters: { action: "search", query: entryId } }]
|
|
3149
3149
|
);
|
|
3150
3150
|
}
|
|
3151
3151
|
}
|
|
@@ -3182,7 +3182,6 @@ function platformGlossarySearch(query, collection, status2) {
|
|
|
3182
3182
|
// src/tools/entriesContract.ts
|
|
3183
3183
|
import { z as z10 } from "zod/v3";
|
|
3184
3184
|
var ENTRIES_ACTIONS = [
|
|
3185
|
-
"search",
|
|
3186
3185
|
"update",
|
|
3187
3186
|
"commit",
|
|
3188
3187
|
"move",
|
|
@@ -3190,7 +3189,6 @@ var ENTRIES_ACTIONS = [
|
|
|
3190
3189
|
"preflight",
|
|
3191
3190
|
"still-true"
|
|
3192
3191
|
];
|
|
3193
|
-
var entriesStatusFilterSchema = z10.union([z10.string().max(200), z10.array(z10.enum(ENTRY_STATUS_READ_WORDS)).max(5)]);
|
|
3194
3192
|
var coherencyAcknowledgementFlatSchema = z10.object({
|
|
3195
3193
|
response: z10.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
|
|
3196
3194
|
entryId: z10.string().max(200).optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
|
|
@@ -3200,16 +3198,15 @@ var preflightLinks = z10.array(z10.object({ type: z10.string().max(200), entryId
|
|
|
3200
3198
|
var entriesSchema = z10.object({
|
|
3201
3199
|
links: preflightLinks.describe("For preflight: proposed context links; saves nothing."),
|
|
3202
3200
|
action: z10.enum(ENTRIES_ACTIONS).describe(
|
|
3203
|
-
"'preflight': inspect structural requirements before composing (requires collection). '
|
|
3201
|
+
"'preflight': inspect structural requirements before composing (requires collection). 'update': change fields on an existing entry (draft by default). 'commit': accept a draft entry onto the Chain. 'move': relocate an entry to a different collection (pass `canonicalKey` too for an atomic move+retype). 'verify': mark an entry as verified (lightweight \u2014 no codebase scan; see `quality action=verify-chain` for that). 'still-true': confirm accuracy (the holder of the owning role, else the nearest seated Team Lead) \u2014 distinct from 'verify'; no content, version, or updatedAt change."
|
|
3204
3202
|
),
|
|
3205
3203
|
entryId: z10.string().max(200).optional().describe(
|
|
3206
3204
|
"Entry ID, e.g. '<PREFIX>-<n>'. Required for: update, commit, move, verify, still-true."
|
|
3207
3205
|
),
|
|
3208
|
-
collection: z10.string().max(200).optional().describe("
|
|
3209
|
-
status:
|
|
3210
|
-
|
|
3206
|
+
collection: z10.string().max(200).optional().describe("For 'preflight': the collection slug the entry would be composed into (required)."),
|
|
3207
|
+
status: z10.string().max(200).optional().describe(
|
|
3208
|
+
"For 'update': draft|archived ONLY \u2014 'accepted' is set via 'commit', never 'update'; 'active'/'deprecated' are legacy read-only words, refused on write. Workflow values use `workflowStatus` instead."
|
|
3211
3209
|
),
|
|
3212
|
-
query: z10.string().min(2).max(500).optional().describe("For 'search': search text (min 2 characters)."),
|
|
3213
3210
|
name: z10.string().max(ENTRY_NAME_MAX_CHARS).optional().describe("For 'update': new display name."),
|
|
3214
3211
|
workflowStatus: z10.string().max(200).optional().describe(
|
|
3215
3212
|
"For 'update': collection workflow state. Valid values are collection-specific and server-owned \u2014 discover via `collections action=describe`. Invalid values are rejected with the valid set."
|
|
@@ -3246,13 +3243,6 @@ var entriesSchema = z10.object({
|
|
|
3246
3243
|
),
|
|
3247
3244
|
toCollection: z10.string().max(200).optional().describe("For 'move': target collection slug, e.g. 'decisions', 'architecture'.")
|
|
3248
3245
|
});
|
|
3249
|
-
var entriesSearchVariant = z10.object({
|
|
3250
|
-
action: z10.literal("search"),
|
|
3251
|
-
query: z10.string().min(2).max(500),
|
|
3252
|
-
collection: z10.string().max(200).optional(),
|
|
3253
|
-
status: entriesStatusFilterSchema.optional()
|
|
3254
|
-
// PR #660 R1 Zqh1K: string|array.
|
|
3255
|
-
});
|
|
3256
3246
|
var entriesUpdateVariant = updateEntrySchema.extend({ action: z10.literal("update") });
|
|
3257
3247
|
var entriesCommitVariant = commitEntrySchema.extend({ action: z10.literal("commit") });
|
|
3258
3248
|
var entriesMoveVariant = z10.object({
|
|
@@ -3266,7 +3256,6 @@ var entriesVerifyVariant = verifyEntrySchema.extend({ action: z10.literal("verif
|
|
|
3266
3256
|
var entriesStillTrueVariant = stillTrueEntrySchema.extend({ action: z10.literal("still-true") });
|
|
3267
3257
|
var entriesActionUnion = z10.discriminatedUnion("action", [
|
|
3268
3258
|
z10.object({ action: z10.literal("preflight"), collection: z10.string().max(200), canonicalKey: z10.string().max(200).optional(), links: preflightLinks }),
|
|
3269
|
-
entriesSearchVariant,
|
|
3270
3259
|
entriesUpdateVariant,
|
|
3271
3260
|
entriesCommitVariant,
|
|
3272
3261
|
entriesMoveVariant,
|
|
@@ -3275,7 +3264,6 @@ var entriesActionUnion = z10.discriminatedUnion("action", [
|
|
|
3275
3264
|
]);
|
|
3276
3265
|
var ENTRIES_ACTION_SPECS = {
|
|
3277
3266
|
preflight: { params: ["collection", "canonicalKey", "links"], description: "Inspect structure before composition; no writes or permission grant." },
|
|
3278
|
-
search: { params: ["query", "collection", "status"], description: "Full-text search; query is required (min 2 chars)." },
|
|
3279
3267
|
update: { params: ["entryId", "name", "status", "workflowStatus", "data", "order", "canonicalKey", "autoPublish", "changeNote", "changeReason", "sourceRef", "sourceExcerpt", "steeringOverrideReason", "coherencyAcknowledgement"], description: "entryId is required; every other field is optional." },
|
|
3280
3268
|
commit: { params: ["entryId", "preview", "steeringOverrideReason", "coherencyAcknowledgement"], description: "entryId is required." },
|
|
3281
3269
|
move: { params: ["entryId", "toCollection", "canonicalKey"], description: "entryId and toCollection are required; canonicalKey is optional (atomic move+retype)." },
|
|
@@ -3429,7 +3417,6 @@ function registerEntriesTools(server) {
|
|
|
3429
3417
|
const result2 = await kernelQuery("chain.preflightEntry", { collectionSlug: data.collection, canonicalKey: data.canonicalKey, links: data.links });
|
|
3430
3418
|
return { content: [{ type: "text", text: renderEntryPreflight(result2).join("\n") }], structuredContent: success("Structural requirements checked; nothing saved.", result2) };
|
|
3431
3419
|
},
|
|
3432
|
-
search: (data) => handleSearch(server, data.query, data.collection, data.status),
|
|
3433
3420
|
// update/commit reuse knowledge.ts's extracted handlers — "entries" routes
|
|
3434
3421
|
// `next` at itself (toolName="entries") instead of the legacy tool names.
|
|
3435
3422
|
update: (data) => handleUpdateEntry(data, "entries"),
|
|
@@ -3442,10 +3429,10 @@ function registerEntriesTools(server) {
|
|
|
3442
3429
|
"entries",
|
|
3443
3430
|
{
|
|
3444
3431
|
title: "Entries",
|
|
3445
|
-
description: '
|
|
3432
|
+
description: 'Write entries on the Chain: the entry lifecycle after capture. Reads live on `context`.\n\n- **preflight**: Inspect a type and selected context before composing. No writes, capacity reservation or authority grant.\n- **update**: Change fields on an existing entry (publishes whenever the entry is not draft \u2014 includes archived, not just accepted/active; autoPublish is accepted but ignored).\n- **commit**: Accept a draft entry onto the Chain (SSOT). Runs the contradiction preflight first.\n- **move**: Relocate an entry to a different collection; pass canonicalKey too for an atomic move+retype.\n- **verify**: Mark verified (lightweight, no scan \u2014 see `quality action=verify-chain`).\n- **still-true**: confirm accuracy (the holder of the owning role; if that role is empty, the nearest seated Team Lead up the team tree).\n\nRead entries with the read-only `context` tool: `context action=get entryId="..."`, `context action=search query="..."`.',
|
|
3446
3433
|
inputSchema: entriesSchema,
|
|
3447
|
-
//
|
|
3448
|
-
//
|
|
3434
|
+
// DEC-1894 / DEC-74: every look-up lives on the read-only `context` tool, so this
|
|
3435
|
+
// annotation tells hosts the truth about the writes left here.
|
|
3449
3436
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }
|
|
3450
3437
|
},
|
|
3451
3438
|
thinWrapper(async (args) => {
|
|
@@ -3728,9 +3715,9 @@ async function handleSearch(server, query, collection, status2) {
|
|
|
3728
3715
|
const platform = platformGlossarySearch(query, collection, status2);
|
|
3729
3716
|
const matches = results.length + platform.count;
|
|
3730
3717
|
if (matches === 0) {
|
|
3731
|
-
const recorded = recordGap({ query, tool: "
|
|
3718
|
+
const recorded = recordGap({ query, tool: "context", action: "search", gapType: "search_zero", collectionScope: collection });
|
|
3732
3719
|
if (recorded) {
|
|
3733
|
-
getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query, tool: "
|
|
3720
|
+
getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query, tool: "context", action: "search", gap_type: "search_zero", collection_scope: collection })).catch(() => {
|
|
3734
3721
|
});
|
|
3735
3722
|
}
|
|
3736
3723
|
return {
|
|
@@ -3742,7 +3729,7 @@ async function handleSearch(server, query, collection, status2) {
|
|
|
3742
3729
|
`'${query}' is not yet on the Chain${scope}.`,
|
|
3743
3730
|
{ entries: [], total: 0, query },
|
|
3744
3731
|
[
|
|
3745
|
-
{ tool: "
|
|
3732
|
+
{ tool: "context", description: "Try a broader search", parameters: { action: "search", query: query.split(" ")[0] } },
|
|
3746
3733
|
{ tool: "collections", description: "Browse available collections", parameters: { action: "list" } }
|
|
3747
3734
|
]
|
|
3748
3735
|
)
|
|
@@ -3842,7 +3829,7 @@ async function handleFind(entryId, direction) {
|
|
|
3842
3829
|
}
|
|
3843
3830
|
const sourceEntry = await kernelQuery("chain.getEntry", { entryId });
|
|
3844
3831
|
if (!sourceEntry) {
|
|
3845
|
-
return notFoundResult(entryId, `Entry '${entryId}' not found. Try
|
|
3832
|
+
return notFoundResult(entryId, `Entry '${entryId}' not found. Try context action=search to find the right ID.`);
|
|
3846
3833
|
}
|
|
3847
3834
|
const sourceInternalId = sourceEntry._id;
|
|
3848
3835
|
const MAX_RELATIONS = 25;
|
|
@@ -3989,7 +3976,7 @@ function registerRelationsTools(server) {
|
|
|
3989
3976
|
"relations",
|
|
3990
3977
|
{
|
|
3991
3978
|
title: "Relations",
|
|
3992
|
-
description: "Create, manage, and read relations between entries. A relation is written only when you ask for it, with exactly the verb you send.\n\n- **create**: Link two entries with a typed relation.\n- **batch-create**: Create multiple relations in one call (validates every item before writing any).\n- **delete**: Remove a relation by from, to, and type.\n- **find**: Traverse relations from a specific entry \u2014 shows incoming/outgoing connections. NOT full-text search (use
|
|
3979
|
+
description: "Create, manage, and read relations between entries. A relation is written only when you ask for it, with exactly the verb you send.\n\n- **create**: Link two entries with a typed relation.\n- **batch-create**: Create multiple relations in one call (validates every item before writing any).\n- **delete**: Remove a relation by from, to, and type.\n- **find**: Traverse relations from a specific entry \u2014 shows incoming/outgoing connections. NOT full-text search (use context action=search).",
|
|
3993
3980
|
inputSchema: relationsSchema,
|
|
3994
3981
|
// Mixed read/write noun (§3 R3): find is read-only, create/batch-create/delete write.
|
|
3995
3982
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
@@ -4273,14 +4260,16 @@ This row pre-dates snapshot capture (legacy backfill), so no summary is availabl
|
|
|
4273
4260
|
|
|
4274
4261
|
// src/tools/contextLookups.ts
|
|
4275
4262
|
import { z as z15 } from "zod/v3";
|
|
4276
|
-
var
|
|
4277
|
-
var
|
|
4263
|
+
var statusFilterSchema = z15.union([z15.string().max(200), z15.array(z15.enum(ENTRY_STATUS_READ_WORDS)).max(5)]);
|
|
4264
|
+
var LOOKUP_ACTION_DESCRIBE = "'get': one entry in full by ID. 'batch': up to 20 entries by ID. 'history': audit trail for an entry. 'list': browse entries with filters (accepted by default). 'search': full-text search across entries. ";
|
|
4265
|
+
var LOOKUP_TOOL_LINES = "- **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- **history**: Audit trail for an entry.\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n";
|
|
4278
4266
|
var lookupParams = {
|
|
4279
4267
|
entryIds: z15.array(z15.string().max(200)).min(1).max(20).optional().describe("For 'batch': entry IDs, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
|
|
4280
|
-
collection: z15.string().max(200).optional().describe("For 'list': collection slug, e.g. 'glossary', 'tracking-events'."),
|
|
4268
|
+
collection: z15.string().max(200).optional().describe("For 'list'/'search': collection slug, e.g. 'glossary', 'tracking-events'."),
|
|
4269
|
+
query: z15.string().min(2).max(500).optional().describe("For 'search': search text (min 2 characters)."),
|
|
4281
4270
|
// 'active'/'accepted'/'current' are the same trust level (DEC-1575/DEC-1788) — all enumerated, never one substituted.
|
|
4282
|
-
status:
|
|
4283
|
-
`For 'list': defaults to accepted entries (active/accepted/current); use status='draft' to discover drafts. One lifecycle or category value (${ENTRY_STATUS_READ_WORDS.join("|")}).`
|
|
4271
|
+
status: statusFilterSchema.optional().describe(
|
|
4272
|
+
`For 'list': defaults to accepted entries (active/accepted/current); use status='draft' to discover drafts. One lifecycle or category value (${ENTRY_STATUS_READ_WORDS.join("|")}). For 'search': one value OR an array of up to 5 (e.g. ['active','accepted']).`
|
|
4284
4273
|
),
|
|
4285
4274
|
tag: z15.string().max(200).optional().describe("For 'list': filter by internal tag."),
|
|
4286
4275
|
label: z15.string().max(200).optional().describe("For 'list': filter by label slug \u2014 matches entries across all collections.")
|
|
@@ -4293,23 +4282,34 @@ var lookupVariants = [
|
|
|
4293
4282
|
action: z15.literal("list"),
|
|
4294
4283
|
collection: z15.string().max(200).optional(),
|
|
4295
4284
|
status: z15.string().max(200).optional(),
|
|
4296
|
-
// one status word
|
|
4285
|
+
// one status word; the flat union serves search
|
|
4297
4286
|
tag: z15.string().max(200).optional(),
|
|
4298
4287
|
label: z15.string().max(200).optional()
|
|
4288
|
+
}),
|
|
4289
|
+
z15.object({
|
|
4290
|
+
action: z15.literal("search"),
|
|
4291
|
+
query: z15.string().min(2).max(500),
|
|
4292
|
+
collection: z15.string().max(200).optional(),
|
|
4293
|
+
status: statusFilterSchema.optional()
|
|
4299
4294
|
})
|
|
4300
4295
|
];
|
|
4301
4296
|
var LOOKUP_ACTION_SPECS = {
|
|
4302
4297
|
get: { params: ["entryId"], description: "entryId is required." },
|
|
4303
4298
|
batch: { params: ["entryIds"], description: "entryIds (1-20) is required." },
|
|
4304
4299
|
history: { params: ["entryId"], description: "entryId is required." },
|
|
4305
|
-
list: { params: ["collection", "status", "tag", "label"], description: "Browse accepted entries by default; status='draft' lists drafts. All params optional." }
|
|
4306
|
-
}
|
|
4307
|
-
var lookupHandlers = {
|
|
4308
|
-
get: (data) => handleGet(data.entryId),
|
|
4309
|
-
batch: (data) => handleBatch(data.entryIds),
|
|
4310
|
-
history: (data) => handleGetHistory(data),
|
|
4311
|
-
list: (data) => handleList(data.collection, data.status, data.tag, data.label)
|
|
4300
|
+
list: { params: ["collection", "status", "tag", "label"], description: "Browse accepted entries by default; status='draft' lists drafts; status is one word. All params optional." },
|
|
4301
|
+
search: { params: ["query", "collection", "status"], description: "Full-text search; query is required (min 2 chars)." }
|
|
4312
4302
|
};
|
|
4303
|
+
function lookupHandlers(server) {
|
|
4304
|
+
return {
|
|
4305
|
+
get: (data) => handleGet(data.entryId),
|
|
4306
|
+
batch: (data) => handleBatch(data.entryIds),
|
|
4307
|
+
history: (data) => handleGetHistory(data),
|
|
4308
|
+
list: (data) => handleList(data.collection, data.status, data.tag, data.label),
|
|
4309
|
+
search: (data) => handleSearch(server, data.query, data.collection, data.status)
|
|
4310
|
+
// logs progress to the client
|
|
4311
|
+
};
|
|
4312
|
+
}
|
|
4313
4313
|
|
|
4314
4314
|
// src/tools/context.ts
|
|
4315
4315
|
function annotateStaleNames(text) {
|
|
@@ -4322,7 +4322,7 @@ function epistemicCollectionHint(collectionName) {
|
|
|
4322
4322
|
if (lc === "assumptions") return " \u2014 _check evidence strength with `context action=get`_";
|
|
4323
4323
|
return "";
|
|
4324
4324
|
}
|
|
4325
|
-
var CONTEXT_ACTIONS = ["get", "batch", "history", "list", "gather", "build", "neighborhood", "changes", "chain", "cross-cut", "incremental", "brief", "last-verified-brief"];
|
|
4325
|
+
var CONTEXT_ACTIONS = ["get", "batch", "history", "list", "search", "gather", "build", "neighborhood", "changes", "chain", "cross-cut", "incremental", "brief", "last-verified-brief"];
|
|
4326
4326
|
var contextSchema = z16.object({
|
|
4327
4327
|
// provenance: neighborhood BET-142; changes/chain/cross-cut/incremental/brief BET-239 (E4, E6)
|
|
4328
4328
|
action: z16.enum(CONTEXT_ACTIONS).describe(
|
|
@@ -4432,7 +4432,7 @@ var CONTEXT_ACTION_SPECS = {
|
|
|
4432
4432
|
};
|
|
4433
4433
|
function registerContextTools(server) {
|
|
4434
4434
|
const contextHandlers = {
|
|
4435
|
-
...lookupHandlers,
|
|
4435
|
+
...lookupHandlers(server),
|
|
4436
4436
|
gather: (data) => data.mapEntryId ? handleJourneyGather(server, data.mapEntryId, data.maxHops ?? 2, data.maxResults ?? 20) : handleGather(server, data.entryId, data.task, data.mode ?? "search", data.maxHops ?? 2, data.maxResults ?? 10, data.strategy ?? "keyword"),
|
|
4437
4437
|
build: (data) => handleBuild(server, data.entryId, data.maxHops ?? 2),
|
|
4438
4438
|
neighborhood: (data) => handleNeighborhood(data.entryId),
|
|
@@ -4600,7 +4600,7 @@ _This helps future sessions start with better constraints and context._`
|
|
|
4600
4600
|
"NOT_FOUND",
|
|
4601
4601
|
"No task-relevant governance or supporting context was found yet.",
|
|
4602
4602
|
"If you discover relevant knowledge during this task, capture it with a name and description.",
|
|
4603
|
-
[{ tool: "
|
|
4603
|
+
[{ tool: "context", description: "Search for related terms", parameters: { action: "search", query: task.split(" ").slice(0, 3).join(" ") } }]
|
|
4604
4604
|
)
|
|
4605
4605
|
};
|
|
4606
4606
|
}
|
|
@@ -6567,7 +6567,7 @@ function buildTaskAlignmentLines(ta) {
|
|
|
6567
6567
|
return lines;
|
|
6568
6568
|
}
|
|
6569
6569
|
var CORE_PROTOCOL_BASE = [
|
|
6570
|
-
'**Search before proposing.** Before suggesting new features, architecture, or changes, search the Chain: `
|
|
6570
|
+
'**Search before proposing.** Before suggesting new features, architecture, or changes, search the Chain: `context action=search query="<relevant terms>"`. Build on what exists.',
|
|
6571
6571
|
"**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.",
|
|
6572
6572
|
"**Check scope.** If the proposed work doesn't fall under an active work package, stop and say so. Do not design implementation for out-of-scope work without explicit user go-ahead.",
|
|
6573
6573
|
`**Capture continuously.** When a decision, tension, insight, or new term surfaces during work, capture it as a draft immediately. Don't defer to "later."`
|
|
@@ -6798,7 +6798,7 @@ var WORKING_WITH_PEOPLE_LINES = [
|
|
|
6798
6798
|
var TITLES_LINE = "These are titles: read an entry in full before you explain or judge it.";
|
|
6799
6799
|
var BRIEFING_PULL_COMMANDS = {
|
|
6800
6800
|
cli: 'pb orient --task "<what you are doing>" \xB7 pb get <ID> \xB7 pb search <query>',
|
|
6801
|
-
mcp: 'orient task="<what you are doing>" \xB7 context action=get entryId=<ID> \xB7
|
|
6801
|
+
mcp: 'orient task="<what you are doing>" \xB7 context action=get entryId=<ID> \xB7 context action=search query=<query>'
|
|
6802
6802
|
};
|
|
6803
6803
|
var BRIEFING_ANSWER_COMMANDS = {
|
|
6804
6804
|
cli: 'pb question answer <ID> "<answer>"',
|
|
@@ -8481,7 +8481,7 @@ Use \`workflows action=checkpoint\` after each round to persist progress to the
|
|
|
8481
8481
|
label: "Gather Context",
|
|
8482
8482
|
type: "open",
|
|
8483
8483
|
instruction: "Before shaping, let's see what the Chain already knows. Search for related entries, business rules, and existing decisions.",
|
|
8484
|
-
facilitatorGuidance: "**Investigate proactively.** Spawn sub-agents in parallel: (1) `explore` agent to search the codebase for code related to the work package topic \u2014 find modules, patterns, and pain points. (2) `generalPurpose` agent to search the Chain: call `orient`, use `
|
|
8484
|
+
facilitatorGuidance: "**Investigate proactively.** Spawn sub-agents in parallel: (1) `explore` agent to search the codebase for code related to the work package topic \u2014 find modules, patterns, and pain points. (2) `generalPurpose` agent to search the Chain: call `orient`, use `context action=search` with keywords, surface related tensions, active work packages, and applicable business rules. Synthesize both into a 3-5 line context brief: what the codebase reveals, what the Chain knows, what governance applies. Present with IDs and file paths. Build a system map: what modules, data flows, and contracts exist in this area today? Check governance: do any principles, standards, or business rules constrain this design space? Then transition: 'Here's what I found. Does this match the problem you're seeing?'",
|
|
8485
8485
|
outputSchema: {
|
|
8486
8486
|
field: "context",
|
|
8487
8487
|
description: "System map, Chain context, governance constraints, related entries",
|
|
@@ -8669,7 +8669,7 @@ var IMPLEMENTATION_REVIEW_WORKFLOW_DESCRIPTOR = {
|
|
|
8669
8669
|
1. **Tool-heavy, not chat-heavy.** Each round calls specific tools: orient, quality, verify, context action=gather, review-against-rules. Use Context7 **CLI** (\`npx ctx7 library\` then \`npx ctx7 docs\` \u2014 project-local after \`npm install\`; avoid cold \`npx ctx7@latest\` in short-timeout shells) for relevant testing and framework docs \u2014 not for Chain truth. Do not use Context7 MCP.
|
|
8670
8670
|
2. **Spawn sub-agents** for parallel review: (a) code/architecture review, (b) test honesty (did we edit tests to pass or do they validate real behavior?). Max 2 agents in parallel, 30s budget each. **Constrain each sub-agent to the stated review scope only.**
|
|
8671
8671
|
3. **Fix-as-you-go (FEAT-172).** When you find a HIGH or MEDIUM issue: fix it immediately, verify (lints, types), then proceed. The user sees clean work, not a list of issues. Only defer if estimated >5 min \u2014 capture deferred items as tensions. If user says "skip", capture as tension and continue.
|
|
8672
|
-
4. **Chain is SSOT.** Call orient or start first. Use
|
|
8672
|
+
4. **Chain is SSOT.** Call orient or start first. Use context action=search and context action=gather to load relevant BETs, DECs, BRs. If findings conflict with Chain entries, report the conflict and cite the entry ID.
|
|
8673
8673
|
5. **One round at a time.** Complete each round before moving to the next. Checkpoint progress.
|
|
8674
8674
|
6. **Extract learnings (FEAT-174).** After fixing issues, ask: is this a recurring pattern? Offer to capture structural patterns as standards or business rules so future reviews check automatically.
|
|
8675
8675
|
7. **CRITICAL: End with BET/chain IDs.** The final output MUST include a single sentence: "BET/feature IDs reviewed: [IDs]. [One-line summary of findings]."
|
|
@@ -8839,7 +8839,7 @@ var PROCESS_CHANGE_WORKFLOW_DESCRIPTOR = {
|
|
|
8839
8839
|
## Tool Usage
|
|
8840
8840
|
|
|
8841
8841
|
- \`orient\` \u2014 load workspace context (governance, active work packages, stale entries)
|
|
8842
|
-
- \`
|
|
8842
|
+
- \`context action=search\` \u2014 find related entries
|
|
8843
8843
|
- \`capture\` \u2014 manual fallback only if workflow finalization cannot safely route the entry
|
|
8844
8844
|
- \`relations action=create\` or \`relations action=batch-create\` \u2014 link to related entries
|
|
8845
8845
|
- \`entries action=commit\` \u2014 promote to SSOT (only on user confirmation)
|
|
@@ -8858,7 +8858,7 @@ var PROCESS_CHANGE_WORKFLOW_DESCRIPTOR = {
|
|
|
8858
8858
|
label: "Quick Context",
|
|
8859
8859
|
type: "open",
|
|
8860
8860
|
instruction: "What are you working on? Orient to load relevant Chain context.",
|
|
8861
|
-
facilitatorGuidance: "Call orient to get workspace context. Ask what the user is changing \u2014 or infer from their initial message. Search the Chain for related entries:
|
|
8861
|
+
facilitatorGuidance: "Call orient to get workspace context. Ask what the user is changing \u2014 or infer from their initial message. Search the Chain for related entries: context action=search with keywords from their description. Present only the 2-3 most relevant entries, not a full briefing. If the user already described the change, skip the question and confirm what you understood.",
|
|
8862
8862
|
outputSchema: {
|
|
8863
8863
|
field: "context",
|
|
8864
8864
|
description: "What's being changed and relevant Chain context",
|
|
@@ -8886,7 +8886,7 @@ var PROCESS_CHANGE_WORKFLOW_DESCRIPTOR = {
|
|
|
8886
8886
|
label: "Impact & Links",
|
|
8887
8887
|
type: "synthesis",
|
|
8888
8888
|
instruction: "What's affected? Are there existing Chain entries that relate to this change?",
|
|
8889
|
-
facilitatorGuidance: "Search the Chain for entries that should be linked:
|
|
8889
|
+
facilitatorGuidance: "Search the Chain for entries that should be linked: context action=search with keywords from the change. Check: does this change affect an active work package? Does it resolve a known tension? Does it supersede an existing decision? If the change is small and self-contained, this round can be brief \u2014 just confirm there's nothing obvious to link. If there are stale entries that this change invalidates, flag them for reconfirmation.",
|
|
8890
8890
|
outputSchema: {
|
|
8891
8891
|
field: "impact",
|
|
8892
8892
|
description: "Affected entries and proposed links",
|
|
@@ -10132,8 +10132,8 @@ async function handleReEvaluate(entryId, context) {
|
|
|
10132
10132
|
`Entry '${entryId}' not found or has no rubric.`,
|
|
10133
10133
|
"NOT_FOUND",
|
|
10134
10134
|
`Entry '${entryId}' not found or has no rubric.`,
|
|
10135
|
-
"Use
|
|
10136
|
-
[{ tool: "
|
|
10135
|
+
"Use context action=search to find the correct ID.",
|
|
10136
|
+
[{ tool: "context", description: "Search entries", parameters: { action: "search", query: entryId } }]
|
|
10137
10137
|
);
|
|
10138
10138
|
}
|
|
10139
10139
|
const llmScheduled = result2.verdict.tier !== "passive";
|
|
@@ -12769,9 +12769,9 @@ var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
|
|
|
12769
12769
|
|---|---|---|
|
|
12770
12770
|
| \`orient\` | Workspace context, governance, active work packages, session start | \`action\`: start, task |
|
|
12771
12771
|
| \`capture\` | Create entry | \`action\`: capture |
|
|
12772
|
-
| \`entries\` |
|
|
12772
|
+
| \`entries\` | Write entries | \`action\`: update, commit, move, verify, preflight, still-true |
|
|
12773
12773
|
| \`relations\` | Link entries, delete links, find connections | \`action\`: create, batch-create, delete, find |
|
|
12774
|
-
| \`context\` | Reads; only incremental writes | \`action\`: get, batch, history, list, gather, build, neighborhood, changes, chain, cross-cut, incremental, brief, last-verified-brief |
|
|
12774
|
+
| \`context\` | Reads; only incremental writes | \`action\`: get, batch, history, list, search, gather, build, neighborhood, changes, chain, cross-cut, incremental, brief, last-verified-brief |
|
|
12775
12775
|
| \`collections\` | Browse, describe, audit and export collections; manage labels | \`action\`: list, update, describe, audit, export, label-* |
|
|
12776
12776
|
| \`quality\` | Score an entry, verify the Chain, spine check | \`action\`: check, re-evaluate, verify-chain, spine-check |
|
|
12777
12777
|
| \`session\` | Start / close, wrapup, resume, constellation accept | \`action\`: start, close, status, wrapup-review, wrapup-commit, resume, commit-constellation |
|
|
@@ -12846,7 +12846,7 @@ Tags for filtering (e.g. \`severity:high\`), relations via \`entryRelations\`, v
|
|
|
12846
12846
|
);
|
|
12847
12847
|
}
|
|
12848
12848
|
sections.push(
|
|
12849
|
-
'## Rules\nThe rules that bind you are in the briefing above, each with its why. A rule on no list binds nobody.\nOpen one: `context action=get entryId="<ID>"`. Find one: `
|
|
12849
|
+
'## Rules\nThe rules that bind you are in the briefing above, each with its why. A rule on no list binds nobody.\nOpen one: `context action=get entryId="<ID>"`. Find one: `context action=search query="<noun>"`.\nDraft a new rule: use the `draft-rule-from-context` prompt.'
|
|
12850
12850
|
);
|
|
12851
12851
|
sections.push(
|
|
12852
12852
|
"## Knowledge Graph\nEntries are connected via typed relations (`entryRelations` table). Relations are bidirectional and collection-agnostic \u2014 any entry can link to any other entry.\n\n**Recommended relation types** (extensible \u2014 any string accepted):\n- `governs` \u2014 a rule constrains behavior of a feature\n- `defines_term_for` \u2014 a glossary term is canonical vocabulary for a feature/area\n- `belongs_to` \u2014 a feature belongs to a product area or parent concept (typed successor: `anchored_to`)\n- `informs` \u2014 a decision or insight informs a feature\n- `surfaces_tension_in` \u2014 a tension exists within a feature area\n- `related_to`, `depends_on`, `replaces`, `conflicts_with`, `references`, `confused_with`\n\nEach relation type is defined as a glossary entry (prefix `GT-REL-*`) to prevent terminology drift.\n\n**Tools:**\n- `context action=gather` \u2014 get the full context around any entry (multi-hop graph traversal)\n- `relations action=create` \u2014 create a typed link between two entries\n- `relations action=find` \u2014 list direct relations for an entry\n\n**Convention:** A relation is written only when you ask for it, with exactly the verb you send \u2014 link the entries you know are related with `relations action=create`."
|
|
@@ -13445,7 +13445,7 @@ var INSTRUCTIONS = [
|
|
|
13445
13445
|
"",
|
|
13446
13446
|
'- `orient action=task task="<what you are doing>"`: context shaped to the task, with the rules for your team and role.',
|
|
13447
13447
|
'- `context action=get entryId="<ID>"`: one entry in full, with data, relations and history.',
|
|
13448
|
-
'- `
|
|
13448
|
+
'- `context action=search query="<noun>"`: find entries by what they are about.',
|
|
13449
13449
|
"",
|
|
13450
13450
|
"## Writing",
|
|
13451
13451
|
"",
|
|
@@ -13552,4 +13552,4 @@ export {
|
|
|
13552
13552
|
createProductBrainServer,
|
|
13553
13553
|
initFeatureFlags
|
|
13554
13554
|
};
|
|
13555
|
-
//# sourceMappingURL=chunk-
|
|
13555
|
+
//# sourceMappingURL=chunk-O6HEYDXJ.js.map
|