@arnilo/prism 0.3.1 → 0.4.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +34 -57
  3. package/dist/agent-definitions.js +4 -1
  4. package/dist/agent-run-lifecycle.js +4 -0
  5. package/dist/agent-run-state.d.ts +4 -0
  6. package/dist/agent-run-state.js +18 -5
  7. package/dist/agent-session/session.d.ts +7 -0
  8. package/dist/agent-session/session.js +59 -2
  9. package/dist/cli-dev.d.ts +29 -0
  10. package/dist/cli-dev.js +52 -0
  11. package/dist/cli-init.d.ts +17 -2
  12. package/dist/cli-init.js +194 -21
  13. package/dist/cli-runner.d.ts +5 -1
  14. package/dist/cli-runner.js +12 -1
  15. package/dist/contracts-core/agent.d.ts +29 -2
  16. package/dist/contracts-protocol.d.ts +18 -0
  17. package/dist/contracts-run-state.d.ts +1 -2
  18. package/dist/index.d.ts +3 -1
  19. package/dist/index.js +2 -1
  20. package/dist/input.d.ts +8 -0
  21. package/dist/input.js +4 -0
  22. package/dist/rpc.d.ts +4 -1
  23. package/dist/rpc.js +5 -1
  24. package/dist/testing/persistence-schema.d.ts +1 -1
  25. package/dist/testing/persistence-schema.js +32 -28
  26. package/dist/testing/tool-conformance.d.ts +25 -0
  27. package/dist/testing/tool-conformance.js +128 -1
  28. package/dist/tool-search.d.ts +76 -0
  29. package/dist/tool-search.js +199 -0
  30. package/docs/0.1.0-readiness.md +2 -2
  31. package/docs/acp-agent.md +1 -1
  32. package/docs/agent-definitions.md +1 -1
  33. package/docs/antigravity-agent.md +1 -1
  34. package/docs/browser-automation.md +5 -5
  35. package/docs/caveman.md +2 -2
  36. package/docs/cli-rpc.md +26 -3
  37. package/docs/coding-agent-tools.md +7 -1
  38. package/docs/coding-security.md +1 -1
  39. package/docs/coding-tools.md +82 -0
  40. package/docs/compaction-and-retry.md +5 -2
  41. package/docs/compaction-llm.md +4 -4
  42. package/docs/compaction-observational-memory.md +49 -2
  43. package/docs/context-and-skills.md +2 -0
  44. package/docs/core.md +85 -0
  45. package/docs/credential-storage.md +1 -1
  46. package/docs/database-persistence.md +4 -0
  47. package/docs/dev-inspector.md +103 -0
  48. package/docs/diagrams.md +247 -0
  49. package/docs/documents.md +213 -0
  50. package/docs/evaluations.md +35 -1
  51. package/docs/extension-authoring.md +42 -0
  52. package/docs/graft.md +3 -3
  53. package/docs/guardrails.md +1 -1
  54. package/docs/host-security.md +4 -3
  55. package/docs/impeccable.md +2 -2
  56. package/docs/index.md +34 -23
  57. package/docs/mcp-tools.md +1 -1
  58. package/docs/migrate-to-0.4.md +312 -0
  59. package/docs/migration.md +22 -0
  60. package/docs/model-routing.md +1 -1
  61. package/docs/multi-agent-patterns.md +177 -0
  62. package/docs/multimodal-content.md +1 -1
  63. package/docs/obscura.md +10 -10
  64. package/docs/openapi-tools.md +1 -1
  65. package/docs/performance.md +23 -3
  66. package/docs/persistence-credentials-multimodality-primitives.md +1 -1
  67. package/docs/policy-and-audit.md +1 -1
  68. package/docs/ponytail.md +2 -2
  69. package/docs/prompt-registry.md +106 -0
  70. package/docs/provider-caching.md +32 -32
  71. package/docs/provider-conformance.md +1 -1
  72. package/docs/provider-packages.md +19 -19
  73. package/docs/provider-primitives.md +4 -4
  74. package/docs/providers/ai-sdk.md +3 -3
  75. package/docs/providers/alibaba.md +5 -5
  76. package/docs/providers/anthropic.md +6 -6
  77. package/docs/providers/azure.md +3 -3
  78. package/docs/providers/bedrock.md +3 -3
  79. package/docs/providers/clinepass.md +3 -3
  80. package/docs/providers/deepseek.md +3 -3
  81. package/docs/providers/google.md +4 -4
  82. package/docs/providers/kimi.md +3 -3
  83. package/docs/providers/neuralwatt.md +8 -8
  84. package/docs/providers/ollama.md +3 -3
  85. package/docs/providers/openai-compatible.md +1 -1
  86. package/docs/providers/openai.md +5 -5
  87. package/docs/providers/opencode-go.md +4 -4
  88. package/docs/providers/openrouter.md +3 -3
  89. package/docs/providers/vertex.md +5 -5
  90. package/docs/providers/xai.md +3 -3
  91. package/docs/providers/zai.md +3 -3
  92. package/docs/public-contracts.md +1 -1
  93. package/docs/rag.md +5 -5
  94. package/docs/release-and-install.md +116 -50
  95. package/docs/runs-and-usage.md +14 -1
  96. package/docs/server.md +90 -1
  97. package/docs/sheets.md +229 -0
  98. package/docs/supervisors.md +9 -1
  99. package/docs/thinking-and-reasoning.md +10 -10
  100. package/docs/tool-conformance.md +27 -2
  101. package/docs/tools.md +29 -2
  102. package/docs/web-tools.md +2 -2
  103. package/docs/wiki.md +24 -10
  104. package/docs/workflow-orchestration-primitives.md +24 -0
  105. package/docs/workflows.md +102 -8
  106. package/docs/working-and-semantic-memory.md +53 -5
  107. package/package.json +10 -30
  108. package/templates/README.md +23 -0
  109. package/templates/deep-research/README.md.tmpl +47 -0
  110. package/templates/deep-research/env.example.tmpl +12 -0
  111. package/templates/deep-research/gitignore.tmpl +7 -0
  112. package/templates/deep-research/manifest.json +12 -0
  113. package/templates/deep-research/package.json.tmpl +23 -0
  114. package/templates/deep-research/src/agent.ts.tmpl +81 -0
  115. package/templates/deep-research/src/index.ts.tmpl +53 -0
  116. package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
  117. package/templates/deep-research/src/tools.ts.tmpl +86 -0
  118. package/templates/deep-research/src/types.ts.tmpl +45 -0
  119. package/templates/deep-research/src/workflow.ts.tmpl +156 -0
  120. package/templates/deep-research/tsconfig.json.tmpl +15 -0
  121. package/templates/init/manifest.json +5 -0
  122. package/templates/init/package.json.tmpl +2 -1
  123. package/templates/init/providers.json +16 -16
package/dist/cli-init.js CHANGED
@@ -1,4 +1,4 @@
1
- import { constants as fsConstants, readFileSync } from "node:fs";
1
+ import { existsSync, constants as fsConstants, readdirSync, readFileSync } from "node:fs";
2
2
  import { access, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
@@ -34,16 +34,76 @@ export function listInitProviders(templatesRoot) {
34
34
  return cachedProviderIds;
35
35
  return Object.freeze([...loadProvidersCatalog(templatesRoot).keys()]);
36
36
  }
37
- export function getInitUsage(templatesRoot) {
37
+ /** Template list discovered from the templates gallery. */
38
+ export function listInitTemplates(galleryRoot = defaultGalleryRoot()) {
39
+ try {
40
+ const entries = readdirSync(galleryRoot, { withFileTypes: true });
41
+ const templates = [];
42
+ for (const entry of entries) {
43
+ if (entry.isDirectory()) {
44
+ const manifestPath = join(galleryRoot, entry.name, "manifest.json");
45
+ if (existsSync(manifestPath)) {
46
+ try {
47
+ const raw = JSON.parse(readFileSync(manifestPath, "utf8"));
48
+ if (raw && typeof raw === "object" && typeof raw.name === "string") {
49
+ templates.push({
50
+ name: raw.name,
51
+ description: typeof raw.description === "string" ? raw.description : "",
52
+ version: typeof raw.version === "string" ? raw.version : undefined,
53
+ path: join(galleryRoot, entry.name),
54
+ });
55
+ }
56
+ }
57
+ catch {
58
+ // skip invalid manifests
59
+ }
60
+ }
61
+ else if (entry.name === "init") {
62
+ templates.push({
63
+ name: "init",
64
+ description: "Minimal starter Prism agent with one selected provider and offline mock test",
65
+ path: join(galleryRoot, "init"),
66
+ });
67
+ }
68
+ }
69
+ }
70
+ return Object.freeze(templates.sort((a, b) => {
71
+ if (a.name === "init")
72
+ return -1;
73
+ if (b.name === "init")
74
+ return 1;
75
+ return a.name.localeCompare(b.name);
76
+ }));
77
+ }
78
+ catch {
79
+ return Object.freeze([
80
+ {
81
+ name: "init",
82
+ description: "Minimal starter Prism agent with one selected provider and offline mock test",
83
+ path: join(galleryRoot, "init"),
84
+ },
85
+ ]);
86
+ }
87
+ }
88
+ export function isInitTemplate(value, galleryRoot) {
89
+ return listInitTemplates(galleryRoot).some((t) => t.name === value);
90
+ }
91
+ export function getInitUsage(templatesRoot, galleryRoot) {
38
92
  const providers = listInitProviders(templatesRoot).join("|");
93
+ const templates = listInitTemplates(galleryRoot)
94
+ .map((t) => t.name)
95
+ .join("|");
39
96
  return `Usage: prism init <dir> [options]
97
+ prism init --list-templates
40
98
 
41
- Create a minimal TypeScript Prism project with one explicit provider and an offline mock test.
99
+ Create a minimal TypeScript Prism project or scaffold from a template gallery.
42
100
 
43
101
  Arguments:
44
102
  <dir> Destination directory (created if missing)
45
103
 
46
104
  Options:
105
+ --template <name> Template name (${templates || "init|deep-research"}). Default: init
106
+ --list-templates List available templates from the gallery
47
107
  --provider <name> Provider id (${providers}). Default: mock
48
108
  --with-workflows Add optional workflows dependency and example
49
109
  --with-evals Add optional evals dependency and example
@@ -52,19 +112,24 @@ Options:
52
112
 
53
113
  Examples:
54
114
  prism init my-agent
115
+ prism init my-research --template deep-research
116
+ prism init --list-templates
55
117
  prism init my-agent --provider openai
56
118
  prism init my-agent --provider openai --with-workflows
57
119
  `;
58
120
  }
59
121
  export const initUsage = getInitUsage();
60
- export function parseInitArgs(argv, templatesRoot) {
122
+ export function parseInitArgs(argv, templatesRoot, galleryRoot) {
61
123
  let directory;
124
+ let template;
125
+ let listTemplates = false;
62
126
  let provider = "mock";
63
127
  let withWorkflows = false;
64
128
  let withEvals = false;
65
129
  let force = false;
66
130
  let help = false;
67
131
  const providers = listInitProviders(templatesRoot);
132
+ const availableTemplates = listInitTemplates(galleryRoot);
68
133
  for (let i = 0; i < argv.length; i += 1) {
69
134
  const arg = argv[i];
70
135
  if (arg === "-h" || arg === "--help") {
@@ -75,6 +140,10 @@ export function parseInitArgs(argv, templatesRoot) {
75
140
  force = true;
76
141
  continue;
77
142
  }
143
+ if (arg === "--list-templates") {
144
+ listTemplates = true;
145
+ continue;
146
+ }
78
147
  if (arg === "--with-workflows") {
79
148
  withWorkflows = true;
80
149
  continue;
@@ -83,6 +152,18 @@ export function parseInitArgs(argv, templatesRoot) {
83
152
  withEvals = true;
84
153
  continue;
85
154
  }
155
+ if (arg === "--template") {
156
+ const value = argv[i + 1];
157
+ if (value === undefined || value.startsWith("-")) {
158
+ throw new InitUsageError("Missing value for --template");
159
+ }
160
+ i += 1;
161
+ if (!availableTemplates.some((t) => t.name === value)) {
162
+ throw new InitUsageError(`Unknown template: ${value}. Expected one of ${availableTemplates.map((t) => t.name).join(", ")}`);
163
+ }
164
+ template = value;
165
+ continue;
166
+ }
86
167
  if (arg === "--provider") {
87
168
  const value = argv[i + 1];
88
169
  if (value === undefined || value.startsWith("-")) {
@@ -103,11 +184,13 @@ export function parseInitArgs(argv, templatesRoot) {
103
184
  }
104
185
  directory = arg;
105
186
  }
106
- if (!help && directory === undefined) {
187
+ if (!help && !listTemplates && directory === undefined) {
107
188
  throw new InitUsageError("Missing destination directory");
108
189
  }
109
190
  return {
110
191
  directory: directory ?? ".",
192
+ template,
193
+ listTemplates,
111
194
  provider,
112
195
  withWorkflows,
113
196
  withEvals,
@@ -118,20 +201,34 @@ export function parseInitArgs(argv, templatesRoot) {
118
201
  export async function runInitCommand(argv, runtime) {
119
202
  let options;
120
203
  try {
121
- options = parseInitArgs(argv, runtime.templatesRoot);
204
+ options = parseInitArgs(argv, runtime.templatesRoot, runtime.galleryRoot);
122
205
  }
123
206
  catch (error) {
124
- write(runtime.stderr, `${error instanceof Error ? error.message : String(error)}\n${getInitUsage(runtime.templatesRoot)}`);
207
+ write(runtime.stderr, `${error instanceof Error ? error.message : String(error)}\n${getInitUsage(runtime.templatesRoot, runtime.galleryRoot)}`);
125
208
  return 2;
126
209
  }
127
210
  if (options.help) {
128
- write(runtime.stdout, getInitUsage(runtime.templatesRoot));
211
+ write(runtime.stdout, getInitUsage(runtime.templatesRoot, runtime.galleryRoot));
212
+ return 0;
213
+ }
214
+ if (options.listTemplates) {
215
+ const templates = listInitTemplates(runtime.galleryRoot);
216
+ const lines = [
217
+ "Available templates:",
218
+ ...templates.map((t) => ` ${t.name.padEnd(16)} - ${t.description}`),
219
+ "",
220
+ "Usage:",
221
+ " prism init <dir> --template <name>",
222
+ "",
223
+ ];
224
+ write(runtime.stdout, lines.join("\n"));
129
225
  return 0;
130
226
  }
131
227
  try {
132
228
  const result = await createInitProject(options, runtime);
133
229
  write(runtime.stdout, [
134
230
  `Created Prism project in ${result.targetDir}`,
231
+ ...(result.template ? [` template: ${result.template}`] : []),
135
232
  ` provider: ${result.provider}`,
136
233
  ` files: ${result.writtenFiles.length}`,
137
234
  ` bytes: ${result.totalBytes}`,
@@ -149,7 +246,7 @@ export async function runInitCommand(argv, runtime) {
149
246
  catch (error) {
150
247
  const message = error instanceof Error ? error.message : String(error);
151
248
  if (error instanceof InitUsageError) {
152
- write(runtime.stderr, `${message}\n${getInitUsage(runtime.templatesRoot)}`);
249
+ write(runtime.stderr, `${message}\n${getInitUsage(runtime.templatesRoot, runtime.galleryRoot)}`);
153
250
  return 2;
154
251
  }
155
252
  write(runtime.stderr, `${message}\n`);
@@ -163,6 +260,7 @@ export async function createInitProject(options, runtime = {
163
260
  const cwd = runtime.cwd ?? process.cwd();
164
261
  const targetDir = resolveInitDirectory(options.directory, cwd);
165
262
  const templatesRoot = runtime.templatesRoot ?? defaultTemplatesRoot();
263
+ const galleryRoot = runtime.galleryRoot ?? defaultGalleryRoot();
166
264
  const version = runtime.packageVersion ?? (await readPackageVersion());
167
265
  const catalog = loadProvidersCatalog(templatesRoot);
168
266
  const provider = catalog.get(options.provider);
@@ -171,18 +269,38 @@ export async function createInitProject(options, runtime = {
171
269
  }
172
270
  const projectName = sanitizePackageName(basenameSafe(targetDir));
173
271
  await assertDestinationWritable(targetDir, options.force);
174
- const tokens = buildTokens({
175
- projectName,
176
- version,
177
- provider,
178
- withWorkflows: options.withWorkflows,
179
- withEvals: options.withEvals,
180
- });
181
- const planned = await planFiles({
182
- templatesRoot,
183
- withWorkflows: options.withWorkflows,
184
- withEvals: options.withEvals,
185
- });
272
+ const isCustomTemplate = Boolean(options.template && options.template !== "init");
273
+ let planned;
274
+ let tokens;
275
+ if (isCustomTemplate) {
276
+ const templateName = options.template;
277
+ const templateDir = join(galleryRoot, templateName);
278
+ if (!(await exists(templateDir))) {
279
+ const available = listInitTemplates(galleryRoot);
280
+ throw new InitUsageError(`Unknown template: ${templateName}. Expected one of ${available.map((t) => t.name).join(", ")}`);
281
+ }
282
+ planned = await planTemplateFiles(templateDir);
283
+ tokens = buildTokensForTemplate({
284
+ projectName,
285
+ version,
286
+ templateName,
287
+ provider,
288
+ });
289
+ }
290
+ else {
291
+ tokens = buildTokens({
292
+ projectName,
293
+ version,
294
+ provider,
295
+ withWorkflows: options.withWorkflows,
296
+ withEvals: options.withEvals,
297
+ });
298
+ planned = await planFiles({
299
+ templatesRoot,
300
+ withWorkflows: options.withWorkflows,
301
+ withEvals: options.withEvals,
302
+ });
303
+ }
186
304
  if (!options.force) {
187
305
  for (const file of planned) {
188
306
  const dest = join(targetDir, file.relativePath);
@@ -206,6 +324,7 @@ export async function createInitProject(options, runtime = {
206
324
  return {
207
325
  targetDir,
208
326
  writtenFiles,
327
+ template: options.template,
209
328
  provider: options.provider,
210
329
  withWorkflows: options.withWorkflows,
211
330
  withEvals: options.withEvals,
@@ -215,6 +334,60 @@ export async function createInitProject(options, runtime = {
215
334
  export function defaultTemplatesRoot() {
216
335
  return join(dirname(fileURLToPath(import.meta.url)), "..", "templates", "init");
217
336
  }
337
+ export function defaultGalleryRoot() {
338
+ return join(dirname(fileURLToPath(import.meta.url)), "..", "templates");
339
+ }
340
+ async function planTemplateFiles(templateDir) {
341
+ const files = [];
342
+ async function walk(dir, baseRel = "") {
343
+ const entries = await readdir(dir, { withFileTypes: true });
344
+ for (const entry of entries) {
345
+ const fullPath = join(dir, entry.name);
346
+ const relPath = baseRel ? `${baseRel}/${entry.name}` : entry.name;
347
+ if (entry.isDirectory()) {
348
+ await walk(fullPath, relPath);
349
+ }
350
+ else if (entry.isFile()) {
351
+ if (entry.name === "manifest.json")
352
+ continue;
353
+ let targetRel = relPath.endsWith(".tmpl") ? relPath.slice(0, -5) : relPath;
354
+ if (targetRel.startsWith("src/tests/")) {
355
+ targetRel = `src/__tests__/${targetRel.slice("src/tests/".length)}`;
356
+ }
357
+ files.push({ relativePath: targetRel, sourcePath: fullPath });
358
+ }
359
+ }
360
+ }
361
+ await walk(templateDir);
362
+ return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
363
+ }
364
+ function buildTokensForTemplate(input) {
365
+ const dependencies = {
366
+ "@arnilo/prism": input.version,
367
+ "@arnilo/prism-memory": input.version,
368
+ "@arnilo/prism-web-tools": input.version,
369
+ "@arnilo/prism-workflows": input.version,
370
+ };
371
+ const dependencyLines = Object.entries(dependencies)
372
+ .sort(([a], [b]) => a.localeCompare(b))
373
+ .map(([name, ver]) => ` ${JSON.stringify(name)}: ${JSON.stringify(ver)}`)
374
+ .join(",\n");
375
+ return {
376
+ __PROJECT_NAME__: input.projectName,
377
+ __PRISM_VERSION__: input.version,
378
+ __TEMPLATE_NAME__: input.templateName,
379
+ __PROVIDER_ID__: input.provider.id,
380
+ __PROVIDER_PACKAGE__: input.provider.packageName ?? "",
381
+ __DEPENDENCIES__: dependencyLines,
382
+ __PROVIDER_IMPORTS__: input.provider.imports,
383
+ __PROVIDER_EXPRESSION__: input.provider.providerExpression,
384
+ __MODEL_EXPRESSION__: input.provider.modelExpression,
385
+ __ENV_EXAMPLE__: "",
386
+ __NEXT_STEPS_LIVE__: "",
387
+ __OPTIONAL_DOCS__: "",
388
+ __PROVIDER_README_NOTE__: "",
389
+ };
390
+ }
218
391
  export function isInitProvider(value, templatesRoot) {
219
392
  return listInitProviders(templatesRoot).includes(value);
220
393
  }
@@ -58,6 +58,8 @@ export interface CliRuntime {
58
58
  readonly globalRoot?: string;
59
59
  /** Override init template root (tests). */
60
60
  readonly initTemplatesRoot?: string;
61
+ /** Override template gallery root (tests). */
62
+ readonly initGalleryRoot?: string;
61
63
  /** Override version stamped by `prism init` (tests). */
62
64
  readonly initPackageVersion?: string;
63
65
  /** Override provider-scaffold template root (tests). */
@@ -66,8 +68,10 @@ export interface CliRuntime {
66
68
  readonly providerPackageVersion?: string;
67
69
  /** Working directory for relative `prism init` destinations (tests). */
68
70
  readonly cwd?: string;
71
+ /** Test injection for `prism dev`: overrides `@arnilo/prism-dev` resolution. */
72
+ readonly loadDevCli?: () => Promise<unknown>;
69
73
  }
70
- export declare const usage = "Usage: prism [--mode print|json|rpc] [-p prompt] [options]\n prism init <dir> [--provider <name>] [--with-workflows] [--with-evals] [--force]\n prism providers add <name> [--base-url <url>] [--env-key <name>] [--model <id>] [--force]\n\nOptions:\n -p, --prompt <text> Prompt to run in print/json mode\n --provider <name> Explicit provider id (mock is built in for smoke tests)\n --model <name> Explicit model name\n --session <id> Session id\n --system <text> System instructions\n --context <text> Context text\n --compact <entries> Auto-compaction threshold\n --max-tool-rounds <n> Maximum tool rounds\n --discover Enable workspace contribution discovery (opt-in)\n --discover-kinds <csv> Kinds to discover (default: skill; skill,tool,context,instructions)\n --no-discovery Disable discovery even if --discover is set\n --agents-config <path> App config root holding agents/<name>/AGENT.md bundles (opt-in)\n --no-agents-md Skip auto-loading <workspaceRoot>/AGENTS.md\n --no-system-md Skip auto-loading the global SYSTEM.md layer\n --agents-md-file <path> Read AGENTS.md from <path> instead (trust-gated, source: app)\n --system-md-file <path> Read SYSTEM.md from <path> instead (source: user)\n -h, --help Show this help\n";
74
+ export declare const usage = "Usage: prism [--mode print|json|rpc] [-p prompt] [options]\n prism init <dir> [--template <name>] [--list-templates] [--provider <name>] [--with-workflows] [--with-evals] [--force]\n prism providers add <name> [--base-url <url>] [--env-key <name>] [--model <id>] [--force]\n prism dev [--port <n>] [--host <addr>] (loopback inspector; delegates into @arnilo/prism-dev)\n\n\nOptions:\n -p, --prompt <text> Prompt to run in print/json mode\n --provider <name> Explicit provider id (mock is built in for smoke tests)\n --model <name> Explicit model name\n --session <id> Session id\n --system <text> System instructions\n --context <text> Context text\n --compact <entries> Auto-compaction threshold\n --max-tool-rounds <n> Maximum tool rounds\n --discover Enable workspace contribution discovery (opt-in)\n --discover-kinds <csv> Kinds to discover (default: skill; skill,tool,context,instructions)\n --no-discovery Disable discovery even if --discover is set\n --agents-config <path> App config root holding agents/<name>/AGENT.md bundles (opt-in)\n --no-agents-md Skip auto-loading <workspaceRoot>/AGENTS.md\n --no-system-md Skip auto-loading the global SYSTEM.md layer\n --agents-md-file <path> Read AGENTS.md from <path> instead (trust-gated, source: app)\n --system-md-file <path> Read SYSTEM.md from <path> instead (source: user)\n -h, --help Show this help\n";
71
75
  export declare function parseCliArgs(argv: readonly string[]): CliOptions;
72
76
  export declare function runCli(argv: readonly string[], runtime: CliRuntime): Promise<number>;
73
77
  export declare function runPromptMode(session: AgentSession, options: CliOptions, stdout: Writable, mode: "print" | "json"): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { basename, dirname } from "node:path";
3
3
  import process from "node:process";
4
+ import { runPrismDevSubcommand } from "./cli-dev.js";
4
5
  import { initUsage, runInitCommand } from "./cli-init.js";
5
6
  import { providerAddUsage, runProviderAddCommand } from "./cli-provider-add.js";
6
7
  import { createContributionRegistries, registerDiscoveredContributions } from "./contributions.js";
@@ -13,8 +14,10 @@ import { createPathTrustPolicy } from "./node/trust.js";
13
14
  import { runRpcServer } from "./rpc.js";
14
15
  import { createSkillRegistry } from "./skills.js";
15
16
  export const usage = `Usage: prism [--mode print|json|rpc] [-p prompt] [options]
16
- prism init <dir> [--provider <name>] [--with-workflows] [--with-evals] [--force]
17
+ prism init <dir> [--template <name>] [--list-templates] [--provider <name>] [--with-workflows] [--with-evals] [--force]
17
18
  prism providers add <name> [--base-url <url>] [--env-key <name>] [--model <id>] [--force]
19
+ prism dev [--port <n>] [--host <addr>] (loopback inspector; delegates into @arnilo/prism-dev)
20
+
18
21
 
19
22
  Options:
20
23
  -p, --prompt <text> Prompt to run in print/json mode
@@ -201,11 +204,19 @@ function parseKinds(csv, flag) {
201
204
  return kinds;
202
205
  }
203
206
  export async function runCli(argv, runtime) {
207
+ if (argv[0] === "dev") {
208
+ return runPrismDevSubcommand(argv.slice(1), {
209
+ stdout: runtime.stdout,
210
+ stderr: runtime.stderr,
211
+ ...(runtime.loadDevCli ? { loadDevCli: runtime.loadDevCli } : {}),
212
+ });
213
+ }
204
214
  if (argv[0] === "init") {
205
215
  const initRuntime = {
206
216
  stdout: runtime.stdout,
207
217
  stderr: runtime.stderr,
208
218
  ...(runtime.initTemplatesRoot !== undefined ? { templatesRoot: runtime.initTemplatesRoot } : {}),
219
+ ...(runtime.initGalleryRoot !== undefined ? { galleryRoot: runtime.initGalleryRoot } : {}),
209
220
  ...(runtime.initPackageVersion !== undefined ? { packageVersion: runtime.initPackageVersion } : {}),
210
221
  ...(runtime.cwd !== undefined ? { cwd: runtime.cwd } : {}),
211
222
  };
@@ -1,7 +1,7 @@
1
1
  /** Contracts-core agent family (0.2.5 plan 025 Task 1 split).
2
2
  * Moved verbatim from contracts-core.ts; public surface unchanged behind the barrel. */
3
- import type { InputAssemblyLayout, RunLedger, ToolDefinition, ToolEffectStore, ToolRegistry } from "../contracts-protocol.js";
4
- import type { AgentRunStateOptions, AgentSession } from "../contracts-run-state.js";
3
+ import type { InputAssemblyLayout, RunLedger, RunOptions, ToolDefinition, ToolEffectStore, ToolRegistry } from "../contracts-protocol.js";
4
+ import type { AgentRunResult, AgentRunStateOptions, AgentSession } from "../contracts-run-state.js";
5
5
  import type { ContributionRegistries } from "../contributions.js";
6
6
  import type { MiddlewareRegistry } from "../middleware.js";
7
7
  import type { SecretRedactor } from "../redaction.js";
@@ -59,6 +59,9 @@ export interface AgentConfig {
59
59
  readonly activateAllSkills?: true;
60
60
  /** Progressive: catalog (name+description) unless loaded; eager: full instructions every turn. Default progressive. */
61
61
  readonly skillsDisclosure?: import("../skill-disclosure.js").SkillsDisclosure;
62
+ /** Tools disclosure: "all" (default) sends every active tool schema; "search" sends top-k + the generated `search_tools` tool. */
63
+ readonly toolsDisclosure?: import("../tool-search.js").ToolsDisclosure;
64
+ readonly toolsSearch?: import("../tool-search.js").ToolsSearchOptions;
62
65
  /** Opt-in projection-only fold for aged large tool results in provider view; store untouched. */
63
66
  readonly toolResultFold?: import("../tool-result-fold.js").ToolResultFoldOptions;
64
67
  readonly inputBuilder?: InputBuilder;
@@ -147,6 +150,27 @@ export interface CommandExecutionContext {
147
150
  readonly runId?: string;
148
151
  readonly signal?: AbortSignal;
149
152
  readonly metadata?: Readonly<Record<string, unknown>>;
153
+ /** Host-injected driver capabilities (host-opt-in; never package-supplied).
154
+ * Absent in hosts that don't supply them — commands stay inert data there. */
155
+ readonly drivers?: CommandDrivers;
156
+ }
157
+ /** Minimal run reference returned by {@link CommandDrivers.startWorkflow}. */
158
+ export interface CommandWorkflowRun {
159
+ readonly runId: string;
160
+ readonly status: string;
161
+ }
162
+ /** Host-injected capabilities a contributed command may act through when the
163
+ * host opts in. Drivers are supplied by the host at context construction
164
+ * (e.g. the RPC session factory), never by packages; core only types and
165
+ * forwards them. `metadata.trust` labeling is unaffected. */
166
+ export interface CommandDrivers {
167
+ /** Start a session run. */
168
+ startRun(input: string, options?: RunOptions): Promise<AgentRunResult> | AgentRunResult;
169
+ /** Start a run on a host-understood orchestration definition. Returns at
170
+ * minimum the run id and status; richer host shapes pass through as-is. */
171
+ startWorkflow(definition: object, input: unknown, options?: Readonly<Record<string, unknown>>): Promise<CommandWorkflowRun>;
172
+ /** Steer an active run with additional input. */
173
+ steer(runId: string, input: string): Promise<void> | void;
150
174
  }
151
175
  export interface CommandResult {
152
176
  readonly name: string;
@@ -231,6 +255,9 @@ export interface PromptBuildRequest {
231
255
  readonly skills?: readonly Skill[];
232
256
  readonly skillsDisclosure?: import("../skill-disclosure.js").SkillsDisclosure;
233
257
  readonly loadedSkills?: import("../skill-disclosure.js").LoadedSkillSet;
258
+ /** Tools disclosure: "all" (default) sends every active tool schema; "search" sends top-k + the generated `search_tools` tool. */
259
+ readonly toolsDisclosure?: import("../tool-search.js").ToolsDisclosure;
260
+ readonly toolsSearch?: import("../tool-search.js").ToolsSearchOptions;
234
261
  /** Skills demoted to catalog-only by context budget this turn. */
235
262
  readonly demotedSkillBodies?: readonly string[];
236
263
  readonly tools?: readonly ToolDefinition[];
@@ -57,6 +57,17 @@ export type RealtimeEvent = {
57
57
  /** Neutral bidirectional realtime session seam. The provider owns the transport
58
58
  * (e.g. WebSocket); the host owns audio capture/playback and session lifecycle. */
59
59
  export type InputAssemblyLayout = "legacy" | "cache_aware";
60
+ /** Opaque provenance ref for the resolved prompt version that produced a run
61
+ * (plan 042). Identity only — never prompt content; the body is recoverable
62
+ * from the prompt store via `hash`. */
63
+ export interface PromptVersionRef {
64
+ /** Prompt name within the host's prompt store. */
65
+ readonly name: string;
66
+ /** Immutable version number assigned by the prompt store. */
67
+ readonly version: number;
68
+ /** Content hash of the exact UTF-8 body bytes: `sha256:<64 lowercase hex>`. */
69
+ readonly hash: string;
70
+ }
60
71
  export interface RunOptions {
61
72
  readonly signal?: AbortSignal;
62
73
  readonly model?: ModelConfig;
@@ -84,6 +95,9 @@ export interface RunOptions {
84
95
  readonly activateAllSkills?: true;
85
96
  /** Progressive: catalog (name+description) unless loaded; eager: full instructions every turn. Default progressive. */
86
97
  readonly skillsDisclosure?: import("./skill-disclosure.js").SkillsDisclosure;
98
+ /** Tools disclosure: "all" (default) sends every active tool schema; "search" sends top-k + the generated `search_tools` tool. */
99
+ readonly toolsDisclosure?: import("./tool-search.js").ToolsDisclosure;
100
+ readonly toolsSearch?: import("./tool-search.js").ToolsSearchOptions;
87
101
  /** Opt-in projection-only fold for aged large tool results in provider view; store untouched. */
88
102
  readonly toolResultFold?: import("./tool-result-fold.js").ToolResultFoldOptions;
89
103
  readonly instructionInjectors?: readonly InstructionInjector[];
@@ -93,6 +107,8 @@ export interface RunOptions {
93
107
  readonly guardrails?: Guardrails;
94
108
  /** Opt-in durable interruption/checkpointing. */
95
109
  readonly runState?: AgentRunStateOptions;
110
+ /** Prompt provenance: copied verbatim onto this run's start and finish ledger records. */
111
+ readonly promptVersion?: PromptVersionRef;
96
112
  }
97
113
  export interface ProviderTurnMetadata {
98
114
  readonly providerId: string;
@@ -493,6 +509,8 @@ export interface RunRecord extends OwnershipScope {
493
509
  readonly abortReason?: string;
494
510
  readonly error?: ErrorInfo;
495
511
  readonly metadata?: Readonly<Record<string, unknown>>;
512
+ /** Provenance ref copied from `RunOptions.promptVersion` when the host supplied one. */
513
+ readonly promptVersion?: PromptVersionRef;
496
514
  }
497
515
  export type AgentEventType = AgentEvent["type"];
498
516
  /** Stored agent event ledger row. The `event` payload should be redacted before storage when secrets are present. */
@@ -1,6 +1,5 @@
1
- import type { AgentSessionCloneOptions, AgentSessionForkOptions, CompactionOptions, CompactionResult, ContentBlock, ErrorInfo, JsonObject, JsonValue, Message, ModelConfig, RunLimitBreach, SessionEntry, ToolCallContent, Usage } from "./contracts-core.js";
1
+ import type { AgentSessionCloneOptions, AgentSessionForkOptions, CheckpointStore, CompactionOptions, CompactionResult, ContentBlock, ErrorInfo, JsonObject, JsonValue, Message, ModelConfig, OwnershipScope, RunLimitBreach, SessionEntry, SubscribeOptions, ToolCallContent, Usage } from "./contracts-core.js";
2
2
  import type { AgentEvent, RunOptions, ToolEffectKind } from "./contracts-protocol.js";
3
- import type { CheckpointStore, OwnershipScope, SubscribeOptions } from "./contracts-core.js";
4
3
  export type AgentRunStatus = "succeeded" | "failed" | "aborted" | "suspended" | "denied";
5
4
  export type AgentRunInterruptionKind = "input_guardrail" | "tool_approval" | "elicitation";
6
5
  export type ApprovalOutcome = "allow_once" | "allow_for_run" | "reject_once" | "reject_for_run";
package/dist/index.d.ts CHANGED
@@ -109,11 +109,13 @@ export type { ToolEffectErrorCode } from "./tool-effects.js";
109
109
  export { createMemoryToolEffectStore, ToolEffectError } from "./tool-effects.js";
110
110
  export type { FoldToolResultsContext, ResolvedToolResultFoldOptions, ToolResultFoldInput, ToolResultFoldOptions, } from "./tool-result-fold.js";
111
111
  export { DEFAULT_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, DEFAULT_TOOL_RESULT_FOLD_MIN_AGE_TURNS, DEFAULT_TOOL_RESULT_FOLD_MIN_BYTES, foldedToolResultHeader, foldToolResultHistory, foldToolResults, formatFoldedToolResult, HARD_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, resolveToolResultFold, TOOL_RESULT_FOLD_TURN_METADATA_KEY, } from "./tool-result-fold.js";
112
+ export type { ActiveToolSet, ToolSearchIndex, ToolSearchMatch, ToolSearchState, ToolsDisclosure, ToolsSearchOptions, } from "./tool-search.js";
113
+ export { createActiveToolSet, createSearchToolsTool, createToolSearchIndex, createToolSearchState, DEFAULT_MAX_TOOLS_SEARCH_QUERY_BYTES, DEFAULT_TOOLS_SEARCH_TOP_K, HARD_MAX_TOOLS_INDEX, HARD_MAX_TOOLS_SEARCH_QUERY_BYTES, HARD_MAX_TOOLS_SEARCH_TOP_K, isToolDisclosureError, resolveToolsDisclosure, SEARCH_TOOLS_TOOL_NAME, scoreTools, selectDisclosedTools, TOOL_DISCLOSURE_ERROR_CODE, ToolDisclosureError, } from "./tool-search.js";
112
114
  export type { DispatchToolCallOptions, ToolArgumentValidationError, ToolArgumentValidationResult, ToolArgumentValidator, ToolFilter, ToolFilterInput, ToolParameterValidatorOptions, ToolRegistryOptions, ToolValidator, } from "./tools.js";
113
115
  export { createToolParameterValidator, createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
114
116
  export { trimTrailingSlashes } from "./trim-trailing-slashes.js";
115
117
  export type { ResolvedUseCaseModel, ResolveUseCaseModelInput, UseCaseModelBinding, } from "./use-case-model.js";
116
118
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
117
119
  export declare const name = "prism";
118
- export declare const version = "0.3.1";
120
+ export declare const version = "0.4.0";
119
121
  export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
package/dist/index.js CHANGED
@@ -60,10 +60,11 @@ export { assertAgentEventSourceConforms } from "./testing/agent-event-source-con
60
60
  export { applyThinkingLevel, isThinkingLevel, normalizeThinkingLevel, THINKING_LEVELS, thinkingCompatFor, thinkingFamilyForModel, } from "./thinking.js";
61
61
  export { createMemoryToolEffectStore, ToolEffectError } from "./tool-effects.js";
62
62
  export { DEFAULT_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, DEFAULT_TOOL_RESULT_FOLD_MIN_AGE_TURNS, DEFAULT_TOOL_RESULT_FOLD_MIN_BYTES, foldedToolResultHeader, foldToolResultHistory, foldToolResults, formatFoldedToolResult, HARD_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, resolveToolResultFold, TOOL_RESULT_FOLD_TURN_METADATA_KEY, } from "./tool-result-fold.js";
63
+ export { createActiveToolSet, createSearchToolsTool, createToolSearchIndex, createToolSearchState, DEFAULT_MAX_TOOLS_SEARCH_QUERY_BYTES, DEFAULT_TOOLS_SEARCH_TOP_K, HARD_MAX_TOOLS_INDEX, HARD_MAX_TOOLS_SEARCH_QUERY_BYTES, HARD_MAX_TOOLS_SEARCH_TOP_K, isToolDisclosureError, resolveToolsDisclosure, SEARCH_TOOLS_TOOL_NAME, scoreTools, selectDisclosedTools, TOOL_DISCLOSURE_ERROR_CODE, ToolDisclosureError, } from "./tool-search.js";
63
64
  export { createToolParameterValidator, createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
64
65
  export { trimTrailingSlashes } from "./trim-trailing-slashes.js";
65
66
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
66
67
  export const name = "prism";
67
- export const version = "0.3.1";
68
+ export const version = "0.4.0";
68
69
  export const description = "Agent harness for AI providers, agents, sessions, and tools.";
69
70
  //# sourceMappingURL=index.js.map
package/dist/input.d.ts CHANGED
@@ -4,6 +4,7 @@ import type { MiddlewareRegistry } from "./middleware.js";
4
4
  import type { SecretRedactor } from "./redaction.js";
5
5
  import { type LoadedSkillSet, type SkillsDisclosure } from "./skill-disclosure.js";
6
6
  import { type ResolvedToolResultFoldOptions } from "./tool-result-fold.js";
7
+ import { type ToolsDisclosure, type ToolsSearchOptions } from "./tool-search.js";
7
8
  export type AgentInput = string | Message | readonly Message[];
8
9
  export interface PromptInstruction {
9
10
  readonly text: string;
@@ -58,6 +59,13 @@ export interface AssembleProviderInputOptions extends DefaultInputBuildContext {
58
59
  readonly skillsDisclosure?: SkillsDisclosure;
59
60
  readonly loadedSkills?: LoadedSkillSet;
60
61
  readonly tools?: readonly ToolDefinition[];
62
+ /** Tools disclosure: "search" narrows the disclosed tool list (activated ∪ top-k); default "all" is unchanged. */
63
+ readonly toolsDisclosure?: ToolsDisclosure;
64
+ readonly toolsSearch?: ToolsSearchOptions;
65
+ /** Per-run activated names from `search_tools`; intersected at disclosure only — dispatch re-checks. */
66
+ readonly activatedTools?: {
67
+ has(name: string): boolean;
68
+ };
61
69
  readonly providerOptions?: ProviderRequestOptions;
62
70
  /** Assembler-time eviction; does not delete session store history. */
63
71
  readonly contextBudget?: ContextBudget;
package/dist/input.js CHANGED
@@ -6,6 +6,7 @@ import { loadTextResource } from "./resources.js";
6
6
  import { skillMessages as buildSkillMessages } from "./skill-disclosure.js";
7
7
  import { composeSystemPrompt } from "./system-prompts.js";
8
8
  import { foldToolResultHistory, foldToolResults } from "./tool-result-fold.js";
9
+ import { selectDisclosedTools } from "./tool-search.js";
9
10
  export function createDefaultInputBuilder() {
10
11
  return {
11
12
  name: "default-input",
@@ -120,6 +121,9 @@ export async function assembleProviderInput(options) {
120
121
  let context;
121
122
  let skills = options.skills;
122
123
  let tools = options.tools;
124
+ if (options.toolsDisclosure === "search" && tools?.length) {
125
+ tools = selectDisclosedTools({ tools, input: options.input, search: options.toolsSearch, activated: options.activatedTools });
126
+ }
123
127
  let demotedSkillBodies;
124
128
  let budgetReport;
125
129
  if (options.contextBudget) {
package/dist/rpc.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Readable, Writable } from "node:stream";
2
- import type { AgentSession, CommandDefinition, InstructionInjector } from "./contracts.js";
2
+ import type { AgentSession, CommandDefinition, CommandDrivers, InstructionInjector } from "./contracts.js";
3
3
  import type { ContributionRegistry } from "./contributions.js";
4
4
  export type RpcCommandName = "prompt" | "steer" | "followUp" | "abort" | "state" | "messages" | "setModel" | "compact" | "switchSession" | "forkSession" | "cloneSession" | "checkout" | "command";
5
5
  export interface RpcRequest {
@@ -10,6 +10,9 @@ export interface RpcRequest {
10
10
  export interface RpcSessionFactory {
11
11
  createSession(id?: string): AgentSession;
12
12
  readonly commands?: readonly CommandDefinition[];
13
+ /** Host-opt-in driver capabilities forwarded to contributed commands on the
14
+ * `command` execution context. Absent ⇒ context shape unchanged. */
15
+ readonly drivers?: CommandDrivers;
13
16
  /** Optional registry for resolving `instructionInjectors` names in `prompt`/`followUp`
14
17
  * params (Phase 30). Names resolve fail-closed. */
15
18
  readonly instructionInjectors?: ContributionRegistry<InstructionInjector>;
package/dist/rpc.js CHANGED
@@ -9,6 +9,7 @@ export async function runRpcServer(options) {
9
9
  sessions: new Map([[first.id, first]]),
10
10
  commands: new Map((options.commands ?? []).map((command) => [command.name, command])),
11
11
  createSession: options.createSession,
12
+ ...(options.drivers ? { drivers: options.drivers } : {}),
12
13
  ...(options.instructionInjectors ? { instructionInjectors: options.instructionInjectors } : {}),
13
14
  };
14
15
  const activeRuns = new Map();
@@ -181,7 +182,10 @@ async function handleRequest(request, state, stdout, activeRuns) {
181
182
  if (!command)
182
183
  throw new Error(`Unknown command: ${name}`);
183
184
  const args = objectParam(request.params, "args") ?? {};
184
- const result = await command.execute(args, { sessionId: state.current.id });
185
+ const result = await command.execute(args,
186
+ // FEATURE-3 (plan 050 Task 5): host-opt-in drivers forwarded verbatim; the
187
+ // context carries no `drivers` key when the host supplied none.
188
+ state.drivers ? { sessionId: state.current.id, drivers: state.drivers } : { sessionId: state.current.id });
185
189
  write(stdout, { id: request.id, ok: true, result });
186
190
  break;
187
191
  }
@@ -1,6 +1,6 @@
1
1
  import type { PersistencePage, SessionEntry, SessionEntryQuery } from "../contracts.js";
2
2
  /** Current shared persistence schema version for production database adapters. */
3
- export declare const PERSISTENCE_SCHEMA_VERSION = 8;
3
+ export declare const PERSISTENCE_SCHEMA_VERSION = 9;
4
4
  export type PersistenceTableName = "prism_tenants" | "prism_accounts" | "prism_users" | "prism_agent_definitions" | "prism_sessions" | "prism_branches" | "prism_session_entries" | "prism_session_append_idempotency" | "prism_runs" | "prism_agent_events" | "prism_agent_event_streams" | "prism_tool_calls" | "prism_usage" | "prism_run_feedback" | "prism_retention_policies" | "prism_legal_holds" | "prism_tenant_quotas" | "prism_migrations";
5
5
  export type PersistenceColumnType = "text" | "integer" | "number" | "boolean" | "json" | "timestamp";
6
6
  export interface PersistenceColumnDefinition {