@the-open-engine-company/zeroshot 10.3.1 → 10.5.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 +14 -1
- package/bin/zeroshot.js +1 -1
- package/install.js +2 -1
- package/lib/install.js +8 -0
- package/lib/skills.js +196 -0
- package/package.json +2 -1
- package/skills/zeroshot/SKILL.md +109 -0
package/README.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# `@the-open-engine-company/zeroshot`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Installer for the canonical `zeroshot` executable and agent skill. The package selects the release
|
|
4
|
+
archive for the current Node platform and architecture, verifies it against that release's
|
|
5
|
+
`SHA256SUMS`, and installs the executable.
|
|
6
|
+
|
|
7
|
+
The same managed skill is installed for Codex and GitHub Copilot at
|
|
8
|
+
`$HOME/.agents/skills/zeroshot/SKILL.md`, and for Claude Code at
|
|
9
|
+
`${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/zeroshot/SKILL.md`. Reinstalling updates an unchanged
|
|
10
|
+
managed copy. A conflicting or edited skill is preserved; installation fails with the exact path so
|
|
11
|
+
the conflict cannot pass unnoticed.
|
|
12
|
+
|
|
13
|
+
When set, `CLAUDE_CONFIG_DIR` must be absolute so the global skill has one stable location.
|
|
14
|
+
|
|
15
|
+
npm 7 and newer do not run uninstall lifecycle scripts. After uninstalling the package, remove the
|
|
16
|
+
two skill directories above manually if their `SKILL.md` files are still unmodified managed copies.
|
|
4
17
|
|
|
5
18
|
Installation fails closed with `UNSUPPORTED_ZEROSHOT_HOST` when the host has no declared release target. Source compilation and cross-target substitution are not supported.
|
|
6
19
|
|
package/bin/zeroshot.js
CHANGED
|
@@ -11,7 +11,7 @@ try {
|
|
|
11
11
|
const binary = path.join(__dirname, 'native', executable);
|
|
12
12
|
if (!fs.existsSync(binary)) {
|
|
13
13
|
throw new Error(
|
|
14
|
-
`NATIVE_BINARY_MISSING: ${binary}; reinstall @the-open-engine-company/zeroshot`
|
|
14
|
+
`NATIVE_BINARY_MISSING: ${binary}; reinstall @the-open-engine-company/zeroshot with lifecycle scripts enabled`
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
17
|
const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
package/install.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const { install } = require('./lib/install');
|
|
5
|
+
const { requireCompleteSkillInstall } = require('./lib/skills');
|
|
5
6
|
|
|
6
|
-
install().catch((error) => {
|
|
7
|
+
install({ onSkillResults: requireCompleteSkillInstall }).catch((error) => {
|
|
7
8
|
process.stderr.write(`zeroshot install failed: ${error.message}\n`);
|
|
8
9
|
process.exitCode = 1;
|
|
9
10
|
});
|
package/lib/install.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const https = require('https');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { URL } = require('url');
|
|
7
|
+
const { installSkills } = require('./skills');
|
|
7
8
|
const {
|
|
8
9
|
archiveName,
|
|
9
10
|
extractExecutable,
|
|
@@ -120,6 +121,13 @@ async function install(options = {}) {
|
|
|
120
121
|
} finally {
|
|
121
122
|
fs.rmSync(temporary, { force: true });
|
|
122
123
|
}
|
|
124
|
+
const skillResults = installSkills({
|
|
125
|
+
packageRoot,
|
|
126
|
+
homeDirectory: options.homeDirectory,
|
|
127
|
+
environment: options.environment,
|
|
128
|
+
uid: options.uid,
|
|
129
|
+
});
|
|
130
|
+
if (options.onSkillResults) options.onSkillResults(skillResults);
|
|
123
131
|
return destination;
|
|
124
132
|
}
|
|
125
133
|
|
package/lib/skills.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
|
|
8
|
+
const SKILL_NAME = 'zeroshot';
|
|
9
|
+
const MANAGED_MARKER = 'managed by @the-open-engine-company/zeroshot';
|
|
10
|
+
const MANAGED_PATTERN =
|
|
11
|
+
/^<!-- managed by @the-open-engine-company\/zeroshot; sha256=([a-f0-9]{64}) -->\n/;
|
|
12
|
+
const TARGETS = Object.freeze([
|
|
13
|
+
Object.freeze({ id: 'agents', label: 'Codex/GitHub Copilot' }),
|
|
14
|
+
Object.freeze({ id: 'claude', label: 'Claude Code' }),
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
function digest(value) {
|
|
18
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function frontmatterEnd(document) {
|
|
22
|
+
if (!document.startsWith('---\n')) {
|
|
23
|
+
throw new Error('SKILL_INVALID: SKILL.md needs YAML frontmatter');
|
|
24
|
+
}
|
|
25
|
+
const closing = document.indexOf('\n---\n', 4);
|
|
26
|
+
if (closing === -1) throw new Error('SKILL_INVALID: SKILL.md frontmatter is not closed');
|
|
27
|
+
return closing + 5;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function managedDocument(canonical) {
|
|
31
|
+
const offset = frontmatterEnd(canonical);
|
|
32
|
+
const marker = `<!-- ${MANAGED_MARKER}; sha256=${digest(canonical)} -->\n`;
|
|
33
|
+
return `${canonical.slice(0, offset)}${marker}${canonical.slice(offset)}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function managedSource(document) {
|
|
37
|
+
let offset;
|
|
38
|
+
try {
|
|
39
|
+
offset = frontmatterEnd(document);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const match = MANAGED_PATTERN.exec(document.slice(offset));
|
|
44
|
+
if (!match) return null;
|
|
45
|
+
const source = `${document.slice(0, offset)}${document.slice(offset + match[0].length)}`;
|
|
46
|
+
return digest(source) === match[1] ? source : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function locationResults(homeDirectory, environment) {
|
|
50
|
+
if (!homeDirectory || !path.isAbsolute(homeDirectory)) {
|
|
51
|
+
return TARGETS.map((target) => ({
|
|
52
|
+
...target,
|
|
53
|
+
status: 'failed',
|
|
54
|
+
message: 'user home is unavailable or not absolute',
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
const shared = path.join(homeDirectory, '.agents', 'skills', SKILL_NAME);
|
|
58
|
+
const configuredClaude = environment.CLAUDE_CONFIG_DIR;
|
|
59
|
+
const claudeRoot = configuredClaude || path.join(homeDirectory, '.claude');
|
|
60
|
+
return [
|
|
61
|
+
{ ...TARGETS[0], directory: shared },
|
|
62
|
+
path.isAbsolute(claudeRoot)
|
|
63
|
+
? { ...TARGETS[1], directory: path.join(claudeRoot, 'skills', SKILL_NAME) }
|
|
64
|
+
: {
|
|
65
|
+
...TARGETS[1],
|
|
66
|
+
status: 'failed',
|
|
67
|
+
message: 'CLAUDE_CONFIG_DIR must be absolute during package installation',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function lstatIfPresent(filename) {
|
|
73
|
+
try {
|
|
74
|
+
return fs.lstatSync(filename);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (error.code === 'ENOENT') return null;
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function atomicWrite(filename, contents) {
|
|
82
|
+
const temporary = path.join(
|
|
83
|
+
path.dirname(filename),
|
|
84
|
+
`.SKILL.md.${process.pid}.${crypto.randomBytes(6).toString('hex')}.tmp`
|
|
85
|
+
);
|
|
86
|
+
try {
|
|
87
|
+
fs.writeFileSync(temporary, contents, { encoding: 'utf8', flag: 'wx', mode: 0o644 });
|
|
88
|
+
fs.renameSync(temporary, filename);
|
|
89
|
+
} finally {
|
|
90
|
+
fs.rmSync(temporary, { force: true });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function inspectExisting(filename, canonical, managed) {
|
|
95
|
+
const existingStat = lstatIfPresent(filename);
|
|
96
|
+
if (!existingStat) return { status: 'installed' };
|
|
97
|
+
if (!existingStat.isFile() || existingStat.isSymbolicLink()) {
|
|
98
|
+
return { status: 'conflict', message: 'SKILL.md is not a regular file' };
|
|
99
|
+
}
|
|
100
|
+
const existing = fs.readFileSync(filename, 'utf8');
|
|
101
|
+
if (existing === managed) return { status: 'unchanged' };
|
|
102
|
+
if (existing === canonical || managedSource(existing) !== null) return { status: 'updated' };
|
|
103
|
+
return {
|
|
104
|
+
status: 'conflict',
|
|
105
|
+
message: 'existing skill is not an unmodified Zeroshot-managed copy',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function installAt(location, canonical, managed) {
|
|
110
|
+
if (location.status === 'failed') return location;
|
|
111
|
+
const filename = path.join(location.directory, 'SKILL.md');
|
|
112
|
+
try {
|
|
113
|
+
fs.mkdirSync(location.directory, { recursive: true });
|
|
114
|
+
const directory = fs.lstatSync(location.directory);
|
|
115
|
+
if (!directory.isDirectory() || directory.isSymbolicLink()) {
|
|
116
|
+
return {
|
|
117
|
+
...location,
|
|
118
|
+
path: filename,
|
|
119
|
+
status: 'conflict',
|
|
120
|
+
message: 'skill directory is not a regular directory',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const inspection = inspectExisting(filename, canonical, managed);
|
|
124
|
+
if (inspection.status === 'unchanged' || inspection.status === 'conflict') {
|
|
125
|
+
return { ...location, path: filename, ...inspection };
|
|
126
|
+
}
|
|
127
|
+
atomicWrite(filename, managed);
|
|
128
|
+
return { ...location, path: filename, status: inspection.status };
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return { ...location, path: filename, status: 'failed', message: error.message };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function installSkills(options = {}) {
|
|
135
|
+
const packageRoot = options.packageRoot || path.resolve(__dirname, '..');
|
|
136
|
+
const source = path.join(packageRoot, 'skills', SKILL_NAME, 'SKILL.md');
|
|
137
|
+
const canonical = fs.readFileSync(source, 'utf8');
|
|
138
|
+
const managed = managedDocument(canonical);
|
|
139
|
+
const homeDirectory = options.homeDirectory ?? os.homedir();
|
|
140
|
+
const environment = options.environment ?? process.env;
|
|
141
|
+
const uid = options.uid ?? (typeof process.getuid === 'function' ? process.getuid() : undefined);
|
|
142
|
+
const locations = locationResults(homeDirectory, environment);
|
|
143
|
+
if (uid === 0 && environment.SUDO_USER && environment.SUDO_USER !== 'root') {
|
|
144
|
+
return locations.map((location) => ({
|
|
145
|
+
...location,
|
|
146
|
+
status: 'failed',
|
|
147
|
+
message:
|
|
148
|
+
'refusing to create user skills from a sudo npm install; use a user-owned npm prefix',
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
return locations.map((location) => installAt(location, canonical, managed));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function humanList(values) {
|
|
155
|
+
if (values.length < 2) return values[0] || '';
|
|
156
|
+
if (values.length === 2) return `${values[0]} and ${values[1]}`;
|
|
157
|
+
return `${values.slice(0, -1).join(', ')}, and ${values.at(-1)}`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function reportSkillResults(results, output = process.stdout, errorOutput = process.stderr) {
|
|
161
|
+
const ready = results.filter(({ status }) =>
|
|
162
|
+
['installed', 'updated', 'unchanged'].includes(status)
|
|
163
|
+
);
|
|
164
|
+
const incomplete = results.filter(
|
|
165
|
+
({ status }) => !['installed', 'updated', 'unchanged'].includes(status)
|
|
166
|
+
);
|
|
167
|
+
if (ready.length > 0) {
|
|
168
|
+
output.write(`zeroshot skill ready for ${humanList(ready.map(({ label }) => label))}\n`);
|
|
169
|
+
}
|
|
170
|
+
for (const result of incomplete) {
|
|
171
|
+
const location = result.path ? `${result.path}: ` : '';
|
|
172
|
+
errorOutput.write(
|
|
173
|
+
`zeroshot skill not installed for ${result.label}: ${location}${result.message}\n`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
if (incomplete.length > 0) {
|
|
177
|
+
errorOutput.write(
|
|
178
|
+
'Re-run npm install with lifecycle scripts enabled after resolving these paths.\n'
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return incomplete.length === 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function requireCompleteSkillInstall(results, output, errorOutput) {
|
|
185
|
+
if (!reportSkillResults(results, output, errorOutput)) {
|
|
186
|
+
throw new Error('SKILL_INSTALL_INCOMPLETE: Zeroshot skill installation was incomplete');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
module.exports = {
|
|
191
|
+
installSkills,
|
|
192
|
+
managedDocument,
|
|
193
|
+
managedSource,
|
|
194
|
+
reportSkillResults,
|
|
195
|
+
requireCompleteSkillInstall,
|
|
196
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-open-engine-company/zeroshot",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.5.0",
|
|
4
4
|
"description": "Verified prebuilt binary installer for the standalone Zeroshot engine",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"bin/",
|
|
21
21
|
"lib/",
|
|
22
|
+
"skills/",
|
|
22
23
|
"install.js",
|
|
23
24
|
"targets.json",
|
|
24
25
|
"README.md"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zeroshot
|
|
3
|
+
description: Use Zeroshot to prepare, run, observe, or troubleshoot explicit multi-agent software work locally or on Zeroshot Cloud. Apply when the user names Zeroshot or asks about its CLI; do not route ordinary local work into Zeroshot without that intent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Zeroshot
|
|
7
|
+
|
|
8
|
+
Zeroshot executes an explicit graph of software agents. Workers make changes; independent verifiers
|
|
9
|
+
judge the evidence, and the graph decides when to repair or deliver. A successful run means the
|
|
10
|
+
graph reached its declared outcome; it does not always mean a pull request was created or merged.
|
|
11
|
+
|
|
12
|
+
Use the installed CLI help as the exact contract when commands differ from this overview.
|
|
13
|
+
|
|
14
|
+
## Shape the task
|
|
15
|
+
|
|
16
|
+
Before submitting, inspect the request, repository guidance, existing issue, and enough code to know:
|
|
17
|
+
|
|
18
|
+
- the desired behavior and observable success;
|
|
19
|
+
- material constraints and behavior that must remain unchanged;
|
|
20
|
+
- whether a separate worker could implement it and a verifier could judge it.
|
|
21
|
+
|
|
22
|
+
Fill gaps from available evidence. Choose routine technical details without interrogating the user.
|
|
23
|
+
If an unresolved product choice would materially change the outcome, propose the narrowest supported
|
|
24
|
+
interpretation and ask one focused question. Do not submit while that decision remains unanswered.
|
|
25
|
+
Suggest separate tasks only for independently useful outcomes or real prerequisites.
|
|
26
|
+
|
|
27
|
+
Never start a Zeroshot run merely because the skill is available. The user must ask to use Zeroshot.
|
|
28
|
+
A worker already executing inside a Zeroshot run should perform its assigned work directly, not start
|
|
29
|
+
another run. A failed Cloud run does not authorize silently implementing the task locally.
|
|
30
|
+
|
|
31
|
+
## Choose the target
|
|
32
|
+
|
|
33
|
+
- Local execution omits `--target` and is the only mode that edits the invoking worktree directly.
|
|
34
|
+
- Zeroshot Cloud is built in. Sign in once with `zeroshot target login cloud`, then use
|
|
35
|
+
`--target cloud` explicitly on Cloud commands.
|
|
36
|
+
- Do not add or set up the built-in Cloud target. Named targets store endpoints and login identity,
|
|
37
|
+
not repository configuration.
|
|
38
|
+
|
|
39
|
+
## Reuse profiles and connections
|
|
40
|
+
|
|
41
|
+
Prefer a saved profile over inventing a graph or runtime. Inspect its input, runtime, and delivery
|
|
42
|
+
behavior before constructing a run:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
zeroshot profile list --target cloud --scope user
|
|
46
|
+
zeroshot profile list --target cloud --scope org
|
|
47
|
+
zeroshot profile show NAME --target cloud --scope org
|
|
48
|
+
zeroshot connection list --target cloud --scope user
|
|
49
|
+
zeroshot connection list --target cloud --scope org
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Do not assume a profile creates a pull request. `--pr` requests pull-request delivery and `--ship`
|
|
53
|
+
requests merge delivery when materializing a compatible template; use either only when intended.
|
|
54
|
+
|
|
55
|
+
## Validate and submit
|
|
56
|
+
|
|
57
|
+
Put profile input in a JSON file matching the profile's declared schema. Use a stable, non-secret
|
|
58
|
+
submission key for safe retries:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
zeroshot run --title "TASK" --profile org:NAME --input input.json \
|
|
62
|
+
--target cloud --submission-key KEY --validate-only
|
|
63
|
+
|
|
64
|
+
zeroshot run --title "TASK" --profile org:NAME --input input.json \
|
|
65
|
+
--target cloud --submission-key KEY
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`--validate-only` materializes and validates without starting a run. A named Cloud profile must
|
|
69
|
+
still be fetched from the target first, so this command requires Cloud access. It does not prove
|
|
70
|
+
connection availability.
|
|
71
|
+
|
|
72
|
+
For named targets, Zeroshot resolves source from the invoking Git worktree's attached upstream.
|
|
73
|
+
Without an upstream, it requires exactly one GitHub remote. Detached worktrees require explicit
|
|
74
|
+
repository and branch values. Override source only when needed:
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
--target cloud --repository OWNER/REPOSITORY --branch BRANCH --revision SHA
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Cloud receives the remote revision, not uncommitted files. Check relevant dirty or unpushed work and
|
|
81
|
+
never push or omit it without authorization. Confirm the exact repository, branch, revision, target,
|
|
82
|
+
profile, and delivery intent reported for the run.
|
|
83
|
+
|
|
84
|
+
## Observe and troubleshoot
|
|
85
|
+
|
|
86
|
+
Keep the run ID and target:
|
|
87
|
+
|
|
88
|
+
```console
|
|
89
|
+
zeroshot status RUN_ID --target cloud
|
|
90
|
+
zeroshot watch RUN_ID --target cloud
|
|
91
|
+
zeroshot logs RUN_ID --target cloud
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
A foreground run streams events. Ctrl-C detaches observation without stopping the run. Use
|
|
95
|
+
`zeroshot force-stop RUN_ID --target cloud` only when the user explicitly intends to stop it.
|
|
96
|
+
|
|
97
|
+
For command errors, check `zeroshot --version` and the relevant `--help`; do not revive removed
|
|
98
|
+
commands such as `target setup`. If login cannot retain credentials, fix the credential store before
|
|
99
|
+
requesting another device code; `zeroshot target login --help` lists the supported
|
|
100
|
+
`ZEROSHOT_CREDENTIAL_STORE` modes.
|
|
101
|
+
|
|
102
|
+
For `connection_unavailable`, list connections for the same target and both relevant scopes. A
|
|
103
|
+
static `connection set` replaces the whole named connection, so supply every required field through
|
|
104
|
+
repeated `--field` prompts or JSON stdin. Never put secret values in arguments, task files, runtime
|
|
105
|
+
configuration, issues, or logs.
|
|
106
|
+
|
|
107
|
+
After an uncertain submission response, reconcile by submission key before retrying. Do not create a
|
|
108
|
+
second logical run. Report submitted, running, verified, delivered, failed, and stopped states
|
|
109
|
+
accurately; submission alone is not completion.
|