@arnilo/prism 0.3.2 → 0.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.
Files changed (208) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +42 -62
  3. package/dist/agent-run-lifecycle.js +4 -0
  4. package/dist/agent-run-state.d.ts +5 -2
  5. package/dist/agent-run-state.js +18 -8
  6. package/dist/agent-session/session/assemble.d.ts +6 -0
  7. package/dist/agent-session/session/assemble.js +391 -0
  8. package/dist/agent-session/session/persist.d.ts +28 -0
  9. package/dist/agent-session/session/persist.js +166 -0
  10. package/dist/agent-session/session/provider-round.d.ts +6 -0
  11. package/dist/agent-session/session/provider-round.js +231 -0
  12. package/dist/agent-session/session/tool-round.d.ts +31 -0
  13. package/dist/agent-session/session/tool-round.js +473 -0
  14. package/dist/agent-session/session/types.d.ts +115 -0
  15. package/dist/agent-session/session/types.js +5 -0
  16. package/dist/agent-session/session.d.ts +54 -41
  17. package/dist/agent-session/session.js +23 -1132
  18. package/dist/capture.d.ts +63 -0
  19. package/dist/capture.js +67 -0
  20. package/dist/cli-dev.d.ts +29 -0
  21. package/dist/cli-dev.js +52 -0
  22. package/dist/cli-init.d.ts +34 -3
  23. package/dist/cli-init.js +192 -24
  24. package/dist/cli-runner.d.ts +6 -2
  25. package/dist/cli-runner.js +57 -10
  26. package/dist/content.d.ts +3 -3
  27. package/dist/content.js +3 -1
  28. package/dist/contracts-core/agent.d.ts +8 -0
  29. package/dist/contracts-core/batch.d.ts +97 -0
  30. package/dist/contracts-core/batch.js +65 -0
  31. package/dist/contracts-core/content.d.ts +72 -1
  32. package/dist/contracts-core/embeddings.d.ts +30 -0
  33. package/dist/contracts-core/embeddings.js +17 -0
  34. package/dist/contracts-core/images.d.ts +60 -0
  35. package/dist/contracts-core/images.js +17 -0
  36. package/dist/contracts-core/moderation.d.ts +46 -0
  37. package/dist/contracts-core/moderation.js +34 -0
  38. package/dist/contracts-core/speech.d.ts +39 -0
  39. package/dist/contracts-core/speech.js +17 -0
  40. package/dist/contracts-core/transcription.d.ts +48 -0
  41. package/dist/contracts-core/transcription.js +17 -0
  42. package/dist/contracts-core/video.d.ts +61 -0
  43. package/dist/contracts-core/video.js +17 -0
  44. package/dist/contracts-core.d.ts +7 -0
  45. package/dist/contracts-core.js +7 -0
  46. package/dist/contracts-protocol.d.ts +18 -0
  47. package/dist/contracts-run-state.d.ts +1 -2
  48. package/dist/index.d.ts +7 -3
  49. package/dist/index.js +5 -3
  50. package/dist/input.d.ts +8 -0
  51. package/dist/input.js +4 -0
  52. package/dist/node/agent-definitions.d.ts +1 -8
  53. package/dist/node/agent-definitions.js +0 -34
  54. package/dist/node/settings.d.ts +0 -1
  55. package/dist/node/settings.js +0 -5
  56. package/dist/pinned-fetch.js +29 -3
  57. package/dist/provider-events.js +3 -4
  58. package/dist/providers/media.d.ts +1 -2
  59. package/dist/providers/media.js +1 -4
  60. package/dist/rpc.d.ts +1 -1
  61. package/dist/rpc.js +4 -4
  62. package/dist/testing/persistence-schema.d.ts +1 -1
  63. package/dist/testing/persistence-schema.js +32 -28
  64. package/dist/testing/provider-conformance.d.ts +114 -5
  65. package/dist/testing/provider-conformance.js +342 -0
  66. package/dist/testing/tool-conformance.d.ts +25 -0
  67. package/dist/testing/tool-conformance.js +128 -1
  68. package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
  69. package/dist/testing/tool-effect-store-conformance.js +0 -3
  70. package/dist/thinking.d.ts +48 -9
  71. package/dist/thinking.js +134 -8
  72. package/dist/tool-search.d.ts +76 -0
  73. package/dist/tool-search.js +199 -0
  74. package/docs/0.1.0-readiness.md +3 -3
  75. package/docs/a2a.md +2 -2
  76. package/docs/acp-agent.md +1 -1
  77. package/docs/acp.md +3 -3
  78. package/docs/ag-ui-adoption.md +1 -1
  79. package/docs/ag-ui.md +1 -2
  80. package/docs/agent-definitions.md +1 -1
  81. package/docs/agent-events.md +5 -5
  82. package/docs/agent-identity.md +13 -2
  83. package/docs/audit-export.md +3 -3
  84. package/docs/batch-jobs.md +120 -0
  85. package/docs/browser-automation.md +5 -5
  86. package/docs/caveman.md +2 -2
  87. package/docs/cli-rpc.md +43 -9
  88. package/docs/coding-agent-tools.md +19 -19
  89. package/docs/coding-review-and-diagnostics.md +2 -2
  90. package/docs/coding-security.md +5 -5
  91. package/docs/coding-tools.md +82 -0
  92. package/docs/coding-workspaces.md +2 -2
  93. package/docs/compaction-and-retry.md +2 -2
  94. package/docs/compaction-llm.md +4 -4
  95. package/docs/compaction-observational-memory.md +3 -3
  96. package/docs/computer-use-linux.md +13 -2
  97. package/docs/context-and-skills.md +3 -1
  98. package/docs/conversations.md +4 -4
  99. package/docs/core.md +85 -0
  100. package/docs/credential-storage.md +12 -8
  101. package/docs/credentials-and-redaction.md +1 -1
  102. package/docs/data-classification.md +1 -1
  103. package/docs/database-persistence.md +7 -3
  104. package/docs/dev-inspector.md +103 -0
  105. package/docs/device-adapters.md +2 -2
  106. package/docs/diagrams.md +247 -0
  107. package/docs/document-reader.md +6 -6
  108. package/docs/documents.md +214 -0
  109. package/docs/embeddings.md +112 -0
  110. package/docs/enterprise-postgres-state.md +7 -7
  111. package/docs/evaluations.md +41 -7
  112. package/docs/extensions.md +3 -3
  113. package/docs/forge-integration.md +3 -3
  114. package/docs/graft.md +5 -5
  115. package/docs/guardrails.md +2 -2
  116. package/docs/host-security.md +16 -15
  117. package/docs/image-generation.md +129 -0
  118. package/docs/impeccable.md +7 -5
  119. package/docs/index.md +84 -46
  120. package/docs/indexed-code-search.md +2 -2
  121. package/docs/language-intelligence.md +4 -4
  122. package/docs/live-testing.md +126 -0
  123. package/docs/mcp-tools.md +44 -13
  124. package/docs/middleware-hooks.md +1 -1
  125. package/docs/migrate-to-0.4.md +312 -0
  126. package/docs/migrate-to-0.5.md +122 -0
  127. package/docs/migration.md +51 -1
  128. package/docs/model-registry.md +38 -0
  129. package/docs/model-routing.md +6 -6
  130. package/docs/moderation.md +117 -0
  131. package/docs/multi-agent-patterns.md +177 -0
  132. package/docs/multimodal-content.md +27 -3
  133. package/docs/obscura.md +12 -12
  134. package/docs/observability.md +32 -7
  135. package/docs/openapi-tools.md +14 -4
  136. package/docs/operations.md +11 -0
  137. package/docs/performance.md +30 -10
  138. package/docs/persistence-credentials-multimodality-primitives.md +7 -7
  139. package/docs/policy-and-audit.md +18 -8
  140. package/docs/ponytail.md +3 -3
  141. package/docs/postgres-persistence.md +5 -5
  142. package/docs/process-sessions.md +2 -2
  143. package/docs/prompt-registry.md +106 -0
  144. package/docs/provider-caching.md +36 -32
  145. package/docs/provider-conformance.md +24 -2
  146. package/docs/provider-packages.md +58 -22
  147. package/docs/provider-primitives.md +5 -5
  148. package/docs/provider-request-policies.md +1 -1
  149. package/docs/providers/ai-sdk.md +18 -6
  150. package/docs/providers/alibaba.md +10 -6
  151. package/docs/providers/anthropic.md +10 -6
  152. package/docs/providers/azure.md +20 -4
  153. package/docs/providers/bedrock.md +18 -3
  154. package/docs/providers/clinepass.md +7 -3
  155. package/docs/providers/commandcode.md +253 -0
  156. package/docs/providers/deepseek.md +7 -3
  157. package/docs/providers/google.md +8 -4
  158. package/docs/providers/hyper.md +284 -0
  159. package/docs/providers/kimi.md +7 -3
  160. package/docs/providers/neuralwatt.md +12 -8
  161. package/docs/providers/ollama.md +18 -3
  162. package/docs/providers/openai-compatible.md +5 -1
  163. package/docs/providers/openai.md +9 -5
  164. package/docs/providers/opencode-go.md +8 -4
  165. package/docs/providers/openrouter.md +8 -4
  166. package/docs/providers/vertex.md +21 -5
  167. package/docs/providers/xai.md +7 -3
  168. package/docs/providers/zai.md +7 -3
  169. package/docs/rag.md +31 -9
  170. package/docs/release-and-install.md +181 -76
  171. package/docs/resource-loading.md +1 -1
  172. package/docs/runs-and-usage.md +28 -3
  173. package/docs/server.md +94 -5
  174. package/docs/settings-auth-trust-security.md +7 -5
  175. package/docs/sheets.md +229 -0
  176. package/docs/speech.md +126 -0
  177. package/docs/sqlite-persistence.md +4 -4
  178. package/docs/supervisors.md +4 -3
  179. package/docs/thinking-and-reasoning.md +93 -60
  180. package/docs/tool-conformance.md +28 -3
  181. package/docs/tool-execution-primitives.md +8 -8
  182. package/docs/tools.md +32 -5
  183. package/docs/web-tools.md +3 -3
  184. package/docs/wiki.md +7 -7
  185. package/docs/work-artifacts-and-review.md +17 -6
  186. package/docs/work-connectors.md +4 -4
  187. package/docs/work-tools.md +5 -5
  188. package/docs/workflow-orchestration-primitives.md +35 -11
  189. package/docs/workflows.md +74 -13
  190. package/docs/working-and-semantic-memory.md +53 -5
  191. package/package.json +14 -31
  192. package/templates/README.md +23 -0
  193. package/templates/deep-research/README.md.tmpl +47 -0
  194. package/templates/deep-research/env.example.tmpl +12 -0
  195. package/templates/deep-research/gitignore.tmpl +7 -0
  196. package/templates/deep-research/manifest.json +12 -0
  197. package/templates/deep-research/package.json.tmpl +23 -0
  198. package/templates/deep-research/src/agent.ts.tmpl +81 -0
  199. package/templates/deep-research/src/index.ts.tmpl +53 -0
  200. package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
  201. package/templates/deep-research/src/tools.ts.tmpl +86 -0
  202. package/templates/deep-research/src/types.ts.tmpl +45 -0
  203. package/templates/deep-research/src/workflow.ts.tmpl +156 -0
  204. package/templates/deep-research/tsconfig.json.tmpl +15 -0
  205. package/templates/init/manifest.json +5 -0
  206. package/templates/init/package.json.tmpl +2 -1
  207. package/templates/init/providers.json +40 -24
  208. package/docs/antigravity-agent.md +0 -207
@@ -0,0 +1,63 @@
1
+ /** Provider request/response capture middleware (plan 062, review §7 P1):
2
+ * opt-in observation of already-normalized provider shapes — never raw HTTP.
3
+ *
4
+ * Request side rides the existing `provider_request` middleware hook; response
5
+ * side rides the existing subscriber-event seam (`provider_turn_finished`,
6
+ * which core already redacts). No new seam. Captured entries land in a capped
7
+ * FIFO ring buffer (`maxEvents`, default 100).
8
+ *
9
+ * Privacy policy `redact` controls content retention:
10
+ * - `"all"`: structure only — model id, counts, tool names, usage, latency.
11
+ * - `"secrets"` (default): also drops message content (the privacy default:
12
+ * captured buffers carry no conversation text unless the host opts in).
13
+ * - `"none"`: retains message content for replay debugging.
14
+ * Secret redaction is unconditional in every mode (replay-safe by
15
+ * construction): retained material passes through the same `redactSecrets`
16
+ * helper the logging seams use, so credentials never survive into a buffer
17
+ * that a host might persist or replay. Provider request/response options and
18
+ * headers are never captured at all — headers are where credentials ride.
19
+ */
20
+ import type { AgentEvent, ProviderRequest } from "./contracts.js";
21
+ import type { Middleware } from "./middleware.js";
22
+ import { type SecretRedactor } from "./redaction.js";
23
+ export type CaptureRedaction = "secrets" | "all" | "none";
24
+ export interface ProviderCapturePolicy {
25
+ /** Content-retention level; `"secrets"` (default) drops message content. */
26
+ readonly redact?: CaptureRedaction;
27
+ /** Ring-buffer capacity; oldest entries evict first. Default 100. */
28
+ readonly maxEvents?: number;
29
+ }
30
+ export interface ProviderCaptureOptions {
31
+ readonly policy?: ProviderCapturePolicy;
32
+ /** Secrets redacted from every retained field, matching the logging seams. */
33
+ readonly secrets?: readonly (string | undefined)[];
34
+ readonly redactor?: SecretRedactor;
35
+ readonly now?: () => number;
36
+ }
37
+ export interface ProviderCaptureEntry {
38
+ readonly kind: "request" | "response";
39
+ readonly at: string;
40
+ readonly redaction: CaptureRedaction;
41
+ readonly provider?: string;
42
+ readonly model?: string;
43
+ readonly messageCount?: number;
44
+ readonly toolNames?: readonly string[];
45
+ /** Message content — present only when the policy retains it (`"none"`), secrets redacted. */
46
+ readonly content?: unknown;
47
+ /** Response entries: normalized usage numbers (never sensitive). */
48
+ readonly usage?: unknown;
49
+ readonly latencyMs?: number;
50
+ readonly error?: unknown;
51
+ }
52
+ export interface ProviderCapture {
53
+ /** Register on the existing `provider_request` middleware hook. Passes the
54
+ * request through untouched and records one entry per round. */
55
+ middleware(): Middleware<ProviderRequest>;
56
+ /** Feed `provider_turn_finished` events from the session's existing
57
+ * subscriber loop (`session.subscribe()`) to record response entries. */
58
+ observeEvent(event: AgentEvent): void;
59
+ /** Ring-buffer snapshot, oldest first. */
60
+ events(): readonly ProviderCaptureEntry[];
61
+ clear(): void;
62
+ }
63
+ export declare function createProviderCapture(options?: ProviderCaptureOptions): ProviderCapture;
@@ -0,0 +1,67 @@
1
+ import { resolveRedactor } from "./redaction.js";
2
+ const DEFAULT_MAX_EVENTS = 100;
3
+ const HARD_MAX_EVENTS_CAP = 10_000;
4
+ function resolveMaxEvents(maxEvents) {
5
+ const value = maxEvents ?? DEFAULT_MAX_EVENTS;
6
+ if (!Number.isSafeInteger(value) || value < 1)
7
+ throw new Error("maxEvents must be a positive integer");
8
+ return Math.min(value, HARD_MAX_EVENTS_CAP);
9
+ }
10
+ export function createProviderCapture(options = {}) {
11
+ const redaction = options.policy?.redact ?? "secrets";
12
+ const maxEvents = resolveMaxEvents(options.policy?.maxEvents);
13
+ const now = options.now ?? Date.now;
14
+ const redactor = resolveRedactor(options.redactor, options.secrets);
15
+ const buffer = [];
16
+ const record = (entry) => {
17
+ buffer.push(entry);
18
+ if (buffer.length > maxEvents)
19
+ buffer.splice(0, buffer.length - maxEvents);
20
+ };
21
+ return {
22
+ middleware() {
23
+ return (request, next) => {
24
+ const entry = {
25
+ kind: "request",
26
+ at: new Date(now()).toISOString(),
27
+ redaction,
28
+ provider: request.model.provider,
29
+ model: request.model.model,
30
+ messageCount: request.messages.length,
31
+ toolNames: request.tools?.map((tool) => tool.name),
32
+ ...(redaction === "none" && request.messages.length > 0
33
+ ? { content: redactor ? redactor.redact(request.messages) : request.messages }
34
+ : {}),
35
+ };
36
+ record(entry);
37
+ return next(request);
38
+ };
39
+ },
40
+ observeEvent(event) {
41
+ if (event.type !== "provider_turn_finished")
42
+ return;
43
+ const metadata = (event.metadata ?? {});
44
+ record({
45
+ kind: "response",
46
+ at: new Date(now()).toISOString(),
47
+ redaction,
48
+ provider: typeof metadata.providerId === "string" ? metadata.providerId : undefined,
49
+ model: typeof metadata.model?.model === "string"
50
+ ? metadata.model.model
51
+ : undefined,
52
+ usage: event.usage,
53
+ latencyMs: typeof metadata.latencyMs === "number" ? metadata.latencyMs : undefined,
54
+ // Core already redacts emitted errors; redact again so replay safety holds even
55
+ // when a host feeds events captured before redaction.
56
+ error: event.error && redactor ? redactor.redact(event.error) : event.error,
57
+ });
58
+ },
59
+ events() {
60
+ return [...buffer];
61
+ },
62
+ clear() {
63
+ buffer.length = 0;
64
+ },
65
+ };
66
+ }
67
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Plan 040 Task 4 — `prism dev` delegation into `@arnilo/prism-dev`.
3
+ * The core deliberately holds no compile-time dependency on the dev package
4
+ * (dev-only surface, omitted from umbrellas): the subcommand resolves the
5
+ * package from the current project's own `node_modules` and hands the CLI
6
+ * over. Unresolvable → actionable install hint, exit 2.
7
+ */
8
+ import type { Writable } from "node:stream";
9
+ export interface DevCliModule {
10
+ runDevCli(argv: readonly string[], runtime: {
11
+ stdout: Writable;
12
+ stderr: Writable;
13
+ cwd?: string;
14
+ }): Promise<number>;
15
+ }
16
+ export type PrismDevLoader = () => Promise<DevCliModule | undefined>;
17
+ export interface PrismDevSubcommandRuntime {
18
+ readonly stdout: Writable;
19
+ readonly stderr: Writable;
20
+ /** Test injection: overrides project-level `@arnilo/prism-dev` resolution. */
21
+ readonly loadDevCli?: PrismDevLoader;
22
+ }
23
+ /**
24
+ * Default loader: resolve `@arnilo/prism-coding-tools/dev/cli` (or `@arnilo/prism-dev/cli`)
25
+ * from the project the user is standing in, falling back to this CLI's own installation.
26
+ */
27
+ export declare const defaultLoadDevCli: PrismDevLoader;
28
+ /** Runs the `prism dev` subcommand by delegating into the resolved package. */
29
+ export declare function runPrismDevSubcommand(argv: readonly string[], runtime: PrismDevSubcommandRuntime): Promise<number>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Plan 040 Task 4 — `prism dev` delegation into `@arnilo/prism-dev`.
3
+ * The core deliberately holds no compile-time dependency on the dev package
4
+ * (dev-only surface, omitted from umbrellas): the subcommand resolves the
5
+ * package from the current project's own `node_modules` and hands the CLI
6
+ * over. Unresolvable → actionable install hint, exit 2.
7
+ */
8
+ import { createRequire } from "node:module";
9
+ import { join } from "node:path";
10
+ import process from "node:process";
11
+ import { pathToFileURL } from "node:url";
12
+ const installHint = "prism dev requires the dev inspector package in this project.\n" +
13
+ " npm install --save-dev @arnilo/prism-coding-tools\n" +
14
+ "(Scaffolded projects from newer `prism init` templates already include it.)\n";
15
+ /**
16
+ * Default loader: resolve `@arnilo/prism-coding-tools/dev/cli` (or `@arnilo/prism-dev/cli`)
17
+ * from the project the user is standing in, falling back to this CLI's own installation.
18
+ */
19
+ export const defaultLoadDevCli = async () => {
20
+ const specifiers = ["@arnilo/prism-coding-tools/dev/cli", "@arnilo/prism-dev/cli"];
21
+ for (const specifier of specifiers) {
22
+ try {
23
+ const require = createRequire(join(process.cwd(), "package.json"));
24
+ const resolved = require.resolve(specifier);
25
+ const mod = (await import(pathToFileURL(resolved).href));
26
+ if (typeof mod.runDevCli === "function")
27
+ return mod;
28
+ }
29
+ catch {
30
+ try {
31
+ const mod = (await import(specifier));
32
+ if (typeof mod.runDevCli === "function")
33
+ return mod;
34
+ }
35
+ catch {
36
+ // try next specifier
37
+ }
38
+ }
39
+ }
40
+ return undefined;
41
+ };
42
+ /** Runs the `prism dev` subcommand by delegating into the resolved package. */
43
+ export async function runPrismDevSubcommand(argv, runtime) {
44
+ const load = runtime.loadDevCli ?? defaultLoadDevCli;
45
+ const mod = await load();
46
+ if (!mod || typeof mod.runDevCli !== "function") {
47
+ runtime.stderr.write(installHint);
48
+ return 2;
49
+ }
50
+ return mod.runDevCli(argv, { stdout: runtime.stdout, stderr: runtime.stderr });
51
+ }
52
+ //# sourceMappingURL=cli-dev.js.map
@@ -4,6 +4,8 @@ export declare class InitUsageError extends Error {
4
4
  export type InitProvider = string;
5
5
  export interface InitOptions {
6
6
  readonly directory: string;
7
+ readonly template?: string;
8
+ readonly listTemplates?: boolean;
7
9
  readonly provider: InitProvider;
8
10
  readonly withWorkflows: boolean;
9
11
  readonly withEvals: boolean;
@@ -15,6 +17,8 @@ export interface InitRuntime {
15
17
  readonly stderr: Writable;
16
18
  /** Override template root (tests). Defaults to package `templates/init`. */
17
19
  readonly templatesRoot?: string;
20
+ /** Override gallery root (tests). Defaults to package `templates`. */
21
+ readonly galleryRoot?: string;
18
22
  /** Override package version stamped into generated package.json. */
19
23
  readonly packageVersion?: string;
20
24
  /** Working directory used to resolve relative destinations. Defaults to process.cwd(). */
@@ -23,17 +27,44 @@ export interface InitRuntime {
23
27
  export interface InitResult {
24
28
  readonly targetDir: string;
25
29
  readonly writtenFiles: readonly string[];
30
+ readonly template?: string;
26
31
  readonly provider: InitProvider;
27
32
  readonly withWorkflows: boolean;
28
33
  readonly withEvals: boolean;
29
34
  readonly totalBytes: number;
30
35
  }
36
+ export interface TemplateInfo {
37
+ readonly name: string;
38
+ readonly description: string;
39
+ readonly version?: string;
40
+ readonly path: string;
41
+ }
42
+ interface ProviderSpec {
43
+ readonly id: string;
44
+ readonly packageName?: string;
45
+ /** Module specifier the CLI's real-provider mode dynamically imports (e.g. `@arnilo/prism-providers/openai`). */
46
+ readonly factoryModule?: string;
47
+ /** Named export on `factoryModule` that builds the provider. */
48
+ readonly factoryExport?: string;
49
+ readonly envKey?: string;
50
+ readonly envPlaceholder?: string;
51
+ readonly modelProvider: string;
52
+ readonly modelName: string;
53
+ readonly imports: string;
54
+ readonly providerExpression: string;
55
+ readonly modelExpression: string;
56
+ }
57
+ /** Provider catalog shared by `prism init` templates and the CLI's real-provider mode. */
58
+ export declare function loadProvidersCatalog(templatesRoot?: string): ReadonlyMap<string, ProviderSpec>;
31
59
  /** Provider ids supported by `prism init --provider`. Loaded from templates data. */
32
60
  export declare function listInitProviders(templatesRoot?: string): readonly string[];
33
- export declare function getInitUsage(templatesRoot?: string): string;
61
+ /** Template list discovered from the templates gallery. */
62
+ export declare function listInitTemplates(galleryRoot?: string): readonly TemplateInfo[];
63
+ export declare function getInitUsage(templatesRoot?: string, galleryRoot?: string): string;
34
64
  export declare const initUsage: string;
35
- export declare function parseInitArgs(argv: readonly string[], templatesRoot?: string): InitOptions;
65
+ export declare function parseInitArgs(argv: readonly string[], templatesRoot?: string, galleryRoot?: string): InitOptions;
36
66
  export declare function runInitCommand(argv: readonly string[], runtime: InitRuntime): Promise<number>;
37
67
  export declare function createInitProject(options: InitOptions, runtime?: InitRuntime): Promise<InitResult>;
38
68
  export declare function defaultTemplatesRoot(): string;
39
- export declare function isInitProvider(value: string, templatesRoot?: string): value is InitProvider;
69
+ export declare function defaultGalleryRoot(): string;
70
+ export {};
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";
@@ -9,7 +9,8 @@ let cachedProviderIds;
9
9
  function providersCatalogPath(templatesRoot) {
10
10
  return join(templatesRoot, "providers.json");
11
11
  }
12
- function loadProvidersCatalog(templatesRoot = defaultTemplatesRoot()) {
12
+ /** Provider catalog shared by `prism init` templates and the CLI's real-provider mode. */
13
+ export function loadProvidersCatalog(templatesRoot = defaultTemplatesRoot()) {
13
14
  if (cachedCatalog && templatesRoot === defaultTemplatesRoot())
14
15
  return cachedCatalog;
15
16
  const raw = JSON.parse(readFileSync(providersCatalogPath(templatesRoot), "utf8"));
@@ -34,16 +35,73 @@ export function listInitProviders(templatesRoot) {
34
35
  return cachedProviderIds;
35
36
  return Object.freeze([...loadProvidersCatalog(templatesRoot).keys()]);
36
37
  }
37
- export function getInitUsage(templatesRoot) {
38
+ /** Template list discovered from the templates gallery. */
39
+ export function listInitTemplates(galleryRoot = defaultGalleryRoot()) {
40
+ try {
41
+ const entries = readdirSync(galleryRoot, { withFileTypes: true });
42
+ const templates = [];
43
+ for (const entry of entries) {
44
+ if (entry.isDirectory()) {
45
+ const manifestPath = join(galleryRoot, entry.name, "manifest.json");
46
+ if (existsSync(manifestPath)) {
47
+ try {
48
+ const raw = JSON.parse(readFileSync(manifestPath, "utf8"));
49
+ if (raw && typeof raw === "object" && typeof raw.name === "string") {
50
+ templates.push({
51
+ name: raw.name,
52
+ description: typeof raw.description === "string" ? raw.description : "",
53
+ version: typeof raw.version === "string" ? raw.version : undefined,
54
+ path: join(galleryRoot, entry.name),
55
+ });
56
+ }
57
+ }
58
+ catch {
59
+ // skip invalid manifests
60
+ }
61
+ }
62
+ else if (entry.name === "init") {
63
+ templates.push({
64
+ name: "init",
65
+ description: "Minimal starter Prism agent with one selected provider and offline mock test",
66
+ path: join(galleryRoot, "init"),
67
+ });
68
+ }
69
+ }
70
+ }
71
+ return Object.freeze(templates.sort((a, b) => {
72
+ if (a.name === "init")
73
+ return -1;
74
+ if (b.name === "init")
75
+ return 1;
76
+ return a.name.localeCompare(b.name);
77
+ }));
78
+ }
79
+ catch {
80
+ return Object.freeze([
81
+ {
82
+ name: "init",
83
+ description: "Minimal starter Prism agent with one selected provider and offline mock test",
84
+ path: join(galleryRoot, "init"),
85
+ },
86
+ ]);
87
+ }
88
+ }
89
+ export function getInitUsage(templatesRoot, galleryRoot) {
38
90
  const providers = listInitProviders(templatesRoot).join("|");
91
+ const templates = listInitTemplates(galleryRoot)
92
+ .map((t) => t.name)
93
+ .join("|");
39
94
  return `Usage: prism init <dir> [options]
95
+ prism init --list-templates
40
96
 
41
- Create a minimal TypeScript Prism project with one explicit provider and an offline mock test.
97
+ Create a minimal TypeScript Prism project or scaffold from a template gallery.
42
98
 
43
99
  Arguments:
44
100
  <dir> Destination directory (created if missing)
45
101
 
46
102
  Options:
103
+ --template <name> Template name (${templates || "init|deep-research"}). Default: init
104
+ --list-templates List available templates from the gallery
47
105
  --provider <name> Provider id (${providers}). Default: mock
48
106
  --with-workflows Add optional workflows dependency and example
49
107
  --with-evals Add optional evals dependency and example
@@ -52,19 +110,24 @@ Options:
52
110
 
53
111
  Examples:
54
112
  prism init my-agent
113
+ prism init my-research --template deep-research
114
+ prism init --list-templates
55
115
  prism init my-agent --provider openai
56
116
  prism init my-agent --provider openai --with-workflows
57
117
  `;
58
118
  }
59
119
  export const initUsage = getInitUsage();
60
- export function parseInitArgs(argv, templatesRoot) {
120
+ export function parseInitArgs(argv, templatesRoot, galleryRoot) {
61
121
  let directory;
122
+ let template;
123
+ let listTemplates = false;
62
124
  let provider = "mock";
63
125
  let withWorkflows = false;
64
126
  let withEvals = false;
65
127
  let force = false;
66
128
  let help = false;
67
129
  const providers = listInitProviders(templatesRoot);
130
+ const availableTemplates = listInitTemplates(galleryRoot);
68
131
  for (let i = 0; i < argv.length; i += 1) {
69
132
  const arg = argv[i];
70
133
  if (arg === "-h" || arg === "--help") {
@@ -75,6 +138,10 @@ export function parseInitArgs(argv, templatesRoot) {
75
138
  force = true;
76
139
  continue;
77
140
  }
141
+ if (arg === "--list-templates") {
142
+ listTemplates = true;
143
+ continue;
144
+ }
78
145
  if (arg === "--with-workflows") {
79
146
  withWorkflows = true;
80
147
  continue;
@@ -83,6 +150,18 @@ export function parseInitArgs(argv, templatesRoot) {
83
150
  withEvals = true;
84
151
  continue;
85
152
  }
153
+ if (arg === "--template") {
154
+ const value = argv[i + 1];
155
+ if (value === undefined || value.startsWith("-")) {
156
+ throw new InitUsageError("Missing value for --template");
157
+ }
158
+ i += 1;
159
+ if (!availableTemplates.some((t) => t.name === value)) {
160
+ throw new InitUsageError(`Unknown template: ${value}. Expected one of ${availableTemplates.map((t) => t.name).join(", ")}`);
161
+ }
162
+ template = value;
163
+ continue;
164
+ }
86
165
  if (arg === "--provider") {
87
166
  const value = argv[i + 1];
88
167
  if (value === undefined || value.startsWith("-")) {
@@ -103,11 +182,13 @@ export function parseInitArgs(argv, templatesRoot) {
103
182
  }
104
183
  directory = arg;
105
184
  }
106
- if (!help && directory === undefined) {
185
+ if (!help && !listTemplates && directory === undefined) {
107
186
  throw new InitUsageError("Missing destination directory");
108
187
  }
109
188
  return {
110
189
  directory: directory ?? ".",
190
+ template,
191
+ listTemplates,
111
192
  provider,
112
193
  withWorkflows,
113
194
  withEvals,
@@ -118,20 +199,34 @@ export function parseInitArgs(argv, templatesRoot) {
118
199
  export async function runInitCommand(argv, runtime) {
119
200
  let options;
120
201
  try {
121
- options = parseInitArgs(argv, runtime.templatesRoot);
202
+ options = parseInitArgs(argv, runtime.templatesRoot, runtime.galleryRoot);
122
203
  }
123
204
  catch (error) {
124
- write(runtime.stderr, `${error instanceof Error ? error.message : String(error)}\n${getInitUsage(runtime.templatesRoot)}`);
205
+ write(runtime.stderr, `${error instanceof Error ? error.message : String(error)}\n${getInitUsage(runtime.templatesRoot, runtime.galleryRoot)}`);
125
206
  return 2;
126
207
  }
127
208
  if (options.help) {
128
- write(runtime.stdout, getInitUsage(runtime.templatesRoot));
209
+ write(runtime.stdout, getInitUsage(runtime.templatesRoot, runtime.galleryRoot));
210
+ return 0;
211
+ }
212
+ if (options.listTemplates) {
213
+ const templates = listInitTemplates(runtime.galleryRoot);
214
+ const lines = [
215
+ "Available templates:",
216
+ ...templates.map((t) => ` ${t.name.padEnd(16)} - ${t.description}`),
217
+ "",
218
+ "Usage:",
219
+ " prism init <dir> --template <name>",
220
+ "",
221
+ ];
222
+ write(runtime.stdout, lines.join("\n"));
129
223
  return 0;
130
224
  }
131
225
  try {
132
226
  const result = await createInitProject(options, runtime);
133
227
  write(runtime.stdout, [
134
228
  `Created Prism project in ${result.targetDir}`,
229
+ ...(result.template ? [` template: ${result.template}`] : []),
135
230
  ` provider: ${result.provider}`,
136
231
  ` files: ${result.writtenFiles.length}`,
137
232
  ` bytes: ${result.totalBytes}`,
@@ -149,7 +244,7 @@ export async function runInitCommand(argv, runtime) {
149
244
  catch (error) {
150
245
  const message = error instanceof Error ? error.message : String(error);
151
246
  if (error instanceof InitUsageError) {
152
- write(runtime.stderr, `${message}\n${getInitUsage(runtime.templatesRoot)}`);
247
+ write(runtime.stderr, `${message}\n${getInitUsage(runtime.templatesRoot, runtime.galleryRoot)}`);
153
248
  return 2;
154
249
  }
155
250
  write(runtime.stderr, `${message}\n`);
@@ -163,6 +258,7 @@ export async function createInitProject(options, runtime = {
163
258
  const cwd = runtime.cwd ?? process.cwd();
164
259
  const targetDir = resolveInitDirectory(options.directory, cwd);
165
260
  const templatesRoot = runtime.templatesRoot ?? defaultTemplatesRoot();
261
+ const galleryRoot = runtime.galleryRoot ?? defaultGalleryRoot();
166
262
  const version = runtime.packageVersion ?? (await readPackageVersion());
167
263
  const catalog = loadProvidersCatalog(templatesRoot);
168
264
  const provider = catalog.get(options.provider);
@@ -171,18 +267,38 @@ export async function createInitProject(options, runtime = {
171
267
  }
172
268
  const projectName = sanitizePackageName(basenameSafe(targetDir));
173
269
  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
- });
270
+ const isCustomTemplate = Boolean(options.template && options.template !== "init");
271
+ let planned;
272
+ let tokens;
273
+ if (isCustomTemplate) {
274
+ const templateName = options.template;
275
+ const templateDir = join(galleryRoot, templateName);
276
+ if (!(await exists(templateDir))) {
277
+ const available = listInitTemplates(galleryRoot);
278
+ throw new InitUsageError(`Unknown template: ${templateName}. Expected one of ${available.map((t) => t.name).join(", ")}`);
279
+ }
280
+ planned = await planTemplateFiles(templateDir);
281
+ tokens = buildTokensForTemplate({
282
+ projectName,
283
+ version,
284
+ templateName,
285
+ provider,
286
+ });
287
+ }
288
+ else {
289
+ tokens = buildTokens({
290
+ projectName,
291
+ version,
292
+ provider,
293
+ withWorkflows: options.withWorkflows,
294
+ withEvals: options.withEvals,
295
+ });
296
+ planned = await planFiles({
297
+ templatesRoot,
298
+ withWorkflows: options.withWorkflows,
299
+ withEvals: options.withEvals,
300
+ });
301
+ }
186
302
  if (!options.force) {
187
303
  for (const file of planned) {
188
304
  const dest = join(targetDir, file.relativePath);
@@ -206,6 +322,7 @@ export async function createInitProject(options, runtime = {
206
322
  return {
207
323
  targetDir,
208
324
  writtenFiles,
325
+ template: options.template,
209
326
  provider: options.provider,
210
327
  withWorkflows: options.withWorkflows,
211
328
  withEvals: options.withEvals,
@@ -215,8 +332,59 @@ export async function createInitProject(options, runtime = {
215
332
  export function defaultTemplatesRoot() {
216
333
  return join(dirname(fileURLToPath(import.meta.url)), "..", "templates", "init");
217
334
  }
218
- export function isInitProvider(value, templatesRoot) {
219
- return listInitProviders(templatesRoot).includes(value);
335
+ export function defaultGalleryRoot() {
336
+ return join(dirname(fileURLToPath(import.meta.url)), "..", "templates");
337
+ }
338
+ async function planTemplateFiles(templateDir) {
339
+ const files = [];
340
+ async function walk(dir, baseRel = "") {
341
+ const entries = await readdir(dir, { withFileTypes: true });
342
+ for (const entry of entries) {
343
+ const fullPath = join(dir, entry.name);
344
+ const relPath = baseRel ? `${baseRel}/${entry.name}` : entry.name;
345
+ if (entry.isDirectory()) {
346
+ await walk(fullPath, relPath);
347
+ }
348
+ else if (entry.isFile()) {
349
+ if (entry.name === "manifest.json")
350
+ continue;
351
+ let targetRel = relPath.endsWith(".tmpl") ? relPath.slice(0, -5) : relPath;
352
+ if (targetRel.startsWith("src/tests/")) {
353
+ targetRel = `src/__tests__/${targetRel.slice("src/tests/".length)}`;
354
+ }
355
+ files.push({ relativePath: targetRel, sourcePath: fullPath });
356
+ }
357
+ }
358
+ }
359
+ await walk(templateDir);
360
+ return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
361
+ }
362
+ function buildTokensForTemplate(input) {
363
+ const dependencies = {
364
+ "@arnilo/prism": input.version,
365
+ "@arnilo/prism-memory": input.version,
366
+ "@arnilo/prism-web-tools": input.version,
367
+ "@arnilo/prism-workflows": input.version,
368
+ };
369
+ const dependencyLines = Object.entries(dependencies)
370
+ .sort(([a], [b]) => a.localeCompare(b))
371
+ .map(([name, ver]) => ` ${JSON.stringify(name)}: ${JSON.stringify(ver)}`)
372
+ .join(",\n");
373
+ return {
374
+ __PROJECT_NAME__: input.projectName,
375
+ __PRISM_VERSION__: input.version,
376
+ __TEMPLATE_NAME__: input.templateName,
377
+ __PROVIDER_ID__: input.provider.id,
378
+ __PROVIDER_PACKAGE__: input.provider.packageName ?? "",
379
+ __DEPENDENCIES__: dependencyLines,
380
+ __PROVIDER_IMPORTS__: input.provider.imports,
381
+ __PROVIDER_EXPRESSION__: input.provider.providerExpression,
382
+ __MODEL_EXPRESSION__: input.provider.modelExpression,
383
+ __ENV_EXAMPLE__: "",
384
+ __NEXT_STEPS_LIVE__: "",
385
+ __OPTIONAL_DOCS__: "",
386
+ __PROVIDER_README_NOTE__: "",
387
+ };
220
388
  }
221
389
  function resolveInitDirectory(input, cwd) {
222
390
  const trimmed = input.trim();
@@ -49,7 +49,7 @@ export interface CliRuntime {
49
49
  readonly stdin: Readable;
50
50
  readonly stdout: Writable;
51
51
  readonly stderr: Writable;
52
- readonly createSession?: (options: CliOptions) => AgentSession;
52
+ readonly createSession?: (options: CliOptions) => AgentSession | Promise<AgentSession>;
53
53
  readonly commands?: RpcSessionFactory["commands"];
54
54
  /** Workspace root for `--discover`. Defaults to `process.cwd()`. */
55
55
  readonly workspaceRoot?: string;
@@ -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> Provider id from the init provider catalog ('mock' is built in;\n real providers need their @arnilo/prism-providers package +\n credential env var)\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>;