@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.
Files changed (119) hide show
  1. package/CHANGELOG.md +3430 -0
  2. package/README.md +34 -12
  3. package/apc/skills/FIELD-DICTIONARY.md +111 -0
  4. package/apc/skills/bug-reproduce/SKILL.md +150 -0
  5. package/apc/skills/bug-reproduce/skill.json +96 -0
  6. package/apc/skills/code-review/SKILL.md +198 -0
  7. package/apc/skills/code-review/skill.json +124 -0
  8. package/apc/skills/design-review/SKILL.md +122 -0
  9. package/apc/skills/design-review/skill.json +88 -0
  10. package/apc/skills/doc-sync/SKILL.md +168 -0
  11. package/apc/skills/doc-sync/skill.json +81 -0
  12. package/apc/skills/env-doctor/SKILL.md +194 -0
  13. package/apc/skills/env-doctor/skill.json +209 -0
  14. package/apc/skills/git-ops/SKILL.md +189 -0
  15. package/apc/skills/git-ops/skill.json +94 -0
  16. package/apc/skills/impact-trace/SKILL.md +168 -0
  17. package/apc/skills/impact-trace/skill.json +104 -0
  18. package/apc/skills/observability/SKILL.md +195 -0
  19. package/apc/skills/observability/skill.json +116 -0
  20. package/apc/skills/release-db-config-sync/SKILL.md +186 -0
  21. package/apc/skills/release-db-config-sync/skill.json +109 -0
  22. package/apc/skills/release-ota-promote/SKILL.md +195 -0
  23. package/apc/skills/release-ota-promote/skill.json +176 -0
  24. package/apc/skills/release-preflight/SKILL.md +174 -0
  25. package/apc/skills/release-preflight/skill.json +175 -0
  26. package/apc/skills/release-rollback/SKILL.md +214 -0
  27. package/apc/skills/release-rollback/skill.json +230 -0
  28. package/apc/skills/release-tag/SKILL.md +194 -0
  29. package/apc/skills/release-tag/skill.json +94 -0
  30. package/apc/skills/releasing-prod/SKILL.md +49 -0
  31. package/apc/skills/releasing-test/SKILL.md +135 -0
  32. package/apc/skills/sdk-release/SKILL.md +200 -0
  33. package/apc/skills/spec-intake/SKILL.md +169 -0
  34. package/apc/skills/spec-intake/skill.json +93 -0
  35. package/apc/skills/test-result-feedback/SKILL.md +239 -0
  36. package/apc/skills/test-result-feedback/skill.json +193 -0
  37. package/apc/skills/test-runner/SKILL.md +169 -0
  38. package/apc/skills/test-runner/skill.json +103 -0
  39. package/apc/skills/ui-align/SKILL.md +209 -0
  40. package/apc/skills/ui-align/skill.json +114 -0
  41. package/apc/skills/ui-canvas/SKILL.md +148 -0
  42. package/apc/skills/ui-canvas/skill.json +127 -0
  43. package/built-in-skills/agent-coordination/SKILL.md +59 -37
  44. package/built-in-skills/agent-meta/SKILL.md +1 -0
  45. package/built-in-skills/assets/SKILL.md +8 -6
  46. package/built-in-skills/browser-use/SKILL.md +93 -0
  47. package/built-in-skills/canvas-design/SKILL.md +1 -0
  48. package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
  49. package/built-in-skills/claude-api/SKILL.md +1 -0
  50. package/built-in-skills/codebase-design/DEEPENING.md +37 -0
  51. package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/built-in-skills/codebase-design/LICENSE +21 -0
  53. package/built-in-skills/codebase-design/SKILL.md +116 -0
  54. package/built-in-skills/conversation-compaction/SKILL.md +114 -0
  55. package/built-in-skills/council-creator/SKILL.md +426 -0
  56. package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
  57. package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
  58. package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  59. package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
  60. package/built-in-skills/document-generation/SKILL.md +105 -0
  61. package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
  62. package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  63. package/built-in-skills/domain-modeling/LICENSE +21 -0
  64. package/built-in-skills/domain-modeling/SKILL.md +76 -0
  65. package/built-in-skills/frontend-design/SKILL.md +1 -0
  66. package/built-in-skills/human-approval/SKILL.md +17 -2
  67. package/built-in-skills/image-generate/SKILL.md +103 -302
  68. package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
  69. package/built-in-skills/ingest/SKILL.md +13 -45
  70. package/built-in-skills/internal-comms/SKILL.md +1 -0
  71. package/built-in-skills/liteparse/SKILL.md +130 -110
  72. package/built-in-skills/mcp-builder/SKILL.md +1 -0
  73. package/built-in-skills/memory/SKILL.md +420 -55
  74. package/built-in-skills/memory-dream/SKILL.md +339 -0
  75. package/built-in-skills/office-artifacts/SKILL.md +17 -4
  76. package/built-in-skills/okr/SKILL.md +154 -0
  77. package/built-in-skills/persona/SKILL.md +81 -0
  78. package/built-in-skills/persona-generator/SKILL.md +296 -0
  79. package/built-in-skills/pkf-svg/SKILL.md +253 -0
  80. package/built-in-skills/pkf-writing/SKILL.md +236 -0
  81. package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
  82. package/built-in-skills/proactivity/SKILL.md +84 -0
  83. package/built-in-skills/remotion/SKILL.md +431 -0
  84. package/built-in-skills/role-builder/SKILL.md +203 -0
  85. package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
  86. package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
  87. package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
  88. package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
  89. package/built-in-skills/skill-authoring/SKILL.md +110 -100
  90. package/built-in-skills/skill-authoring/skill.json +3 -3
  91. package/built-in-skills/skill-builder/SKILL.md +171 -0
  92. package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
  93. package/built-in-skills/skill-creator/SKILL.md +165 -423
  94. package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
  95. package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
  96. package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
  97. package/built-in-skills/tasks/SKILL.md +38 -23
  98. package/built-in-skills/tdd/LICENSE +21 -0
  99. package/built-in-skills/tdd/SKILL.md +110 -0
  100. package/built-in-skills/tdd/mocking.md +59 -0
  101. package/built-in-skills/tdd/refactoring.md +10 -0
  102. package/built-in-skills/tdd/tests.md +61 -0
  103. package/built-in-skills/team/SKILL.md +2 -1
  104. package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
  105. package/built-in-skills/webapp-testing/SKILL.md +1 -0
  106. package/built-in-skills/wechat-pay/SKILL.md +59 -0
  107. package/dist/cli.cjs +71872 -19960
  108. package/dist/cli.js +71803 -19846
  109. package/dist/index.cjs +72010 -19966
  110. package/dist/index.d.cts +4258 -712
  111. package/dist/index.d.ts +4258 -712
  112. package/dist/index.js +72156 -20118
  113. package/package.json +37 -6
  114. package/plugins/memory/prismer/__init__.py +1211 -0
  115. package/plugins/memory/prismer/plugin.yaml +8 -0
  116. package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
  117. package/plugins/tools/prismer-recall/__init__.py +282 -0
  118. package/plugins/tools/prismer-recall/plugin.yaml +15 -0
  119. 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)));