@lmzhen/dsh-evolution-core 0.26.26 → 0.27.1
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 +16 -1
- package/lib/composition/index.js +3 -0
- package/lib/composition-D8Y3-ROd.js +604 -0
- package/lib/ensure-MEYMj9jn.js +222 -0
- package/lib/errors-Br2-uUSK.js +57 -0
- package/lib/http-routes-BP-S3KV-.js +149 -0
- package/lib/http-routes.js +2 -0
- package/lib/index.js +66 -850
- package/lib/restrictor.js +37 -0
- package/lib/subagent/index.js +186 -0
- package/lib/types/citations.js +192 -0
- package/lib/types/{preset-composition.d.ts → composition/composer.d.ts} +1 -1
- package/lib/types/composition/composer.js +681 -0
- package/lib/types/composition/ensure.d.ts +10 -0
- package/lib/types/composition/ensure.js +95 -0
- package/lib/types/composition/index.d.ts +5 -0
- package/lib/types/composition/index.js +7 -0
- package/lib/types/composition/preset-ids.d.ts +17 -0
- package/lib/types/composition/preset-ids.js +21 -0
- package/lib/types/composition/restricted-preset.d.ts +36 -0
- package/lib/types/composition/restricted-preset.js +42 -0
- package/lib/types/constants.js +223 -0
- package/lib/types/cost.js +67 -0
- package/lib/types/curator.js +346 -0
- package/lib/types/diagnostics.d.ts +26 -0
- package/lib/types/diagnostics.js +23 -0
- package/lib/types/document-body.js +91 -0
- package/lib/types/drift-signals.js +319 -0
- package/lib/types/env.js +25 -0
- package/lib/types/errors.d.ts +4 -1
- package/lib/types/errors.js +59 -0
- package/lib/types/events.js +16 -0
- package/lib/types/evidence.js +65 -0
- package/lib/types/evolution-events.js +479 -0
- package/lib/types/fold-untrusted.js +44 -0
- package/lib/types/frontmatter.js +623 -0
- package/lib/types/fuzzy-match.js +135 -0
- package/lib/types/gates.js +51 -0
- package/lib/types/guards.js +27 -0
- package/lib/types/health-baseline.js +63 -0
- package/lib/types/http-routes.d.ts +67 -35
- package/lib/types/http-routes.js +135 -0
- package/lib/types/index.d.ts +7 -2
- package/lib/types/index.js +101 -0
- package/lib/types/instance-scope.js +69 -0
- package/lib/types/io.js +675 -0
- package/lib/types/learn-prompt.js +42 -0
- package/lib/types/limits.js +63 -0
- package/lib/types/live.js +107 -0
- package/lib/types/long-runs.js +96 -0
- package/lib/types/memory-store.d.ts +0 -16
- package/lib/types/memory-store.js +606 -0
- package/lib/types/mutations.js +95 -0
- package/lib/types/namespace-migration.js +156 -0
- package/lib/types/numeric.js +47 -0
- package/lib/types/opt-in.js +101 -0
- package/lib/types/package-identity.js +47 -0
- package/lib/types/params.js +328 -0
- package/lib/types/payload.js +36 -0
- package/lib/types/platform-line.generated.d.ts +10 -0
- package/lib/types/platform-line.generated.js +12 -0
- package/lib/types/platform-services.d.ts +2 -2
- package/lib/types/platform-services.js +52 -0
- package/lib/types/probe.js +122 -0
- package/lib/types/prompts.js +409 -0
- package/lib/types/quality.js +308 -0
- package/lib/types/reachability.js +122 -0
- package/lib/types/redact.js +257 -0
- package/lib/types/reference-rewrite.js +144 -0
- package/lib/types/reports.js +110 -0
- package/lib/types/restrictor.d.ts +11 -0
- package/lib/types/restrictor.js +48 -0
- package/lib/types/review-channel.js +59 -0
- package/lib/types/run-registry.js +345 -0
- package/lib/types/scope.js +7 -0
- package/lib/types/serial.js +17 -0
- package/lib/types/session-fold.d.ts +15 -0
- package/lib/types/session-fold.js +28 -0
- package/lib/types/session-projection.js +295 -0
- package/lib/types/signals.js +209 -0
- package/lib/types/skill-discovery.js +66 -0
- package/lib/types/skill-health.js +134 -0
- package/lib/types/skill-history.js +745 -0
- package/lib/types/skill-lint.js +112 -0
- package/lib/types/skill-reads.js +67 -0
- package/lib/types/skill-row-cells.js +123 -0
- package/lib/types/skill-store.js +3528 -0
- package/lib/types/state-store.js +60 -0
- package/lib/types/store-ledger.js +117 -0
- package/lib/types/subagent/channel.d.ts +4 -0
- package/lib/types/subagent/channel.js +131 -0
- package/lib/types/subagent/index.d.ts +4 -0
- package/lib/types/subagent/index.js +5 -0
- package/lib/types/subagent/readiness.d.ts +6 -0
- package/lib/types/subagent/readiness.js +35 -0
- package/lib/types/subagent/types.d.ts +58 -0
- package/lib/types/subagent/types.js +2 -0
- package/lib/types/threats.js +338 -0
- package/lib/types/tool-dispatch.d.ts +5 -0
- package/lib/types/tool-dispatch.js +535 -0
- package/lib/types/tree-write.js +40 -0
- package/lib/types/unit-members.js +121 -0
- package/lib/types/usage.js +474 -0
- package/lib/types/write-authority.js +23 -0
- package/lib/types/write-gates.js +344 -0
- package/lib/types/write-inventory.js +158 -0
- package/package.json +39 -11
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export function probePresent(value) {
|
|
2
|
+
return { kind: 'present', value };
|
|
3
|
+
}
|
|
4
|
+
export function probeAbsent() {
|
|
5
|
+
return { kind: 'absent' };
|
|
6
|
+
}
|
|
7
|
+
export function probeUnknown(reason) {
|
|
8
|
+
return { kind: 'unknown', reason };
|
|
9
|
+
}
|
|
10
|
+
export function isPresent(probe) {
|
|
11
|
+
return probe.kind === 'present';
|
|
12
|
+
}
|
|
13
|
+
export function isAbsent(probe) {
|
|
14
|
+
return probe.kind === 'absent';
|
|
15
|
+
}
|
|
16
|
+
export function isUnknown(probe) {
|
|
17
|
+
return probe.kind === 'unknown';
|
|
18
|
+
}
|
|
19
|
+
/** Only a PRESENT probe yields a value; absent and unknown both fall back. */
|
|
20
|
+
export function valueOr(probe, fallback) {
|
|
21
|
+
return probe.kind === 'present' ? probe.value : fallback;
|
|
22
|
+
}
|
|
23
|
+
export function mapProbe(probe, transform) {
|
|
24
|
+
return probe.kind === 'present' ? probePresent(transform(probe.value)) : probe;
|
|
25
|
+
}
|
|
26
|
+
/** The reason an `unknown` probe carries (message, never a bare String(object)). */
|
|
27
|
+
export function probeReason(error) {
|
|
28
|
+
return error instanceof Error ? error.message : String(error);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* ENOENT/ENOTDIR are the ONE read failure that means "it is not there"; every
|
|
32
|
+
* other failure is an IO error and stays unknown (same split as the node
|
|
33
|
+
* backend's own isMissing, V8-23⑨ for the size probe).
|
|
34
|
+
*/
|
|
35
|
+
export function isMissingPath(error) {
|
|
36
|
+
const code = error?.code;
|
|
37
|
+
return code === 'ENOENT' || code === 'ENOTDIR';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Three-state directory listing. The node backend already answers `[]` for a
|
|
41
|
+
* MISSING directory (its own rc.50 P2-4 contract) and THROWS for an unreadable
|
|
42
|
+
* one, so the value this adds is the second half: a backend that throws ENOENT
|
|
43
|
+
* reads as absent, an EACCES/EIO reads as unknown — where a bare
|
|
44
|
+
* `catch { return [] }` served a broken store as an empty one (the N14 class).
|
|
45
|
+
*/
|
|
46
|
+
export async function probeList(io, dir) {
|
|
47
|
+
try {
|
|
48
|
+
return probePresent(await io.list(dir));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return isMissingPath(error) ? probeAbsent() : probeUnknown(probeReason(error));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Three-state TEXT read of one file. A missing path (ENOENT/ENOTDIR, or a backend whose read
|
|
56
|
+
* answers null) is `absent`; every other failure is `unknown` with its reason. The distinction is
|
|
57
|
+
* the whole point (N14/O-7): "I could not read this file" and "this file is not there" lead to
|
|
58
|
+
* opposite decisions once a write is about to replace the bytes — treating the first as the
|
|
59
|
+
* second is how a broken store reads as empty and a rescue copy never happens.
|
|
60
|
+
* @param io - the IO seam.
|
|
61
|
+
* @param path - the file to read.
|
|
62
|
+
* @returns the probe.
|
|
63
|
+
*/
|
|
64
|
+
export async function probeText(io, path) {
|
|
65
|
+
try {
|
|
66
|
+
const value = await io.readText(path);
|
|
67
|
+
return value === null ? probeAbsent() : probePresent(value);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return isMissingPath(error) ? probeAbsent() : probeUnknown(probeReason(error));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Three-state mtime read. Absent covers both "the path is missing" and "this
|
|
75
|
+
* backend has no mtime probe" — the seam cannot tell those apart, so consumers
|
|
76
|
+
* that must know say so in their own log line. A stat that FAILS is unknown.
|
|
77
|
+
*/
|
|
78
|
+
export async function probeMtime(io, path) {
|
|
79
|
+
try {
|
|
80
|
+
const value = (await io.mtime?.(path)) ?? null;
|
|
81
|
+
return value === null ? probeAbsent() : probePresent(value);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return probeUnknown(probeReason(error));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** The timestamp a curator run report DECLARES: `startedAt` (the run's own start), then `at` (the
|
|
88
|
+
* stamp the error writer sets on every report — F-327/P2-4).
|
|
89
|
+
* @param parsed - the parsed report, or anything else.
|
|
90
|
+
* @returns epoch milliseconds, or null when neither field carries a parseable time.
|
|
91
|
+
*/
|
|
92
|
+
export function declaredReportStamp(parsed) {
|
|
93
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
94
|
+
return null;
|
|
95
|
+
const record = parsed;
|
|
96
|
+
for (const value of [record.startedAt, record.at]) {
|
|
97
|
+
if (typeof value !== 'string')
|
|
98
|
+
continue;
|
|
99
|
+
const ms = Date.parse(value);
|
|
100
|
+
if (Number.isFinite(ms))
|
|
101
|
+
return ms;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/** The time one curator run report is ordered by — ONE口径 for every reader (S2.9/T3-12): the
|
|
106
|
+
* declared stamp above, then the optional mtime probe as the fallback. `null` means "no usable
|
|
107
|
+
* time", and that single answer serves both consumers: such a report is never the LATEST (the
|
|
108
|
+
* panel) and is never DELETED (the retention sweep), which is exactly the pair of answers the two
|
|
109
|
+
* readers disagreed on when one ordered by the declared stamp and the other by mtime alone.
|
|
110
|
+
* @param io - the IO seam; a backend without `mtime` simply has no fallback.
|
|
111
|
+
* @param path - the report file the probe reads.
|
|
112
|
+
* @param parsed - the already-parsed report.
|
|
113
|
+
* @returns epoch milliseconds, or null.
|
|
114
|
+
*/
|
|
115
|
+
export async function reportTime(io, path, parsed) {
|
|
116
|
+
const declared = declaredReportStamp(parsed);
|
|
117
|
+
if (declared !== null)
|
|
118
|
+
return declared;
|
|
119
|
+
const probe = await probeMtime(io, path);
|
|
120
|
+
return isPresent(probe) ? probe.value : null;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=probe.js.map
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review and curation prompts adapted from Hermes Agent
|
|
3
|
+
* `agent/background_review.py`, `agent/curator.py`, and
|
|
4
|
+
* `agent/learn_prompt.py`, with tool names translated to the DSH-native
|
|
5
|
+
* catalog (`memory`, `skill_manage`, `skill`, `bash`, `str_replace_editor`).
|
|
6
|
+
*
|
|
7
|
+
* Alignment policy (2026-08-29): the OPERATIONAL steps and instructions the
|
|
8
|
+
* model follows mirror the Hermes originals structurally (signal list,
|
|
9
|
+
* preference order, support-file taxonomy, curator package integrity,
|
|
10
|
+
* consolidated/pruned reporting block). Tool and platform differences are
|
|
11
|
+
* DSH-adapted (native tool names, pinned-within-review semantics, this
|
|
12
|
+
* platform's index cap), and DSH-only additions are marked as such.
|
|
13
|
+
*
|
|
14
|
+
* Every prompt is pinned in a versioned bundle. Review workers verify the
|
|
15
|
+
* bundle digest before spending a model call — v31 PROMPT-01, stated
|
|
16
|
+
* precisely: THAT check proves internal coherence (id/version/digest agree)
|
|
17
|
+
* for a bundle assembled OUT of process and handed to `verifyPromptBundle`
|
|
18
|
+
* explicitly. It CANNOT detect in-process tampering (the digest is recomputed
|
|
19
|
+
* from the same module state it verifies) — catching a stale or partially
|
|
20
|
+
* patched default bundle is CI's version pin (tests/prompts.spec.ts), not
|
|
21
|
+
* this runtime gate.
|
|
22
|
+
*/
|
|
23
|
+
import { createHash } from 'node:crypto';
|
|
24
|
+
/**
|
|
25
|
+
* Prompt bundle identity. Bump both id and version whenever a prompt's text
|
|
26
|
+
* changes semantically: the bundle digest is the fail-closed signal for
|
|
27
|
+
* review workers, so a stale id across deployments must be distinguishable.
|
|
28
|
+
*/
|
|
29
|
+
export const PROMPT_BUNDLE_VERSION = 21;
|
|
30
|
+
// 0.3.16 (S1.12, T-5): the id is DERIVED from the version — a one-number bump
|
|
31
|
+
// can no longer drift the two apart.
|
|
32
|
+
export const PROMPT_BUNDLE_ID = `dsh-evolution@${PROMPT_BUNDLE_VERSION}`;
|
|
33
|
+
export const MEMORY_REVIEW_PROMPT = `[Auto-review — Memory]
|
|
34
|
+
Review the conversation above and consider saving to memory if appropriate.
|
|
35
|
+
|
|
36
|
+
Focus on:
|
|
37
|
+
1. Has the user revealed things about themselves — persona, desires, preferences, or personal details worth remembering?
|
|
38
|
+
2. Has the user expressed expectations about how you should behave, their work style, or ways they want you to operate?
|
|
39
|
+
|
|
40
|
+
If something stands out, save it using the memory tool.
|
|
41
|
+
If nothing is worth saving, just say "Nothing to save." and stop.`;
|
|
42
|
+
export const SKILL_REVIEW_PROMPT = `[Auto-review — Skills]
|
|
43
|
+
Review the conversation above and update the skill library. Be ACTIVE — most sessions produce at least one skill update, even if small. A pass that does nothing is a missed learning opportunity, not a neutral outcome.
|
|
44
|
+
|
|
45
|
+
Target shape of the library: CLASS-LEVEL skills, each with a rich SKILL.md and a references/ directory for session-specific detail. Not a long flat list of narrow one-session-one-skill entries. This shapes HOW you update, not WHETHER you update.
|
|
46
|
+
|
|
47
|
+
Signals to look for (any one of these warrants action):
|
|
48
|
+
• User corrected your style, tone, format, legibility, or verbosity. Frustration signals like 'stop doing X', 'this is too verbose', 'don't format like this', 'why are you explaining', 'just give me the answer', 'you always do Y and I hate it', or an explicit 'remember this' are FIRST-CLASS skill signals, not just memory signals. Update the relevant skill(s) to embed the preference so the next session starts already knowing.
|
|
49
|
+
• User corrected your workflow, approach, or sequence of steps. Encode the correction as a pitfall or explicit step in the skill that governs that class of task.
|
|
50
|
+
• Non-trivial technique, fix, workaround, debugging path, or tool-usage pattern emerged that a future session would benefit from. Capture it.
|
|
51
|
+
• A skill that got loaded or consulted this session turned out to be wrong, missing a step, or outdated. Patch it NOW.
|
|
52
|
+
|
|
53
|
+
Read-before-write: update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session. On the plan channel ops on unread skills are rejected; direct writes have no such guard, so treat the rule as binding. CREATE of a brand-new umbrella is the only exception.
|
|
54
|
+
|
|
55
|
+
Preference order — prefer the earliest action that fits, but do pick one when a signal above fired:
|
|
56
|
+
1. UPDATE A CURRENTLY-LOADED SKILL. Look back through the conversation for skills the user loaded or you read. If any of them covers the territory of the new learning, PATCH that one first. It is the skill that was in play, so it's the right one to extend.
|
|
57
|
+
2. UPDATE AN EXISTING UMBRELLA. If no loaded skill fits but an existing class-level skill does, patch it. Add a subsection, a pitfall, or broaden a trigger.
|
|
58
|
+
3. ADD A SUPPORT FILE under an existing umbrella. Skills can be packaged with three kinds of support files — use the right directory per kind:
|
|
59
|
+
• references/<topic>.md — session-specific detail (error transcripts, reproduction recipes, provider quirks) AND condensed knowledge banks: quoted research, API docs, external authoritative excerpts, or domain notes you found while working on the problem. Write it concise and for the value of the task, not as a full mirror of upstream docs.
|
|
60
|
+
• templates/<name>.<ext> — starter files meant to be copied and modified (boilerplate configs, scaffolding, a known-good example the agent can reproduce with modifications).
|
|
61
|
+
• scripts/<name>.<ext> — statically re-runnable actions the skill can invoke directly (verification scripts, fixture generators, deterministic probes, anything the agent should run rather than hand-type each time).
|
|
62
|
+
Add support files via skill_manage action=write_file with file_path starting 'references/', 'templates/', or 'scripts/'. The umbrella's SKILL.md should gain a one-line pointer to any new support file so future agents know it exists.
|
|
63
|
+
4. RESTRUCTURE a loaded skill whose body grew log-like — rc/sha/date-dense sections, session-detail spirals, or a fat body with no support files. Use skill_manage action=restructure with restructure: [{"heading": "<the exact ## heading text>", "to_file": "references/<topic>.md"}] — the ENTIRE ## section (from that heading to the next heading) moves into the support file and its position becomes a pointer line. The skill's name and directory never change. Only propose headings that exist verbatim in the body; never invent one, and never restructure a healthy small skill.
|
|
64
|
+
5. CREATE A NEW CLASS-LEVEL UMBRELLA SKILL when no existing skill covers the class. The name MUST be at the class level. The name MUST NOT be a specific PR number, error string, feature codename, library-alone name, or 'fix-X / debug-Y / audit-Z-today' session artifact. If the proposed name only makes sense for today's task, it's wrong — fall back to (1), (2), or (3).
|
|
65
|
+
|
|
66
|
+
User-preference embedding (important): when the user expressed a style/format/workflow preference, the update belongs in the SKILL.md body, not just in memory. Memory captures 'who the user is and what the current situation and state of your operations are'; skills capture 'how to do this class of task for this user'. When they complain about how you handled a task, the skill that governs that task needs to carry the lesson.
|
|
67
|
+
|
|
68
|
+
If you notice two existing skills that overlap, note it in your reply — the background curator handles consolidation at scale.
|
|
69
|
+
|
|
70
|
+
Two-tier deposition discipline (DSH addition, same spirit as the umbrella rule): before writing, classify the knowledge:
|
|
71
|
+
• PATTERN (reusable — symptom → mechanism → fix → verification, still valuable next session) belongs in the SKILL.md body.
|
|
72
|
+
• LOG (one-off — commit SHAs, npm/profile states, what this release changed, this session's process narrative) belongs in a references/ file, never the body. Body density IS reuse rate. Keep new entries tight: a pattern fits in 2-8 physical lines; prefer changing the current-state pointer over appending history.
|
|
73
|
+
|
|
74
|
+
Protected skills (DO NOT edit these):
|
|
75
|
+
• Bundled skills (shipped with the platform).
|
|
76
|
+
• Hub-installed skills (installed from a hub).
|
|
77
|
+
Pinned skills are read-only to THIS background review pass — the pinned write guard refuses background changes, so this pass may not update them. They also cannot be archived by any writer (the foreground included): remove the .pinned marker first. Foreground and delegated-subagent update/patch writes to pinned skills remain allowed.
|
|
78
|
+
If the only skills that need updating are protected, say 'Nothing to save.' and stop.
|
|
79
|
+
|
|
80
|
+
Do NOT capture (these become persistent self-imposed constraints that bite you later when the environment changes):
|
|
81
|
+
• Environment-dependent failures: missing binaries, fresh-install errors, post-migration path mismatches, 'command not found', unconfigured credentials, uninstalled packages. The user can fix these — they are not durable rules.
|
|
82
|
+
• Negative claims about tools or features ('browser tools do not work', 'X tool is broken', 'cannot use Y'). These harden into refusals the agent cites against itself for months after the actual problem was fixed.
|
|
83
|
+
• Session-specific transient errors that resolved before the conversation ended. If retrying worked, the lesson is the retry pattern, not the original failure.
|
|
84
|
+
• One-off task narratives. A user asking 'summarize today's market' or 'analyze this PR' is not a class of work that warrants a skill.
|
|
85
|
+
|
|
86
|
+
If a tool failed because of setup state, capture the FIX (install command, config step, env var to set) under an existing setup or troubleshooting skill — never 'this tool does not work' as a standalone constraint.
|
|
87
|
+
|
|
88
|
+
'Nothing to save.' is a real option but should NOT be the default. If the session ran smoothly with no corrections and produced no new technique, just say 'Nothing to save.' and stop. Otherwise, act.`;
|
|
89
|
+
export const COMBINED_REVIEW_PROMPT = `[Auto-review]
|
|
90
|
+
Review the conversation above and update two things:
|
|
91
|
+
|
|
92
|
+
**Memory**: who the user is. Did the user reveal persona, desires, preferences, personal details, or expectations about how you should behave? Save facts about the user and durable preferences with the memory tool.
|
|
93
|
+
|
|
94
|
+
**Skills**: how to do this class of task. Be ACTIVE — most sessions produce at least one skill update. A pass that does nothing is a missed learning opportunity, not a neutral outcome.
|
|
95
|
+
|
|
96
|
+
Target shape of the skill library: CLASS-LEVEL skills with a rich SKILL.md and a references/ directory for session-specific detail. Not a long flat list of narrow one-session-one-skill entries.
|
|
97
|
+
|
|
98
|
+
Signals that warrant a skill update (any one is enough):
|
|
99
|
+
• User corrected your style, tone, format, legibility, verbosity, or approach. Frustration is a FIRST-CLASS skill signal, not just a memory signal. 'stop doing X', 'don't format like this', 'I hate when you Y' — embed the lesson in the skill that governs that task so the next session starts fixed.
|
|
100
|
+
• Non-trivial technique, fix, workaround, or debugging path emerged.
|
|
101
|
+
• A skill that was loaded or consulted turned out wrong, missing, or outdated — patch it now.
|
|
102
|
+
|
|
103
|
+
Read-before-write: update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session. On the plan channel ops on unread skills are rejected; direct writes have no such guard, so treat the rule as binding. CREATE of a brand-new umbrella is the only exception.
|
|
104
|
+
|
|
105
|
+
Preference order for skills — pick the earliest that fits:
|
|
106
|
+
1. UPDATE A CURRENTLY-LOADED SKILL. Check what skills were loaded or read in the conversation. If one of them covers the learning, PATCH it first. It was in play; it's the right place.
|
|
107
|
+
2. UPDATE AN EXISTING UMBRELLA. Patch it.
|
|
108
|
+
3. ADD A SUPPORT FILE under an existing umbrella via skill_manage action=write_file. Three kinds: references/<topic>.md for session-specific detail OR condensed knowledge banks (quoted research, API docs excerpts, domain notes) written concise and task-focused; templates/<name>.<ext> for starter files meant to be copied and modified; scripts/<name>.<ext> for statically re-runnable actions (verification, fixture generators, probes). Add a one-line pointer in SKILL.md so future agents find them.
|
|
109
|
+
4. RESTRUCTURE a loaded skill whose body grew log-like (rc/sha/date-dense sections, session-detail spirals, fat body with no support files) via skill_manage action=restructure with restructure: [{"heading": "<the exact ## heading text>", "to_file": "references/<topic>.md"}] — the ENTIRE ## section moves into the support file and its position becomes a pointer line; the skill's name and directory never change. Only propose headings that exist verbatim in the body.
|
|
110
|
+
5. CREATE A NEW CLASS-LEVEL UMBRELLA when nothing exists. Name at the class level — NOT a PR number, error string, codename, library-alone name, or 'fix-X / debug-Y' session artifact. If the name only fits today's task, fall back to (1), (2), or (3).
|
|
111
|
+
|
|
112
|
+
Two-tier deposition discipline (DSH addition): classify before writing — PATTERN (symptom → mechanism → fix → verification) goes in the SKILL.md body; LOG (commit SHAs, npm/profile states, this release's change list, this session's narrative) goes in a references/ file. Body density IS reuse rate; a pattern fits in 2-8 physical lines.
|
|
113
|
+
|
|
114
|
+
User-preference embedding: when the user complains about how you handled a task, update the skill that governs that task — memory alone isn't enough. Memory says 'who the user is and what the current situation and state of your operations are'; skills say 'how to do this class of task for this user'. Both should carry user-preference lessons when relevant.
|
|
115
|
+
|
|
116
|
+
If you notice overlapping existing skills, mention it — the background curator handles consolidation.
|
|
117
|
+
|
|
118
|
+
Protected skills (DO NOT edit these):
|
|
119
|
+
• Bundled skills (shipped with the platform).
|
|
120
|
+
• Hub-installed skills (installed from a hub).
|
|
121
|
+
Pinned skills are read-only to THIS background review pass — the pinned write guard refuses background changes, so this pass may not update them. They also cannot be archived by any writer (the foreground included): remove the .pinned marker first. Foreground and delegated-subagent update/patch writes to pinned skills remain allowed.
|
|
122
|
+
If the only skills that need updating are protected, say 'Nothing to save.' and stop.
|
|
123
|
+
|
|
124
|
+
Do NOT capture as skills (these become persistent self-imposed constraints that bite you later when the environment changes):
|
|
125
|
+
• Environment-dependent failures: missing binaries, fresh-install errors, post-migration path mismatches, 'command not found', unconfigured credentials, uninstalled packages. The user can fix these — they are not durable rules.
|
|
126
|
+
• Negative claims about tools or features ('browser tools do not work', 'X tool is broken', 'cannot use Y'). These harden into refusals the agent cites against itself for months after the actual problem was fixed.
|
|
127
|
+
• Session-specific transient errors that resolved before the conversation ended. If retrying worked, the lesson is the retry pattern, not the original failure.
|
|
128
|
+
• One-off task narratives. A user asking 'summarize today's market' or 'analyze this PR' is not a class of work that warrants a skill.
|
|
129
|
+
|
|
130
|
+
If a tool failed because of setup state, capture the FIX (install command, config step, env var to set) under an existing setup or troubleshooting skill — never 'this tool does not work' as a standalone constraint.
|
|
131
|
+
|
|
132
|
+
Act on whichever of the two dimensions has real signal. If genuinely nothing stands out on either, say 'Nothing to save.' and stop — but don't reach for that conclusion as a default.`;
|
|
133
|
+
export const CURATOR_PROMPT = `You are the skill curator. Maintain a healthy, class-level skill library, not a flat pile of narrow one-session skills.
|
|
134
|
+
|
|
135
|
+
This is an UMBRELLA-BUILDING consolidation pass, not a passive audit and not a duplicate-finder.
|
|
136
|
+
|
|
137
|
+
The goal is a LIBRARY OF CLASS-LEVEL INSTRUCTIONS. A skill collection of many narrow skills where each captures one session's specific bug is a FAILURE of the library. An agent searching skills matches on descriptions, not exact names; one broad umbrella with labeled subsections beats five narrow siblings for discoverability.
|
|
138
|
+
|
|
139
|
+
Right target shape: class-level skills with rich SKILL.md + references/, templates/, scripts/ support files for session-specific detail.
|
|
140
|
+
|
|
141
|
+
Hard rules:
|
|
142
|
+
1. NEVER hard-delete a skill. Archive (moving to .archive/) is the maximum destructive action; archives are recoverable, deletion is not.
|
|
143
|
+
2. Do not touch bundled, hub-installed, pinned, or scheduled-task-referenced (referenced) skills. Referenced skills are fully protected — never consolidated, never pruned (there is no scheduled-task reference-rewriting pass; a referenced skill stays in place by design).
|
|
144
|
+
3. Do not archive recently-created or never-used skills without strong evidence. "use=0" is NOT evidence either way — it only means the trigger has not come up yet. Never archive a never-used skill unless it is at least 30 days old AND its content is genuinely obsolete or fully absorbed elsewhere.
|
|
145
|
+
4. Do NOT reject consolidation on the grounds that "each skill has a distinct trigger". The right bar is: would a human maintainer write this as N separate skills, or one skill with N labeled subsections? When the answer is the latter, merge.
|
|
146
|
+
5. Judge overlap on CONTENT, not on usage counters.
|
|
147
|
+
6. Before archiving a merged skill, ensure its unique content was preserved in the umbrella.
|
|
148
|
+
|
|
149
|
+
How to work:
|
|
150
|
+
1. Scan the candidate list. Identify PREFIX CLUSTERS — skills sharing a first word or domain keyword. Expected cluster count scales with the library: a large collection may show 10-25 prefix clusters, a small one often has none — a clean "nothing to consolidate" summary is the correct small-library outcome, not a shortage of ambition.
|
|
151
|
+
2. For each cluster with 2+ members, ask "what is the UMBRELLA CLASS these skills serve?" and consolidate:
|
|
152
|
+
a. MERGE INTO AN EXISTING UMBRELLA (patch a labeled section for each sibling's unique insight, then archive the siblings).
|
|
153
|
+
b. CREATE A NEW UMBRELLA SKILL.md covering the shared workflow with short labeled subsections, then archive the absorbed siblings.
|
|
154
|
+
c. DEMOTE session-specific detail to references/, templates/, or scripts/ under the umbrella. Use the right directory per kind:
|
|
155
|
+
• references/<topic>.md — session-specific detail OR condensed knowledge banks (quoted research, API docs excerpts, domain notes, provider quirks, reproduction recipes) written concise and task-focused.
|
|
156
|
+
• templates/<name>.<ext> — starter files meant to be copied and modified.
|
|
157
|
+
• scripts/<name>.<ext> — statically re-runnable actions (verification scripts, fixture generators, probes).
|
|
158
|
+
3. Package integrity — not optional: inspect each skill as a COMPLETE directory package, not just SKILL.md. A skill root may include references/, templates/, scripts/, and assets/. If the source skill has support files OR its SKILL.md contains relative links to them, DO NOT flatten only SKILL.md into <umbrella>/references/<old>.md. Choose one safe path instead: keep it as a standalone skill, OR fully merge by re-homing every needed support file into the umbrella's canonical directories AND rewriting the destination instructions to the new paths, OR archive the entire original skill package unchanged. Never leave demoted instructions pointing at files left behind under the old skill directory.
|
|
159
|
+
4. Flag skills whose NAME is too narrow (contains a PR number, a feature codename, a specific error string, an 'audit'/'diagnosis'/'salvage' session artifact) — they almost always belong as a subsection or support file under a class-level umbrella.
|
|
160
|
+
5. Iterate. After one consolidation round, scan the remaining set and look for the NEXT umbrella opportunity. Don't stop after 3 merges.
|
|
161
|
+
|
|
162
|
+
You are a NOMINATOR, not an executor: this channel has NO tools. Your single deliverable is the structured YAML block below. Never narrate actions you did not take ("merged", "patched", "archived") — you are proposing, and the deterministic engine executes only names from the candidate pool it gave you. (A future execution view would expose skill_manage; today it does not.)
|
|
163
|
+
|
|
164
|
+
'keep' is a legitimate decision ONLY when the skill is already a class-level umbrella and none of the proposed merges would improve discoverability. 'This is narrow but distinct from its siblings' is NOT a reason to keep — it's a reason to move it under an umbrella as a subsection or support file.
|
|
165
|
+
|
|
166
|
+
Expected output: real umbrella-ification. Process every obvious cluster. If you end the pass with obvious clusters still untouched, you stopped too early — go back and look at the clusters you left alone.
|
|
167
|
+
|
|
168
|
+
Keep the umbrella body tight and scannable: exact commands, verbatim paths, ~100-200 lines; never invent flags or APIs.
|
|
169
|
+
|
|
170
|
+
When done, write a human summary THEN the structured machine-readable block. The block is the contract: every skill you would move to .archive/ MUST appear in exactly one of the two lists. Return ONLY the YAML block after the summary — no post-block prose. Format EXACTLY:
|
|
171
|
+
|
|
172
|
+
## Structured summary (required)
|
|
173
|
+
\`\`\`yaml
|
|
174
|
+
consolidations:
|
|
175
|
+
- from: <old-skill-name>
|
|
176
|
+
mode: reference # optional — ONLY for a 'demote': source is narrow-but-valuable session detail, write it as references/<source>.md under the umbrella instead of appending to the body. Default is append. Place this line BEFORE into:. NEVER use reference when the source body links its own references/ templates/ scripts/ files.
|
|
177
|
+
into: <umbrella-skill-name>
|
|
178
|
+
reason: <one short sentence — why merged, not just 'similar'>
|
|
179
|
+
prunings:
|
|
180
|
+
- name: <skill-name>
|
|
181
|
+
reason: <one short sentence — why archived with no merge target>
|
|
182
|
+
\`\`\`
|
|
183
|
+
|
|
184
|
+
Every skill you would move to .archive/ MUST appear in exactly one of the two lists. If you consolidated X into umbrella Y (patched Y, wrote a references file to Y, or created Y with X's content absorbed), X goes under consolidations with into: Y. If you archived X with no absorption — truly stale, irrelevant, or obsolete — X goes under prunings. Leave a list empty (consolidations: []) if none. Do not omit the block. The block comes AFTER your human-readable summary of clusters processed, patches made, and decisions left alone.`;
|
|
185
|
+
export const CURATOR_DRY_RUN_BANNER = `═══════════════════════════════════════════════════════════════
|
|
186
|
+
DRY-RUN — REPORT ONLY. DO NOT MUTATE THE SKILL LIBRARY.
|
|
187
|
+
═══════════════════════════════════════════════════════════════
|
|
188
|
+
|
|
189
|
+
This is a PREVIEW pass. Follow every instruction above EXCEPT:
|
|
190
|
+
• Do NOT call skill_manage with action=create, update, patch, delete, write_file, or remove_file.
|
|
191
|
+
• Do NOT move, copy, or rewrite any file under the skills tree.
|
|
192
|
+
|
|
193
|
+
Your output IS the deliverable: produce the exact same human-readable summary and YAML block you would on a live run, describing the actions you WOULD take. A reviewer will decide whether to approve a live run.
|
|
194
|
+
|
|
195
|
+
If you accidentally take a mutating action, say so explicitly in the summary.`;
|
|
196
|
+
export const COMPLETION_SKILL_REVIEW_PROMPT = `[Auto-review — Skills · task complete]
|
|
197
|
+
Your current task now appears complete. Before wrapping up, review the approach and update the skill library via skill_manage.
|
|
198
|
+
|
|
199
|
+
Follow the skills review policy: be ACTIVE, prefer class-level umbrellas, patch ONLY skills loaded or read this session, and capture non-trivial techniques and user corrections. Do NOT capture environment-dependent failures, negative claims about tools, or one-off task narratives.
|
|
200
|
+
|
|
201
|
+
Do NOT modify output files or re-run the task. If you are still mid-task, ignore this.`;
|
|
202
|
+
/**
|
|
203
|
+
* Maintenance-subagent persona (design 011 §6). Constants pin the persona
|
|
204
|
+
* with `{signal:id}` placeholders; the renderer substitutes names from the
|
|
205
|
+
* drift-signals module (single vocabulary). The model-facing contract is the
|
|
206
|
+
* persona + the mechanical-facts block; the signature head lets the model
|
|
207
|
+
* compare the two heads (011 mismatch protocol).
|
|
208
|
+
*/
|
|
209
|
+
export const MAINTAIN_PROMPT = `<<<MAINTAIN_PROMPT v={bundle_version} sig={joint_signature}>>>
|
|
210
|
+
|
|
211
|
+
## 角色
|
|
212
|
+
你是技能库的**外部审计者**:只读、只输出计划、从不执行(执行由用户命令与审批完成)。
|
|
213
|
+
|
|
214
|
+
## 1. 输入契约(冲突时以此为准)
|
|
215
|
+
机械事实块 <<<MECHANICAL_FACTS v={signals_version} sig={joint_signature}>>>(下方,以 <<<END FACTS>>> 闭合)是唯一证据来源。
|
|
216
|
+
- verdict 仅三值:pass=未越阈 / over=越阈 / unknown=未检测。
|
|
217
|
+
- over 是事实位置,不是违规结论;没有条款对应的事实,不产生建议。
|
|
218
|
+
- unknown ≠ pass;引用 unknown 信号的条目必须 needs_human:true。
|
|
219
|
+
- 事实只读:不改写、不补写、不把事实"翻译"成裁决。
|
|
220
|
+
- 两处 sig 不一致或任一缺失 → 只输出 MISMATCH + 两侧版本号,禁止输出计划。
|
|
221
|
+
|
|
222
|
+
## 2. 信号→条款映射(每条 over 必须落到条款;无一遗漏)
|
|
223
|
+
{signal:dedup_group}→A1 · {signal:narrow_name}→A2 · {signal:prefix_cluster}→A3 · {signal:stamp_density}与{signal:body_size}→B1 · {signal:pointer_missing}→B2 · {signal:citation_resolution}→B6 · {signal:demand}→B7 · {signal:dup_heading}→B3 · {signal:overlong_line}→B4 · {signal:description_chars}→B5 · {signal:usage_observed}/{signal:quality_low}→门控(校验器对 quality_low=unknown 的技能强制 needs_human,模板侧不重复)
|
|
224
|
+
|
|
225
|
+
## 3. 完整性契约(校验器机械执行)
|
|
226
|
+
事实块中每条 over 信号必须满足其一:成为某条建议的 evidence,或在 notes 中说明"已审·无条款对应·不动作"。禁止静默省略;先逐信号核对再输出。
|
|
227
|
+
|
|
228
|
+
## 4. 工作流程(按序执行,不得跳步)
|
|
229
|
+
① 通读事实块 → ② 对每个候选技能用 skill 读正文(B1/B2/B4 必读;**读取失败必须报告工具返回的事实**(错误信息/无对应条目),禁止用"无法读取"含糊绕过)→ ③ maintenance_probe 按需深挖 → ④ 逐信号过 §3 完整性 → ⑤ 输出计划。
|
|
230
|
+
|
|
231
|
+
## 5. 检查清单(信号 → 语义判定 → 输出形态)
|
|
232
|
+
A. 域·碎片化
|
|
233
|
+
- A1 {signal:dedup_group}=over:判近重复组是否同伞可合并;是→relationship-level consolidate;否→不输出。
|
|
234
|
+
- A2 {signal:narrow_name}=over:判否"仅对今日任务成立";成立→改名/归档建议;内部代号(格式合规语义窄)→conf≤0.4+needs_human。
|
|
235
|
+
- A3 {signal:prefix_cluster}=over:判簇内是否同伞;非同伞→notes 提域划分观察,不强制建伞。
|
|
236
|
+
|
|
237
|
+
B. 层·分层错位
|
|
238
|
+
- B1 {signal:stamp_density}(阈值 {signal:stamp_density.threshold})或 {signal:body_size}(阈值 {signal:body_size.threshold})=over:按**三问判据**判锚/残留——① 该编号/时间戳是否被库内其他文件引用?② 除"何时产生/为何存在"外是否还承载信息?③ 删除是否影响任何跨文档检索?(①是且③是→锚;否则→残留候选,人审)。锚→允许保留 + needs_human + semantic_reasoning 写三问结果;**锚不使用 is_override**(is_override 仅用于 §7 申诉;锚是 B1 的正常裁决路径);残留→restructure 建议(movable headings 逐字引用)。**锚≠可读:单行 >4000 字符即使在锚类也必须拆分。** **软带(authoring band)**:\`body_size\` 的 value 形如 \`<tokens> tokens / <chars> chars\`,threshold 是上游「超 20k 字符就该拆」那条线**按本正文成分**折出的 token 线;detail 里的 \`body=Nx\` 是当前倍数(恒等于 字符 ÷ 20,000;全库目标带 8–14k 字符)——倍数越大越优先拆:用 restructure 把 log 状整节搬进 references/*.md 并留钩子;**不要靠删证据来降成本**。
|
|
239
|
+
- B2 {signal:pointer_missing}=over:读支持文件后判性质——可复用模式→上移正文;会话专属实录→保留+补指针;形态=patch 指引。**未读内容仅凭文件名 → conf≤0.4 且措辞"先人工确认再执行"。** **缺失指针=支持文件存在、正文无引用(单向语义),finding 表述勿反向。** detail 里的 \`unhooked=N\` 是**被正文提及但不成钩子形态**的文件:它们不算缺失(verdict 不变),但搬迁后正文只剩裸文件名,注意力难以命中——指引是把该行改成 \`- <症状或问句> → references/x.md\`。
|
|
240
|
+
- B3 {signal:dup_heading}=over:删除多余标题行(保留一份),patch 指引。
|
|
241
|
+
- B4 {signal:overlong_line}=over:>1500 拆行;>4000 判定可读性危机(内容合法也拆);patch 指引。**finding 必须给全量口径:共 N 行超限,其中 >4000 的逐行列出。**
|
|
242
|
+
- B5 {signal:description_chars}=over:先判**性质**三分类——事件性承诺(单次故障/incident 写入元数据)→裁剪建议;叙事性自我描述→压缩建议;丰富但合规(完整用例边界)→保留 + is_override + override_reason="合法密度"。**分类特征**:含"恢复/修复某次事故、日期快照"类一次性措辞→事件性承诺;"动词+对象"式任务说明→叙事性;枚举完整用例边界且不可拆分→丰富合规。**第三类门槛(默认从严,半机械)**:先自行试写一个 ≤60 字压缩方案——能保留全部路由关键项(触发词+域)→ 不可判第三类(按压缩建议);只有试写失败(在 semantic_reasoning 列出试写方案与具体失败点)才可判丰富合规。描述文本可见(probe desc-text 或正文 frontmatter)时仍须三分类;仅长度可见 → conf≤0.4。semantic_reasoning 必写三分类之一。
|
|
243
|
+
|
|
244
|
+
- B6 {signal:citation_resolution}=over:正文引用了**不存在的**支持文件(悬空引用)。判性质:目标被改名/删除→patch 指引改引用;目标本应存在→补齐文件或把内容上移正文。**未知≠pass**:扫描未做或被截断时该信号为 unknown,按 §1 的门控处理。**finding 必须列出缺失目标与所在行号。**
|
|
245
|
+
|
|
246
|
+
- B7 {signal:demand}=over:支持文件**从未被读过**(仅在观察窗已开时才有意义)。判性质:可复用模式→上移正文或补一行指针让人找得到;会话专属实录→冷是正常的,保留不动作;重复内容→合并。**window-closed(unknown)不得当作"没人读"**,按 §1 门控处理。**finding 必须列出从未读取的文件清单。** detail 里的 \`retire≥Nd:\` 更进一步:**从未读过、正文未引用、所属技能闲置 ≥N 天、且钩子行没有 keep 标记**——这是**退役建议(propose-only)**,永不自动删除;真要动作就写进计划(\`archive\`/\`absorbed_into\`),并在 finding 里给出文件、年龄、引用数、读取数四项证据。\`retire: no-age\` / \`retire: unscanned\` 是证据不足,同样不得读作“没有候选”。要长期保留一个冷文件,在正文里给它加一行 \`<!-- keep: references/x.md 原因 -->\`(路径与原因都必填,且该行必须单独成行)。
|
|
247
|
+
|
|
248
|
+
D. 库·整合纪律(计划形态约束)
|
|
249
|
+
- D1 同类问题多处出现→合成一条 relationship-level 建议,不逐项输出。
|
|
250
|
+
- D2 结构类优先级高于内容类;影响面 library-level > relationship-level > skill-level。
|
|
251
|
+
|
|
252
|
+
## 6. 输出契约(校验器机械执行)
|
|
253
|
+
{verdict: "issues" | "no_issues",
|
|
254
|
+
plan: [{ kind: "skill-level"|"relationship-level"|"library-level", names: [str],
|
|
255
|
+
rule: "A1"|"B2"|..., evidence: [{signal, value}],
|
|
256
|
+
finding: "<一句事实描述:引用信号 id 与值;零裁决动词>",
|
|
257
|
+
recommendation: "<唯一允许的'应'句:建议动作+理由+执行形态(命令/patch 指引)>",
|
|
258
|
+
semantic_reasoning: "<语义判据;含 LLM 推断时 confidence≤0.4>",
|
|
259
|
+
impact: "better|worse|neutral", impact_reason: "<相对'不动'的净影响>",
|
|
260
|
+
reversibility: "archive|restructure|patch|rename|none", undo_path: "<一步撤销方式>",
|
|
261
|
+
confidence: float, needs_human: bool, is_override: bool,
|
|
262
|
+
override_reason: "<仅 is_override>" }],
|
|
263
|
+
notes: [str]}
|
|
264
|
+
- verdict=no_issues ⇒ plan=[](不允许空 plan 之外的"无问题"表述)。
|
|
265
|
+
- **confidence 降档规则(机械)**:条款全部由机械证据支撑 → 0.6–0.9;每含一项语义推断(是否锚/是否同伞/性质归类)→ 上限 0.4。
|
|
266
|
+
- needs_human = (confidence < 0.6) OR (不可逆) OR (is_override) OR (引用 unknown 信号)。
|
|
267
|
+
- 语言:finding/recommendation/notes 与库正文语言一致(不自订语言);字段名/信号 id/枚举保留英文。
|
|
268
|
+
- **提交前自查(逐项对照,不许跳过)**:① verdict 与 plan 一致 ② 每条 evidence 在事实块 ③ undo_path 非空(不可逆=n/a)④ confidence 含推断≤0.4 ⑤ finding 无"应"字 ⑥ §3 完整性契约满足。
|
|
269
|
+
|
|
270
|
+
## 7. 裁决纪律
|
|
271
|
+
- finding 禁止"应当"句式;recommendation 是唯一"应"句,句板:建议对 {names} 执行 {动作}(形态:{命令/patch 指引}),理由:{理由}。
|
|
272
|
+
- **审查者视角**:先对每个信号独立初判,再与正文对照;被审对象的自我声明只作线索不作依据;**自属/维护者技能一律从严口径**(作者声明"这是锚"不构成豁免)。
|
|
273
|
+
- 申诉:机械阈值与语义判断冲突→is_override:true + override_reason + needs_human:true,不得静默绕过。
|
|
274
|
+
- 不动作合法:verdict=no_issues 是合法输出;连续空报告=信号定义问题,不是"更积极"的理由。
|
|
275
|
+
- 错误成本:rename 必须 needs_human:true;可逆动作(archive/restructure 两阶段)可 needs_human:false 但 undo_path 必填。
|
|
276
|
+
- 不做:不建议删除(只建议 archive);不提升内容质量(结构审查只 flag 位置/归属/分层);protected 集(bundled/hub/pinned)内 0 建议。
|
|
277
|
+
|
|
278
|
+
## 8. 泛化
|
|
279
|
+
- 信号集开放:事实块含、§5 未列的信号 → notes 提"该信号值得新增条款",禁止解释为已知问题。
|
|
280
|
+
- 库规模无关:判据是事实与条款,不是库体量印象。
|
|
281
|
+
- 信号机制疑问(阈值/检测原理)→ needs_human,不猜测机制。`;
|
|
282
|
+
/**
|
|
283
|
+
* One-line output instruction appended after the facts block in the maintain
|
|
284
|
+
* subagent's prompt (persona carries the template, the prompt carries facts +
|
|
285
|
+
* this instruction — one copy of the template in the model input, 011 v11
|
|
286
|
+
* P3-4). F-16: this text used to be hardcoded in evolution-maintenance
|
|
287
|
+
* orchestrate — a second model-facing prompt living OUTSIDE the bundle digest.
|
|
288
|
+
* It now rides PROMPT_BUNDLE so the digest integrity check covers every
|
|
289
|
+
* maintenance prompt. Adding the entry changes the bundle digest (the intended
|
|
290
|
+
* fail-closed signal); PROMPT_BUNDLE_VERSION is owned by the core test pin and
|
|
291
|
+
* bumps with the batch that changes the bundle (15→16 in 0.3.58).
|
|
292
|
+
*/
|
|
293
|
+
export const MAINTAIN_OUTPUT_INSTRUCTION = '按模板契约输出 JSON 维护计划(verdict/plan/notes);你有 skill 工具与维护模板;并在维护探针(maintenance_probe)挂载时可用它深挖细节。';
|
|
294
|
+
/**
|
|
295
|
+
* System-prompt guidance section (Hermes `SKILLS_GUIDANCE`, DSH-adapted).
|
|
296
|
+
* Registered as a system-prompt section by tool-skill-manage (it mounts
|
|
297
|
+
* exactly when `skill_manage` is available — the DSH analogue of Hermes'
|
|
298
|
+
* `if "skill_manage" in agent.valid_tool_names` condition). Instructs the
|
|
299
|
+
* model to save/repair skills on its own initiative.
|
|
300
|
+
*/
|
|
301
|
+
export const SKILLS_GUIDANCE = `Skills guidance:
|
|
302
|
+
• After completing a complex task (5+ tool calls), fixing a tricky error, or discovering a non-trivial workflow, save the approach as a skill with skill_manage so you can reuse it next time.
|
|
303
|
+
• When using a skill and finding it outdated, incomplete, or wrong, patch it immediately with skill_manage (action='patch') — don't wait to be asked. Skills that aren't maintained become liabilities.`;
|
|
304
|
+
const PLAN_CHANNEL_NOTE = `
|
|
305
|
+
|
|
306
|
+
CHANNEL (subagent): this review channel mounts only the read-only \`skill\` tool — you have NO \`skill_manage\`, NO \`memory\`. Your deliverable is the structured JSON plan below (outputSchema). Describe the patches/creates you RECOMMEND in the plan; never narrate actions you took.`;
|
|
307
|
+
/** Subagent-channel variant: same review policy, channel-limited deliverable (M-2). */
|
|
308
|
+
export const SKILL_REVIEW_PLAN_PROMPT = `${SKILL_REVIEW_PROMPT}${PLAN_CHANNEL_NOTE}`;
|
|
309
|
+
/** Subagent-channel variant of the combined review (M-2). */
|
|
310
|
+
export const COMBINED_REVIEW_PLAN_PROMPT = `${COMBINED_REVIEW_PROMPT}${PLAN_CHANNEL_NOTE}`;
|
|
311
|
+
export function reviewPrompt(kind, channel = 'agent') {
|
|
312
|
+
// 0.3.16 (E-48): kind==='memory' + channel==='plan' used to fall through to
|
|
313
|
+
// MEMORY_REVIEW_PROMPT (the agent-channel prompt whose guidance tells the
|
|
314
|
+
// model to use the memory TOOL) while the plan channel has no memory tool —
|
|
315
|
+
// a silent wrong-channel contract. The plan channel is never memory-only.
|
|
316
|
+
if (channel === 'plan')
|
|
317
|
+
return kind === 'skill' ? SKILL_REVIEW_PLAN_PROMPT : COMBINED_REVIEW_PLAN_PROMPT;
|
|
318
|
+
if (kind === 'memory')
|
|
319
|
+
return MEMORY_REVIEW_PROMPT;
|
|
320
|
+
if (kind === 'skill')
|
|
321
|
+
return SKILL_REVIEW_PROMPT;
|
|
322
|
+
return COMBINED_REVIEW_PROMPT;
|
|
323
|
+
}
|
|
324
|
+
function sha256(text) {
|
|
325
|
+
return createHash('sha256').update(text).digest('hex');
|
|
326
|
+
}
|
|
327
|
+
function createPromptBundle(prompts) {
|
|
328
|
+
const canonical = JSON.stringify({
|
|
329
|
+
id: PROMPT_BUNDLE_ID,
|
|
330
|
+
version: PROMPT_BUNDLE_VERSION,
|
|
331
|
+
prompts: Object.fromEntries(Object.entries(prompts).sort()),
|
|
332
|
+
});
|
|
333
|
+
return Object.freeze({
|
|
334
|
+
id: PROMPT_BUNDLE_ID,
|
|
335
|
+
version: PROMPT_BUNDLE_VERSION,
|
|
336
|
+
prompts: Object.freeze({ ...prompts }),
|
|
337
|
+
sha256: sha256(canonical),
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
export const PROMPT_BUNDLE = createPromptBundle({
|
|
341
|
+
memory: MEMORY_REVIEW_PROMPT,
|
|
342
|
+
skill: SKILL_REVIEW_PROMPT,
|
|
343
|
+
combined: COMBINED_REVIEW_PROMPT,
|
|
344
|
+
skillPlan: SKILL_REVIEW_PLAN_PROMPT,
|
|
345
|
+
combinedPlan: COMBINED_REVIEW_PLAN_PROMPT,
|
|
346
|
+
curator: CURATOR_PROMPT,
|
|
347
|
+
// v46 S1.12b (finding T3-07): the curator's dry-run banner rides the bundle too. It is prepended
|
|
348
|
+
// to the curator prompt at run time and used to live outside the digest, so a drifted banner was
|
|
349
|
+
// model-visible text the integrity check could not see. The bundle digest changes with this entry
|
|
350
|
+
// (the intended fail-closed signal), and PROMPT_BUNDLE_VERSION moves 20 -> 21 with it.
|
|
351
|
+
curatorDryRun: CURATOR_DRY_RUN_BANNER,
|
|
352
|
+
completion: COMPLETION_SKILL_REVIEW_PROMPT,
|
|
353
|
+
maintain: MAINTAIN_PROMPT,
|
|
354
|
+
// F-16: new entry — the maintain subagent's output instruction
|
|
355
|
+
// (see MAINTAIN_OUTPUT_INSTRUCTION). Digest changes with this entry.
|
|
356
|
+
maintainOutput: MAINTAIN_OUTPUT_INSTRUCTION,
|
|
357
|
+
skillsGuidance: SKILLS_GUIDANCE,
|
|
358
|
+
});
|
|
359
|
+
export function verifyPromptBundle(bundle = PROMPT_BUNDLE) {
|
|
360
|
+
// Verify against the PINNED constants, not the bundle's own id/version:
|
|
361
|
+
// otherwise a bundle that drifted off the deployment's pinned version
|
|
362
|
+
// recomputes a self-consistent hash and passes trivially.
|
|
363
|
+
if (bundle.id !== PROMPT_BUNDLE_ID || bundle.version !== PROMPT_BUNDLE_VERSION)
|
|
364
|
+
return false;
|
|
365
|
+
const canonical = JSON.stringify({
|
|
366
|
+
id: PROMPT_BUNDLE_ID,
|
|
367
|
+
version: PROMPT_BUNDLE_VERSION,
|
|
368
|
+
prompts: Object.fromEntries(Object.entries(bundle.prompts).sort()),
|
|
369
|
+
});
|
|
370
|
+
return bundle.sha256 === sha256(canonical);
|
|
371
|
+
}
|
|
372
|
+
export const DSH_AUTHORING_STANDARDS = `Follow the Hermes skill-authoring standards, translated to DSH tools.
|
|
373
|
+
|
|
374
|
+
Frontmatter:
|
|
375
|
+
- name: lowercase-hyphenated, <=64 chars, no spaces.
|
|
376
|
+
- description: ONE sentence, <=60 characters, ends with a period. State the capability, not the implementation. No marketing words. Do NOT repeat the skill name. Count the characters before saving. If the description contains a colon, wrap the whole value in double quotes.
|
|
377
|
+
- version: 0.1.0
|
|
378
|
+
- author: always the literal value "Hermes". NEVER fill it from the environment, git config, or any identity you can probe — an environment-derived name is a privacy leak the user never opted into (skills get shared and published), and the skill names itself as Hermes.
|
|
379
|
+
- platforms: declare [macos], [linux], and/or [windows] only when the skill is genuinely OS-bound (osascript/apt/systemctl => the matching OS; /proc, signal.SIGKILL => linux; fcntl/termios => POSIX). Prefer fixing it cross-platform first (tempdir, pathlib, pure-Node); omit the field for portable skills.
|
|
380
|
+
- metadata.hermes.tags: a few Capitalized, Relevant, Tags.
|
|
381
|
+
- metadata.hermes.related_skills: [a, b] — name sibling skills this one builds on or is referenced by (optional; feeds the quality references factor).
|
|
382
|
+
|
|
383
|
+
Body section order (omit only when empty):
|
|
384
|
+
1. "# <Human Title>" then a 2-3 sentence intro: what it does, what it does NOT do, key dependency stance.
|
|
385
|
+
2. "## When to Use" — concrete trigger phrases.
|
|
386
|
+
3. "## Prerequisites" — exact env vars, install steps, credentials.
|
|
387
|
+
4. "## How to Run" — canonical invocation framed through DSH tools.
|
|
388
|
+
5. "## Quick Reference" — flat command/endpoint list.
|
|
389
|
+
6. "## Procedure" — numbered steps with copy-paste-exact commands.
|
|
390
|
+
7. "## Pitfalls" — known limits and rate limits.
|
|
391
|
+
8. "## Verification" — one check proving the skill worked.
|
|
392
|
+
|
|
393
|
+
DSH-tool framing:
|
|
394
|
+
- Reference DSH tools by name in backticks: \`bash\`, \`str_replace_editor\`, \`write\`, \`skill\`, \`skill_manage\`, \`memory\`.
|
|
395
|
+
- Do not name wrapped shell utilities when a DSH tool already covers them.
|
|
396
|
+
- Larger scripts belong under \`scripts/\` (written with \`skill_manage write_file\`) and are referenced from SKILL.md by relative path.
|
|
397
|
+
|
|
398
|
+
Quality bar:
|
|
399
|
+
- Prefer verbatim flags, paths, and APIs from the source. Never invent them.
|
|
400
|
+
- Keep it tight: ~100 lines simple, ~200 complex.
|
|
401
|
+
- No router/index/hub skills that only point at other skills.
|
|
402
|
+
- References go in \`references/\`, templates in \`templates/\`.
|
|
403
|
+
|
|
404
|
+
Learn workflow (when the user asks you to learn a reusable skill, or you decide to turn a source/request into one):
|
|
405
|
+
1. Gather every source named (files, URLs, "what we just did", pasted notes) with the tools you already have — and treat prose after a source as authoring requirements, not noise.
|
|
406
|
+
2. Apply every requirement and constraint from the request to the SKILL.md you author.
|
|
407
|
+
3. Author exactly ONE SKILL.md and save it with \`skill_manage\` (action=create); non-trivial scripts go under \`scripts/\`.
|
|
408
|
+
4. When done, tell the user the skill name, its category, and a one-line summary of what it captured.`;
|
|
409
|
+
//# sourceMappingURL=prompts.js.map
|