@1aboveio/skills 0.12.1 → 0.14.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.
- package/README.md +44 -12
- package/package.json +1 -1
- package/runtime/skills/distribution/generated/recipes.json +17 -17
- package/runtime/skills/distribution/scripts/bundles.mjs +620 -72
- package/runtime/skills/engineering/engineering-runtime/scripts/invocation-policy.mjs +187 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +595 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +172 -0
- package/skills/cicd-pipeline/mergify/references/watch-contract.md +7 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +60 -2
- package/skills/engineering/engineering-runtime/coherence/workflow.json +23 -16
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.mjs +187 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +19 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +9 -3
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +20 -13
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +14 -6
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import { isMainModule } from './main-module.mjs';
|
|
8
|
+
|
|
9
|
+
export const MANUAL_ONLY = 'manual-only';
|
|
10
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
11
|
+
|
|
12
|
+
function frontmatterBounds(contents) {
|
|
13
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(contents);
|
|
14
|
+
if (!match) throw new Error('SKILL.md must begin with YAML frontmatter');
|
|
15
|
+
return { body: match[1], end: match[0].length };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function manualOnlySkill(contents) {
|
|
19
|
+
const frontmatter = frontmatterBounds(contents);
|
|
20
|
+
const declarations = frontmatter.body.match(/^disable-model-invocation\s*:\s*.*$/gm) ?? [];
|
|
21
|
+
if (declarations.length > 1) throw new Error('SKILL.md repeats disable-model-invocation');
|
|
22
|
+
|
|
23
|
+
const body = declarations.length === 1
|
|
24
|
+
? frontmatter.body.replace(/^disable-model-invocation\s*:\s*.*$/m, 'disable-model-invocation: true')
|
|
25
|
+
: `${frontmatter.body}\ndisable-model-invocation: true`;
|
|
26
|
+
return `---\n${body}\n---\n${contents.slice(frontmatter.end)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function manualOnlyOpenAi(contents) {
|
|
30
|
+
const policyHeaders = contents.match(/^policy\s*:\s*$/gm) ?? [];
|
|
31
|
+
if (policyHeaders.length > 1) throw new Error('agents/openai.yaml repeats policy');
|
|
32
|
+
if (policyHeaders.length === 0) {
|
|
33
|
+
const prefix = contents.length === 0 || contents.endsWith('\n') ? contents : `${contents}\n`;
|
|
34
|
+
return `${prefix}policy:\n allow_implicit_invocation: false\n`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lines = contents.split('\n');
|
|
38
|
+
const policyIndex = lines.findIndex((line) => /^policy\s*:\s*$/.test(line));
|
|
39
|
+
let policyEnd = lines.length;
|
|
40
|
+
for (let index = policyIndex + 1; index < lines.length; index += 1) {
|
|
41
|
+
if (/^[^\s#][^:]*\s*:/.test(lines[index])) {
|
|
42
|
+
policyEnd = index;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const declarations = lines
|
|
47
|
+
.slice(policyIndex + 1, policyEnd)
|
|
48
|
+
.filter((line) => /^\s+allow_implicit_invocation\s*:/.test(line));
|
|
49
|
+
if (declarations.length > 1) throw new Error('agents/openai.yaml repeats policy.allow_implicit_invocation');
|
|
50
|
+
if (declarations.length === 1) {
|
|
51
|
+
return lines.map((line, index) => (
|
|
52
|
+
index > policyIndex && index < policyEnd && /^\s+allow_implicit_invocation\s*:/.test(line)
|
|
53
|
+
? ' allow_implicit_invocation: false'
|
|
54
|
+
: line
|
|
55
|
+
)).join('\n');
|
|
56
|
+
}
|
|
57
|
+
lines.splice(policyIndex + 1, 0, ' allow_implicit_invocation: false');
|
|
58
|
+
return lines.join('\n');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function manualOnlyPolicyFindings(skillDirectory) {
|
|
62
|
+
const findings = [];
|
|
63
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
64
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
65
|
+
if (!existsSync(skillPath)) return ['SKILL.md is missing'];
|
|
66
|
+
const skill = readFileSync(skillPath, 'utf8');
|
|
67
|
+
const declarations = frontmatterBounds(skill).body.match(/^disable-model-invocation\s*:\s*true\s*$/gm) ?? [];
|
|
68
|
+
if (declarations.length !== 1) findings.push('SKILL.md must declare disable-model-invocation: true exactly once');
|
|
69
|
+
if (!existsSync(openaiPath)) {
|
|
70
|
+
findings.push('agents/openai.yaml is missing');
|
|
71
|
+
} else {
|
|
72
|
+
const openai = readFileSync(openaiPath, 'utf8');
|
|
73
|
+
const policies = openai.match(/^policy\s*:\s*$/gm) ?? [];
|
|
74
|
+
const implicit = openai.match(/^\s+allow_implicit_invocation\s*:\s*false\s*$/gm) ?? [];
|
|
75
|
+
if (policies.length !== 1 || implicit.length !== 1) {
|
|
76
|
+
findings.push('agents/openai.yaml must declare policy.allow_implicit_invocation: false exactly once');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Restore the reviewed upstream bytes for source-integrity hashing. The installed tree must first
|
|
83
|
+
// pass manualOnlyPolicyFindings; these exact trailing additions are the only intentional divergence.
|
|
84
|
+
export function reviewedSourceInjections(skillDirectory, policy) {
|
|
85
|
+
if (policy !== MANUAL_ONLY) return [];
|
|
86
|
+
const findings = manualOnlyPolicyFindings(skillDirectory);
|
|
87
|
+
if (findings.length > 0) throw new Error(findings.join('; '));
|
|
88
|
+
const skill = readFileSync(join(skillDirectory, 'SKILL.md'), 'utf8')
|
|
89
|
+
.replace(/^disable-model-invocation: true\n/m, '');
|
|
90
|
+
const openai = readFileSync(join(skillDirectory, 'agents', 'openai.yaml'), 'utf8')
|
|
91
|
+
.replace(/policy:\n allow_implicit_invocation: false\n?$/, '');
|
|
92
|
+
return [
|
|
93
|
+
{ relativePath: 'SKILL.md', contents: skill },
|
|
94
|
+
{ relativePath: 'agents/openai.yaml', contents: openai },
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function clearInvocationPolicy({ installName, policy, skillsRoot = join(homedir(), '.agents', 'skills') }) {
|
|
99
|
+
if (!SKILL_NAME.test(installName ?? '')) throw new Error(`invalid installed skill name ${JSON.stringify(installName)}`);
|
|
100
|
+
if (policy !== MANUAL_ONLY) throw new Error(`unsupported invocation policy ${JSON.stringify(policy)}`);
|
|
101
|
+
const skillDirectory = join(skillsRoot, installName);
|
|
102
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
103
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
104
|
+
if (!existsSync(skillPath) || !existsSync(openaiPath)) throw new Error(`installed skill is incomplete: ${skillDirectory}`);
|
|
105
|
+
const skill = readFileSync(skillPath, 'utf8');
|
|
106
|
+
const openai = readFileSync(openaiPath, 'utf8');
|
|
107
|
+
const hasSkillPolicy = /^disable-model-invocation\s*:/m.test(frontmatterBounds(skill).body);
|
|
108
|
+
const hasOpenAiPolicy = /^policy\s*:\s*$/m.test(openai) || /^\s+allow_implicit_invocation\s*:/m.test(openai);
|
|
109
|
+
if (!hasSkillPolicy && !hasOpenAiPolicy) {
|
|
110
|
+
return { installName, policy: 'implicit', skillDirectory, changed: false };
|
|
111
|
+
}
|
|
112
|
+
const injected = Object.fromEntries(reviewedSourceInjections(skillDirectory, policy)
|
|
113
|
+
.map((entry) => [entry.relativePath, entry.contents]));
|
|
114
|
+
writeFileSync(skillPath, injected['SKILL.md']);
|
|
115
|
+
writeFileSync(openaiPath, injected['agents/openai.yaml']);
|
|
116
|
+
return { installName, policy: 'implicit', skillDirectory, changed: true };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function applyInvocationPolicy({ installName, policy, skillsRoot = join(homedir(), '.agents', 'skills') }) {
|
|
120
|
+
if (!SKILL_NAME.test(installName ?? '')) throw new Error(`invalid installed skill name ${JSON.stringify(installName)}`);
|
|
121
|
+
if (policy !== MANUAL_ONLY) throw new Error(`unsupported invocation policy ${JSON.stringify(policy)}`);
|
|
122
|
+
const skillDirectory = join(skillsRoot, installName);
|
|
123
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
124
|
+
if (!existsSync(skillPath)) throw new Error(`installed skill is missing: ${skillPath}`);
|
|
125
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
126
|
+
|
|
127
|
+
const skillBefore = readFileSync(skillPath, 'utf8');
|
|
128
|
+
const skillAfter = manualOnlySkill(skillBefore);
|
|
129
|
+
if (skillAfter !== skillBefore) writeFileSync(skillPath, skillAfter);
|
|
130
|
+
|
|
131
|
+
mkdirSync(dirname(openaiPath), { recursive: true });
|
|
132
|
+
const openaiBefore = existsSync(openaiPath) ? readFileSync(openaiPath, 'utf8') : '';
|
|
133
|
+
const openaiAfter = manualOnlyOpenAi(openaiBefore);
|
|
134
|
+
if (openaiAfter !== openaiBefore) writeFileSync(openaiPath, openaiAfter);
|
|
135
|
+
|
|
136
|
+
const findings = manualOnlyPolicyFindings(skillDirectory);
|
|
137
|
+
if (findings.length > 0) throw new Error(findings.join('; '));
|
|
138
|
+
return { installName, policy, skillDirectory, changed: skillAfter !== skillBefore || openaiAfter !== openaiBefore };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function selectionEnablesTdd(env = process.env) {
|
|
142
|
+
const stateHome = env.XDG_STATE_HOME || join(env.HOME || homedir(), '.local', 'state');
|
|
143
|
+
const path = join(stateHome, '1aboveio-skills', 'selection.json');
|
|
144
|
+
if (!existsSync(path)) return true;
|
|
145
|
+
try {
|
|
146
|
+
const state = JSON.parse(readFileSync(path, 'utf8'));
|
|
147
|
+
if (state.tddImplicitInvocation === undefined) return true;
|
|
148
|
+
if (typeof state.tddImplicitInvocation !== 'boolean') {
|
|
149
|
+
throw new Error('tddImplicitInvocation must be a boolean');
|
|
150
|
+
}
|
|
151
|
+
return state.tddImplicitInvocation;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`cannot read TDD invocation selection at ${path}: ${error.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function reconcileInvocationPolicy(options) {
|
|
158
|
+
return selectionEnablesTdd(options.env)
|
|
159
|
+
? clearInvocationPolicy(options)
|
|
160
|
+
: applyInvocationPolicy(options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function parseArgs(argv) {
|
|
164
|
+
const parsed = { installName: null, policy: null, skillsRoot: undefined, fromSelection: false };
|
|
165
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
166
|
+
const arg = argv[index];
|
|
167
|
+
if (arg === '--skill') parsed.installName = argv[++index];
|
|
168
|
+
else if (arg === '--policy') parsed.policy = argv[++index];
|
|
169
|
+
else if (arg === '--skills-root') parsed.skillsRoot = argv[++index];
|
|
170
|
+
else if (arg === '--from-selection') parsed.fromSelection = true;
|
|
171
|
+
else throw new Error(`unknown argument ${arg}`);
|
|
172
|
+
}
|
|
173
|
+
return parsed;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (isMainModule(import.meta.url)) {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
179
|
+
const result = parsed.fromSelection
|
|
180
|
+
? reconcileInvocationPolicy(parsed)
|
|
181
|
+
: applyInvocationPolicy(parsed);
|
|
182
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
process.stderr.write(`invocation-policy: ${error.message}\n`);
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
}
|
|
187
|
+
}
|