@akagilnc/pi-workflow-roles 0.1.5015 → 0.1.5063
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 +2 -2
- package/README.zh-CN.md +2 -2
- package/THIRD_PARTY_NOTICES.md +8 -8
- package/dist/acp-host/production-host.js +525 -978
- package/dist/headless-host/description.js +0 -2
- package/dist/headless-host/production-host.js +528 -1014
- package/dist/host-descriptions.js +2 -3
- package/dist/migrate-book-topology.js +7 -12
- package/dist/packaged-role-registry.js +20 -18
- package/dist/pi/role-turn-host.js +3 -27
- package/dist/public-cli/cli.js +23 -2
- package/dist/public-cli/countersign-run.js +13 -8
- package/dist/public-cli/instruction-seat-run.js +75 -107
- package/dist/public-cli/invocation.js +13 -32
- package/dist/public-cli/machine-method-skills.js +150 -0
- package/dist/public-cli/main.js +549 -679
- package/dist/public-cli/post-admission.js +10 -5
- package/dist/public-cli/registry.js +2 -1
- package/dist/public-cli/run-lifecycle.js +12 -15
- package/dist/public-cli/seat-ticket-binding.js +5 -8
- package/dist/public-cli/settlement.js +12 -99
- package/dist/public-cli/turn-request.js +16 -8
- package/dist/public-role-summons.js +8 -3
- package/package.json +5 -1
- package/resources/countersign-ticket-issue.md +5 -0
- package/resources/diarist-collect.md +1 -0
- package/resources/secretariat-ticket-identity.md +15 -0
- package/scripts/build-package.mjs +1 -6
- package/src/headless-host/description.ts +0 -3
- package/src/headless-host/role-turn-host.ts +2 -23
- package/src/host-contracts.ts +2 -23
- package/src/host-descriptions.ts +2 -3
- package/src/packaged-role-registry.ts +17 -16
- package/src/pi/adapter.ts +0 -27
- package/src/pi/role-turn-host.ts +3 -31
- package/src/public-cli/cli.ts +24 -2
- package/src/public-cli/countersign-run.ts +17 -10
- package/src/public-cli/instruction-seat-run.ts +75 -105
- package/src/public-cli/invocation.ts +10 -38
- package/src/public-cli/machine-method-skills.ts +153 -0
- package/src/public-cli/post-admission.ts +12 -6
- package/src/public-cli/registry.ts +1 -0
- package/src/public-cli/run-lifecycle.ts +12 -13
- package/src/public-cli/seat-ticket-binding.ts +5 -8
- package/src/public-cli/settlement.ts +6 -138
- package/src/public-cli/turn-request.ts +24 -16
- package/src/public-role-summons.ts +16 -3
- package/src/reviewer-role.ts +1 -12
- package/src/role-envelope.ts +0 -13
- package/src/role-runtime-dependencies.ts +0 -13
- package/src/role-runtime.ts +4 -56
- package/src/worker-role.ts +1 -81
- package/dist/method-host-plugin/.claude-plugin/plugin.json +0 -5
- package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +0 -48
- package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +0 -21
- package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +0 -170
- package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
- package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
- package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +0 -41
- package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +0 -134
- package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +0 -3
- package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +0 -31
- package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +0 -14
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +0 -3
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +0 -26
- package/dist/method-host-plugin/skills/tdd/SKILL.md +0 -38
- package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +0 -3
- package/dist/method-host-plugin/skills/tdd/mocking.md +0 -59
- package/dist/method-host-plugin/skills/tdd/provenance.json +0 -36
- package/dist/method-host-plugin/skills/tdd/tests.md +0 -77
- package/dist/package-resources/method-skill.js +0 -259
- package/resources/method-host-plugin/.claude-plugin/plugin.json +0 -5
- package/resources/methods/ak-cross-m-review/CONTEXT.md +0 -48
- package/resources/methods/ak-cross-m-review/LICENSE +0 -21
- package/resources/methods/ak-cross-m-review/SKILL.md +0 -170
- package/resources/methods/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
- package/resources/methods/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
- package/resources/methods/ak-cross-m-review/provenance.json +0 -41
- package/resources/methods/diagnosing-bugs/SKILL.md +0 -134
- package/resources/methods/diagnosing-bugs/agents/openai.yaml +0 -3
- package/resources/methods/diagnosing-bugs/provenance.json +0 -31
- package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
- package/resources/methods/resolving-merge-conflicts/SKILL.md +0 -14
- package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +0 -3
- package/resources/methods/resolving-merge-conflicts/provenance.json +0 -26
- package/resources/methods/tdd/SKILL.md +0 -38
- package/resources/methods/tdd/agents/openai.yaml +0 -3
- package/resources/methods/tdd/mocking.md +0 -59
- package/resources/methods/tdd/provenance.json +0 -36
- package/resources/methods/tdd/tests.md +0 -77
- package/src/canonical-skill-binding.ts +0 -118
- package/src/host-native-method.ts +0 -185
- package/src/package-resources/method-skill-binding.ts +0 -60
- package/src/package-resources/method-skill.ts +0 -363
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { readFile, realpath } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
4
|
-
|
|
5
|
-
import { stripFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import type { HostSkillExpansionEvidence } from "./host-contracts.ts";
|
|
7
|
-
export type CanonicalSkillName = "tdd" | "ak-cross-m-review";
|
|
8
|
-
|
|
9
|
-
export type CanonicalSkillSnapshot = Readonly<{
|
|
10
|
-
raw: string;
|
|
11
|
-
path: string;
|
|
12
|
-
baseDir: string;
|
|
13
|
-
body: string;
|
|
14
|
-
/** Plain skill text — no length/digest identity shell (ADR 0031). */
|
|
15
|
-
snapshotIdentity: Readonly<{ text: string }>;
|
|
16
|
-
}>;
|
|
17
|
-
|
|
18
|
-
export type CanonicalSkillEvidence<Name extends CanonicalSkillName = CanonicalSkillName> = Readonly<{
|
|
19
|
-
name: Name;
|
|
20
|
-
location: string;
|
|
21
|
-
content: string;
|
|
22
|
-
userMessage: string;
|
|
23
|
-
}>;
|
|
24
|
-
|
|
25
|
-
export type CanonicalSkillBinding<Name extends CanonicalSkillName = CanonicalSkillName> = Readonly<{
|
|
26
|
-
name: Name;
|
|
27
|
-
snapshot: CanonicalSkillSnapshot;
|
|
28
|
-
/**
|
|
29
|
-
* Accept host expansion evidence when name/location/content match the binding
|
|
30
|
-
* and userMessage equals the captured original request (ADR 0032).
|
|
31
|
-
*/
|
|
32
|
-
captureExpansion(
|
|
33
|
-
evidence: HostSkillExpansionEvidence | undefined,
|
|
34
|
-
originalRequest: string,
|
|
35
|
-
): CanonicalSkillEvidence<Name> | undefined;
|
|
36
|
-
}>;
|
|
37
|
-
|
|
38
|
-
export type AnyCanonicalSkillBinding =
|
|
39
|
-
| CanonicalSkillBinding<"tdd">
|
|
40
|
-
| CanonicalSkillBinding<"ak-cross-m-review">;
|
|
41
|
-
|
|
42
|
-
export function captureCanonicalSkillExpansion<Name extends CanonicalSkillName>(
|
|
43
|
-
name: Name,
|
|
44
|
-
snapshot: CanonicalSkillSnapshot,
|
|
45
|
-
configuredPath: string,
|
|
46
|
-
evidence: HostSkillExpansionEvidence | undefined,
|
|
47
|
-
originalRequest: string,
|
|
48
|
-
): CanonicalSkillEvidence<Name> | undefined {
|
|
49
|
-
const matchedPath =
|
|
50
|
-
evidence?.location === configuredPath
|
|
51
|
-
? configuredPath
|
|
52
|
-
: evidence?.location === snapshot.path
|
|
53
|
-
? snapshot.path
|
|
54
|
-
: undefined;
|
|
55
|
-
const expectedContent = matchedPath === undefined ? undefined : snapshot.body;
|
|
56
|
-
const prefixedContent = matchedPath === undefined
|
|
57
|
-
? undefined
|
|
58
|
-
: `References are relative to ${dirname(matchedPath)}.\n\n${snapshot.body}`;
|
|
59
|
-
if (
|
|
60
|
-
evidence?.name !== name
|
|
61
|
-
|| matchedPath === undefined
|
|
62
|
-
|| (evidence.content !== expectedContent && evidence.content !== prefixedContent)
|
|
63
|
-
|| evidence.userMessage !== originalRequest
|
|
64
|
-
) {
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
return Object.freeze({ ...evidence, name });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export class CanonicalSkillUnavailableError extends Error {
|
|
71
|
-
readonly code = "canonical-skill-unavailable" as const;
|
|
72
|
-
constructor(readonly skillName: CanonicalSkillName, path: string, cause: unknown) {
|
|
73
|
-
super(`Canonical ${skillName} Skill is unavailable at ${path}`, { cause });
|
|
74
|
-
this.name = "CanonicalSkillUnavailableError";
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function loadCanonicalSkillBinding(
|
|
79
|
-
name: CanonicalSkillName,
|
|
80
|
-
): Promise<AnyCanonicalSkillBinding> {
|
|
81
|
-
const configuredPath = resolve(
|
|
82
|
-
homedir(),
|
|
83
|
-
`.agents/skills/${name}/SKILL.md`,
|
|
84
|
-
);
|
|
85
|
-
let path: string;
|
|
86
|
-
let raw: string;
|
|
87
|
-
try {
|
|
88
|
-
path = await realpath(configuredPath);
|
|
89
|
-
raw = await readFile(path, "utf8");
|
|
90
|
-
} catch (error) {
|
|
91
|
-
throw new CanonicalSkillUnavailableError(name, configuredPath, error);
|
|
92
|
-
}
|
|
93
|
-
const body = stripFrontmatter(raw).trim();
|
|
94
|
-
if (body.length === 0) {
|
|
95
|
-
throw new Error(`Canonical ${name} Skill is empty at ${path}`);
|
|
96
|
-
}
|
|
97
|
-
const snapshot: CanonicalSkillSnapshot = Object.freeze({
|
|
98
|
-
raw,
|
|
99
|
-
path,
|
|
100
|
-
baseDir: dirname(path),
|
|
101
|
-
body,
|
|
102
|
-
snapshotIdentity: Object.freeze({ text: raw }),
|
|
103
|
-
});
|
|
104
|
-
const binding: CanonicalSkillBinding<typeof name> = {
|
|
105
|
-
name,
|
|
106
|
-
snapshot,
|
|
107
|
-
captureExpansion(evidence, originalRequest) {
|
|
108
|
-
return captureCanonicalSkillExpansion(
|
|
109
|
-
name,
|
|
110
|
-
snapshot,
|
|
111
|
-
configuredPath,
|
|
112
|
-
evidence,
|
|
113
|
-
originalRequest,
|
|
114
|
-
);
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
return Object.freeze(binding) as AnyCanonicalSkillBinding;
|
|
118
|
-
}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/** #922 / #980 host-native packaged method delivery. */
|
|
2
|
-
import { access, lstat, mkdir, readdir, readFile, readlink, realpath, symlink } from "node:fs/promises";
|
|
3
|
-
import { basename, dirname, join } from "node:path";
|
|
4
|
-
import type { MethodBinding } from "./host-contracts.ts";
|
|
5
|
-
|
|
6
|
-
type HostMethodSkill = Readonly<{ name: string }>;
|
|
7
|
-
export const HOST_METHOD_PLUGIN_NAME = "ak-methods" as const;
|
|
8
|
-
export const packagedMethodsDir = (root: string) => join(root, "resources", "methods");
|
|
9
|
-
export const packagedMethodPluginDir = (root: string) => join(root, "dist", "method-host-plugin");
|
|
10
|
-
|
|
11
|
-
export function hostMethodSkills(methods: readonly MethodBinding[]): readonly HostMethodSkill[] {
|
|
12
|
-
return Object.freeze(methods.flatMap((method) => {
|
|
13
|
-
if (method.kind !== "skill") return [];
|
|
14
|
-
const name = basename(dirname(method.path));
|
|
15
|
-
return name ? [Object.freeze({ name })] : [];
|
|
16
|
-
}));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const alreadyPrefixed = (prompt: string, token: string) => {
|
|
20
|
-
const text = prompt.trimStart();
|
|
21
|
-
return text === token || text.startsWith(`${token} `) || text.startsWith(`${token}\n`);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function prefixMethodInvocation(token: string, prompt: string): string {
|
|
25
|
-
if (alreadyPrefixed(prompt, token)) return prompt;
|
|
26
|
-
return prompt ? `${token} ${prompt}` : token;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Claude's documented plugin Skill invocation syntax. */
|
|
30
|
-
export function applyClaudeSkillInvocation(methods: readonly MethodBinding[], prompt: string): string {
|
|
31
|
-
const skills = hostMethodSkills(methods);
|
|
32
|
-
if (skills.length !== 1) return prompt;
|
|
33
|
-
return prefixMethodInvocation(`/${HOST_METHOD_PLUGIN_NAME}:${skills[0]!.name}`, prompt);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Codex's documented explicit Skill invocation syntax. */
|
|
37
|
-
export function applyCodexSkillInvocation(methods: readonly MethodBinding[], prompt: string): string {
|
|
38
|
-
return hostMethodSkills(methods).reduceRight(
|
|
39
|
-
(invocation, skill) => prefixMethodInvocation(`$${skill.name}`, invocation),
|
|
40
|
-
prompt,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const isEnoent = (error: unknown): boolean =>
|
|
45
|
-
(error as NodeJS.ErrnoException).code === "ENOENT";
|
|
46
|
-
|
|
47
|
-
/** Packaged method skill directory names (child has SKILL.md). I/O errors propagate. */
|
|
48
|
-
async function packagedMethodSkillNames(packagedMethodsRealpath: string): Promise<readonly string[]> {
|
|
49
|
-
const entries = await readdir(packagedMethodsRealpath, { withFileTypes: true });
|
|
50
|
-
const names: string[] = [];
|
|
51
|
-
for (const entry of entries) {
|
|
52
|
-
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
53
|
-
try {
|
|
54
|
-
await access(join(packagedMethodsRealpath, entry.name, "SKILL.md"));
|
|
55
|
-
} catch (error) {
|
|
56
|
-
if (isEnoent(error)) continue;
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
names.push(entry.name);
|
|
60
|
-
}
|
|
61
|
-
return names;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Byte map of every regular file under a packaged skill directory
|
|
66
|
-
* (relative path → bytes). Undefined when SKILL.md is missing. Other I/O
|
|
67
|
-
* errors propagate. Integrity only — no free-text parsing of Skill prose.
|
|
68
|
-
*/
|
|
69
|
-
async function packagedSkillFileBytes(
|
|
70
|
-
skillDir: string,
|
|
71
|
-
): Promise<ReadonlyMap<string, Buffer> | undefined> {
|
|
72
|
-
try {
|
|
73
|
-
await access(join(skillDir, "SKILL.md"));
|
|
74
|
-
} catch (error) {
|
|
75
|
-
if (isEnoent(error)) return undefined;
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
const files = new Map<string, Buffer>();
|
|
79
|
-
async function walk(dir: string, prefix: string): Promise<void> {
|
|
80
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
81
|
-
for (const entry of entries) {
|
|
82
|
-
const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
83
|
-
const full = join(dir, entry.name);
|
|
84
|
-
if (entry.isDirectory()) {
|
|
85
|
-
await walk(full, rel);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
if (entry.isFile()) {
|
|
89
|
-
files.set(rel, await readFile(full));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
await walk(skillDir, "");
|
|
94
|
-
return files;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* True when catalog skill already carries identical bytes for every required
|
|
99
|
-
* packaged relative path. Only those paths are read — extra catalog files are
|
|
100
|
-
* out of scope for the compatibility proof.
|
|
101
|
-
*/
|
|
102
|
-
async function catalogPublishesPackagedSkill(
|
|
103
|
-
catalogSkillDir: string,
|
|
104
|
-
required: ReadonlyMap<string, Buffer>,
|
|
105
|
-
): Promise<boolean> {
|
|
106
|
-
for (const [rel, bytes] of required) {
|
|
107
|
-
let other: Buffer;
|
|
108
|
-
try {
|
|
109
|
-
other = await readFile(join(catalogSkillDir, rel));
|
|
110
|
-
} catch (error) {
|
|
111
|
-
if (isEnoent(error)) return false;
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
114
|
-
if (!bytes.equals(other)) return false;
|
|
115
|
-
}
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Existing project catalog is usable when it already publishes every packaged
|
|
121
|
-
* method skill with identical file bytes. Path identity is sufficient but not
|
|
122
|
-
* required (#980): a worktree catalog at another realpath that still carries
|
|
123
|
-
* the packaged method bytes must stay put. Name-only / foreign / stale content
|
|
124
|
-
* remains a true conflict. Incomplete, broken, or non-symlink entries too.
|
|
125
|
-
*
|
|
126
|
-
* Caller must only invoke this when `link` is known present; link-missing
|
|
127
|
-
* ENOENT is classified solely by the existence probe in
|
|
128
|
-
* `installWorkspaceMethodSkills`, not here.
|
|
129
|
-
*/
|
|
130
|
-
async function isCompatibleMethodCatalog(
|
|
131
|
-
link: string,
|
|
132
|
-
packagedMethodsRealpath: string,
|
|
133
|
-
): Promise<boolean> {
|
|
134
|
-
const stat = await lstat(link);
|
|
135
|
-
if (!stat.isSymbolicLink()) return false;
|
|
136
|
-
let resolved: string;
|
|
137
|
-
try {
|
|
138
|
-
resolved = await realpath(link);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
if (isEnoent(error)) return false;
|
|
141
|
-
throw error;
|
|
142
|
-
}
|
|
143
|
-
if (resolved === packagedMethodsRealpath) return true;
|
|
144
|
-
const names = await packagedMethodSkillNames(packagedMethodsRealpath);
|
|
145
|
-
if (names.length === 0) return false;
|
|
146
|
-
for (const name of names) {
|
|
147
|
-
const required = await packagedSkillFileBytes(join(packagedMethodsRealpath, name));
|
|
148
|
-
if (required === undefined) return false;
|
|
149
|
-
if (!(await catalogPublishesPackagedSkill(join(resolved, name), required))) return false;
|
|
150
|
-
}
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** Install the documented project Skill catalog once and leave it in place. */
|
|
155
|
-
export async function installWorkspaceMethodSkills(cwd: string, packageRoot: string): Promise<void> {
|
|
156
|
-
const target = await realpath(packagedMethodsDir(packageRoot));
|
|
157
|
-
const link = join(cwd, ".agents", "skills");
|
|
158
|
-
|
|
159
|
-
// Existence probe only — this seam alone classifies link-missing ENOENT.
|
|
160
|
-
let present: boolean;
|
|
161
|
-
try {
|
|
162
|
-
await lstat(link);
|
|
163
|
-
present = true;
|
|
164
|
-
} catch (error) {
|
|
165
|
-
if (!isEnoent(error)) throw error;
|
|
166
|
-
present = false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (present) {
|
|
170
|
-
if (await isCompatibleMethodCatalog(link, target)) return;
|
|
171
|
-
const stat = await lstat(link);
|
|
172
|
-
const detail = stat.isSymbolicLink() ? `symlink to ${await readlink(link)}` : "non-symlink entry";
|
|
173
|
-
throw new Error(`workspace method catalog conflict at ${link}: ${detail}`);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
await mkdir(dirname(link), { recursive: true });
|
|
177
|
-
try {
|
|
178
|
-
await symlink(target, link);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
181
|
-
if (!(await isCompatibleMethodCatalog(link, target))) {
|
|
182
|
-
throw new Error(`workspace method catalog conflict at ${link}`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical Skill binding built from package-owned method material.
|
|
3
|
-
* Lives beside the method seam — used by the Internal role runtime, not the
|
|
4
|
-
* public ak-role bin bundle.
|
|
5
|
-
*/
|
|
6
|
-
import { dirname } from "node:path";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
captureCanonicalSkillExpansion,
|
|
10
|
-
type CanonicalSkillBinding,
|
|
11
|
-
type CanonicalSkillName,
|
|
12
|
-
} from "../canonical-skill-binding.ts";
|
|
13
|
-
import {
|
|
14
|
-
loadPackagedMethodSkillMaterial,
|
|
15
|
-
resolvePackagedMethodSkillPath,
|
|
16
|
-
type PackagedMethodSkillName,
|
|
17
|
-
} from "./method-skill.ts";
|
|
18
|
-
|
|
19
|
-
type PackagedCanonicalSkillName = Extract<
|
|
20
|
-
PackagedMethodSkillName,
|
|
21
|
-
CanonicalSkillName
|
|
22
|
-
>;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Build a CanonicalSkillBinding from package-owned material.
|
|
26
|
-
* captureExpansion accepts the package skill path (configured or realpath).
|
|
27
|
-
*/
|
|
28
|
-
export async function loadPackagedCanonicalSkillBinding<
|
|
29
|
-
Name extends PackagedCanonicalSkillName,
|
|
30
|
-
>(
|
|
31
|
-
packageRoot: string,
|
|
32
|
-
name: Name,
|
|
33
|
-
): Promise<CanonicalSkillBinding<Name>> {
|
|
34
|
-
// Forced expansion bindings are only defined for canonical completion-gated skills.
|
|
35
|
-
// Optional Fixer diagnosing-bugs stays available via --skill without this binding.
|
|
36
|
-
const material = await loadPackagedMethodSkillMaterial(packageRoot, name);
|
|
37
|
-
const configuredPath = resolvePackagedMethodSkillPath(packageRoot, name);
|
|
38
|
-
const snapshot = Object.freeze({
|
|
39
|
-
raw: material.raw,
|
|
40
|
-
path: material.skillPath,
|
|
41
|
-
baseDir: dirname(material.skillPath),
|
|
42
|
-
body: material.body,
|
|
43
|
-
snapshotIdentity: Object.freeze({ text: material.raw }),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const binding: CanonicalSkillBinding<Name> = {
|
|
47
|
-
name,
|
|
48
|
-
snapshot,
|
|
49
|
-
captureExpansion(evidence, originalRequest) {
|
|
50
|
-
return captureCanonicalSkillExpansion(
|
|
51
|
-
name,
|
|
52
|
-
snapshot,
|
|
53
|
-
configuredPath,
|
|
54
|
-
evidence,
|
|
55
|
-
originalRequest,
|
|
56
|
-
);
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return Object.freeze(binding);
|
|
60
|
-
}
|