@lmzhen/dsh-evolution-core 0.26.15 → 0.27.0

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.
Files changed (116) hide show
  1. package/README.md +16 -1
  2. package/lib/composition/index.js +3 -0
  3. package/lib/composition-D8Y3-ROd.js +604 -0
  4. package/lib/ensure-MEYMj9jn.js +222 -0
  5. package/lib/errors-Br2-uUSK.js +57 -0
  6. package/lib/http-routes-BP-S3KV-.js +149 -0
  7. package/lib/http-routes.js +2 -0
  8. package/lib/index.js +777 -840
  9. package/lib/restrictor.js +37 -0
  10. package/lib/subagent/index.js +186 -0
  11. package/lib/types/citations.js +192 -0
  12. package/lib/types/{preset-composition.d.ts → composition/composer.d.ts} +2 -2
  13. package/lib/types/composition/composer.js +681 -0
  14. package/lib/types/composition/ensure.d.ts +10 -0
  15. package/lib/types/composition/ensure.js +95 -0
  16. package/lib/types/composition/index.d.ts +5 -0
  17. package/lib/types/composition/index.js +7 -0
  18. package/lib/types/composition/preset-ids.d.ts +17 -0
  19. package/lib/types/composition/preset-ids.js +21 -0
  20. package/lib/types/composition/restricted-preset.d.ts +36 -0
  21. package/lib/types/composition/restricted-preset.js +42 -0
  22. package/lib/types/constants.js +223 -0
  23. package/lib/types/cost.js +67 -0
  24. package/lib/types/curator.d.ts +2 -0
  25. package/lib/types/curator.js +346 -0
  26. package/lib/types/diagnostics.d.ts +26 -0
  27. package/lib/types/diagnostics.js +23 -0
  28. package/lib/types/document-body.js +91 -0
  29. package/lib/types/drift-signals.js +319 -0
  30. package/lib/types/env.js +25 -0
  31. package/lib/types/errors.d.ts +4 -1
  32. package/lib/types/errors.js +59 -0
  33. package/lib/types/events.js +16 -0
  34. package/lib/types/evidence.js +65 -0
  35. package/lib/types/evolution-events.js +479 -0
  36. package/lib/types/fold-untrusted.js +44 -0
  37. package/lib/types/frontmatter.js +623 -0
  38. package/lib/types/fuzzy-match.js +135 -0
  39. package/lib/types/gates.js +51 -0
  40. package/lib/types/guards.js +27 -0
  41. package/lib/types/health-baseline.js +63 -0
  42. package/lib/types/http-routes.d.ts +67 -35
  43. package/lib/types/http-routes.js +135 -0
  44. package/lib/types/index.d.ts +13 -2
  45. package/lib/types/index.js +101 -0
  46. package/lib/types/instance-scope.js +69 -0
  47. package/lib/types/io.js +675 -0
  48. package/lib/types/learn-prompt.js +42 -0
  49. package/lib/types/limits.js +63 -0
  50. package/lib/types/live.js +107 -0
  51. package/lib/types/long-runs.js +96 -0
  52. package/lib/types/memory-store.d.ts +0 -16
  53. package/lib/types/memory-store.js +606 -0
  54. package/lib/types/mutations.js +95 -0
  55. package/lib/types/namespace-migration.js +156 -0
  56. package/lib/types/numeric.js +47 -0
  57. package/lib/types/opt-in.js +101 -0
  58. package/lib/types/package-identity.d.ts +14 -0
  59. package/lib/types/package-identity.js +47 -0
  60. package/lib/types/params.js +328 -0
  61. package/lib/types/payload.js +36 -0
  62. package/lib/types/platform-line.generated.d.ts +10 -0
  63. package/lib/types/platform-line.generated.js +12 -0
  64. package/lib/types/platform-services.d.ts +2 -2
  65. package/lib/types/platform-services.js +52 -0
  66. package/lib/types/probe.d.ts +9 -3
  67. package/lib/types/probe.js +122 -0
  68. package/lib/types/prompts.js +409 -0
  69. package/lib/types/quality.js +308 -0
  70. package/lib/types/reachability.d.ts +46 -0
  71. package/lib/types/reachability.js +122 -0
  72. package/lib/types/redact.js +257 -0
  73. package/lib/types/reference-rewrite.js +144 -0
  74. package/lib/types/reports.js +110 -0
  75. package/lib/types/restrictor.d.ts +11 -0
  76. package/lib/types/restrictor.js +48 -0
  77. package/lib/types/review-channel.js +59 -0
  78. package/lib/types/run-registry.js +345 -0
  79. package/lib/types/scope.js +7 -0
  80. package/lib/types/serial.js +17 -0
  81. package/lib/types/session-fold.d.ts +15 -0
  82. package/lib/types/session-fold.js +28 -0
  83. package/lib/types/session-projection.js +295 -0
  84. package/lib/types/signals.js +209 -0
  85. package/lib/types/skill-discovery.js +66 -0
  86. package/lib/types/skill-health.js +134 -0
  87. package/lib/types/skill-history.js +745 -0
  88. package/lib/types/skill-lint.js +112 -0
  89. package/lib/types/skill-reads.js +67 -0
  90. package/lib/types/skill-row-cells.js +123 -0
  91. package/lib/types/skill-store.d.ts +34 -3
  92. package/lib/types/skill-store.js +3528 -0
  93. package/lib/types/state-store.js +60 -0
  94. package/lib/types/store-ledger.d.ts +44 -0
  95. package/lib/types/store-ledger.js +117 -0
  96. package/lib/types/subagent/channel.d.ts +4 -0
  97. package/lib/types/subagent/channel.js +131 -0
  98. package/lib/types/subagent/index.d.ts +4 -0
  99. package/lib/types/subagent/index.js +5 -0
  100. package/lib/types/subagent/readiness.d.ts +6 -0
  101. package/lib/types/subagent/readiness.js +35 -0
  102. package/lib/types/subagent/types.d.ts +58 -0
  103. package/lib/types/subagent/types.js +2 -0
  104. package/lib/types/threats.js +338 -0
  105. package/lib/types/tool-dispatch.d.ts +5 -0
  106. package/lib/types/tool-dispatch.js +535 -0
  107. package/lib/types/tree-write.d.ts +53 -0
  108. package/lib/types/tree-write.js +40 -0
  109. package/lib/types/unit-members.js +121 -0
  110. package/lib/types/usage.js +474 -0
  111. package/lib/types/write-authority.d.ts +87 -0
  112. package/lib/types/write-authority.js +23 -0
  113. package/lib/types/write-gates.d.ts +111 -0
  114. package/lib/types/write-gates.js +344 -0
  115. package/lib/types/write-inventory.js +158 -0
  116. package/package.json +39 -11
@@ -0,0 +1,37 @@
1
+ import { n as errorText } from "./errors-Br2-uUSK.js";
2
+ //#region lib/types/restrictor.js
3
+ const name = "evolution-restrictor";
4
+ const inject = ["agentPresets"];
5
+ function normalize(names) {
6
+ return [...new Set((names ?? []).map((value) => value.trim()).filter((value) => value !== ""))].sort();
7
+ }
8
+ function failure(detail) {
9
+ return new Error(errorText("e-324-restricted-preset-unavailable", { a1: "evolution restrictor " + detail }));
10
+ }
11
+ function apply(ctx, config = {}) {
12
+ const allow = normalize(config.allow);
13
+ const deny = normalize(config.deny);
14
+ if (allow.length === 0 && deny.length === 0) throw failure("needs a non-empty allow or deny set");
15
+ const filter = {
16
+ ...allow.length > 0 ? { allow } : {},
17
+ ...deny.length > 0 ? { deny } : {}
18
+ };
19
+ const presetId = typeof config.presetId === "string" && config.presetId.trim() !== "" ? config.presetId : void 0;
20
+ if (presetId === void 0) throw failure("requires the restricted presetId in its row config");
21
+ const on = ctx.on;
22
+ if (typeof on !== "function") throw failure("requires a context that owns on()");
23
+ const presets = ctx.agentPresets;
24
+ if (presets === void 0 || typeof presets.composedPreset !== "function") throw failure("requires the agentPresets service (inject: agentPresets)");
25
+ on.call(ctx, "agent/created", (payload) => {
26
+ const agent = payload.agent;
27
+ if (agent === void 0) return;
28
+ if (presets.composedPreset(agent.ctx) !== presetId) return;
29
+ const tools = agent.ctx.tools;
30
+ if (tools === void 0 || typeof tools.restrict !== "function") throw failure("child scope exposes no tools.restrict()");
31
+ const effect = agent.ctx.effect;
32
+ if (effect === void 0) throw failure("child scope owns no effect() to release the restriction");
33
+ effect.call(agent.ctx, () => tools.restrict(filter), "evolution-restrictor:child");
34
+ });
35
+ }
36
+ //#endregion
37
+ export { apply, inject, name };
@@ -0,0 +1,186 @@
1
+ import { h as restrictedPresetId, n as ensureRestrictedPreset, r as restrictedPresetState } from "../ensure-MEYMj9jn.js";
2
+ //#region lib/types/subagent/readiness.js
3
+ function serviceOf$1(ctx, name) {
4
+ return ctx.get(name);
5
+ }
6
+ function kindOf(kind) {
7
+ return kind === "reviewer" ? "reviewer" : "maintainer";
8
+ }
9
+ /** Pure derivation (no side effects): the doctor reads this, the channel re-probes on every run. */
10
+ function probeChannelState(ctx, kind) {
11
+ const subagents = serviceOf$1(ctx, "subagents");
12
+ if (subagents === void 0 || typeof subagents.getProvider !== "function") return {
13
+ kind: "unavailable",
14
+ code: "E-323",
15
+ reason: "subagents service unavailable"
16
+ };
17
+ const provider = subagents.getProvider("spawn");
18
+ if (provider === void 0) return {
19
+ kind: "unavailable",
20
+ code: "E-323",
21
+ reason: "spawn provider unavailable"
22
+ };
23
+ if (provider.capabilities?.agentPreset !== true) return {
24
+ kind: "unavailable",
25
+ code: "E-323",
26
+ reason: "spawn provider lacks the agentPreset capability"
27
+ };
28
+ if (provider.inheritsParentContext === true) return {
29
+ kind: "unavailable",
30
+ code: "E-323",
31
+ reason: "spawn provider inherits the parent context (independent preset required)"
32
+ };
33
+ const agentPresets = serviceOf$1(ctx, "agentPresets");
34
+ if (agentPresets === void 0 || typeof agentPresets.readDocument !== "function" || typeof agentPresets.register !== "function") return {
35
+ kind: "unavailable",
36
+ code: "E-323",
37
+ reason: "agentPresets service unavailable or incomplete"
38
+ };
39
+ return {
40
+ kind: "available",
41
+ provider: "spawn",
42
+ preset: {
43
+ id: restrictedPresetId(kindOf(kind)),
44
+ registered: restrictedPresetState(ctx, kindOf(kind))?.kind === "ready"
45
+ }
46
+ };
47
+ }
48
+ function subagentChannelState(ctx, kind) {
49
+ return probeChannelState(ctx, kind);
50
+ }
51
+ //#endregion
52
+ //#region lib/types/subagent/channel.js
53
+ function serviceOf(ctx, name) {
54
+ return ctx.get(name);
55
+ }
56
+ function messageOf(error) {
57
+ return error instanceof Error ? error.message : String(error);
58
+ }
59
+ function createSubagentChannel(ctx) {
60
+ let lastKind = "reviewer";
61
+ return {
62
+ get state() {
63
+ return probeChannelState(ctx, lastKind);
64
+ },
65
+ prepare(spec) {
66
+ lastKind = spec.kind;
67
+ const state = probeChannelState(ctx, spec.kind);
68
+ if (state.kind === "unavailable") return Promise.resolve(state);
69
+ if (spec.allow.length === 0) return Promise.resolve({
70
+ kind: "unavailable",
71
+ code: "E-324",
72
+ reason: "allow set is empty"
73
+ });
74
+ return Promise.resolve(state);
75
+ },
76
+ async run(spec) {
77
+ lastKind = spec.kind;
78
+ const probe = probeChannelState(ctx, spec.kind);
79
+ if (probe.kind === "unavailable") return probe;
80
+ const subagents = serviceOf(ctx, "subagents");
81
+ const presets = serviceOf(ctx, "agentPresets");
82
+ if (subagents === void 0 || presets === void 0) return {
83
+ kind: "unavailable",
84
+ code: "E-323",
85
+ reason: "subagents/agentPresets service unavailable"
86
+ };
87
+ const parentPresetId = presets.composedPreset(spec.parent.ctx);
88
+ if (parentPresetId === void 0) return {
89
+ kind: "unavailable",
90
+ code: "E-323",
91
+ reason: "parent preset could not be resolved"
92
+ };
93
+ const ensured = await ensureRestrictedPreset(ctx, {
94
+ kind: spec.kind,
95
+ parentPresetId,
96
+ allow: spec.allow
97
+ });
98
+ if (ensured.kind === "failed") return {
99
+ kind: "unavailable",
100
+ code: "E-324",
101
+ reason: ensured.reason
102
+ };
103
+ const controller = new AbortController();
104
+ const timer = setTimeout(() => {
105
+ controller.abort(/* @__PURE__ */ new Error("subagent timeout"));
106
+ }, spec.timeoutMs);
107
+ const onAbort = () => {
108
+ controller.abort(spec.signal?.reason);
109
+ };
110
+ spec.signal?.addEventListener("abort", onAbort, { once: true });
111
+ let activation;
112
+ try {
113
+ activation = await subagents.startActivation({
114
+ provider: "spawn",
115
+ label: spec.label,
116
+ delivery: "caller",
117
+ request: {
118
+ parent: spec.parent,
119
+ prompt: [{
120
+ type: "text",
121
+ text: spec.promptText
122
+ }],
123
+ agentPreset: ensured.presetId,
124
+ ...spec.outputSchema !== void 0 ? { outputSchema: spec.outputSchema } : {},
125
+ ...spec.maxDepth !== void 0 ? { maxDepth: spec.maxDepth } : {},
126
+ ...spec.agentOptions !== void 0 ? { agentOptions: spec.agentOptions } : {}
127
+ },
128
+ signal: controller.signal
129
+ });
130
+ let result;
131
+ try {
132
+ result = await activation.result;
133
+ } catch (error) {
134
+ if (controller.signal.aborted) return { kind: "aborted" };
135
+ return {
136
+ kind: "unavailable",
137
+ code: "E-323",
138
+ reason: messageOf(error)
139
+ };
140
+ }
141
+ let evidence;
142
+ if (spec.afterResult !== void 0) try {
143
+ const child = serviceOf(ctx, "agents")?.get(activation.childId);
144
+ if (child !== void 0) evidence = spec.afterResult(child);
145
+ } catch {
146
+ evidence = void 0;
147
+ }
148
+ const stopReason = result.stopReason;
149
+ if (stopReason === "completed" && result.structured !== void 0 && result.structured !== null) return {
150
+ kind: "ok",
151
+ structured: result.structured,
152
+ childId: activation.childId,
153
+ stopReason: "completed",
154
+ ...evidence !== void 0 ? { evidence } : {}
155
+ };
156
+ if (stopReason === "aborted") return { kind: "aborted" };
157
+ return {
158
+ kind: "no-structured",
159
+ childId: activation.childId,
160
+ stopReason,
161
+ ...result.diagnostic !== void 0 ? { diagnostic: result.diagnostic } : {},
162
+ ...evidence !== void 0 ? { evidence } : {}
163
+ };
164
+ } catch (error) {
165
+ if (controller.signal.aborted) return { kind: "aborted" };
166
+ return {
167
+ kind: "unavailable",
168
+ code: "E-323",
169
+ reason: messageOf(error)
170
+ };
171
+ } finally {
172
+ clearTimeout(timer);
173
+ spec.signal?.removeEventListener("abort", onAbort);
174
+ if (activation !== void 0) try {
175
+ await activation.dispose();
176
+ } catch (error) {
177
+ try {
178
+ ctx.logger.warn("subagent channel: activation dispose failed: " + messageOf(error));
179
+ } catch {}
180
+ }
181
+ }
182
+ }
183
+ };
184
+ }
185
+ //#endregion
186
+ export { createSubagentChannel, probeChannelState, subagentChannelState };
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Citation resolution for skill bodies and support files (design §5.2).
3
+ *
4
+ * WHY this exists beside `supportRefs` (skill-store.ts): that scanner answers
5
+ * "does this text contain a path-shaped token", which is the right question
6
+ * when a package is being ARCHIVED — every such path may dangle — and the wrong
7
+ * one when a section is only being MOVED, where nothing leaves and the only
8
+ * thing that changes is the directory a citation is read from. Measured false
9
+ * positives of the token scan: a URL tail (`https://host/references/x.md`), a
10
+ * category path the original Hermes documents as legitimate
11
+ * (`skills/scripts/foo.py`), and a prose command line
12
+ * (`npm run scripts/build.mjs`).
13
+ *
14
+ * CONTRACT: a token whose path STARTS WITH a support directory is a citation of
15
+ * this skill and is resolved from the SKILL ROOT, in whichever file it is
16
+ * written. A token that merely contains a support directory further along its
17
+ * path belongs to something else: it is reported as `foreign` and never
18
+ * resolved.
19
+ *
20
+ * PURE: existence is decided against the caller's file list, so identical
21
+ * inputs always answer the same report.
22
+ */
23
+ /** Support directories that make a path a citation of the owning skill. */
24
+ export const CITATION_SUPPORT_DIRS = ['references', 'templates', 'scripts', 'assets'];
25
+ /** Scan budget: bounded so a pathological body cannot stall a maintenance run. */
26
+ export const DEFAULT_CITATION_REF_BUDGET = 500;
27
+ /** Words that introduce an executable command rather than a citation. */
28
+ const PROSE_COMMAND_PREFIXES = ['npm', 'pnpm', 'yarn', 'npx', 'node', 'python', 'python3', 'bash', 'sh', 'git', 'gh', 'run'];
29
+ const TOKEN_RE = /(?:references|templates|scripts|assets)\/[A-Za-z0-9._/-]+/g;
30
+ const TOKEN_CHAR_RE = /[A-Za-z0-9._/-]/;
31
+ const FENCE_RE = /^\s*(`{3,}|~{3,})/;
32
+ const TRAILING_PUNCT_RE = /[.,;:]+$/;
33
+ /** A citation's final segment must look like \u0060name.ext\u0060: a bare \u0060.\u0060 or a dotless
34
+ * segment is a directory mention, not a file. */
35
+ const FILE_SEGMENT_RE = /^[^.].*\.[^.]+$/;
36
+ const FRAGMENT_RE = /^#([A-Za-z0-9._-]+)/;
37
+ /** Whether the token starting at `start` is the argument of a shell command. */
38
+ function isProseCommand(line, start) {
39
+ const head = line.slice(0, start).trimEnd();
40
+ if (head === '')
41
+ return false;
42
+ const word = head.split(/\s+/).pop() ?? '';
43
+ return PROSE_COMMAND_PREFIXES.includes(word);
44
+ }
45
+ /** The token's final path segment (`references/a/b.md` -> `b.md`). */
46
+ function lastSegmentOf(target) {
47
+ return target.slice(target.lastIndexOf('/') + 1);
48
+ }
49
+ /** The token's parent directory within the skill (`references/a/b.md` -> `references/a`). */
50
+ function parentDirOf(target) {
51
+ const cut = target.lastIndexOf('/');
52
+ return cut <= 0 ? '' : target.slice(0, cut);
53
+ }
54
+ /** Classify one token by its first path segment. */
55
+ function classifyToken(token) {
56
+ const head = token.split('/')[0] ?? '';
57
+ return CITATION_SUPPORT_DIRS.includes(head) ? 'citation' : 'foreign';
58
+ }
59
+ /**
60
+ * Resolve every path-shaped token in `content`.
61
+ * @param input - content, the skill-root-relative path of its owner, the skill's
62
+ * file list, and an optional scan budget.
63
+ * @returns the refs plus the dangling and foreign subsets; `truncated` marks a
64
+ * report that stopped at the budget.
65
+ */
66
+ export function resolveCitations(input) {
67
+ const budget = input.budget ?? DEFAULT_CITATION_REF_BUDGET;
68
+ const files = new Set(input.files.map(path => path.replace(/\\/g, '/')));
69
+ const refs = [];
70
+ const seen = new Set();
71
+ let truncated = false;
72
+ let fence = null;
73
+ const lines = input.content.split('\n');
74
+ for (let index = 0; index < lines.length && !truncated; index += 1) {
75
+ const rawLine = lines[index] ?? '';
76
+ const line = rawLine.endsWith('\r') ? rawLine.slice(0, -1) : rawLine;
77
+ const fenceMark = FENCE_RE.exec(line);
78
+ if (fenceMark) {
79
+ const marker = fenceMark[1] ?? '';
80
+ fence = fence === null ? marker.slice(0, 1) : null;
81
+ continue;
82
+ }
83
+ for (const match of line.matchAll(TOKEN_RE)) {
84
+ const matched = match[0];
85
+ const matchedAt = match.index;
86
+ let start = matchedAt;
87
+ while (start > 0 && TOKEN_CHAR_RE.test(line[start - 1] ?? ''))
88
+ start -= 1;
89
+ const prefix = line.slice(0, start);
90
+ const tail = line.slice(matchedAt + matched.length);
91
+ const fragment = FRAGMENT_RE.exec(tail)?.[1];
92
+ const token = matched.replace(TRAILING_PUNCT_RE, '');
93
+ const scanned = line.slice(start, matchedAt + matched.length);
94
+ const classified = fence !== null
95
+ ? 'fence'
96
+ : prefix.endsWith(':') && line.slice(start, start + 2) === '//'
97
+ ? 'url'
98
+ : isProseCommand(line, start)
99
+ ? 'prose'
100
+ : classifyToken(scanned);
101
+ // A citation names a FILE: a dotless last segment is a directory mention
102
+ // (`references/templates/scripts` in prose), and a `..` segment is a
103
+ // traversal — a different defect class the old scanner also skipped. Both
104
+ // are prose unless the listing proves the path is a real entry.
105
+ const traversal = scanned.split('/').includes('..');
106
+ const namesFile = !traversal && (FILE_SEGMENT_RE.test(lastSegmentOf(scanned)) || files.has(token));
107
+ const kind = classified === 'citation' && !namesFile ? 'prose' : classified;
108
+ const target = kind === 'citation' ? token : null;
109
+ const key = `${index}|${kind}|${target ?? token}`;
110
+ if (seen.has(key))
111
+ continue;
112
+ seen.add(key);
113
+ refs.push({
114
+ raw: token,
115
+ line: index + 1,
116
+ target,
117
+ base: 'root',
118
+ kind,
119
+ exists: target !== null && files.has(target),
120
+ ...(fragment === undefined ? {} : { fragment }),
121
+ });
122
+ if (refs.length >= budget) {
123
+ truncated = true;
124
+ break;
125
+ }
126
+ }
127
+ }
128
+ const citations = refs.filter(ref => ref.kind === 'citation');
129
+ const undecidable = (ref) => {
130
+ const target = ref.target;
131
+ return target !== null && !ref.exists && files.has(parentDirOf(target));
132
+ };
133
+ return {
134
+ refs,
135
+ dangling: citations.filter(ref => !ref.exists && !undecidable(ref)),
136
+ unverified: citations.filter(undecidable),
137
+ foreign: refs.filter(ref => ref.kind !== 'citation'),
138
+ truncated,
139
+ };
140
+ }
141
+ /** The sanctioned body hook (design §5.6): a list item whose payload is
142
+ * exactly one support-file path, so the file stays discoverable in the body. */
143
+ export const HOOK_LINE_RE = /^- [^\n]{1,60} → ((?:references|templates|scripts|assets)\/[a-z0-9][a-z0-9._/-]*)$/;
144
+ /** The retirement escape hatch (design §5.6): a standalone body comment that
145
+ * names the support file it exempts and the reason it must survive. The path
146
+ * is part of the marker because the proposal list is per FILE, and a reason is
147
+ * required — an unexplained exemption is what this hook exists to prevent. */
148
+ export const KEEP_LINE_RE = /^<!--\s*keep:\s*((?:references|templates|scripts|assets)\/[a-z0-9][a-z0-9._/-]*)\s+(\S[^>]*?)\s*-->$/;
149
+ /** Whether a skill-relative path names a FILE rather than a directory: the same
150
+ * rule the scanner applies to a token's final segment (`name.ext`). The support
151
+ * listing is one level deep and includes directory entries (a real library has
152
+ * `references/archive`), which no pointer or retirement list may treat as a file.
153
+ * @param path - a skill-root-relative support path.
154
+ * @returns true when the final segment is file-shaped.
155
+ */
156
+ export function isFileShapedPath(path) {
157
+ return FILE_SEGMENT_RE.test(path.slice(path.lastIndexOf('/') + 1));
158
+ }
159
+ /**
160
+ * Scan a body for sanctioned hooks and `keep` markers.
161
+ * @param content - the SKILL.md body (frontmatter included).
162
+ * @returns hook targets plus the `keep` reasons keyed by target.
163
+ */
164
+ export function scanBodyHooks(content) {
165
+ const targets = [];
166
+ const seen = new Set();
167
+ const kept = new Map();
168
+ // A hook-shaped line inside a fenced block is sample text, not a pointer.
169
+ let fence = null;
170
+ for (const rawLine of content.split('\n')) {
171
+ const line = rawLine.endsWith('\r') ? rawLine.slice(0, -1) : rawLine;
172
+ const fenceMark = FENCE_RE.exec(line);
173
+ if (fenceMark) {
174
+ fence = fence === null ? (fenceMark[1] ?? '').slice(0, 1) : null;
175
+ continue;
176
+ }
177
+ if (fence !== null)
178
+ continue;
179
+ const keep = KEEP_LINE_RE.exec(line);
180
+ if (keep?.[1] !== undefined) {
181
+ kept.set(keep[1], (keep[2] ?? '').trim());
182
+ continue;
183
+ }
184
+ const target = HOOK_LINE_RE.exec(line)?.[1];
185
+ if (target === undefined || seen.has(target))
186
+ continue;
187
+ seen.add(target);
188
+ targets.push(target);
189
+ }
190
+ return { targets, kept };
191
+ }
192
+ //# sourceMappingURL=citations.js.map
@@ -82,7 +82,7 @@ export declare function loadRowOverrides(path?: string): RowOverride[];
82
82
  */
83
83
  export declare function compositionRowIds(composition: string): Set<string>;
84
84
  /** The platform package a DECLARATIVE preset row names (0.2.x replaced preset directories with it). */
85
- export declare const AGENT_PRESET_PACKAGE = "@deepseek-ai/dsh-agent-preset";
85
+ export declare const AGENT_PRESET_PACKAGE: string;
86
86
  /** Identity and display metadata of one generated preset row. */
87
87
  export interface PresetRowIdentity {
88
88
  /** The composition row id (`- id:`); what {@link mergePresetRow} replaces by. */
@@ -304,4 +304,4 @@ export declare function trimTrailingBlankLines(lines: string[]): string[];
304
304
  */
305
305
  export declare function presetPatchText(patchText: string): string;
306
306
  export {};
307
- //# sourceMappingURL=preset-composition.d.ts.map
307
+ //# sourceMappingURL=composer.d.ts.map