@duckmind/dm-windows-x64 0.60.6 → 0.60.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +70 -123
- package/extensions/dm-9router-ext/src/index.js +410 -5
- package/extensions/dm-caveman/extensions/caveman.js +283 -12
- package/extensions/dm-cliproxy/index.js +182 -2
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
- package/extensions/dm-cliproxy/src/apply.js +228 -1
- package/extensions/dm-cliproxy/src/cache.js +42 -1
- package/extensions/dm-cliproxy/src/commands.js +50 -2
- package/extensions/dm-cliproxy/src/compat.js +81 -1
- package/extensions/dm-cliproxy/src/config.js +192 -2
- package/extensions/dm-cliproxy/src/conflicts.js +46 -1
- package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
- package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
- package/extensions/dm-cliproxy/src/log.js +23 -1
- package/extensions/dm-cliproxy/src/status-quota.js +77 -1
- package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
- package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
- package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
- package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
- package/extensions/dm-context/src/context.js +144 -1
- package/extensions/dm-context/src/index.js +339 -7
- package/extensions/dm-context/src/utils.js +9 -1
- package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
- package/extensions/dm-cua/index.js +75 -6
- package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
- package/extensions/dm-cua/src/browser-install.mjs +331 -2
- package/extensions/dm-fff/src/index.js +688 -12
- package/extensions/dm-fff/src/query.js +60 -1
- package/extensions/dm-goal/src/goal.js +894 -23
- package/extensions/dm-image2/index.js +103 -9
- package/extensions/dm-image2/src/image-lib.mjs +1275 -8
- package/extensions/dm-subagents/install.mjs +62 -8
- package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
- package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
- package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
- package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
- package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
- package/extensions/dm-subagents/src/agents/agents.js +1139 -11
- package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
- package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
- package/extensions/dm-subagents/src/agents/identity.js +29 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
- package/extensions/dm-subagents/src/agents/skills.js +614 -6
- package/extensions/dm-subagents/src/extension/config.js +35 -2
- package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
- package/extensions/dm-subagents/src/extension/doctor.js +172 -15
- package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
- package/extensions/dm-subagents/src/extension/index.js +521 -359
- package/extensions/dm-subagents/src/extension/rpc.js +266 -7
- package/extensions/dm-subagents/src/extension/schemas.js +275 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
- package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
- package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
- package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
- package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
- package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
- package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
- package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
- package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
- package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
- package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
- package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
- package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
- package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
- package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
- package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
- package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
- package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
- package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
- package/extensions/dm-subagents/src/shared/formatters.js +98 -7
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
- package/extensions/dm-subagents/src/shared/model-info.js +62 -1
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
- package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
- package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
- package/extensions/dm-subagents/src/shared/settings.js +198 -11
- package/extensions/dm-subagents/src/shared/status-format.js +53 -1
- package/extensions/dm-subagents/src/shared/types.js +184 -6
- package/extensions/dm-subagents/src/shared/utils.js +462 -2
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
- package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
- package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
- package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
- package/extensions/dm-subagents/src/tui/render.js +1542 -4
- package/extensions/dm-usage/index.js +1294 -9
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
- package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
- package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
- package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
- package/extensions/greedysearch-dm/bin/search.mjs +620 -540
- package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
- package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
- package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
- package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
- package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
- package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
- package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
- package/extensions/greedysearch-dm/index.js +123 -23
- package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
- package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
- package/extensions/greedysearch-dm/src/github.mjs +222 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
- package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
- package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
- package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
- package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
- package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
- package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
- package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
- package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
- package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
- package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
- package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
- package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
- package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
- package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
- package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
- package/package.json +1 -1
|
@@ -1,12 +1,300 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`),A=X.match(/^([ \t]+)/m)?.[1]??"",V=A?X.replace(new RegExp(`^${P(A)}`,"gm"),"").replace(/^\n/,""):X;J[Z]=V}return{frontmatter:J,body:W}}import*as O from"node:os";import*as M from"node:path";function E($){return $.trim().replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function i($){let J=$?.env??process.env,B=$&&Object.hasOwn($,"getuid")?$.getuid:process.getuid?.bind(process);if(typeof B==="function")return`uid-${B()}`;for(let U of["USERNAME","USER","LOGNAME"]){let Z=J[U];if(Z)return`user-${E(Z)}`}let j=$&&Object.hasOwn($,"userInfo")?$.userInfo:O.userInfo;try{let U=j?.().username;if(U)return`user-${E(U)}`}catch{}let Q=J.USERPROFILE??J.HOME;if(Q)return`home-${E(Q)}`;let W=$&&Object.hasOwn($,"homedir")?$.homedir:O.homedir;try{let U=W?.();if(U)return`home-${E(U)}`}catch{}return"shared"}var S=M.join(O.tmpdir(),`dm-subagents-${i()}`),x$=M.join(S,"async-subagent-results"),k$=M.join(S,"async-subagent-runs"),a=M.join(S,"chain-runs"),g$=M.join(S,"artifacts");function C($){return"parallel"in $&&Array.isArray($.parallel)}function K($){return"expand"in $&&"collect"in $&&"parallel"in $&&!Array.isArray($.parallel)}import{Compile as p$}from"typebox/compile";class _ extends Error{}var t=/^[A-Za-z_][A-Za-z0-9_]*$/,e=/^[A-Za-z_][A-Za-z0-9_]*$/,f=/\{([A-Za-z_][A-Za-z0-9_]*)(?:\.([^{}]+))?\}/g,$$=new Set(["task","previous","chain_dir","outputs"]),v=new Set(["expand","parallel","collect","concurrency","failFast","phase","label","acceptance"]),B$=new Set([...v,"effectiveAcceptance","sessionFiles","thinkingOverrides"]),J$=new Set(["from","item","key","maxItems","onEmpty"]),j$=new Set(["output","path"]),h=new Set(["agent","task","phase","label","outputSchema","cwd","output","outputMode","reads","progress","skill","model","toolBudget","acceptance"]),U$=new Set([...h,"outputName","structured","inheritProjectContext","inheritSkills","skills","outputPath","maxSubagentDepth","structuredOutput","structuredOutputSchema","tools","extensions","subagentOnlyExtensions","mcpDirectTools","completionGuard","systemPrompt","systemPromptMode","thinking","modelCandidates","sessionFile","effectiveAcceptance","parentSessionId"]),Q$=new Set(["as","outputSchema"]);function k($){return t.test($)}function g($,J){if($==="")return;if(!$.startsWith("/"))throw new _(`${J} must be a JSON Pointer starting with '/'.`);for(let B of $.slice(1).split("/"))if(/~(?![01])/.test(B))throw new _(`${J} contains invalid JSON Pointer escape.`)}function T($,J,B){if(!$||typeof $!=="object"||Array.isArray($))throw new _(`${B} must be an object.`);for(let j of Object.keys($))if(!J.has(j))throw new _(`${B} does not support field '${j}'.`)}function Z$($,J,B){for(let j of $.matchAll(/\{([^{}]*)\}/g)){let Q=j[0],W=j[1];if(W===J||W.startsWith(`${J}.`)){if(!f.test(Q)||W===`${J}.`||W.includes(".."))throw new _(`Invalid item reference '${Q}' in ${B}.`);f.lastIndex=0;continue}f.lastIndex=0;let U=W.match(/^[A-Za-z_][A-Za-z0-9_]*/)?.[0];if(U===J)throw new _(`Invalid item reference '${Q}' in ${B}.`);if(U&&$$.has(U))continue;if(U)throw new _(`Unsupported template reference '${Q}' in ${B}.`)}if(f.lastIndex=0,$.includes(`{${J}.}`)||new RegExp(`\\{${J}(?:\\.|$)[^}]*$`).test($))throw new _(`Invalid item reference in ${B}.`)}function m($){return!!$&&typeof $==="object"&&!Array.isArray($)&&(Object.prototype.hasOwnProperty.call($,"expand")||Object.prototype.hasOwnProperty.call($,"collect"))}function d($,J,B={}){let j=`Dynamic chain step ${J+1}`;if(T($,B.allowRunnerFields?B$:v,j),!$.expand||!$.expand.from)throw new _(`${j} requires expand.from.`);if(T($.expand,J$,`${j} expand`),T($.expand.from,j$,`${j} expand.from`),!k($.expand.from.output))throw new _(`${j} has invalid expand.from.output '${$.expand.from.output}'.`);if(g($.expand.from.path,`${j} expand.from.path`),$.expand.key!==void 0)g($.expand.key,`${j} expand.key`);let Q=$.expand.item??"item";if(!e.test(Q))throw new _(`${j} has invalid expand.item '${Q}'.`);if($.expand.maxItems===void 0&&B.maxItems===void 0)throw new _(`${j} requires expand.maxItems or config.chain.dynamicFanout.maxItems.`);if($.expand.maxItems!==void 0&&(!Number.isInteger($.expand.maxItems)||$.expand.maxItems<0))throw new _(`${j} expand.maxItems must be an integer >= 0.`);if(B.maxItems!==void 0&&(!Number.isInteger(B.maxItems)||B.maxItems<0))throw new _("config.chain.dynamicFanout.maxItems must be an integer >= 0.");if(!$.parallel||Array.isArray($.parallel))throw new _(`${j} requires a single parallel template object and cannot mix dynamic expand/collect with static parallel arrays.`);if(T($.parallel,B.allowRunnerFields?U$:h,`${j} parallel`),"expand"in $.parallel)throw new _(`${j} does not support nested dynamic fanout.`);if(!$.parallel.agent)throw new _(`${j} parallel.agent is required.`);if(!$.collect?.as||!k($.collect.as))throw new _(`${j} requires collect.as with a safe output name.`);T($.collect,Q$,`${j} collect`);for(let[W,U]of[["parallel.task",$.parallel.task],["parallel.label",$.parallel.label]])if(U)Z$(U,Q,`${j} ${W}`)}var W$=/\{outputs\.([^}]*)\}/g,u=/^[A-Za-z_][A-Za-z0-9_]*$/;class H extends Error{}function c($){if(C($))return $.parallel.map((B)=>B.as).filter((B)=>Boolean(B));if(K($))return[$.collect.as];let J=$.as;return J?[J]:[]}function X$($){if(C($))return $.parallel.map((J)=>J.task??"{previous}");if(K($))return[$.parallel.task??"{previous}",$.parallel.label??""].filter(Boolean);return[$.task??"{previous}"]}function o($,J={}){Y$($,J)}function Y$($,J={},B={}){let j=[...B.priorOutputNames??[]],Q=new Set(j),W=new Set(j);for(let U=0;U<$.length;U++){let Z=(B.startStepIndex??0)+U+1,Y=$[U];if(m(Y)){if(!K(Y))throw new H(`Dynamic chain step ${Z} requires expand, a single parallel template object, and collect; dynamic expand/collect cannot be mixed with static parallel arrays.`);try{d(Y,Z-1,J)}catch(G){if(G instanceof _)throw new H(G.message);throw G}if(!Q.has(Y.expand.from.output))throw new H(`Dynamic chain step ${Z} references unknown output '${Y.expand.from.output}'. Named outputs are only available after producing step/group completes.`)}for(let G of c(Y)){if(!u.test(G))throw new H(`Invalid chain output name '${G}' at step ${Z}. Use /^[A-Za-z_][A-Za-z0-9_]*$/.`);if(W.has(G))throw new H(`Duplicate chain output name '${G}'. Each as name must be unique.`);W.add(G)}for(let G of X$(Y))for(let X of G.matchAll(W$)){let q=X[0],A=X[1];if(!u.test(A))throw new H(`Invalid chain output reference '${q}' at step ${Z}. Use {outputs.name} with /^[A-Za-z_][A-Za-z0-9_]*$/ names.`);if(!Q.has(A))throw new H(`Unknown chain output reference '${q}' at step ${Z}. Named outputs are only available after producing step/group completes.`)}for(let G of c(Y))Q.add(G)}}var n=new Set(["auto","none","attested","checked","verified","reviewed"]),p=new Set(["changed-files","tests-added","commands-run","validation-output","residual-risks","no-staged-files","diff-summary","review-findings","manual-notes"]),G$=new Set(["level","criteria","evidence","verify","review","stopRules","reason"]),q$=new Set(["id","must","evidence","severity"]),A$=new Set(["id","command","timeoutMs","cwd","env","allowFailure"]),_$=new Set(["agent","focus","required"]);function F($,J="acceptance"){let B=[];if($===void 0)return B;if($===!1)return B;if(typeof $==="string"){if(!n.has($))B.push(`${J} has invalid level '${$}'.`);return B}if(!$||typeof $!=="object"||Array.isArray($))return B.push(`${J} must be a string level, false, or an object.`),B;let j=$;for(let Q of Object.keys(j))if(!G$.has(Q))B.push(`${J}.${Q} is not supported.`);if(j.level!==void 0&&(typeof j.level!=="string"||!n.has(j.level)))B.push(`${J}.level must be one of auto, none, attested, checked, verified, reviewed.`);if(j.level==="none"&&(typeof j.reason!=="string"||!j.reason.trim()))B.push(`${J}.reason is required when level is none.`);if(j.reason!==void 0&&typeof j.reason!=="string")B.push(`${J}.reason must be a string.`);if(j.criteria!==void 0&&!Array.isArray(j.criteria))B.push(`${J}.criteria must be an array.`);if(Array.isArray(j.criteria))for(let[Q,W]of j.criteria.entries()){if(typeof W==="string")continue;let U=`${J}.criteria[${Q}]`;if(!W||typeof W!=="object"||Array.isArray(W)){B.push(`${U} must be a string or an object.`);continue}let Z=W;for(let Y of Object.keys(Z))if(!q$.has(Y))B.push(`${U}.${Y} is not supported.`);if(typeof Z.id!=="string"||!Z.id.trim())B.push(`${U}.id is required.`);if(typeof Z.must!=="string"||!Z.must.trim())B.push(`${U}.must is required.`);if(Z.evidence!==void 0&&!Array.isArray(Z.evidence))B.push(`${U}.evidence must be an array.`);if(Array.isArray(Z.evidence)){for(let[Y,G]of Z.evidence.entries())if(typeof G!=="string"||!p.has(G))B.push(`${U}.evidence[${Y}] is not a supported evidence kind.`)}if(Z.severity!==void 0&&Z.severity!=="required"&&Z.severity!=="recommended")B.push(`${U}.severity must be required or recommended.`)}if(Array.isArray(j.evidence)){for(let[Q,W]of j.evidence.entries())if(typeof W!=="string"||!p.has(W))B.push(`${J}.evidence[${Q}] is not a supported evidence kind.`)}else if(j.evidence!==void 0)B.push(`${J}.evidence must be an array.`);if(j.verify!==void 0&&!Array.isArray(j.verify))B.push(`${J}.verify must be an array.`);if(Array.isArray(j.verify))for(let[Q,W]of j.verify.entries()){if(!W||typeof W!=="object"||Array.isArray(W)){B.push(`${J}.verify[${Q}] must be an object.`);continue}let U=W;for(let Z of Object.keys(U))if(!A$.has(Z))B.push(`${J}.verify[${Q}].${Z} is not supported.`);if(typeof U.id!=="string"||!U.id.trim())B.push(`${J}.verify[${Q}].id is required.`);if(typeof U.command!=="string"||!U.command.trim())B.push(`${J}.verify[${Q}].command is required.`);if(U.timeoutMs!==void 0&&(typeof U.timeoutMs!=="number"||!Number.isInteger(U.timeoutMs)||U.timeoutMs<1))B.push(`${J}.verify[${Q}].timeoutMs must be an integer >= 1.`);if(U.cwd!==void 0&&typeof U.cwd!=="string")B.push(`${J}.verify[${Q}].cwd must be a string.`);if(U.env!==void 0){if(!U.env||typeof U.env!=="object"||Array.isArray(U.env))B.push(`${J}.verify[${Q}].env must be an object.`);else for(let[Z,Y]of Object.entries(U.env))if(typeof Y!=="string")B.push(`${J}.verify[${Q}].env.${Z} must be a string.`)}if(U.allowFailure!==void 0&&typeof U.allowFailure!=="boolean")B.push(`${J}.verify[${Q}].allowFailure must be a boolean.`)}if(j.review!==void 0&&j.review!==!1)if(!j.review||typeof j.review!=="object"||Array.isArray(j.review))B.push(`${J}.review must be false or an object.`);else{let Q=j.review;for(let W of Object.keys(Q))if(!_$.has(W))B.push(`${J}.review.${W} is not supported.`);if(Q.agent!==void 0&&typeof Q.agent!=="string")B.push(`${J}.review.agent must be a string.`);if(Q.focus!==void 0&&typeof Q.focus!=="string")B.push(`${J}.review.focus must be a string.`);if(Q.required!==void 0&&typeof Q.required!=="boolean")B.push(`${J}.review.required must be a boolean.`)}if(j.stopRules!==void 0&&!Array.isArray(j.stopRules))B.push(`${J}.stopRules must be an array.`);if(Array.isArray(j.stopRules)){for(let[Q,W]of j.stopRules.entries())if(typeof W!=="string")B.push(`${J}.stopRules[${Q}] must be a string.`)}return B}var V$=["read","grep","find","ls"];function z$($){if($==="*")return"*";if($===void 0)return[...V$];return[...new Set($.map((J)=>J.trim()).filter(Boolean))]}function b($,J="toolBudget"){if($===void 0)return{};if(!$||typeof $!=="object"||Array.isArray($))return{error:`${J} must be an object with hard and optional soft/block.`};let B=$;if(typeof B.hard!=="number"||!Number.isInteger(B.hard)||B.hard<1)return{error:`${J}.hard must be an integer >= 1.`};if(B.soft!==void 0&&(typeof B.soft!=="number"||!Number.isInteger(B.soft)||B.soft<1))return{error:`${J}.soft must be an integer >= 1 when provided.`};if(B.soft!==void 0&&B.soft>B.hard)return{error:`${J}.soft must be <= ${J}.hard.`};if(B.block!==void 0&&B.block!=="*"){if(!Array.isArray(B.block))return{error:`${J}.block must be "*" or an array of tool names.`};if(B.block.length===0)return{error:`${J}.block must contain at least one tool name.`};for(let j of B.block)if(typeof j!=="string"||!j.trim())return{error:`${J}.block must contain non-empty tool names.`}}return{budget:{hard:B.hard,...B.soft!==void 0?{soft:B.soft}:{},block:z$(B.block)}}}function H$($,J){let B=J.split(`
|
|
7
|
-
|
|
8
|
-
`)
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from "./identity.js";
|
|
2
|
+
import { parseFrontmatter } from "./frontmatter.js";
|
|
3
|
+
import { ChainOutputValidationError, validateChainOutputBindings } from "../runs/shared/chain-outputs.js";
|
|
4
|
+
import { validateAcceptanceInput } from "../runs/shared/acceptance.js";
|
|
5
|
+
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.js";
|
|
6
|
+
function parseStepBody(agent, sectionBody) {
|
|
7
|
+
const lines = sectionBody.split(`
|
|
8
|
+
`);
|
|
9
|
+
const blankIndex = lines.findIndex((line) => line.trim() === "");
|
|
10
|
+
const configLines = blankIndex === -1 ? lines : lines.slice(0, blankIndex);
|
|
11
|
+
const task = (blankIndex === -1 ? "" : lines.slice(blankIndex + 1).join(`
|
|
12
|
+
`)).trim();
|
|
13
|
+
const step = { agent, task };
|
|
14
|
+
for (const line of configLines) {
|
|
15
|
+
const match = line.match(/^([\w-]+):\s*(.*)$/);
|
|
16
|
+
if (!match)
|
|
17
|
+
continue;
|
|
18
|
+
const key = match[1].trim().toLowerCase();
|
|
19
|
+
const rawValue = match[2].trim();
|
|
20
|
+
if (key === "output") {
|
|
21
|
+
if (rawValue === "false")
|
|
22
|
+
step.output = false;
|
|
23
|
+
else if (rawValue)
|
|
24
|
+
step.output = rawValue;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (key === "phase") {
|
|
28
|
+
if (rawValue)
|
|
29
|
+
step.phase = rawValue;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (key === "label") {
|
|
33
|
+
if (rawValue)
|
|
34
|
+
step.label = rawValue;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (key === "as") {
|
|
38
|
+
if (rawValue)
|
|
39
|
+
step.as = rawValue;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (key === "outputschema") {
|
|
43
|
+
if (rawValue.startsWith("{") || rawValue.startsWith("[")) {
|
|
44
|
+
throw new Error("Inline outputSchema values are not supported in .chain.md files; use a schema file path.");
|
|
45
|
+
}
|
|
46
|
+
if (rawValue)
|
|
47
|
+
step.outputSchema = rawValue;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (key === "outputmode") {
|
|
51
|
+
if (rawValue === "inline" || rawValue === "file-only")
|
|
52
|
+
step.outputMode = rawValue;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (key === "reads") {
|
|
56
|
+
if (rawValue === "false") {
|
|
57
|
+
step.reads = false;
|
|
58
|
+
} else {
|
|
59
|
+
const reads = rawValue.split(",").map((v) => v.trim()).filter(Boolean);
|
|
60
|
+
step.reads = reads.length > 0 ? reads : false;
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (key === "model") {
|
|
65
|
+
if (rawValue)
|
|
66
|
+
step.model = rawValue;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (key === "skills") {
|
|
70
|
+
if (rawValue === "false") {
|
|
71
|
+
step.skills = false;
|
|
72
|
+
} else {
|
|
73
|
+
const skills = rawValue.split(",").map((v) => v.trim()).filter(Boolean);
|
|
74
|
+
step.skills = skills.length > 0 ? skills : false;
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (key === "progress") {
|
|
79
|
+
if (rawValue === "true")
|
|
80
|
+
step.progress = true;
|
|
81
|
+
else if (rawValue === "false")
|
|
82
|
+
step.progress = false;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (key === "toolbudget") {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(rawValue);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
throw new Error(`Invalid toolBudget in .chain.md step '${agent}': ${message}`);
|
|
92
|
+
}
|
|
93
|
+
const validation = validateToolBudgetConfig(parsed, `toolBudget for step '${agent}'`);
|
|
94
|
+
if (validation.error)
|
|
95
|
+
throw new Error(validation.error);
|
|
96
|
+
step.toolBudget = parsed;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return step;
|
|
100
|
+
}
|
|
101
|
+
export function parseChain(content, source, filePath) {
|
|
102
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
103
|
+
if (!frontmatter.name || !frontmatter.description) {
|
|
104
|
+
throw new Error("Chain frontmatter must include name and description");
|
|
105
|
+
}
|
|
106
|
+
const matches = [...body.matchAll(/^##\s+(.+)[^\S\n]*$/gm)];
|
|
107
|
+
const steps = [];
|
|
108
|
+
for (let i = 0;i < matches.length; i++) {
|
|
109
|
+
const match = matches[i];
|
|
110
|
+
const agent = match[1].trim();
|
|
111
|
+
const lineEndOffset = body[match.index + match[0].length] === `
|
|
112
|
+
` ? 1 : 0;
|
|
113
|
+
const sectionStart = match.index + match[0].length + lineEndOffset;
|
|
114
|
+
const sectionEnd = i + 1 < matches.length ? matches[i + 1].index : body.length;
|
|
115
|
+
const sectionBody = body.slice(sectionStart, sectionEnd).trimEnd();
|
|
116
|
+
steps.push(parseStepBody(agent, sectionBody));
|
|
117
|
+
}
|
|
118
|
+
const localName = frontmatter.name;
|
|
119
|
+
const parsedPackage = parsePackageName(frontmatter.package, `Chain '${localName}' package`);
|
|
120
|
+
if (parsedPackage.error)
|
|
121
|
+
throw new Error(parsedPackage.error);
|
|
122
|
+
const packageName = parsedPackage.packageName;
|
|
123
|
+
const extraFields = {};
|
|
124
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
125
|
+
if (key === "name" || key === "package" || key === "description")
|
|
126
|
+
continue;
|
|
127
|
+
extraFields[key] = value;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
name: buildRuntimeName(localName, packageName),
|
|
131
|
+
localName,
|
|
132
|
+
packageName,
|
|
133
|
+
description: frontmatter.description,
|
|
134
|
+
source,
|
|
135
|
+
filePath,
|
|
136
|
+
steps,
|
|
137
|
+
extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function validateJsonChainToolBudget(value, label) {
|
|
141
|
+
const validation = validateToolBudgetConfig(value, label);
|
|
142
|
+
if (validation.error)
|
|
143
|
+
throw new Error(validation.error);
|
|
144
|
+
}
|
|
145
|
+
export function parseJsonChain(content, source, filePath) {
|
|
146
|
+
let parsed;
|
|
147
|
+
try {
|
|
148
|
+
parsed = JSON.parse(content);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
151
|
+
throw new Error(`Invalid JSON chain '${filePath}': ${message}`);
|
|
152
|
+
}
|
|
153
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
154
|
+
throw new Error(`JSON chain '${filePath}' must contain an object root.`);
|
|
155
|
+
}
|
|
156
|
+
const input = parsed;
|
|
157
|
+
if (typeof input.name !== "string" || !input.name.trim()) {
|
|
158
|
+
throw new Error(`JSON chain '${filePath}' must include string name.`);
|
|
159
|
+
}
|
|
160
|
+
if (typeof input.description !== "string" || !input.description.trim()) {
|
|
161
|
+
throw new Error(`JSON chain '${filePath}' must include string description.`);
|
|
162
|
+
}
|
|
163
|
+
if (!Array.isArray(input.chain)) {
|
|
164
|
+
throw new Error(`JSON chain '${filePath}' must include array chain.`);
|
|
165
|
+
}
|
|
166
|
+
for (let i = 0;i < input.chain.length; i++) {
|
|
167
|
+
const step = input.chain[i];
|
|
168
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
169
|
+
throw new Error(`JSON chain '${filePath}' step ${i + 1} must be an object.`);
|
|
170
|
+
}
|
|
171
|
+
const stepRecord = step;
|
|
172
|
+
if (stepRecord.toolBudget !== undefined)
|
|
173
|
+
validateJsonChainToolBudget(stepRecord.toolBudget, `step ${i + 1} toolBudget`);
|
|
174
|
+
const acceptanceErrors = validateAcceptanceInput(stepRecord.acceptance, `step ${i + 1} acceptance`);
|
|
175
|
+
if (acceptanceErrors.length > 0) {
|
|
176
|
+
throw new Error(`Invalid JSON chain '${filePath}': ${acceptanceErrors.join(" ")}`);
|
|
177
|
+
}
|
|
178
|
+
const parallel = stepRecord.parallel;
|
|
179
|
+
if (Array.isArray(parallel)) {
|
|
180
|
+
for (let taskIndex = 0;taskIndex < parallel.length; taskIndex++) {
|
|
181
|
+
const task = parallel[taskIndex];
|
|
182
|
+
if (!task || typeof task !== "object" || Array.isArray(task))
|
|
183
|
+
continue;
|
|
184
|
+
const taskRecord = task;
|
|
185
|
+
if (taskRecord.toolBudget !== undefined)
|
|
186
|
+
validateJsonChainToolBudget(taskRecord.toolBudget, `step ${i + 1} parallel task ${taskIndex + 1} toolBudget`);
|
|
187
|
+
const taskErrors = validateAcceptanceInput(taskRecord.acceptance, `step ${i + 1} parallel task ${taskIndex + 1} acceptance`);
|
|
188
|
+
if (taskErrors.length > 0) {
|
|
189
|
+
throw new Error(`Invalid JSON chain '${filePath}': ${taskErrors.join(" ")}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} else if (parallel && typeof parallel === "object") {
|
|
193
|
+
const parallelRecord = parallel;
|
|
194
|
+
if (parallelRecord.toolBudget !== undefined)
|
|
195
|
+
validateJsonChainToolBudget(parallelRecord.toolBudget, `step ${i + 1} dynamic template toolBudget`);
|
|
196
|
+
const templateErrors = validateAcceptanceInput(parallelRecord.acceptance, `step ${i + 1} dynamic template acceptance`);
|
|
197
|
+
if (templateErrors.length > 0) {
|
|
198
|
+
throw new Error(`Invalid JSON chain '${filePath}': ${templateErrors.join(" ")}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
validateChainOutputBindings(input.chain, { maxItems: Number.MAX_SAFE_INTEGER });
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (error instanceof ChainOutputValidationError)
|
|
206
|
+
throw new Error(`Invalid JSON chain '${filePath}': ${error.message}`);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
const parsedPackage = parsePackageName(typeof input.package === "string" ? input.package : undefined, `Chain '${input.name}' package`);
|
|
210
|
+
if (parsedPackage.error)
|
|
211
|
+
throw new Error(parsedPackage.error);
|
|
212
|
+
const extraFields = {};
|
|
213
|
+
for (const [key, value] of Object.entries(input)) {
|
|
214
|
+
if (key === "name" || key === "package" || key === "description" || key === "chain")
|
|
215
|
+
continue;
|
|
216
|
+
if (typeof value === "string")
|
|
217
|
+
extraFields[key] = value;
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
name: buildRuntimeName(input.name.trim(), parsedPackage.packageName),
|
|
221
|
+
localName: input.name.trim(),
|
|
222
|
+
packageName: parsedPackage.packageName,
|
|
223
|
+
description: input.description.trim(),
|
|
224
|
+
source,
|
|
225
|
+
filePath,
|
|
226
|
+
steps: input.chain,
|
|
227
|
+
extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
export function serializeJsonChain(config) {
|
|
231
|
+
const root = {
|
|
232
|
+
name: frontmatterNameForConfig(config),
|
|
233
|
+
description: config.description,
|
|
234
|
+
chain: config.steps
|
|
235
|
+
};
|
|
236
|
+
if (config.packageName)
|
|
237
|
+
root.package = config.packageName;
|
|
238
|
+
if (config.extraFields) {
|
|
239
|
+
for (const [key, value] of Object.entries(config.extraFields)) {
|
|
240
|
+
if (key !== "name" && key !== "description" && key !== "package" && key !== "chain")
|
|
241
|
+
root[key] = value;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return `${JSON.stringify(root, null, 2)}
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
export function serializeChain(config) {
|
|
248
|
+
const lines = [];
|
|
249
|
+
lines.push("---");
|
|
250
|
+
lines.push(`name: ${frontmatterNameForConfig(config)}`);
|
|
251
|
+
if (config.packageName)
|
|
252
|
+
lines.push(`package: ${config.packageName}`);
|
|
253
|
+
lines.push(`description: ${config.description}`);
|
|
254
|
+
if (config.extraFields) {
|
|
255
|
+
for (const [key, value] of Object.entries(config.extraFields)) {
|
|
256
|
+
lines.push(`${key}: ${value}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
lines.push("---");
|
|
260
|
+
lines.push("");
|
|
261
|
+
for (let i = 0;i < config.steps.length; i++) {
|
|
262
|
+
const step = config.steps[i];
|
|
263
|
+
lines.push(`## ${step.agent}`);
|
|
264
|
+
if (step.output === false)
|
|
265
|
+
lines.push("output: false");
|
|
266
|
+
else if (step.output)
|
|
267
|
+
lines.push(`output: ${step.output}`);
|
|
268
|
+
if (step.phase)
|
|
269
|
+
lines.push(`phase: ${step.phase}`);
|
|
270
|
+
if (step.label)
|
|
271
|
+
lines.push(`label: ${step.label}`);
|
|
272
|
+
if (step.as)
|
|
273
|
+
lines.push(`as: ${step.as}`);
|
|
274
|
+
if (step.outputSchema)
|
|
275
|
+
lines.push(`outputSchema: ${step.outputSchema}`);
|
|
276
|
+
if (step.outputMode)
|
|
277
|
+
lines.push(`outputMode: ${step.outputMode}`);
|
|
278
|
+
if (step.reads === false)
|
|
279
|
+
lines.push("reads: false");
|
|
280
|
+
else if (Array.isArray(step.reads) && step.reads.length > 0)
|
|
281
|
+
lines.push(`reads: ${step.reads.join(", ")}`);
|
|
282
|
+
if (step.model)
|
|
283
|
+
lines.push(`model: ${step.model}`);
|
|
284
|
+
if (step.skills === false)
|
|
285
|
+
lines.push("skills: false");
|
|
286
|
+
else if (Array.isArray(step.skills) && step.skills.length > 0)
|
|
287
|
+
lines.push(`skills: ${step.skills.join(", ")}`);
|
|
288
|
+
if (step.progress !== undefined)
|
|
289
|
+
lines.push(`progress: ${step.progress ? "true" : "false"}`);
|
|
290
|
+
if (step.toolBudget !== undefined)
|
|
291
|
+
lines.push(`toolBudget: ${JSON.stringify(step.toolBudget)}`);
|
|
292
|
+
lines.push("");
|
|
293
|
+
lines.push(step.task ?? "");
|
|
294
|
+
if (i < config.steps.length - 1)
|
|
295
|
+
lines.push("");
|
|
296
|
+
}
|
|
297
|
+
return `${lines.join(`
|
|
11
298
|
`)}
|
|
12
|
-
|
|
299
|
+
`;
|
|
300
|
+
}
|
|
@@ -1,6 +1,65 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
function escapeRegex(s) {
|
|
2
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3
|
+
}
|
|
4
|
+
export function parseFrontmatter(content) {
|
|
5
|
+
const frontmatter = {};
|
|
6
|
+
const normalized = content.replace(/\r\n/g, `
|
|
7
|
+
`);
|
|
8
|
+
if (!normalized.startsWith("---")) {
|
|
9
|
+
return { frontmatter, body: normalized };
|
|
10
|
+
}
|
|
11
|
+
const endIndex = normalized.indexOf(`
|
|
12
|
+
---`, 3);
|
|
13
|
+
if (endIndex === -1) {
|
|
14
|
+
return { frontmatter, body: normalized };
|
|
15
|
+
}
|
|
16
|
+
const frontmatterBlock = normalized.slice(4, endIndex);
|
|
17
|
+
const body = normalized.slice(endIndex + 4).trim();
|
|
18
|
+
const lines = frontmatterBlock.split(`
|
|
19
|
+
`);
|
|
20
|
+
let currentKey = null;
|
|
21
|
+
let currentBlockLines = null;
|
|
22
|
+
let currentIndent = null;
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const indent = line.search(/\S|$/);
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (currentKey !== null && currentBlockLines !== null && indent > (currentIndent ?? 0)) {
|
|
27
|
+
currentBlockLines.push(line);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (currentKey !== null && currentBlockLines !== null) {
|
|
31
|
+
const rawBlock = currentBlockLines.join(`
|
|
32
|
+
`);
|
|
33
|
+
const leadingSpaces = rawBlock.match(/^([ \t]+)/m);
|
|
34
|
+
const prefix = leadingSpaces?.[1] ?? "";
|
|
35
|
+
const stripped = prefix ? rawBlock.replace(new RegExp(`^${escapeRegex(prefix)}`, "gm"), "").replace(/^\n/, "") : rawBlock;
|
|
36
|
+
frontmatter[currentKey] = stripped;
|
|
37
|
+
currentKey = null;
|
|
38
|
+
currentBlockLines = null;
|
|
39
|
+
currentIndent = null;
|
|
40
|
+
}
|
|
41
|
+
const match = line.match(/^([\w-]+):\s*(.*)$/);
|
|
42
|
+
if (match) {
|
|
43
|
+
let value = match[2].trim();
|
|
44
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
45
|
+
value = value.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
if (value === "") {
|
|
48
|
+
currentKey = match[1];
|
|
49
|
+
currentBlockLines = [];
|
|
50
|
+
currentIndent = indent;
|
|
51
|
+
} else {
|
|
52
|
+
frontmatter[match[1]] = value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (currentKey !== null && currentBlockLines !== null) {
|
|
57
|
+
const rawBlock = currentBlockLines.join(`
|
|
58
|
+
`);
|
|
59
|
+
const leadingSpaces = rawBlock.match(/^([ \t]+)/m);
|
|
60
|
+
const prefix = leadingSpaces?.[1] ?? "";
|
|
61
|
+
const stripped = prefix ? rawBlock.replace(new RegExp(`^${escapeRegex(prefix)}`, "gm"), "").replace(/^\n/, "") : rawBlock;
|
|
62
|
+
frontmatter[currentKey] = stripped;
|
|
63
|
+
}
|
|
64
|
+
return { frontmatter, body };
|
|
65
|
+
}
|
|
@@ -1 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
const IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/;
|
|
2
|
+
function normalizePackageName(value) {
|
|
3
|
+
const trimmed = value?.trim();
|
|
4
|
+
if (!trimmed)
|
|
5
|
+
return;
|
|
6
|
+
return trimmed.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9.-]/g, "").replace(/-+/g, "-").replace(/\.+/g, ".").replace(/(?:^[-.]+|[-.]+$)/g, "");
|
|
7
|
+
}
|
|
8
|
+
export function parsePackageName(value, label = "package") {
|
|
9
|
+
if (value === undefined || value === false || value === "")
|
|
10
|
+
return { packageName: undefined };
|
|
11
|
+
if (typeof value !== "string")
|
|
12
|
+
return { error: `${label} must be a string or false when provided.` };
|
|
13
|
+
const packageName = normalizePackageName(value);
|
|
14
|
+
if (!packageName || !IDENTIFIER_PATTERN.test(packageName))
|
|
15
|
+
return { error: `${label} is invalid after sanitization.` };
|
|
16
|
+
return { packageName };
|
|
17
|
+
}
|
|
18
|
+
export function buildRuntimeName(localName, packageName) {
|
|
19
|
+
const trimmedPackage = packageName?.trim();
|
|
20
|
+
return trimmedPackage ? `${trimmedPackage}.${localName}` : localName;
|
|
21
|
+
}
|
|
22
|
+
export function frontmatterNameForConfig(config) {
|
|
23
|
+
if (config.localName)
|
|
24
|
+
return config.localName;
|
|
25
|
+
if (config.packageName && config.name.startsWith(`${config.packageName}.`)) {
|
|
26
|
+
return config.name.slice(config.packageName.length + 1);
|
|
27
|
+
}
|
|
28
|
+
return config.name;
|
|
29
|
+
}
|
|
@@ -1 +1,141 @@
|
|
|
1
|
-
|
|
1
|
+
const SUBAGENT_ORCHESTRATION_SKILL = "dm-subagents";
|
|
2
|
+
const DEFAULT_MIN_REFERENCES = 2;
|
|
3
|
+
const DEFAULT_MAX_RECOMMENDATIONS = 3;
|
|
4
|
+
const DEFAULT_PREFERRED_AGENT = "reviewer";
|
|
5
|
+
const FALLBACK_AGENT_ORDER = ["reviewer", "context-builder", "delegate"];
|
|
6
|
+
const MAX_RECOMMENDATION_CAP = 5;
|
|
7
|
+
function positiveInteger(value) {
|
|
8
|
+
if (typeof value !== "number")
|
|
9
|
+
return;
|
|
10
|
+
if (!Number.isInteger(value) || !Number.isFinite(value) || value < 1)
|
|
11
|
+
return;
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
export function resolveProactiveSkillSubagentsConfig(config) {
|
|
15
|
+
if (config === false) {
|
|
16
|
+
return {
|
|
17
|
+
enabled: false,
|
|
18
|
+
minReferences: DEFAULT_MIN_REFERENCES,
|
|
19
|
+
maxRecommendations: DEFAULT_MAX_RECOMMENDATIONS,
|
|
20
|
+
preferredAgent: DEFAULT_PREFERRED_AGENT
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const maxRecommendations = positiveInteger(config?.maxRecommendations) ?? DEFAULT_MAX_RECOMMENDATIONS;
|
|
24
|
+
return {
|
|
25
|
+
enabled: config?.enabled ?? true,
|
|
26
|
+
minReferences: positiveInteger(config?.minReferences) ?? DEFAULT_MIN_REFERENCES,
|
|
27
|
+
maxRecommendations: Math.min(maxRecommendations, MAX_RECOMMENDATION_CAP),
|
|
28
|
+
preferredAgent: typeof config?.preferredAgent === "string" && config.preferredAgent.trim() ? config.preferredAgent.trim() : DEFAULT_PREFERRED_AGENT
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function normalizeSkillNames(value) {
|
|
32
|
+
if (value === false || value === true || value === undefined || value === null)
|
|
33
|
+
return [];
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
return [...new Set(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean))];
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
return [...new Set(value.split(",").map((entry) => entry.trim()).filter(Boolean))];
|
|
39
|
+
}
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
function collectStepSkills(step, out) {
|
|
43
|
+
for (const skill of normalizeSkillNames(step.skills ?? step.skill)) {
|
|
44
|
+
out.add(skill);
|
|
45
|
+
}
|
|
46
|
+
const parallel = step.parallel;
|
|
47
|
+
if (!parallel)
|
|
48
|
+
return;
|
|
49
|
+
if (Array.isArray(parallel)) {
|
|
50
|
+
for (const child of parallel) {
|
|
51
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
52
|
+
collectStepSkills(child, out);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (typeof parallel === "object") {
|
|
58
|
+
collectStepSkills(parallel, out);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function chooseRecommendationAgent(agents, preferredAgent) {
|
|
62
|
+
const enabled = agents.filter((agent) => !agent.disabled);
|
|
63
|
+
if (enabled.some((agent) => agent.name === preferredAgent))
|
|
64
|
+
return preferredAgent;
|
|
65
|
+
for (const name of FALLBACK_AGENT_ORDER) {
|
|
66
|
+
if (enabled.some((agent) => agent.name === name))
|
|
67
|
+
return name;
|
|
68
|
+
}
|
|
69
|
+
return enabled[0]?.name;
|
|
70
|
+
}
|
|
71
|
+
function addSource(counts, skill, source) {
|
|
72
|
+
if (skill === SUBAGENT_ORCHESTRATION_SKILL)
|
|
73
|
+
return;
|
|
74
|
+
const sources = counts.get(skill) ?? new Set;
|
|
75
|
+
sources.add(source);
|
|
76
|
+
counts.set(skill, sources);
|
|
77
|
+
}
|
|
78
|
+
export function recommendProactiveSkillSubagents(input) {
|
|
79
|
+
const config = resolveProactiveSkillSubagentsConfig(input.config);
|
|
80
|
+
if (!config.enabled)
|
|
81
|
+
return [];
|
|
82
|
+
const agent = chooseRecommendationAgent(input.agents, config.preferredAgent);
|
|
83
|
+
if (!agent)
|
|
84
|
+
return [];
|
|
85
|
+
const availableByName = input.availableSkills ? new Map(input.availableSkills.map((skill) => [skill.name, skill])) : undefined;
|
|
86
|
+
const counts = new Map;
|
|
87
|
+
for (const candidate of input.agents) {
|
|
88
|
+
if (candidate.disabled)
|
|
89
|
+
continue;
|
|
90
|
+
for (const skill of candidate.skills ?? []) {
|
|
91
|
+
addSource(counts, skill, `agent:${candidate.name}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const chain of input.chains ?? []) {
|
|
95
|
+
const chainSkills = new Set;
|
|
96
|
+
for (const step of chain.steps) {
|
|
97
|
+
collectStepSkills(step, chainSkills);
|
|
98
|
+
}
|
|
99
|
+
for (const skill of chainSkills) {
|
|
100
|
+
addSource(counts, skill, `chain:${chain.name}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return [...counts.entries()].filter(([skill, sources]) => sources.size >= config.minReferences && (!availableByName || availableByName.has(skill))).map(([skill, sources]) => ({
|
|
104
|
+
skill,
|
|
105
|
+
agent,
|
|
106
|
+
references: sources.size,
|
|
107
|
+
sources: [...sources].sort((a, b) => a.localeCompare(b)),
|
|
108
|
+
description: availableByName?.get(skill)?.description,
|
|
109
|
+
reason: `referenced by ${sources.size} configured agents/chains`
|
|
110
|
+
})).sort((a, b) => b.references - a.references || a.skill.localeCompare(b.skill)).slice(0, config.maxRecommendations);
|
|
111
|
+
}
|
|
112
|
+
export function formatProactiveSkillSubagentRecommendations(recommendations) {
|
|
113
|
+
if (recommendations.length === 0)
|
|
114
|
+
return [];
|
|
115
|
+
return [
|
|
116
|
+
"Proactive skill subagent suggestions:",
|
|
117
|
+
...recommendations.map((recommendation) => {
|
|
118
|
+
const sampleSources = recommendation.sources.slice(0, 3).join(", ");
|
|
119
|
+
const extra = recommendation.sources.length > 3 ? `, +${recommendation.sources.length - 3} more` : "";
|
|
120
|
+
const description = recommendation.description ? ` - ${recommendation.description}` : "";
|
|
121
|
+
return `- ${recommendation.skill} via ${recommendation.agent} (${recommendation.reason}; ${sampleSources}${extra})${description}`;
|
|
122
|
+
}),
|
|
123
|
+
"Guardrails: use these for broad tasks where a skill-specialist pass is useful; keep fanout small, use fresh context unless private/session context is explicitly needed, and skip when the user asks for a direct answer."
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
export function buildProactiveSkillSubagentRecommendationLines(input) {
|
|
127
|
+
if (!resolveProactiveSkillSubagentsConfig(input.config).enabled)
|
|
128
|
+
return [];
|
|
129
|
+
let availableSkills;
|
|
130
|
+
try {
|
|
131
|
+
availableSkills = input.discoverAvailableSkills();
|
|
132
|
+
} catch {
|
|
133
|
+
availableSkills = [];
|
|
134
|
+
}
|
|
135
|
+
return formatProactiveSkillSubagentRecommendations(recommendProactiveSkillSubagents({
|
|
136
|
+
agents: input.agents,
|
|
137
|
+
chains: input.chains,
|
|
138
|
+
availableSkills,
|
|
139
|
+
config: input.config
|
|
140
|
+
}));
|
|
141
|
+
}
|