deepclause-sdk 0.0.65 → 0.0.66
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/README.md +83 -6
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +131 -30
- package/dist/agent.js.map +1 -1
- package/dist/cli/commands.d.ts +5 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +75 -5
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/compile.d.ts +3 -0
- package/dist/cli/compile.d.ts.map +1 -1
- package/dist/cli/compile.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +31 -2
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +34 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/tui.d.ts +9 -0
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +100 -30
- package/dist/cli/tui.js.map +1 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +6 -8
- package/dist/compiler.js.map +1 -1
- package/dist/prolog/bridge.d.ts +10 -1
- package/dist/prolog/bridge.d.ts.map +1 -1
- package/dist/prolog/bridge.js +26 -1
- package/dist/prolog/bridge.js.map +1 -1
- package/dist/runner.d.ts +2 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +19 -16
- package/dist/runner.js.map +1 -1
- package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +39 -5
- package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +17 -4
- package/dist/system/assets/index.d.ts +2 -0
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +7 -0
- package/dist/system/assets/index.js.map +1 -1
- package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +45 -0
- package/dist/system/assets/skills/conductor.dml +20 -14
- package/dist/system/runtime/catalog-recipes.d.ts +24 -0
- package/dist/system/runtime/catalog-recipes.d.ts.map +1 -0
- package/dist/system/runtime/catalog-recipes.js +273 -0
- package/dist/system/runtime/catalog-recipes.js.map +1 -0
- package/dist/system/runtime/catalog-skills.d.ts +6 -1
- package/dist/system/runtime/catalog-skills.d.ts.map +1 -1
- package/dist/system/runtime/catalog-skills.js +28 -0
- package/dist/system/runtime/catalog-skills.js.map +1 -1
- package/dist/system/runtime/conductor.d.ts +29 -0
- package/dist/system/runtime/conductor.d.ts.map +1 -1
- package/dist/system/runtime/conductor.js +199 -59
- package/dist/system/runtime/conductor.js.map +1 -1
- package/dist/system/runtime/runtime-tools.d.ts +6 -0
- package/dist/system/runtime/runtime-tools.d.ts.map +1 -1
- package/dist/system/runtime/runtime-tools.js +26 -1
- package/dist/system/runtime/runtime-tools.js.map +1 -1
- package/dist/system/runtime/shell-manager.d.ts.map +1 -1
- package/dist/system/runtime/shell-manager.js +112 -29
- package/dist/system/runtime/shell-manager.js.map +1 -1
- package/dist/system/runtime/skill-creator.d.ts +2 -0
- package/dist/system/runtime/skill-creator.d.ts.map +1 -1
- package/dist/system/runtime/skill-creator.js +199 -15
- package/dist/system/runtime/skill-creator.js.map +1 -1
- package/package.json +2 -2
|
@@ -4,32 +4,43 @@ You are **{ASSISTANT_NAME}**, an agent build using the DeepClause framework. Com
|
|
|
4
4
|
|
|
5
5
|
## What You Can Do
|
|
6
6
|
- **Run skills** from the local catalog via `run_skill`
|
|
7
|
+
- **Consult recipes** from the local recipe library via `consult_recipes`
|
|
7
8
|
- **Create new skills** via `create_new_skill`
|
|
8
9
|
- **Execute shell commands** via `run_bash`
|
|
9
10
|
- **Research the web** via `search_web`, `search_news`, and `fetch_url`
|
|
10
11
|
- **Download files** via `download_file`
|
|
11
12
|
- **Evaluate math** via `calculate`
|
|
12
|
-
- **Record technical learnings** via `save_memory`
|
|
13
13
|
|
|
14
14
|
## Workspace Environment
|
|
15
15
|
|
|
16
16
|
You run inside the local DeepClause runtime. The exact workspace path, skill catalog, docs path, and session directory are appended below in the local runtime context.
|
|
17
17
|
|
|
18
|
+
The local runtime context also includes the current session execution log path. That JSONL file accumulates structured records for conductor turns, session-scoped skill runs, child-skill events, tool calls, streamed model output, errors, and completion summaries.
|
|
19
|
+
|
|
18
20
|
Shell commands (`run_bash`) execute with the workspace as the current working directory. Prefer relative paths. Verify tool availability before relying on it, and install missing packages only when the task actually needs them.
|
|
19
21
|
|
|
22
|
+
Large web pages and raw HTML can blow the model context window. Treat text returned by `fetch_url` as a convenience preview, not as a safe place to dump entire docs sites or HTML pages into the next model call.
|
|
23
|
+
|
|
24
|
+
When a page is likely to be large, noisy, or highly structured, prefer downloading it first and inspecting it locally with focused commands or parsers. Use `download_file` to save the page, then `run_bash` with narrow inspection commands such as `rg`, `grep`, `sed -n`, `head`, or a small Python/Node parser to extract only the relevant snippet before you continue.
|
|
25
|
+
|
|
26
|
+
If you need to start a background service from `run_bash`, do not rely on a bare `command &` alone. Detach it from the tool's stdio, redirect logs, and print the PID or readiness marker, for example: `nohup python3 -m http.server 8080 >/tmp/http.log 2>&1 < /dev/null & echo $!`.
|
|
27
|
+
|
|
20
28
|
If the user asks about the fullscreen CLI TUI, consult the local TUI guide in the docs directory appended below. It documents the pane layout, menus, slash commands, direct `!<command>` shell mode, skill execution, and session behavior.
|
|
21
29
|
|
|
22
30
|
## Decision Flow
|
|
23
31
|
|
|
24
32
|
1. **Check your task instructions**.
|
|
25
33
|
2. **If an existing skill fits** -> run it with `run_skill(slug, args)`.
|
|
26
|
-
3. **If
|
|
27
|
-
4. **If
|
|
28
|
-
5. **If it needs
|
|
34
|
+
3. **If the user is asking how to do something, or you need workflow/convention guidance** -> use `consult_recipes(query)`.
|
|
35
|
+
4. **If the user asks to create a new recipe or update an existing recipe** -> treat it as a workspace file-editing task under `.deepclause/system/recipes/<slug>/SKILL.md`. Consult existing recipes first when helpful, then create or update the recipe markdown directly. Do **not** use `create_new_skill` for recipe authoring.
|
|
36
|
+
5. **If it needs code, files, or local tooling** -> use `run_bash`.
|
|
37
|
+
6. **If it needs research** -> use `search_web`, `search_news`, or `fetch_url`.
|
|
38
|
+
7. **If it needs a reusable automation** -> use `create_new_skill` with a detailed spec.
|
|
39
|
+
8. **If you are debugging a failure, retrying a similar task, or trying to reuse a previously working pattern** -> inspect the session execution log first with focused shell commands such as `tail`, `sed`, or `rg`, then adapt your next step based on the concrete failure or success pattern you find.
|
|
29
40
|
|
|
30
41
|
## Memory
|
|
31
42
|
|
|
32
|
-
You manage **task memory**: technical learnings from task execution.
|
|
43
|
+
You manage **task memory**: technical learnings from task execution. When the task instructions ask for a `MemoryUpdate` output, put the COMPLETE updated task memory markdown there if the run produced useful technical learnings. If nothing technically noteworthy should be recorded, return `NONE` for that memory output.
|
|
33
44
|
|
|
34
45
|
You may also receive optional **assistant memory** loaded from the session's `assistant-memory.md` file. It may be empty, and in the current CLI runtime it is not automatically maintained by a built-in conductor tool. Use it when relevant.
|
|
35
46
|
|
|
@@ -37,11 +48,15 @@ You may also receive optional **assistant memory** loaded from the session's `as
|
|
|
37
48
|
- Work autonomously, but ask the user clarifying questions when required.
|
|
38
49
|
- Report results clearly when done.
|
|
39
50
|
- For `create_new_skill`, write a thorough spec covering purpose, inputs, outputs, tools, and edge cases.
|
|
51
|
+
- Recipe creation and recipe updates are file-authoring tasks, not skill-creation tasks. Edit recipe markdown under `.deepclause/system/recipes/<slug>/SKILL.md` directly.
|
|
40
52
|
- Forward the user's original intent faithfully.
|
|
41
53
|
- Keep the final answer concise and focused on whether the task succeeded, what result was produced, or what blocked completion.
|
|
42
54
|
- Only write task results to files when the user asked for files or the result is too large to present clearly inline.
|
|
43
55
|
- Not every intermediate action is visible to the user.
|
|
44
56
|
- Before you call any tool, briefly explain why you are using it.
|
|
57
|
+
- When a task failed earlier in this session, do not guess blindly. Inspect the session execution log first, identify the relevant failing tool call, error text, or successful prior pattern, and then decide whether to retry, adjust the approach, or reuse the working pattern.
|
|
58
|
+
- Prefer focused log inspection over dumping the whole file. Use recent tails and targeted searches so you can diagnose the issue or recover a known-good pattern quickly.
|
|
59
|
+
- Do not paste large raw HTML or whole documentation pages back into the model unless the task truly depends on that exact text. Prefer downloaded files plus narrow local extraction.
|
|
45
60
|
|
|
46
61
|
|
|
47
62
|
## Background on Skills
|
|
@@ -57,9 +72,28 @@ When you decide a task should become a reusable capability, do **not** try to in
|
|
|
57
72
|
Use this model:
|
|
58
73
|
|
|
59
74
|
- If a matching existing skill already exists, run it with `run_skill`.
|
|
75
|
+
- If you need guidance on workflow, conventions, or how to approach a task, use `consult_recipes`.
|
|
60
76
|
- If the task is one-off and does not need reuse, solve it directly with the available tools.
|
|
61
77
|
- If the task should become a reusable automation, call `create_new_skill` with a strong specification.
|
|
62
78
|
|
|
79
|
+
## Background on Recipes
|
|
80
|
+
|
|
81
|
+
Recipes are **read-only markdown instruction packs**. They are not executable DML workers.
|
|
82
|
+
|
|
83
|
+
- Recipes capture workflow guidance, conventions, checklists, and examples.
|
|
84
|
+
- Recipes are searched through `consult_recipes`.
|
|
85
|
+
- Recipes may live in packaged defaults or in the workspace under `.deepclause/system/recipes/`.
|
|
86
|
+
- Recipes are useful when you need to know *how* to approach a task, not when you need to *execute* a reusable automation.
|
|
87
|
+
- A workspace recipe normally lives at `.deepclause/system/recipes/<slug>/SKILL.md`.
|
|
88
|
+
- If the user asks to create or update a recipe, first inspect nearby recipes for style and structure when helpful, then edit the target recipe markdown directly.
|
|
89
|
+
- Recipe requests should stay in markdown. Do **not** route them through `create_new_skill` unless the user explicitly asked for an executable skill instead of a recipe.
|
|
90
|
+
|
|
91
|
+
Use this model:
|
|
92
|
+
|
|
93
|
+
- **Skill**: executable DML worker for reusable automation.
|
|
94
|
+
- **Recipe**: markdown guidance for process, conventions, and decision-making.
|
|
95
|
+
- **Conductor**: the router that decides whether to run a skill, consult a recipe, or solve the task directly.
|
|
96
|
+
|
|
63
97
|
When writing a spec for `create_new_skill`, make it concrete. Describe:
|
|
64
98
|
|
|
65
99
|
- the skill's purpose
|
|
@@ -26,6 +26,12 @@ Work as a good companion and - if in doubt - always ask for clarification and pe
|
|
|
26
26
|
|
|
27
27
|
Note: Skills run inside the active DeepClause shell environment. By default shell commands run in the local workspace shell. With `--sandbox`, they run inside AgentVM. For web content, use runtime tools such as `web_search`, `url_fetch`, and `news_search` instead of `curl` or `wget`.
|
|
28
28
|
|
|
29
|
+
Note: In the local CLI runtime, `url_fetch` text responses may be truncated to protect the model context window. For large documentation pages, HTML, or other bulky responses, prefer `exec(url_fetch(url: URL, save_to: "tmp/page.html"), R)` and then inspect the saved file with focused local commands such as `rg`, `grep`, `sed -n`, `head`, or a small parser instead of feeding the whole page body into `task()`.
|
|
30
|
+
|
|
31
|
+
Note: Recipes are not skills. If the request is actually to create or update a markdown recipe or instruction pack under `.deepclause/system/recipes/<slug>/SKILL.md`, that work should be handled by editing the recipe file directly rather than compiling a DML skill.
|
|
32
|
+
|
|
33
|
+
Note: When you are iterating on a failing skill, retrying a similar execution, or trying to reuse a proven workflow pattern, inspect the relevant session `execution-log.jsonl` first when it is available. Use the concrete tool calls, streamed outputs, and error records there to diagnose what failed or to copy a working pattern instead of starting from scratch.
|
|
34
|
+
|
|
29
35
|
|
|
30
36
|
</role>
|
|
31
37
|
|
|
@@ -151,8 +157,9 @@ EXACT CALLING SYNTAX AND RETURN TYPES:
|
|
|
151
157
|
|
|
152
158
|
3. url_fetch - Fetch a web page
|
|
153
159
|
Call: exec(url_fetch(url: "https://example.com"), Result)
|
|
154
|
-
|
|
160
|
+
Returns: Dict with keys: body (string), status (integer), headers, truncated (boolean), original_length (integer), returned_length (integer)
|
|
155
161
|
Access: get_dict(body, Result, Content), get_dict(status, Result, Status)
|
|
162
|
+
NOTE: Text responses may be truncated for context safety. If you need the full page or precise snippets from a large page, save it to a file and inspect it locally.
|
|
156
163
|
|
|
157
164
|
Download to file:
|
|
158
165
|
Call: exec(url_fetch(url: "https://example.com/file.csv", save_to: "data.csv"), Result)
|
|
@@ -176,7 +183,7 @@ QUICK REFERENCE TABLE:
|
|
|
176
183
|
|-------------|---------------------------------------------|------------------------------------------------|
|
|
177
184
|
| web_search | exec(web_search(query: Q), R) | List of {title, url, snippet} |
|
|
178
185
|
| news_search | exec(news_search(query: Q), R) | List of {title, url, snippet} |
|
|
179
|
-
| url_fetch | exec(url_fetch(url: U), R) | {body, status, headers}
|
|
186
|
+
| url_fetch | exec(url_fetch(url: U), R) | {body, status, headers, truncated?, lengths?} |
|
|
180
187
|
| url_fetch | exec(url_fetch(url: U, save_to: F), R) | {file_path, size, status} |
|
|
181
188
|
| bash | exec(bash(command: C), R) | {success, stdout, stderr, exitCode, summary} |
|
|
182
189
|
| ask_user | exec(ask_user(prompt: P), R) | {user_response} |
|
|
@@ -237,6 +244,8 @@ atom_json_dict('[1, 2, 3]', List, []), % List = [1, 2, 3]
|
|
|
237
244
|
|
|
238
245
|
Use atom_json_dict/3 for structured data extraction instead of wasting an LLM call on task().
|
|
239
246
|
Reserve task() for free-form text understanding, summarization, and reasoning.
|
|
247
|
+
|
|
248
|
+
If `url_fetch` returns bulky HTML or documentation text, do not stuff the full `body` into `task()`. Save the page to disk and extract the smallest relevant snippet first.
|
|
240
249
|
</json_parsing>
|
|
241
250
|
|
|
242
251
|
<prolog_idioms>
|
|
@@ -400,7 +409,8 @@ CHOOSING THE RIGHT APPROACH
|
|
|
400
409
|
|
|
401
410
|
| I need to... | Use this |
|
|
402
411
|
|---------------------------------------|---------------------------------------------|
|
|
403
|
-
| Reason, summarize, extract, classify | task() -
|
|
412
|
+
| Reason, summarize, extract, classify | task() - use the LLM when open-ended judgment is needed |
|
|
413
|
+
| Follow a simple deterministic workflow| Pure Prolog + exec() - no task() needed |
|
|
404
414
|
| Read/write files | Prolog: open/3, write/2, close/1 |
|
|
405
415
|
| Build strings | {Variable} interpolation or format/3 |
|
|
406
416
|
| Run shell commands (grep, find, ls) | exec(bash(command: "..."), R) |
|
|
@@ -412,6 +422,8 @@ CHOOSING THE RIGHT APPROACH
|
|
|
412
422
|
|
|
413
423
|
DO NOT use Python for: simple file writing - use Prolog open/3, write/2, close/1.
|
|
414
424
|
DO NOT use Prolog for: complex data analysis - use Python via bash.
|
|
425
|
+
It is fine for simple or deterministic skills to avoid task()/prompt() entirely.
|
|
426
|
+
Use task()/prompt() only when the skill needs open-ended reasoning, summarization, extraction, classification, or free-form text generation.
|
|
415
427
|
</when_to_use_what>
|
|
416
428
|
|
|
417
429
|
<skill_reuse>
|
|
@@ -448,6 +460,7 @@ GENERAL GUIDELINES:
|
|
|
448
460
|
- Use the configured workspace for persistent task files.
|
|
449
461
|
- Put helper scripts, templates, prompt fixtures, and other skill-specific runtime artifacts in a dedicated `.deepclause` subfolder, typically `.deepclause/tools/<skill-slug>/`, instead of scattering them in the workspace root.
|
|
450
462
|
- Reference those helper files from DML with workspace-relative paths.
|
|
463
|
+
- If a skill needs to launch a background process and continue, do not use a bare `command &` alone. Detach stdio, redirect logs, and emit the PID or readiness marker, for example: `nohup python3 -m http.server 8080 >/tmp/http.log 2>&1 < /dev/null & echo $!`.
|
|
451
464
|
|
|
452
465
|
PACKAGE INSTALLATION (done by YOU, the skill creator, via bash - NOT inside DML skills):
|
|
453
466
|
Python: bash("pip install --no-cache-dir pandas numpy matplotlib")
|
|
@@ -667,7 +680,7 @@ BEFORE SUBMITTING YOUR DML CODE, VERIFY ALL OF THESE:
|
|
|
667
680
|
[ ] 2-4 tool definitions using tool/3 with clear descriptions
|
|
668
681
|
[ ] ask_user tool included if the task may need user input
|
|
669
682
|
[ ] agent_main with correct number of arguments (all strings)
|
|
670
|
-
[ ] system() call with clear LLM instructions
|
|
683
|
+
[ ] system() call with clear LLM instructions when task()/prompt() is used
|
|
671
684
|
[ ] output() before every long-running operation
|
|
672
685
|
[ ] answer() at the end with descriptive message
|
|
673
686
|
[ ] Fallback agent_main clause with NO LLM calls - just answer() with static error
|
|
@@ -4,6 +4,8 @@ export type WorkspaceDocAssetName = 'tui';
|
|
|
4
4
|
export declare function getSystemSkillAssetPath(name: SystemSkillAssetName): string;
|
|
5
5
|
export declare function getSystemPromptAssetPath(name: SystemPromptAssetName): string;
|
|
6
6
|
export declare function getWorkspaceDocAssetPath(name: WorkspaceDocAssetName): string;
|
|
7
|
+
export declare function getPackagedRecipeAssetsDir(): string;
|
|
8
|
+
export declare function getWorkspaceRecipeAssetsDir(workspaceRoot: string): string;
|
|
7
9
|
export declare function getSystemAssetSourcePaths(workspaceRoot?: string): {
|
|
8
10
|
conductorDml: string;
|
|
9
11
|
conductorPrompt: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/system/assets/index.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,eAAe,CAAC;AACjE,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,eAAe,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/system/assets/index.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,eAAe,CAAC;AACjE,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,eAAe,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC;AA2B1C,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAE1E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAE5E;AASD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAE5E;AAED,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD;AAED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEzE;AAoED,wBAAgB,yBAAyB,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAOA;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,qBAAqB,EAC3B,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
|
|
@@ -6,6 +6,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = dirname(__filename);
|
|
7
7
|
const SKILLS_DIR = join(__dirname, 'skills');
|
|
8
8
|
const DOCS_DIR = join(__dirname, 'docs');
|
|
9
|
+
const RECIPES_DIR = join(__dirname, 'recipes');
|
|
9
10
|
const SYSTEM_OVERRIDE_DIR = '.deepclause/system';
|
|
10
11
|
function getSystemSkillFileName(name) {
|
|
11
12
|
switch (name) {
|
|
@@ -38,6 +39,12 @@ function getWorkspaceDocFileName(name) {
|
|
|
38
39
|
export function getWorkspaceDocAssetPath(name) {
|
|
39
40
|
return join(DOCS_DIR, getWorkspaceDocFileName(name));
|
|
40
41
|
}
|
|
42
|
+
export function getPackagedRecipeAssetsDir() {
|
|
43
|
+
return RECIPES_DIR;
|
|
44
|
+
}
|
|
45
|
+
export function getWorkspaceRecipeAssetsDir(workspaceRoot) {
|
|
46
|
+
return join(workspaceRoot, SYSTEM_OVERRIDE_DIR, 'recipes');
|
|
47
|
+
}
|
|
41
48
|
function getWorkspaceOverridePath(workspaceRoot, fileName) {
|
|
42
49
|
return join(workspaceRoot, SYSTEM_OVERRIDE_DIR, fileName);
|
|
43
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/system/assets/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/system/assets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAMpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACzC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAC/C,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEjD,SAAS,sBAAsB,CAAC,IAA0B;IACxD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW;YACd,OAAO,eAAe,CAAC;QACzB,KAAK,eAAe;YAClB,OAAO,mBAAmB,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,IAA2B;IAC1D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW;YACd,OAAO,qBAAqB,CAAC;QAC/B,KAAK,eAAe;YAClB,OAAO,wBAAwB,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,OAAO,IAAI,CAAC,UAAU,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAA2B;IAClE,OAAO,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,uBAAuB,CAAC,IAA2B;IAC1D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAA2B;IAClE,OAAO,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,aAAqB;IAC/D,OAAO,IAAI,CAAC,aAAa,EAAE,mBAAmB,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,wBAAwB,CAAC,aAAqB,EAAE,QAAgB;IACvE,OAAO,IAAI,CAAC,aAAa,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC;AAC5D,CAAC;AAED,KAAK,UAAU,2BAA2B,CACxC,IAA0B,EAC1B,aAAsB;IAEtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,wBAAwB,CAAC,aAAa,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3F,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3B,OAAO,YAAY,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IAED,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,4BAA4B,CACzC,IAA2B,EAC3B,aAAsB;IAEtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,wBAAwB,CAAC,aAAa,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3B,OAAO,YAAY,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IAED,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,+BAA+B,CACtC,IAA0B,EAC1B,aAAsB;IAEtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,wBAAwB,CAAC,aAAa,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3F,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,gCAAgC,CACvC,IAA2B,EAC3B,aAAsB;IAEtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,wBAAwB,CAAC,aAAa,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,aAAsB;IAM9D,OAAO;QACL,YAAY,EAAE,+BAA+B,CAAC,WAAW,EAAE,aAAa,CAAC;QACzE,eAAe,EAAE,gCAAgC,CAAC,WAAW,EAAE,aAAa,CAAC;QAC7E,eAAe,EAAE,+BAA+B,CAAC,eAAe,EAAE,aAAa,CAAC;QAChF,kBAAkB,EAAE,gCAAgC,CAAC,eAAe,EAAE,aAAa,CAAC;KACrF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA0B,EAC1B,UAAsC,EAAE;IAExC,OAAO,QAAQ,CAAC,MAAM,2BAA2B,CAAC,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA2B,EAC3B,UAAsC,EAAE;IAExC,OAAO,QAAQ,CAAC,MAAM,4BAA4B,CAAC,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: DeepClause Coding Workflow
|
|
3
|
+
description: Guidance for implementing and validating local repository changes in a DeepClause workspace.
|
|
4
|
+
tags: [coding, repository, tests, docs, deepclause]
|
|
5
|
+
when_to_use:
|
|
6
|
+
- implementing a feature or bug fix in the current repository
|
|
7
|
+
- updating tests and documentation alongside code changes
|
|
8
|
+
- debugging a local behavior before editing files
|
|
9
|
+
when_not_to_use:
|
|
10
|
+
- purely informational web research
|
|
11
|
+
- work that should become a reusable executable skill instead of a one-off repo change
|
|
12
|
+
globs: [src/**, tests/**, README.md, docs/**]
|
|
13
|
+
priority: high
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Goal
|
|
17
|
+
|
|
18
|
+
Make small, grounded repository changes with focused validation and clear outcomes.
|
|
19
|
+
|
|
20
|
+
# Workflow
|
|
21
|
+
|
|
22
|
+
1. Start from a concrete anchor such as a failing test, a named file, a command, or the nearest implementation surface.
|
|
23
|
+
2. Read only enough nearby code to form one falsifiable local hypothesis about what should change.
|
|
24
|
+
3. Prefer the smallest edit that tests that hypothesis.
|
|
25
|
+
4. Run the narrowest validation that can falsify the change before widening scope.
|
|
26
|
+
5. If the validation fails, repair the same slice first instead of opening new work.
|
|
27
|
+
6. Update documentation when behavior, workflow, or user-visible commands changed.
|
|
28
|
+
|
|
29
|
+
# When To Use
|
|
30
|
+
|
|
31
|
+
Use this recipe when the task is primarily about changing repository files, adding tests, or updating documentation in a controlled way.
|
|
32
|
+
|
|
33
|
+
# When Not To Use
|
|
34
|
+
|
|
35
|
+
Do not use this recipe for pure research or when the right outcome is to create a reusable DML worker skill.
|
|
36
|
+
|
|
37
|
+
# Examples
|
|
38
|
+
|
|
39
|
+
- Implement a narrow bug fix in `src/` and validate it with one focused Vitest file.
|
|
40
|
+
- Update a CLI workflow and document the changed behavior in `README.md`.
|
|
41
|
+
- Add a new config seed and verify it with the corresponding init tests.
|
|
42
|
+
|
|
43
|
+
# Escalation
|
|
44
|
+
|
|
45
|
+
If the task repeats often or clearly represents a reusable automation, stop treating it as a one-off workflow and create a proper skill instead.
|
|
@@ -13,6 +13,10 @@ tool(run_skill(Slug, Args, Result), "Run an existing skill. Slug is the skill sl
|
|
|
13
13
|
|
|
14
14
|
exec(run_skill(slug: Slug, args: Args), Result).
|
|
15
15
|
|
|
16
|
+
tool(consult_recipes(Query, Result), "Search the recipe library for workflow guidance and conventions. Query is a natural-language description. Returns matching recipe metadata and content.") :-
|
|
17
|
+
|
|
18
|
+
exec(consult_recipes(query: Query, max_results: 3), Result).
|
|
19
|
+
|
|
16
20
|
tool(search_web(Query, Results), "Search the web for current information. Returns search results.") :-
|
|
17
21
|
exec(web_search(query: Query), Results).
|
|
18
22
|
|
|
@@ -42,29 +46,31 @@ tool(inform_user(Message, Result), "Send a status update or progress report to t
|
|
|
42
46
|
output(Message),
|
|
43
47
|
Result = "ok".
|
|
44
48
|
|
|
45
|
-
tool(save_memory(Content, Result), "Update task memory with technical learnings from this execution: what tools/approaches worked, what failed, useful commands, patterns discovered. Pass the COMPLETE updated memory in markdown (old + new learnings). This is technical memory - things that help future tasks.") :-
|
|
46
|
-
exec(update_memory(content: Content), Result).
|
|
47
|
-
|
|
48
49
|
% --- Main entry point ---
|
|
49
50
|
|
|
50
51
|
agent_main(UserMessage) :-
|
|
51
52
|
param(system_prompt, "Conductor system prompt", SysPrompt),
|
|
52
53
|
system(SysPrompt),
|
|
53
54
|
system("When using bash or similar tools, avoid dumping large outputs directly into the conversation context. Write large or uncertain outputs to temporary files first, then inspect them with focused commands such as wc, grep, head, tail, sed, or similar narrow follow-up commands so the context stays small and relevant."),
|
|
54
|
-
format(string(TaskPrompt), "Task instructions: ~w\n\nComplete this task autonomously using your tools.\n\nIf you can complete the task, do so and report the result.\nIf you are blocked by a task-specific, tool-specific, external-service, environment, permission, dependency, or data issue that is not an LLM/provider/API/transport failure, do not go silent. Diagnose the blocker and explain clearly to the user why the task could not be completed
|
|
55
|
-
task(TaskPrompt, string(
|
|
56
|
-
|
|
57
|
-
answer(
|
|
55
|
+
format(string(TaskPrompt), "Task instructions: ~w\n\nComplete this task autonomously using your tools.\n\nIf you can complete the task, do so and report the result.\nIf you are blocked by a task-specific, tool-specific, external-service, environment, permission, dependency, or data issue that is not an LLM/provider/API/transport failure, do not go silent. Diagnose the blocker and explain clearly to the user why the task could not be completed.\nIf the problem appears to be an LLM/provider/API/transport failure, do not invent a speculative diagnosis.\n\nStore the user-facing response in FinalAnswer.\nStore the COMPLETE updated task memory markdown in MemoryUpdate only if this execution produced useful technical insights such as what worked, what failed, useful commands, error resolutions, or reusable lessons from a non-LLM task failure.\nIf nothing technically noteworthy should be recorded, store exactly NONE in MemoryUpdate.\nDo not call update_memory or any separate memory tool from this main task.\n\nReturn a good final answer in all non-LLM cases, including when the task is blocked.", [UserMessage]),
|
|
56
|
+
task(TaskPrompt, string(FinalAnswer), string(MemoryUpdate)),
|
|
57
|
+
maybe_update_session_memory(MemoryUpdate),
|
|
58
|
+
answer(FinalAnswer).
|
|
58
59
|
|
|
59
60
|
% Fallback for technical failures where the main task itself cannot run to completion
|
|
60
61
|
agent_main(_) :-
|
|
61
62
|
answer("Task failed. Please try again.").
|
|
62
63
|
|
|
63
|
-
% Memory update
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
% Memory update is best-effort and uses the already-produced MemoryUpdate output.
|
|
65
|
+
maybe_update_session_memory("NONE") :-
|
|
66
|
+
!.
|
|
67
|
+
maybe_update_session_memory("none") :-
|
|
68
|
+
!.
|
|
69
|
+
maybe_update_session_memory("ok") :-
|
|
70
|
+
!.
|
|
71
|
+
maybe_update_session_memory("") :-
|
|
72
|
+
!.
|
|
73
|
+
maybe_update_session_memory(Content) :-
|
|
74
|
+
catch(exec(update_memory(content: Content), _), _, true),
|
|
69
75
|
!.
|
|
70
|
-
|
|
76
|
+
maybe_update_session_memory(_).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type RecipePriority = 'low' | 'normal' | 'high';
|
|
2
|
+
export interface RecipeCatalogEntry {
|
|
3
|
+
slug: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
tags: string[];
|
|
7
|
+
whenToUse: string[];
|
|
8
|
+
whenNotToUse: string[];
|
|
9
|
+
globs: string[];
|
|
10
|
+
priority: RecipePriority;
|
|
11
|
+
content: string;
|
|
12
|
+
sourcePath: string;
|
|
13
|
+
source: 'packaged' | 'workspace';
|
|
14
|
+
}
|
|
15
|
+
export interface RecipeCatalogMatch extends RecipeCatalogEntry {
|
|
16
|
+
score: number;
|
|
17
|
+
matchedOn: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function listRecipeCatalog(workspaceRoot: string): Promise<RecipeCatalogEntry[]>;
|
|
20
|
+
export declare function searchRecipeCatalog(workspaceRoot: string, query: string, options?: {
|
|
21
|
+
maxResults?: number;
|
|
22
|
+
}): Promise<RecipeCatalogMatch[]>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=catalog-recipes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-recipes.d.ts","sourceRoot":"","sources":["../../../src/system/runtime/catalog-recipes.ts"],"names":[],"mappings":"AAQA,KAAK,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAYhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;CAClC;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAa5F;AAED,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACpC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmB/B"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { getPackagedRecipeAssetsDir, getWorkspaceRecipeAssetsDir, } from '../assets/index.js';
|
|
4
|
+
export async function listRecipeCatalog(workspaceRoot) {
|
|
5
|
+
const packaged = await readRecipeEntries(getPackagedRecipeAssetsDir(), 'packaged');
|
|
6
|
+
const workspace = await readRecipeEntries(getWorkspaceRecipeAssetsDir(workspaceRoot), 'workspace');
|
|
7
|
+
const bySlug = new Map();
|
|
8
|
+
for (const entry of packaged) {
|
|
9
|
+
bySlug.set(entry.slug, entry);
|
|
10
|
+
}
|
|
11
|
+
for (const entry of workspace) {
|
|
12
|
+
bySlug.set(entry.slug, entry);
|
|
13
|
+
}
|
|
14
|
+
return [...bySlug.values()].sort((left, right) => left.slug.localeCompare(right.slug));
|
|
15
|
+
}
|
|
16
|
+
export async function searchRecipeCatalog(workspaceRoot, query, options = {}) {
|
|
17
|
+
const trimmedQuery = query.trim();
|
|
18
|
+
const recipes = await listRecipeCatalog(workspaceRoot);
|
|
19
|
+
if (!trimmedQuery) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const tokens = tokenize(trimmedQuery);
|
|
23
|
+
const matches = recipes
|
|
24
|
+
.map((recipe) => scoreRecipe(recipe, trimmedQuery, tokens))
|
|
25
|
+
.filter((recipe) => recipe !== null)
|
|
26
|
+
.sort((left, right) => {
|
|
27
|
+
if (right.score !== left.score) {
|
|
28
|
+
return right.score - left.score;
|
|
29
|
+
}
|
|
30
|
+
return left.slug.localeCompare(right.slug);
|
|
31
|
+
});
|
|
32
|
+
return matches.slice(0, Math.max(1, options.maxResults ?? 3));
|
|
33
|
+
}
|
|
34
|
+
async function readRecipeEntries(recipesDir, source) {
|
|
35
|
+
let entries;
|
|
36
|
+
try {
|
|
37
|
+
entries = await fs.readdir(recipesDir, { withFileTypes: true });
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code === 'ENOENT') {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
const recipes = await Promise.all(entries
|
|
46
|
+
.filter((entry) => entry.isDirectory())
|
|
47
|
+
.map(async (entry) => loadRecipeEntry(path.join(recipesDir, entry.name), entry.name, source)));
|
|
48
|
+
return recipes.filter((entry) => entry !== null);
|
|
49
|
+
}
|
|
50
|
+
async function loadRecipeEntry(recipeDir, slug, source) {
|
|
51
|
+
const skillPath = await findRecipeSkillPath(recipeDir);
|
|
52
|
+
if (!skillPath) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const rawMarkdown = await fs.readFile(skillPath, 'utf8');
|
|
56
|
+
const { frontmatter, body } = parseRecipeMarkdown(rawMarkdown);
|
|
57
|
+
return {
|
|
58
|
+
slug,
|
|
59
|
+
name: frontmatter.name?.trim() || humanizeSlug(slug),
|
|
60
|
+
description: frontmatter.description?.trim() || inferDescription(body),
|
|
61
|
+
tags: normalizeStringList(frontmatter.tags),
|
|
62
|
+
whenToUse: normalizeStringList(frontmatter.when_to_use),
|
|
63
|
+
whenNotToUse: normalizeStringList(frontmatter.when_not_to_use),
|
|
64
|
+
globs: normalizeStringList(frontmatter.globs),
|
|
65
|
+
priority: normalizePriority(frontmatter.priority),
|
|
66
|
+
content: body.trim(),
|
|
67
|
+
sourcePath: skillPath,
|
|
68
|
+
source,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function findRecipeSkillPath(recipeDir) {
|
|
72
|
+
let entries;
|
|
73
|
+
try {
|
|
74
|
+
entries = await fs.readdir(recipeDir);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (error.code === 'ENOENT') {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
const skillFile = entries.find((entry) => /^skill\.md$/i.test(entry));
|
|
83
|
+
return skillFile ? path.join(recipeDir, skillFile) : null;
|
|
84
|
+
}
|
|
85
|
+
function parseRecipeMarkdown(markdown) {
|
|
86
|
+
const lines = markdown.split(/\r?\n/);
|
|
87
|
+
if (lines[0]?.trim() !== '---') {
|
|
88
|
+
return { frontmatter: {}, body: markdown };
|
|
89
|
+
}
|
|
90
|
+
const frontmatterLines = [];
|
|
91
|
+
let closingIndex = -1;
|
|
92
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
93
|
+
if (lines[index].trim() === '---') {
|
|
94
|
+
closingIndex = index;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
frontmatterLines.push(lines[index]);
|
|
98
|
+
}
|
|
99
|
+
if (closingIndex === -1) {
|
|
100
|
+
return { frontmatter: {}, body: markdown };
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
frontmatter: parseFrontmatter(frontmatterLines),
|
|
104
|
+
body: lines.slice(closingIndex + 1).join('\n'),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function parseFrontmatter(lines) {
|
|
108
|
+
const frontmatter = {};
|
|
109
|
+
let currentListKey = null;
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const trimmed = line.trim();
|
|
112
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const listStartMatch = line.match(/^\s*([a-zA-Z0-9_]+):\s*$/);
|
|
116
|
+
if (listStartMatch) {
|
|
117
|
+
currentListKey = listStartMatch[1];
|
|
118
|
+
frontmatter[currentListKey] = [];
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const inlineArrayMatch = line.match(/^\s*([a-zA-Z0-9_]+):\s*\[(.*)\]\s*$/);
|
|
122
|
+
if (inlineArrayMatch) {
|
|
123
|
+
currentListKey = null;
|
|
124
|
+
frontmatter[inlineArrayMatch[1]] = inlineArrayMatch[2]
|
|
125
|
+
.split(',')
|
|
126
|
+
.map((item) => stripQuotes(item.trim()))
|
|
127
|
+
.filter((item) => item.length > 0);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const scalarMatch = line.match(/^\s*([a-zA-Z0-9_]+):\s*(.+?)\s*$/);
|
|
131
|
+
if (scalarMatch) {
|
|
132
|
+
currentListKey = null;
|
|
133
|
+
frontmatter[scalarMatch[1]] = stripQuotes(scalarMatch[2]);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const listItemMatch = line.match(/^\s*-\s*(.+?)\s*$/);
|
|
137
|
+
if (listItemMatch && currentListKey) {
|
|
138
|
+
const current = frontmatter[currentListKey];
|
|
139
|
+
if (Array.isArray(current)) {
|
|
140
|
+
current.push(stripQuotes(listItemMatch[1]));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return frontmatter;
|
|
145
|
+
}
|
|
146
|
+
function stripQuotes(value) {
|
|
147
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
148
|
+
return value.slice(1, -1);
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
function normalizeStringList(value) {
|
|
153
|
+
if (!value || value.length === 0) {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
return Array.from(new Set(value
|
|
157
|
+
.map((item) => item.trim())
|
|
158
|
+
.filter((item) => item.length > 0)));
|
|
159
|
+
}
|
|
160
|
+
function normalizePriority(value) {
|
|
161
|
+
switch ((value ?? '').trim().toLowerCase()) {
|
|
162
|
+
case 'high':
|
|
163
|
+
return 'high';
|
|
164
|
+
case 'low':
|
|
165
|
+
return 'low';
|
|
166
|
+
default:
|
|
167
|
+
return 'normal';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function inferDescription(markdown) {
|
|
171
|
+
const lines = markdown.split(/\r?\n/)
|
|
172
|
+
.map((line) => line.trim())
|
|
173
|
+
.filter((line) => line.length > 0 && !line.startsWith('#'));
|
|
174
|
+
return lines[0] ?? 'No description provided.';
|
|
175
|
+
}
|
|
176
|
+
function humanizeSlug(slug) {
|
|
177
|
+
return slug
|
|
178
|
+
.split(/[-_]+/)
|
|
179
|
+
.filter((part) => part.length > 0)
|
|
180
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
181
|
+
.join(' ');
|
|
182
|
+
}
|
|
183
|
+
function tokenize(value) {
|
|
184
|
+
return Array.from(new Set(value
|
|
185
|
+
.toLowerCase()
|
|
186
|
+
.split(/[^a-z0-9]+/)
|
|
187
|
+
.map((token) => token.trim())
|
|
188
|
+
.filter((token) => token.length >= 3)));
|
|
189
|
+
}
|
|
190
|
+
function scoreRecipe(recipe, query, tokens) {
|
|
191
|
+
const fields = {
|
|
192
|
+
slug: recipe.slug.toLowerCase(),
|
|
193
|
+
name: recipe.name.toLowerCase(),
|
|
194
|
+
description: recipe.description.toLowerCase(),
|
|
195
|
+
tags: recipe.tags.join(' ').toLowerCase(),
|
|
196
|
+
whenToUse: recipe.whenToUse.join(' ').toLowerCase(),
|
|
197
|
+
whenNotToUse: recipe.whenNotToUse.join(' ').toLowerCase(),
|
|
198
|
+
content: recipe.content.toLowerCase(),
|
|
199
|
+
};
|
|
200
|
+
const normalizedQuery = query.toLowerCase();
|
|
201
|
+
let score = priorityBonus(recipe.priority);
|
|
202
|
+
const matchedOn = new Set();
|
|
203
|
+
const strongMatchFields = new Set();
|
|
204
|
+
if (fields.slug.includes(normalizedQuery)) {
|
|
205
|
+
score += 40;
|
|
206
|
+
matchedOn.add('slug');
|
|
207
|
+
strongMatchFields.add('slug');
|
|
208
|
+
}
|
|
209
|
+
if (fields.name.includes(normalizedQuery)) {
|
|
210
|
+
score += 36;
|
|
211
|
+
matchedOn.add('name');
|
|
212
|
+
strongMatchFields.add('name');
|
|
213
|
+
}
|
|
214
|
+
if (fields.description.includes(normalizedQuery)) {
|
|
215
|
+
score += 28;
|
|
216
|
+
matchedOn.add('description');
|
|
217
|
+
strongMatchFields.add('description');
|
|
218
|
+
}
|
|
219
|
+
for (const token of tokens) {
|
|
220
|
+
if (fields.slug.includes(token)) {
|
|
221
|
+
score += 12;
|
|
222
|
+
matchedOn.add('slug');
|
|
223
|
+
strongMatchFields.add('slug');
|
|
224
|
+
}
|
|
225
|
+
if (fields.name.includes(token)) {
|
|
226
|
+
score += 10;
|
|
227
|
+
matchedOn.add('name');
|
|
228
|
+
strongMatchFields.add('name');
|
|
229
|
+
}
|
|
230
|
+
if (fields.description.includes(token)) {
|
|
231
|
+
score += 8;
|
|
232
|
+
matchedOn.add('description');
|
|
233
|
+
strongMatchFields.add('description');
|
|
234
|
+
}
|
|
235
|
+
if (fields.tags.includes(token)) {
|
|
236
|
+
score += 7;
|
|
237
|
+
matchedOn.add('tags');
|
|
238
|
+
strongMatchFields.add('tags');
|
|
239
|
+
}
|
|
240
|
+
if (fields.whenToUse.includes(token)) {
|
|
241
|
+
score += 6;
|
|
242
|
+
matchedOn.add('when_to_use');
|
|
243
|
+
strongMatchFields.add('when_to_use');
|
|
244
|
+
}
|
|
245
|
+
if (fields.whenNotToUse.includes(token)) {
|
|
246
|
+
score += 3;
|
|
247
|
+
matchedOn.add('when_not_to_use');
|
|
248
|
+
}
|
|
249
|
+
if (fields.content.includes(token)) {
|
|
250
|
+
score += 2;
|
|
251
|
+
matchedOn.add('content');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (strongMatchFields.size === 0 || score <= 0) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
...recipe,
|
|
259
|
+
score,
|
|
260
|
+
matchedOn: [...matchedOn],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function priorityBonus(priority) {
|
|
264
|
+
switch (priority) {
|
|
265
|
+
case 'high':
|
|
266
|
+
return 3;
|
|
267
|
+
case 'normal':
|
|
268
|
+
return 1;
|
|
269
|
+
case 'low':
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=catalog-recipes.js.map
|