@pattern-js/mod-buddy 0.4.0-main.c8eb671

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Makkr Studio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @pattern-js/mod-buddy
2
+
3
+ Buddy — the workflow assistant inside
4
+ [Pattern](https://github.com/makkr-studio/pattern)'s admin, and the Pattern
5
+ **control plane**: ten restricted `pattern_*` tool workflows (list/search the
6
+ catalog and docs, read workflows and runs, validate, propose, save drafts,
7
+ deploy-with-approval) consumed three ways —
8
+
9
+ - **the editor dock**: Buddy drafts workflows, self-repairs against the
10
+ validator, debugs failed runs from traces, and applies proposals to your
11
+ open canvas; you keep Save and Deploy,
12
+ - **`POST /mcp/pattern`**: the same tools for external MCP clients, gated by
13
+ scoped API tokens (author vs deploy split),
14
+ - **`pattern mcp`**: stdio for local dev — Claude Code or Cursor becomes a
15
+ Pattern author.
16
+
17
+ Knowledge is lexical over the live handbook by default and silently upgrades
18
+ to hybrid semantic retrieval when `@pattern-js/mod-vectors` + an embedding
19
+ alias are installed. Threads persist via `@pattern-js/mod-store` when
20
+ present. Buddy's own turn pipeline is a Pattern workflow — open it on the
21
+ canvas.
22
+
23
+ Full chapter: your app's `/docs` → **Buddy** (or
24
+ [the handbook source](./docs/index.md)).
@@ -0,0 +1,9 @@
1
+ /** @pattern-js/mod-buddy — public surface (Buddy + the Pattern control plane). */
2
+ export { buddyMod, type BuddyOptions } from "./mod.js";
3
+ export { default } from "./mod.js";
4
+ export { CONTROL_PLANE_TOOLS, patternMcpServerWorkflow, toolWorkflows } from "./tools.js";
5
+ export { KnowledgeService, knowledgeSearchOp, DOCS_COLLECTION, type KnowledgeResult } from "./knowledge.js";
6
+ export { turnPipelineWorkflow, buddyRoutes, turnOps } from "./turn.js";
7
+ export { BUDDY_INSTRUCTIONS, contextBlock } from "./prompts.js";
8
+ export { THREADS, loadThread, saveThread, clearThread } from "./threads.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /** @pattern-js/mod-buddy — public surface (Buddy + the Pattern control plane). */
2
+ export { buddyMod } from "./mod.js";
3
+ export { default } from "./mod.js";
4
+ export { CONTROL_PLANE_TOOLS, patternMcpServerWorkflow, toolWorkflows } from "./tools.js";
5
+ export { KnowledgeService, knowledgeSearchOp, DOCS_COLLECTION } from "./knowledge.js";
6
+ export { turnPipelineWorkflow, buddyRoutes, turnOps } from "./turn.js";
7
+ export { BUDDY_INSTRUCTIONS, contextBlock } from "./prompts.js";
8
+ export { THREADS, loadThread, saveThread, clearThread } from "./threads.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,EAAE,QAAQ,EAAqB,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAwB,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — Buddy's knowledge retrieval.
3
+ *
4
+ * One op, `buddy.knowledge.search`, behind one output shape
5
+ * `{ results: [{ title, path, snippet, score }] }`. The BASELINE engine is
6
+ * lexical over the live handbook (mod-docs' DocsContent: page titles,
7
+ * headings, page bodies) plus the op catalog — first-class, not a fallback:
8
+ * this corpus is structured docs and exact op names, where lexical genuinely
9
+ * shines. When mod-vectors + an embedding alias are present the same op
10
+ * silently upgrades to semantic retrieval (0.4 phase 7); the output shape
11
+ * never changes, so nothing downstream cares which engine answered.
12
+ */
13
+ import { type Engine, type OpContext, type OpDefinition } from "@pattern-js/core";
14
+ export interface KnowledgeResult {
15
+ title: string;
16
+ /** `guide/<chapter>/<file>` for handbook pages, `op/<type>` for catalog hits. */
17
+ path: string;
18
+ snippet: string;
19
+ score: number;
20
+ }
21
+ export declare const DOCS_COLLECTION = "buddy.docs";
22
+ export declare class KnowledgeService {
23
+ private readonly getEngine;
24
+ private readonly content;
25
+ /** True once the boot indexer has the docs corpus in vectors — search upgrades itself. */
26
+ private semanticReady;
27
+ constructor(getEngine: () => Engine | undefined);
28
+ /** Whether searches currently run semantically (the status probe reports it). */
29
+ isSemantic(): boolean;
30
+ /**
31
+ * Boot indexer (fire-and-forget from ready(), never blocks boot): when
32
+ * mod-vectors AND an embedding alias are present, chunk every handbook page
33
+ * into the "buddy.docs" collection. Content-hashing in vectors.upsert makes
34
+ * re-runs after upgrades cost only the diff. Any failure leaves the lexical
35
+ * baseline in charge — one warn, no drama.
36
+ */
37
+ indexDocs(ctx: OpContext): Promise<void>;
38
+ /** Semantic path: hybrid retrieval over the indexed handbook + lexical op-catalog hits. */
39
+ private searchSemantic;
40
+ search(query: string, k?: number, ctx?: OpContext): Promise<KnowledgeResult[]>;
41
+ }
42
+ /** `buddy.knowledge.search` — retrieval for Buddy and the pattern_search_docs tool. */
43
+ export declare function knowledgeSearchOp(service: () => KnowledgeService): OpDefinition;
44
+ //# sourceMappingURL=knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../src/knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAY,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG5F,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAOD,eAAO,MAAM,eAAe,eAAe,CAAC;AAqE5C,qBAAa,gBAAgB;IAKf,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,0FAA0F;IAC1F,OAAO,CAAC,aAAa,CAAS;gBAED,SAAS,EAAE,MAAM,MAAM,GAAG,SAAS;IAIhE,iFAAiF;IACjF,UAAU,IAAI,OAAO;IAIrB;;;;;;OAMG;IACG,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC9C,2FAA2F;YAC7E,cAAc;IA4BtB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,SAAI,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAkDhF;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,gBAAgB,GAAG,YAAY,CAgB/E"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — Buddy's knowledge retrieval.
3
+ *
4
+ * One op, `buddy.knowledge.search`, behind one output shape
5
+ * `{ results: [{ title, path, snippet, score }] }`. The BASELINE engine is
6
+ * lexical over the live handbook (mod-docs' DocsContent: page titles,
7
+ * headings, page bodies) plus the op catalog — first-class, not a fallback:
8
+ * this corpus is structured docs and exact op names, where lexical genuinely
9
+ * shines. When mod-vectors + an embedding alias are present the same op
10
+ * silently upgrades to semantic retrieval (0.4 phase 7); the output shape
11
+ * never changes, so nothing downstream cares which engine answered.
12
+ */
13
+ import { value, z } from "@pattern-js/core";
14
+ import { DocsContent, resolveOptions } from "@pattern-js/mod-docs";
15
+ /* ── duck-typed views of mod-vectors + mod-ai (NEVER imported) ───────────── */
16
+ const VECTORS_SERVICE = "vectorsService";
17
+ const AI_CONFIG_SERVICE = "aiConfig";
18
+ export const DOCS_COLLECTION = "buddy.docs";
19
+ function vectorsOf(services) {
20
+ const svc = services[VECTORS_SERVICE];
21
+ return svc && typeof svc.query === "function" ? svc : null;
22
+ }
23
+ /** The embedding alias Buddy indexes with: "buddy" when it embeds, else the first embedding alias. */
24
+ function embeddingAlias(services) {
25
+ const config = services[AI_CONFIG_SERVICE];
26
+ if (!config || typeof config.aliases !== "function")
27
+ return null;
28
+ const embedding = config.aliases().filter((a) => a.modality === "embedding");
29
+ return embedding.find((a) => a.name === "buddy")?.name ?? embedding[0]?.name ?? null;
30
+ }
31
+ const tokenize = (s) => s
32
+ .toLowerCase()
33
+ .split(/[^a-z0-9.]+/)
34
+ .filter((t) => t.length > 1);
35
+ /** Overlap score of query tokens against a text (whole-token 2, substring 1). */
36
+ function overlap(queryTokens, text) {
37
+ const hay = text.toLowerCase();
38
+ const hayTokens = new Set(tokenize(hay));
39
+ let score = 0;
40
+ for (const q of queryTokens) {
41
+ if (hayTokens.has(q))
42
+ score += 2;
43
+ else if (hay.includes(q))
44
+ score += 1;
45
+ }
46
+ return score;
47
+ }
48
+ /** A ±2-line window around the best-matching line of a markdown body. */
49
+ function snippetAround(markdown, queryTokens) {
50
+ const lines = markdown.split("\n").filter((l) => l.trim().length > 0);
51
+ let bestIdx = 0;
52
+ let bestScore = -1;
53
+ for (let i = 0; i < lines.length; i++) {
54
+ const s = overlap(queryTokens, lines[i]);
55
+ if (s > bestScore) {
56
+ bestScore = s;
57
+ bestIdx = i;
58
+ }
59
+ }
60
+ return lines
61
+ .slice(Math.max(0, bestIdx - 1), bestIdx + 3)
62
+ .join(" ")
63
+ .slice(0, 500);
64
+ }
65
+ export class KnowledgeService {
66
+ getEngine;
67
+ content;
68
+ /** True once the boot indexer has the docs corpus in vectors — search upgrades itself. */
69
+ semanticReady = false;
70
+ constructor(getEngine) {
71
+ this.getEngine = getEngine;
72
+ this.content = new DocsContent(getEngine, resolveOptions({}));
73
+ }
74
+ /** Whether searches currently run semantically (the status probe reports it). */
75
+ isSemantic() {
76
+ return this.semanticReady;
77
+ }
78
+ /**
79
+ * Boot indexer (fire-and-forget from ready(), never blocks boot): when
80
+ * mod-vectors AND an embedding alias are present, chunk every handbook page
81
+ * into the "buddy.docs" collection. Content-hashing in vectors.upsert makes
82
+ * re-runs after upgrades cost only the diff. Any failure leaves the lexical
83
+ * baseline in charge — one warn, no drama.
84
+ */
85
+ async indexDocs(ctx) {
86
+ const vectors = vectorsOf(ctx.services);
87
+ const alias = embeddingAlias(ctx.services);
88
+ if (!vectors || !alias)
89
+ return;
90
+ try {
91
+ await vectors.ensureCollection({ name: DOCS_COLLECTION, alias, metric: "cosine", filterables: ["kind", "chapter"] });
92
+ const items = [];
93
+ for (const page of await this.content.searchIndex()) {
94
+ const md = await this.content.page(page.chapter, page.file).catch(() => null);
95
+ if (!md?.markdown.trim())
96
+ continue;
97
+ // Coarse paragraph packing (~1500 chars) — pages are structured prose,
98
+ // this keeps chunks self-contained without a tokenizer.
99
+ const paragraphs = md.markdown.split("\n\n");
100
+ let buf = "";
101
+ let i = 0;
102
+ const flush = () => {
103
+ if (!buf.trim())
104
+ return;
105
+ items.push({
106
+ id: `guide/${page.chapter}/${page.file}#${i++}`,
107
+ text: buf,
108
+ meta: { kind: "guide", chapter: page.chapter, title: page.title, path: `guide/${page.chapter}/${page.file}` },
109
+ });
110
+ buf = "";
111
+ };
112
+ for (const p of paragraphs) {
113
+ if (buf.length + p.length > 1500)
114
+ flush();
115
+ buf = buf ? `${buf}\n\n${p}` : p;
116
+ }
117
+ flush();
118
+ }
119
+ if (!items.length)
120
+ return;
121
+ const res = await vectors.upsert(DOCS_COLLECTION, items, ctx);
122
+ this.semanticReady = true;
123
+ if (res.embedded > 0) {
124
+ console.log(`[pattern/mod-buddy] knowledge index ready — ${res.embedded} chunk(s) embedded via alias "${alias}"`);
125
+ }
126
+ }
127
+ catch (err) {
128
+ console.warn(`[pattern/mod-buddy] semantic indexing unavailable (lexical search stays on): ${err.message}`);
129
+ }
130
+ }
131
+ /** Semantic path: hybrid retrieval over the indexed handbook + lexical op-catalog hits. */
132
+ async searchSemantic(query, k, ctx) {
133
+ const vectors = vectorsOf(ctx.services);
134
+ const engine = this.getEngine();
135
+ if (!vectors || !engine || !this.semanticReady)
136
+ return null;
137
+ try {
138
+ const matches = await vectors.query(DOCS_COLLECTION, { text: query, k, mode: "hybrid" }, ctx);
139
+ const guide = matches.map((m) => ({
140
+ title: String(m.meta?.title ?? m.id),
141
+ path: String(m.meta?.path ?? m.id),
142
+ snippet: (m.text ?? "").slice(0, 500),
143
+ score: m.score,
144
+ }));
145
+ // Ops aren't vector-indexed (exact names are lexical's home turf) — blend
146
+ // the top catalog hits in after the guide results.
147
+ const queryTokens = tokenize(query);
148
+ const ops = engine.ops
149
+ .list()
150
+ .map((op) => ({ op, score: overlap(queryTokens, `${op.type} ${op.description ?? ""}`) }))
151
+ .filter((s) => s.score > 0)
152
+ .sort((a, b) => b.score - a.score)
153
+ .slice(0, Math.max(2, Math.floor(k / 3)))
154
+ .map(({ op, score }) => ({ title: op.type, path: `op/${op.type}`, snippet: op.description ?? "", score }));
155
+ return [...guide, ...ops].slice(0, k + ops.length);
156
+ }
157
+ catch {
158
+ return null; // embedding hiccup → the lexical baseline answers
159
+ }
160
+ }
161
+ async search(query, k = 6, ctx) {
162
+ if (ctx) {
163
+ const semantic = await this.searchSemantic(query, k, ctx);
164
+ if (semantic)
165
+ return semantic;
166
+ }
167
+ const engine = this.getEngine();
168
+ if (!engine)
169
+ return [];
170
+ const queryTokens = tokenize(query);
171
+ if (!queryTokens.length)
172
+ return [];
173
+ // Rank the whole corpus on cheap metadata first (titles, headings, op
174
+ // descriptions) — then load ONLY the winning pages' markdown for snippets.
175
+ const scored = [];
176
+ for (const page of await this.content.searchIndex().catch(() => [])) {
177
+ const meta = `${page.title} ${page.headings.join(" ")} ${page.chapter} ${page.file}`;
178
+ const score = overlap(queryTokens, meta);
179
+ if (score > 0) {
180
+ scored.push({
181
+ title: page.title,
182
+ path: `guide/${page.chapter}/${page.file}`,
183
+ score,
184
+ page: { chapter: page.chapter, file: page.file },
185
+ });
186
+ }
187
+ }
188
+ for (const op of engine.ops.list()) {
189
+ const score = overlap(queryTokens, `${op.type} ${op.description ?? ""}`);
190
+ if (score > 0) {
191
+ scored.push({ title: op.type, path: `op/${op.type}`, score: score + (queryTokens.includes(op.type.toLowerCase()) ? 4 : 0) });
192
+ }
193
+ }
194
+ scored.sort((a, b) => b.score - a.score);
195
+ const top = scored.slice(0, Math.max(1, Math.min(k, 20)));
196
+ return Promise.all(top.map(async (hit) => {
197
+ let snippet = "";
198
+ if (hit.page) {
199
+ const page = await this.content.page(hit.page.chapter, hit.page.file).catch(() => null);
200
+ snippet = page ? snippetAround(page.markdown, queryTokens) : "";
201
+ }
202
+ else {
203
+ const type = hit.path.slice("op/".length);
204
+ snippet = engine.ops.get(type)?.description ?? "";
205
+ }
206
+ return { title: hit.title, path: hit.path, snippet, score: hit.score };
207
+ }));
208
+ }
209
+ }
210
+ /** `buddy.knowledge.search` — retrieval for Buddy and the pattern_search_docs tool. */
211
+ export function knowledgeSearchOp(service) {
212
+ return {
213
+ type: "buddy.knowledge.search",
214
+ title: "buddy.knowledge.search",
215
+ description: "Search Buddy's knowledge (the live handbook + op catalog). Inputs { query, k? } → { results: [{ title, path, snippet, score }] }. " +
216
+ "Lexical by default; upgrades to semantic retrieval when mod-vectors + an embedding alias are installed.",
217
+ reusable: false,
218
+ inputs: { query: value(z.string()), k: value(z.number().optional()) },
219
+ outputs: { results: value() },
220
+ execute: async (ctx) => {
221
+ const query = String((await ctx.input.value("query")) ?? "");
222
+ const k = ctx.input.has("k") ? Number((await ctx.input.value("k")) ?? 6) : 6;
223
+ return { results: await service().search(query, Number.isFinite(k) && k > 0 ? k : 6, ctx) };
224
+ },
225
+ };
226
+ }
227
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../src/knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,EAAE,CAAC,EAAkD,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAUnE,gFAAgF;AAEhF,MAAM,eAAe,GAAG,gBAAgB,CAAC;AACzC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAErC,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC;AAoB5C,SAAS,SAAS,CAAC,QAAiC;IAClD,MAAM,GAAG,GAAG,QAAQ,CAAC,eAAe,CAA4B,CAAC;IACjE,OAAO,GAAG,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,sGAAsG;AACtG,SAAS,cAAc,CAAC,QAAiC;IACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,iBAAiB,CAA6B,CAAC;IACvE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC;IAC7E,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAY,EAAE,CACvC,CAAC;KACE,WAAW,EAAE;KACb,KAAK,CAAC,aAAa,CAAC;KACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAEjC,iFAAiF;AACjF,SAAS,OAAO,CAAC,WAAqB,EAAE,IAAY;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;aAC5B,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yEAAyE;AACzE,SAAS,aAAa,CAAC,QAAgB,EAAE,WAAqB;IAC5D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,SAAS,EAAE,CAAC;YAClB,SAAS,GAAG,CAAC,CAAC;YACd,OAAO,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK;SACT,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC;SAC5C,IAAI,CAAC,GAAG,CAAC;SACT,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,OAAO,gBAAgB;IAKE;IAJZ,OAAO,CAAc;IACtC,0FAA0F;IAClF,aAAa,GAAG,KAAK,CAAC;IAE9B,YAA6B,SAAmC;QAAnC,cAAS,GAAT,SAAS,CAA0B;QAC9D,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,iFAAiF;IACjF,UAAU;QACR,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,GAAc;QAC5B,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO;QAC/B,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;YACrH,MAAM,KAAK,GAAuE,EAAE,CAAC;YACrF,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC9E,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE;oBAAE,SAAS;gBACnC,uEAAuE;gBACvE,wDAAwD;gBACxD,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC7C,IAAI,GAAG,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,CAAC;gBACV,MAAM,KAAK,GAAG,GAAG,EAAE;oBACjB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;wBAAE,OAAO;oBACxB,KAAK,CAAC,IAAI,CAAC;wBACT,EAAE,EAAE,SAAS,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE;wBAC/C,IAAI,EAAE,GAAG;wBACT,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;qBAC9G,CAAC,CAAC;oBACH,GAAG,GAAG,EAAE,CAAC;gBACX,CAAC,CAAC;gBACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;oBAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI;wBAAE,KAAK,EAAE,CAAC;oBAC1C,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnC,CAAC;gBACD,KAAK,EAAE,CAAC;YACV,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC1B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,+CAA+C,GAAG,CAAC,QAAQ,iCAAiC,KAAK,GAAG,CAAC,CAAC;YACpH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,gFAAiF,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACzH,CAAC;IACH,CAAC;IAED,2FAA2F;IACnF,KAAK,CAAC,cAAc,CAAC,KAAa,EAAE,CAAS,EAAE,GAAc;QACnE,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9F,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAChC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;gBACpC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC;gBAClC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBACrC,KAAK,EAAE,CAAC,CAAC,KAAK;aACf,CAAC,CAAC,CAAC;YACJ,0EAA0E;YAC1E,mDAAmD;YACnD,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG;iBACnB,IAAI,EAAE;iBACN,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;iBACxF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;iBAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;iBACjC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;iBACxC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC7G,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,CAAC,kDAAkD;QACjE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,CAAC,GAAG,CAAC,EAAE,GAAe;QAChD,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1D,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;QAChC,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,WAAW,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEnC,sEAAsE;QACtE,2EAA2E;QAC3E,MAAM,MAAM,GAAoG,EAAE,CAAC;QAEnH,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACrF,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,SAAS,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE;oBAC1C,KAAK;oBACL,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;iBACjD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,CAAC;YACzE,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC/H,CAAC;QACH,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAE1D,OAAO,OAAO,CAAC,GAAG,CAChB,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;gBACxF,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC1C,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,IAAI,EAAE,CAAC;YACpD,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;QACzE,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AAED,uFAAuF;AACvF,MAAM,UAAU,iBAAiB,CAAC,OAA+B;IAC/D,OAAO;QACL,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,oIAAoI;YACpI,yGAAyG;QAC3G,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE;QACrE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC7B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9F,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/mod.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — the mod.
3
+ *
4
+ * Ships the control-plane capability layer (the ten restricted `pattern_*`
5
+ * tool workflows + the token-gated /mcp/pattern route) and Buddy's knowledge
6
+ * op. The chat dock, turn pipeline and thread persistence arrive with the
7
+ * buddy backend (`buddy.turn`); this half is useful on its own — point
8
+ * Claude Code at /mcp/pattern (or run `pattern mcp`) and your editor's agent
9
+ * becomes a Pattern author.
10
+ *
11
+ * mod-vectors is NEVER imported: knowledge probes `ctx.services` at runtime
12
+ * and upgrades itself when a vector engine + embedding alias are present.
13
+ */
14
+ import { type PatternMod } from "@pattern-js/core";
15
+ export interface BuddyOptions {
16
+ /** Where the Pattern MCP server listens (default "/mcp/pattern"). */
17
+ mcpPath?: string;
18
+ /** Skip the boot-time knowledge indexing (tests). */
19
+ indexOnBoot?: boolean;
20
+ }
21
+ export declare function buddyMod(options?: BuddyOptions): PatternMod;
22
+ /** A ready-to-use buddy mod with defaults (for `loadMods`/`engine.use`). */
23
+ declare const _default: PatternMod;
24
+ export default _default;
25
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAK3F,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAYD,wBAAgB,QAAQ,CAAC,OAAO,GAAE,YAAiB,GAAG,UAAU,CAmC/D;AAED,4EAA4E;;AAC5E,wBAA0B"}
package/dist/mod.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — the mod.
3
+ *
4
+ * Ships the control-plane capability layer (the ten restricted `pattern_*`
5
+ * tool workflows + the token-gated /mcp/pattern route) and Buddy's knowledge
6
+ * op. The chat dock, turn pipeline and thread persistence arrive with the
7
+ * buddy backend (`buddy.turn`); this half is useful on its own — point
8
+ * Claude Code at /mcp/pattern (or run `pattern mcp`) and your editor's agent
9
+ * becomes a Pattern author.
10
+ *
11
+ * mod-vectors is NEVER imported: knowledge probes `ctx.services` at runtime
12
+ * and upgrades itself when a vector engine + embedding alias are present.
13
+ */
14
+ import { existsSync } from "node:fs";
15
+ import { fileURLToPath } from "node:url";
16
+ import { localFs, provideFilesystem } from "@pattern-js/runtime-node";
17
+ import { defineMod } from "@pattern-js/core";
18
+ import { KnowledgeService, knowledgeSearchOp } from "./knowledge.js";
19
+ import { patternMcpServerWorkflow, toolWorkflows } from "./tools.js";
20
+ import { buddyRoutes, turnOps, turnPipelineWorkflow } from "./turn.js";
21
+ /** The packaged docs/ chapter (registered when the docs dir ships with the package). */
22
+ function packagedDocs(engine) {
23
+ try {
24
+ const dir = fileURLToPath(new URL("../docs", import.meta.url));
25
+ if (existsSync(dir))
26
+ provideFilesystem(engine, "buddy-docs", localFs(dir));
27
+ }
28
+ catch {
29
+ /* packaged without docs — the contribution is simply skipped */
30
+ }
31
+ }
32
+ export function buddyMod(options = {}) {
33
+ let engineRef;
34
+ const knowledge = new KnowledgeService(() => engineRef);
35
+ return defineMod({
36
+ name: "@pattern-js/mod-buddy",
37
+ docs: { filesystem: "buddy-docs", title: "Buddy", order: 52 },
38
+ ops: [knowledgeSearchOp(() => knowledge), ...turnOps(() => knowledge)],
39
+ workflows: [...toolWorkflows(), patternMcpServerWorkflow(options.mcpPath), turnPipelineWorkflow(), ...buddyRoutes()],
40
+ // The dock detects Buddy through this command (EditorPage checks the
41
+ // aggregated ui manifest) — it also gives ⌘K a way in.
42
+ frontend: {
43
+ commands: [{ id: "buddy.open", label: "Open Buddy", group: "Buddy", icon: "wand", path: "/x/workflows" }],
44
+ },
45
+ setup: (engine) => {
46
+ engineRef = engine;
47
+ packagedDocs(engine);
48
+ },
49
+ ready: async (engine) => {
50
+ if (options.indexOnBoot === false)
51
+ return;
52
+ // Fire-and-forget semantic indexing: never blocks boot, never fails it.
53
+ // A minimal ctx-shaped bag is enough — the vectors service only reads
54
+ // `services` (provider/vault duck-typing) and `env` on this path.
55
+ const ctx = {
56
+ services: {
57
+ vectorsService: engine.service("vectorsService"),
58
+ aiProviderService: engine.service("aiProviderService"),
59
+ aiConfig: engine.service("aiConfig"),
60
+ vaultService: engine.service("vaultService"),
61
+ },
62
+ env: process.env,
63
+ };
64
+ setTimeout(() => void knowledge.indexDocs(ctx).catch(() => { }), 2_000);
65
+ },
66
+ });
67
+ }
68
+ /** A ready-to-use buddy mod with defaults (for `loadMods`/`engine.use`). */
69
+ export default buddyMod();
70
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — Buddy's system prompt.
3
+ *
4
+ * The prompt is the product here: it teaches the WorkflowDoc shape, the port
5
+ * discipline, and — most importantly — the LOOP: ground yourself in the docs,
6
+ * read real op schemas, validate BEFORE proposing, and let the human own
7
+ * save/deploy. Context (the open workflow, a failing run) is appended per
8
+ * turn by buddy.turn.begin.
9
+ */
10
+ export declare const BUDDY_INSTRUCTIONS = "You are Buddy, the workflow assistant living inside a Pattern app's admin. You help the person build, understand, and debug Pattern workflows. Be warm, direct, and concrete; keep prose short and put substance in tool calls.\n\n## What a workflow is\n\nA workflow document is JSON: { \"id\": string, \"nodes\": [...], \"edges\": [...] }.\n- A node is { \"id\": string, \"op\": string, \"config\"?: object, \"comment\"?: string }. Node ids are short slugs, unique within the workflow.\n- An edge is { \"from\": { \"node\", \"port\" }, \"to\": { \"node\", \"port\" } } \u2014 dataflow from an output port to an input port.\n- Every workflow starts at a TRIGGER (boundary.http.request, boundary.schedule, boundary.event, boundary.tool, boundary.manual, ...) and normally ends at the trigger's paired OUT-GATE (boundary.http.response, boundary.tool.return, boundary.return, ...). The trigger must reach the out-gate through edges.\n- Ports are typed and come in kinds: value (one datum), stream (chunks), control (pulses). Value outputs wire to value inputs; every node also has implicit control ports \"in\"/\"out\" \u2014 a control edge threads reachability when no data flows.\n- config holds registration-time settings (paths, collection names, templates); inputs are per-run data. When both exist, a wired input overrides config.\n\n## How to work\n\n1. GROUND first: pattern_search_docs for the house pattern, pattern_list_ops to see what exists, pattern_get_op for the EXACT ports and config schema of every op you plan to use. Never guess an op type or port name \u2014 look it up.\n2. Build the doc, then pattern_validate_workflow. Fix EVERY issue it reports (issues carry nodeId + code) and validate again. Do not show the human an invalid doc.\n3. Propose with pattern_propose_workflow ({ doc, summary }): the doc appears as an Apply card in the editor \u2014 the human applies it to their canvas, reviews, and owns Save. Prefer proposing over saving; use pattern_save_workflow_draft only when asked to save.\n4. NEVER deploy unless the human explicitly asks; pattern_deploy_workflow requires their approval anyway.\n5. Debugging: pattern_list_runs (filter status \"error\"), then pattern_get_run \u2014 spans carry per-node status, timings, error messages and sampled I/O. Explain the failure by pointing at the node and the evidence, then propose the fix.\n6. When editing an existing workflow, pattern_get_workflow first and keep everything you don't need to change \u2014 node ids, ui positions, comments. Propose the FULL updated doc, never a fragment.\n\n## House rules for docs you produce\n\n- Secrets never appear as values: config references env (\"$env\" / ${VAR}) or vault-sourced refs.\n- HTTP routes that reach privileged data must set requireAuth on the trigger.\n- Give nodes honest ids (\"fetch\", \"summarize\", \"reply\") and use \"comment\" to explain non-obvious steps.\n- Lay nodes out left-to-right in execution order: ui { x, y } roughly 280 apart on x.\n- One workflow does one job; compose bigger behavior from several workflows and events.";
11
+ /** Per-turn context appended to the instructions (the open canvas, a run under debug). */
12
+ export declare function contextBlock(input: {
13
+ slug?: string;
14
+ doc?: unknown;
15
+ runId?: string;
16
+ }): string;
17
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,kBAAkB,qgGA0ByD,CAAC;AAEzF,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAe5F"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — Buddy's system prompt.
3
+ *
4
+ * The prompt is the product here: it teaches the WorkflowDoc shape, the port
5
+ * discipline, and — most importantly — the LOOP: ground yourself in the docs,
6
+ * read real op schemas, validate BEFORE proposing, and let the human own
7
+ * save/deploy. Context (the open workflow, a failing run) is appended per
8
+ * turn by buddy.turn.begin.
9
+ */
10
+ export const BUDDY_INSTRUCTIONS = `You are Buddy, the workflow assistant living inside a Pattern app's admin. You help the person build, understand, and debug Pattern workflows. Be warm, direct, and concrete; keep prose short and put substance in tool calls.
11
+
12
+ ## What a workflow is
13
+
14
+ A workflow document is JSON: { "id": string, "nodes": [...], "edges": [...] }.
15
+ - A node is { "id": string, "op": string, "config"?: object, "comment"?: string }. Node ids are short slugs, unique within the workflow.
16
+ - An edge is { "from": { "node", "port" }, "to": { "node", "port" } } — dataflow from an output port to an input port.
17
+ - Every workflow starts at a TRIGGER (boundary.http.request, boundary.schedule, boundary.event, boundary.tool, boundary.manual, ...) and normally ends at the trigger's paired OUT-GATE (boundary.http.response, boundary.tool.return, boundary.return, ...). The trigger must reach the out-gate through edges.
18
+ - Ports are typed and come in kinds: value (one datum), stream (chunks), control (pulses). Value outputs wire to value inputs; every node also has implicit control ports "in"/"out" — a control edge threads reachability when no data flows.
19
+ - config holds registration-time settings (paths, collection names, templates); inputs are per-run data. When both exist, a wired input overrides config.
20
+
21
+ ## How to work
22
+
23
+ 1. GROUND first: pattern_search_docs for the house pattern, pattern_list_ops to see what exists, pattern_get_op for the EXACT ports and config schema of every op you plan to use. Never guess an op type or port name — look it up.
24
+ 2. Build the doc, then pattern_validate_workflow. Fix EVERY issue it reports (issues carry nodeId + code) and validate again. Do not show the human an invalid doc.
25
+ 3. Propose with pattern_propose_workflow ({ doc, summary }): the doc appears as an Apply card in the editor — the human applies it to their canvas, reviews, and owns Save. Prefer proposing over saving; use pattern_save_workflow_draft only when asked to save.
26
+ 4. NEVER deploy unless the human explicitly asks; pattern_deploy_workflow requires their approval anyway.
27
+ 5. Debugging: pattern_list_runs (filter status "error"), then pattern_get_run — spans carry per-node status, timings, error messages and sampled I/O. Explain the failure by pointing at the node and the evidence, then propose the fix.
28
+ 6. When editing an existing workflow, pattern_get_workflow first and keep everything you don't need to change — node ids, ui positions, comments. Propose the FULL updated doc, never a fragment.
29
+
30
+ ## House rules for docs you produce
31
+
32
+ - Secrets never appear as values: config references env ("$env" / \${VAR}) or vault-sourced refs.
33
+ - HTTP routes that reach privileged data must set requireAuth on the trigger.
34
+ - Give nodes honest ids ("fetch", "summarize", "reply") and use "comment" to explain non-obvious steps.
35
+ - Lay nodes out left-to-right in execution order: ui { x, y } roughly 280 apart on x.
36
+ - One workflow does one job; compose bigger behavior from several workflows and events.`;
37
+ /** Per-turn context appended to the instructions (the open canvas, a run under debug). */
38
+ export function contextBlock(input) {
39
+ const parts = [];
40
+ if (input.slug)
41
+ parts.push(`The editor has workflow "${input.slug}" open.`);
42
+ if (input.doc) {
43
+ let json = "";
44
+ try {
45
+ json = JSON.stringify(input.doc);
46
+ }
47
+ catch {
48
+ json = "";
49
+ }
50
+ if (json.length > 12_000)
51
+ json = `${json.slice(0, 12_000)}… (truncated — pattern_get_workflow for the stored version)`;
52
+ if (json)
53
+ parts.push(`Current canvas document (may have unsaved edits):\n${json}`);
54
+ }
55
+ if (input.runId)
56
+ parts.push(`The person is looking at run "${input.runId}" — pattern_get_run it before answering.`);
57
+ return parts.length ? `\n\n## Current context\n\n${parts.join("\n\n")}` : "";
58
+ }
59
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;wFA0BsD,CAAC;AAEzF,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAAC,KAAuD;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,4BAA4B,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC;IAC5E,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM;YAAE,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,6DAA6D,CAAC;QACvH,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,sDAAsD,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,KAAK,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,iCAAiC,KAAK,CAAC,KAAK,0CAA0C,CAAC,CAAC;IACpH,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,6BAA6B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @pattern-js/mod-buddy — thread persistence.
3
+ *
4
+ * One thread per (workflow slug, owner): the dock reloads it on mount, the
5
+ * turn pipeline replaces its messages with the agent's updated history after
6
+ * every turn (CAS-retried). mod-store is duck-typed via its well-known
7
+ * "storeService" key — when absent, Buddy degrades gracefully to stateless
8
+ * turns (the dock still works; memory just doesn't survive a reload).
9
+ */
10
+ import type { OpContext, Principal } from "@pattern-js/core";
11
+ export declare const THREADS = "buddy.threads";
12
+ export interface ThreadDoc {
13
+ slug: string;
14
+ ownerId: string;
15
+ messages: unknown[];
16
+ updatedAt: number;
17
+ }
18
+ export declare function ownerOf(principal: Principal): string;
19
+ /** The thread's messages (empty when no store / no thread yet). */
20
+ export declare function loadThread(ctx: OpContext, slug: string): Promise<unknown[]>;
21
+ /** Replace the thread's messages with the turn's updated history (CAS-retried). */
22
+ export declare function saveThread(ctx: OpContext, slug: string, messages: unknown[]): Promise<boolean>;
23
+ export declare function clearThread(ctx: OpContext, slug: string): Promise<boolean>;
24
+ /** Whether persistence is available (the dock's status probe reports it). */
25
+ export declare function hasThreadStore(services: Record<string, unknown>): boolean;
26
+ //# sourceMappingURL=threads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7D,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAoBvC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAEpD;AAYD,mEAAmE;AACnE,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAOjF;AAED,mFAAmF;AACnF,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAcpG;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAKhF;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEzE"}