@prismer/runtime 2.0.8 → 2.2.55
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/CHANGELOG.md +3430 -0
- package/README.md +34 -12
- package/apc/skills/FIELD-DICTIONARY.md +111 -0
- package/apc/skills/bug-reproduce/SKILL.md +150 -0
- package/apc/skills/bug-reproduce/skill.json +96 -0
- package/apc/skills/code-review/SKILL.md +198 -0
- package/apc/skills/code-review/skill.json +124 -0
- package/apc/skills/design-review/SKILL.md +122 -0
- package/apc/skills/design-review/skill.json +88 -0
- package/apc/skills/doc-sync/SKILL.md +168 -0
- package/apc/skills/doc-sync/skill.json +81 -0
- package/apc/skills/env-doctor/SKILL.md +194 -0
- package/apc/skills/env-doctor/skill.json +209 -0
- package/apc/skills/git-ops/SKILL.md +189 -0
- package/apc/skills/git-ops/skill.json +94 -0
- package/apc/skills/impact-trace/SKILL.md +168 -0
- package/apc/skills/impact-trace/skill.json +104 -0
- package/apc/skills/observability/SKILL.md +195 -0
- package/apc/skills/observability/skill.json +116 -0
- package/apc/skills/release-db-config-sync/SKILL.md +186 -0
- package/apc/skills/release-db-config-sync/skill.json +109 -0
- package/apc/skills/release-ota-promote/SKILL.md +195 -0
- package/apc/skills/release-ota-promote/skill.json +176 -0
- package/apc/skills/release-preflight/SKILL.md +174 -0
- package/apc/skills/release-preflight/skill.json +175 -0
- package/apc/skills/release-rollback/SKILL.md +214 -0
- package/apc/skills/release-rollback/skill.json +230 -0
- package/apc/skills/release-tag/SKILL.md +194 -0
- package/apc/skills/release-tag/skill.json +94 -0
- package/apc/skills/releasing-prod/SKILL.md +49 -0
- package/apc/skills/releasing-test/SKILL.md +135 -0
- package/apc/skills/sdk-release/SKILL.md +200 -0
- package/apc/skills/spec-intake/SKILL.md +169 -0
- package/apc/skills/spec-intake/skill.json +93 -0
- package/apc/skills/test-result-feedback/SKILL.md +239 -0
- package/apc/skills/test-result-feedback/skill.json +193 -0
- package/apc/skills/test-runner/SKILL.md +169 -0
- package/apc/skills/test-runner/skill.json +103 -0
- package/apc/skills/ui-align/SKILL.md +209 -0
- package/apc/skills/ui-align/skill.json +114 -0
- package/apc/skills/ui-canvas/SKILL.md +148 -0
- package/apc/skills/ui-canvas/skill.json +127 -0
- package/built-in-skills/agent-coordination/SKILL.md +59 -37
- package/built-in-skills/agent-meta/SKILL.md +1 -0
- package/built-in-skills/assets/SKILL.md +8 -6
- package/built-in-skills/browser-use/SKILL.md +93 -0
- package/built-in-skills/canvas-design/SKILL.md +1 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
- package/built-in-skills/claude-api/SKILL.md +1 -0
- package/built-in-skills/codebase-design/DEEPENING.md +37 -0
- package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/built-in-skills/codebase-design/LICENSE +21 -0
- package/built-in-skills/codebase-design/SKILL.md +116 -0
- package/built-in-skills/conversation-compaction/SKILL.md +114 -0
- package/built-in-skills/council-creator/SKILL.md +426 -0
- package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
- package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
- package/built-in-skills/document-generation/SKILL.md +105 -0
- package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/built-in-skills/domain-modeling/LICENSE +21 -0
- package/built-in-skills/domain-modeling/SKILL.md +76 -0
- package/built-in-skills/frontend-design/SKILL.md +1 -0
- package/built-in-skills/human-approval/SKILL.md +17 -2
- package/built-in-skills/image-generate/SKILL.md +103 -302
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
- package/built-in-skills/ingest/SKILL.md +13 -45
- package/built-in-skills/internal-comms/SKILL.md +1 -0
- package/built-in-skills/liteparse/SKILL.md +130 -110
- package/built-in-skills/mcp-builder/SKILL.md +1 -0
- package/built-in-skills/memory/SKILL.md +420 -55
- package/built-in-skills/memory-dream/SKILL.md +339 -0
- package/built-in-skills/office-artifacts/SKILL.md +17 -4
- package/built-in-skills/okr/SKILL.md +154 -0
- package/built-in-skills/persona/SKILL.md +81 -0
- package/built-in-skills/persona-generator/SKILL.md +296 -0
- package/built-in-skills/pkf-svg/SKILL.md +253 -0
- package/built-in-skills/pkf-writing/SKILL.md +236 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
- package/built-in-skills/proactivity/SKILL.md +84 -0
- package/built-in-skills/remotion/SKILL.md +431 -0
- package/built-in-skills/role-builder/SKILL.md +203 -0
- package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
- package/built-in-skills/skill-authoring/SKILL.md +110 -100
- package/built-in-skills/skill-authoring/skill.json +3 -3
- package/built-in-skills/skill-builder/SKILL.md +171 -0
- package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
- package/built-in-skills/skill-creator/SKILL.md +165 -423
- package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
- package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
- package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
- package/built-in-skills/tasks/SKILL.md +38 -23
- package/built-in-skills/tdd/LICENSE +21 -0
- package/built-in-skills/tdd/SKILL.md +110 -0
- package/built-in-skills/tdd/mocking.md +59 -0
- package/built-in-skills/tdd/refactoring.md +10 -0
- package/built-in-skills/tdd/tests.md +61 -0
- package/built-in-skills/team/SKILL.md +2 -1
- package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
- package/built-in-skills/webapp-testing/SKILL.md +1 -0
- package/built-in-skills/wechat-pay/SKILL.md +59 -0
- package/dist/cli.cjs +71872 -19960
- package/dist/cli.js +71803 -19846
- package/dist/index.cjs +72010 -19966
- package/dist/index.d.cts +4258 -712
- package/dist/index.d.ts +4258 -712
- package/dist/index.js +72156 -20118
- package/package.json +37 -6
- package/plugins/memory/prismer/__init__.py +1211 -0
- package/plugins/memory/prismer/plugin.yaml +8 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
- package/plugins/tools/prismer-recall/__init__.py +282 -0
- package/plugins/tools/prismer-recall/plugin.yaml +15 -0
- package/built-in-skills/memory-curation/SKILL.md +0 -135
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// skill-builder ingest — material→bundle→live catalog, via SDK + API key.
|
|
3
|
+
//
|
|
4
|
+
// Zero runtime dependencies (Node ≥18 built-ins only). Reads a SS-01 skill
|
|
5
|
+
// bundle directory, parses SKILL.md frontmatter, builds an SS-01 contentManifest
|
|
6
|
+
// with a server-matching merkle revision, and POSTs it to the real catalog
|
|
7
|
+
// endpoint authenticated with an `sk-prismer-*` API key.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// PRISMER_API_KEY=sk-prismer-... [PRISMER_CLOUD_BASE=http://127.0.0.1:3000] \
|
|
11
|
+
// node scripts/ingest.mjs <bundle-dir> [--install] [--agent <imUserId>] [--json]
|
|
12
|
+
//
|
|
13
|
+
// Env:
|
|
14
|
+
// PRISMER_API_KEY (required) Bearer token; admin not required for skill create.
|
|
15
|
+
// PRISMER_CLOUD_BASE (default http://127.0.0.1:3000) cloud base URL.
|
|
16
|
+
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
19
|
+
import { join, relative, sep } from 'node:path';
|
|
20
|
+
|
|
21
|
+
function die(msg, code = 1) {
|
|
22
|
+
console.error(`[skill-builder] ✗ ${msg}`);
|
|
23
|
+
process.exit(code);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const secretOptions = new Set(['--api-key', '--token', '--jwt', '--secret', '--password']);
|
|
28
|
+
let bundleDir;
|
|
29
|
+
let wantInstall = false;
|
|
30
|
+
let asJson = false;
|
|
31
|
+
let agentId;
|
|
32
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
33
|
+
const arg = args[index];
|
|
34
|
+
const equalsAt = arg.indexOf('=');
|
|
35
|
+
const option = equalsAt === -1 ? arg : arg.slice(0, equalsAt);
|
|
36
|
+
if (secretOptions.has(option)) {
|
|
37
|
+
die(`${option} is forbidden; credentials must come from environment variables`, 2);
|
|
38
|
+
}
|
|
39
|
+
if (arg === '--install') {
|
|
40
|
+
wantInstall = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (arg === '--json') {
|
|
44
|
+
asJson = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (arg === '--agent') {
|
|
48
|
+
const value = args[index + 1];
|
|
49
|
+
if (!value || value.startsWith('--')) die('--agent requires an imUserId', 2);
|
|
50
|
+
agentId = value;
|
|
51
|
+
index += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (arg.startsWith('--')) die(`unknown argument at position ${index + 1}`, 2);
|
|
55
|
+
if (bundleDir) die('only one bundle directory may be supplied', 2);
|
|
56
|
+
bundleDir = arg;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const API_KEY = process.env.PRISMER_API_KEY;
|
|
60
|
+
const BASE = (process.env.PRISMER_CLOUD_BASE || 'http://127.0.0.1:3000').replace(/\/$/, '');
|
|
61
|
+
|
|
62
|
+
if (!bundleDir) die('usage: node ingest.mjs <bundle-dir> [--install] [--agent <imUserId>] [--json]');
|
|
63
|
+
if (!API_KEY) die('PRISMER_API_KEY env is required (sk-prismer-*)');
|
|
64
|
+
let target;
|
|
65
|
+
try {
|
|
66
|
+
target = new URL(BASE);
|
|
67
|
+
} catch {
|
|
68
|
+
die('PRISMER_CLOUD_BASE must be a valid URL', 2);
|
|
69
|
+
}
|
|
70
|
+
if (
|
|
71
|
+
!['http:', 'https:'].includes(target.protocol) ||
|
|
72
|
+
target.username ||
|
|
73
|
+
target.password ||
|
|
74
|
+
target.search ||
|
|
75
|
+
target.hash
|
|
76
|
+
) {
|
|
77
|
+
die('PRISMER_CLOUD_BASE must be a plain http(s) origin without credentials, query, or hash', 2);
|
|
78
|
+
}
|
|
79
|
+
const isLocalTarget = ['localhost', '127.0.0.1', '::1', 'host.docker.internal'].includes(target.hostname);
|
|
80
|
+
const allowRemote = ['1', 'true', 'yes'].includes(String(process.env.PRISMER_ALLOW_REMOTE_WRITE).toLowerCase());
|
|
81
|
+
if (!isLocalTarget && !allowRemote) {
|
|
82
|
+
die('remote mutation is blocked; set PRISMER_ALLOW_REMOTE_WRITE=1 after confirming the target environment', 2);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── collect bundle files (SS-01 §3.1 — exclude dotfiles + LICENSE*) ──────────
|
|
86
|
+
const EXCLUDED = new Set(['.DS_Store', 'Thumbs.db', 'LICENSE', 'LICENSE.txt', 'LICENSE.md']);
|
|
87
|
+
function collect(dir) {
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
90
|
+
if (entry.name.startsWith('.')) continue;
|
|
91
|
+
const abs = join(dir, entry.name);
|
|
92
|
+
if (entry.isDirectory()) out.push(...collect(abs));
|
|
93
|
+
else if (!EXCLUDED.has(entry.name)) out.push(abs);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let bundleStat;
|
|
99
|
+
try {
|
|
100
|
+
bundleStat = statSync(bundleDir);
|
|
101
|
+
} catch {
|
|
102
|
+
die(`bundle dir not found: ${bundleDir}`);
|
|
103
|
+
}
|
|
104
|
+
if (!bundleStat.isDirectory()) die(`not a directory: ${bundleDir}`);
|
|
105
|
+
|
|
106
|
+
const absFiles = collect(bundleDir).sort();
|
|
107
|
+
const toPosix = (abs) => relative(bundleDir, abs).split(sep).join('/');
|
|
108
|
+
const files = absFiles.map((abs) => ({ path: toPosix(abs), bytes: readFileSync(abs) }));
|
|
109
|
+
|
|
110
|
+
const skillMd = files.find((f) => f.path === 'SKILL.md');
|
|
111
|
+
if (!skillMd) die('SKILL.md not found at bundle root');
|
|
112
|
+
|
|
113
|
+
// ── parse frontmatter (minimal YAML — flat keys, lists, block scalars) ────
|
|
114
|
+
function parseFrontmatter(text) {
|
|
115
|
+
const m = text.match(/^---\n([\s\S]*?)\n---\n?/);
|
|
116
|
+
if (!m) return { fm: {}, body: text };
|
|
117
|
+
const fm = {};
|
|
118
|
+
let key = null;
|
|
119
|
+
const lines = m[1].split('\n');
|
|
120
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
121
|
+
const rawLine = lines[index];
|
|
122
|
+
const line = rawLine.replace(/\s+$/, '');
|
|
123
|
+
if (!line.trim()) continue;
|
|
124
|
+
const listItem = line.match(/^\s+-\s+(.*)$/);
|
|
125
|
+
if (listItem && key) {
|
|
126
|
+
(Array.isArray(fm[key]) ? fm[key] : (fm[key] = [])).push(stripQuotes(listItem[1]));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
130
|
+
if (kv) {
|
|
131
|
+
key = kv[1];
|
|
132
|
+
const val = kv[2];
|
|
133
|
+
const block = /^([|>])([+-])?$/.exec(val.trim());
|
|
134
|
+
if (block) {
|
|
135
|
+
const body = [];
|
|
136
|
+
let next = index + 1;
|
|
137
|
+
for (; next < lines.length; next += 1) {
|
|
138
|
+
const candidate = lines[next];
|
|
139
|
+
if (candidate.trim() && !/^\s+/.test(candidate)) break;
|
|
140
|
+
body.push(candidate);
|
|
141
|
+
}
|
|
142
|
+
const indents = body
|
|
143
|
+
.filter((candidate) => candidate.trim())
|
|
144
|
+
.map((candidate) => /^\s*/.exec(candidate)?.[0].length ?? 0);
|
|
145
|
+
const indent = indents.length > 0 ? Math.min(...indents) : 0;
|
|
146
|
+
const unindented = body.map((candidate) => candidate.slice(Math.min(indent, candidate.length)));
|
|
147
|
+
let parsed =
|
|
148
|
+
block[1] === '>'
|
|
149
|
+
? unindented.reduce((out, candidate, bodyIndex) => {
|
|
150
|
+
if (bodyIndex === 0) return candidate;
|
|
151
|
+
const previous = unindented[bodyIndex - 1] ?? '';
|
|
152
|
+
return out + (previous === '' || candidate === '' ? '\n' : ' ') + candidate;
|
|
153
|
+
}, '')
|
|
154
|
+
: unindented.join('\n');
|
|
155
|
+
if (block[2] === '-') parsed = parsed.replace(/\n+$/, '');
|
|
156
|
+
else if (block[2] !== '+') parsed = parsed.replace(/\n*$/, '\n');
|
|
157
|
+
fm[key] = parsed;
|
|
158
|
+
index = next - 1;
|
|
159
|
+
} else if (val === '')
|
|
160
|
+
fm[key] = []; // expect a list or nested block below
|
|
161
|
+
else fm[key] = stripQuotes(val);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { fm, body: text.slice(m[0].length) };
|
|
165
|
+
}
|
|
166
|
+
const stripQuotes = (s) => s.replace(/^["']|["']$/g, '').trim();
|
|
167
|
+
|
|
168
|
+
const { fm } = parseFrontmatter(skillMd.bytes.toString('utf8'));
|
|
169
|
+
const name = fm.name;
|
|
170
|
+
if (!name || !/^[a-z][a-z0-9-]*$/.test(name)) die(`frontmatter.name invalid or missing: ${name}`);
|
|
171
|
+
if (!fm.description || fm.description === '|' || fm.description === '>') {
|
|
172
|
+
die('frontmatter.description is required');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// category: prefer metadata.category; the nested `metadata:` block isn't parsed
|
|
176
|
+
// by the flat reader, so allow a top-level `category:` too, else default.
|
|
177
|
+
const category = fm.category || 'general';
|
|
178
|
+
const compatibility = Array.isArray(fm.compatibility)
|
|
179
|
+
? fm.compatibility
|
|
180
|
+
: fm.compatibility
|
|
181
|
+
? [fm.compatibility]
|
|
182
|
+
: undefined;
|
|
183
|
+
|
|
184
|
+
// ── build SS-01 manifest (merkle matches src/im/skills/manifest.ts) ──────────
|
|
185
|
+
const sha256 = (buf) => createHash('sha256').update(buf).digest('hex');
|
|
186
|
+
const manifest = files.map((f) => ({
|
|
187
|
+
path: f.path,
|
|
188
|
+
size: f.bytes.byteLength,
|
|
189
|
+
sha256: sha256(f.bytes),
|
|
190
|
+
inline: true,
|
|
191
|
+
content: f.bytes.toString('base64'),
|
|
192
|
+
}));
|
|
193
|
+
const revision = sha256(
|
|
194
|
+
[...manifest]
|
|
195
|
+
.sort((a, b) => a.path.localeCompare(b.path))
|
|
196
|
+
.map((f) => `${f.path}:${f.sha256}`)
|
|
197
|
+
.join('\n'),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const isMultiFile = files.length > 1;
|
|
201
|
+
const createBody = {
|
|
202
|
+
name,
|
|
203
|
+
description: fm.description,
|
|
204
|
+
category,
|
|
205
|
+
...(fm.license ? { license: fm.license } : {}),
|
|
206
|
+
...(compatibility ? { compatibility } : {}),
|
|
207
|
+
// Single-file → send plain content (server wraps). Multi-file → send manifest.
|
|
208
|
+
content: skillMd.bytes.toString('utf8'),
|
|
209
|
+
...(isMultiFile ? { contentManifest: manifest, contentManifestRevision: revision } : {}),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
async function api(method, path, body) {
|
|
213
|
+
const res = await fetch(`${BASE}${path}`, {
|
|
214
|
+
method,
|
|
215
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${API_KEY}` },
|
|
216
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
217
|
+
});
|
|
218
|
+
let json = null;
|
|
219
|
+
try {
|
|
220
|
+
json = await res.json();
|
|
221
|
+
} catch {
|
|
222
|
+
/* non-JSON */
|
|
223
|
+
}
|
|
224
|
+
return { status: res.status, json };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
(async () => {
|
|
228
|
+
const created = await api('POST', '/api/im/skills', createBody);
|
|
229
|
+
if (created.status === 409) die(`slug "${name}" already exists (409). Use update or pick a new name.`, 2);
|
|
230
|
+
if (created.status !== 201 || !created.json?.ok) {
|
|
231
|
+
die(`create failed (HTTP ${created.status}): ${created.json?.error || 'unknown error'}`);
|
|
232
|
+
}
|
|
233
|
+
const skill = created.json.data;
|
|
234
|
+
const result = {
|
|
235
|
+
id: skill.id,
|
|
236
|
+
slug: skill.slug,
|
|
237
|
+
rev: revision,
|
|
238
|
+
files: files.length,
|
|
239
|
+
installed: false,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
if (wantInstall) {
|
|
243
|
+
const path = agentId
|
|
244
|
+
? `/api/im/agents/${encodeURIComponent(agentId)}/skills`
|
|
245
|
+
: `/api/im/skills/${encodeURIComponent(skill.slug)}/install`;
|
|
246
|
+
const body = agentId ? { skillId: skill.slug } : {};
|
|
247
|
+
const inst = await api('POST', path, body);
|
|
248
|
+
if (inst.status >= 200 && inst.status < 300 && inst.json?.ok !== false) {
|
|
249
|
+
result.installed = agentId || true;
|
|
250
|
+
} else {
|
|
251
|
+
result.installError = `HTTP ${inst.status}: ${inst.json?.error || 'install failed'}`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (asJson) {
|
|
256
|
+
console.log(JSON.stringify(result, null, 2));
|
|
257
|
+
} else {
|
|
258
|
+
console.log(`[skill-builder] ✓ ingested ${result.slug}`);
|
|
259
|
+
console.log(` id: ${result.id}`);
|
|
260
|
+
console.log(` rev: ${result.rev}`);
|
|
261
|
+
console.log(` files: ${result.files}`);
|
|
262
|
+
console.log(` installed: ${result.installed}${result.installError ? ` (${result.installError})` : ''}`);
|
|
263
|
+
console.log(` verify: cloud skill show ${result.slug} --content`);
|
|
264
|
+
}
|
|
265
|
+
})().catch((err) => die(err?.message || String(err)));
|