@bastani/atomic 0.8.17-0 → 0.8.18-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 (53) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +5 -0
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/CHANGELOG.md +5 -0
  5. package/dist/builtin/mcp/package.json +1 -1
  6. package/dist/builtin/subagents/CHANGELOG.md +5 -0
  7. package/dist/builtin/subagents/package.json +1 -1
  8. package/dist/builtin/web-access/CHANGELOG.md +5 -0
  9. package/dist/builtin/web-access/package.json +1 -1
  10. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  11. package/dist/builtin/workflows/README.md +62 -3
  12. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +555 -537
  13. package/dist/builtin/workflows/builtin/goal.ts +5 -0
  14. package/dist/builtin/workflows/builtin/open-claude-design.ts +3 -3
  15. package/dist/builtin/workflows/builtin/ralph.ts +737 -713
  16. package/dist/builtin/workflows/builtin/shared-prompts.ts +11 -0
  17. package/dist/builtin/workflows/package.json +1 -1
  18. package/dist/builtin/workflows/src/extension/discovery.ts +61 -22
  19. package/dist/builtin/workflows/src/extension/index.ts +2 -0
  20. package/dist/builtin/workflows/src/extension/runtime.ts +4 -0
  21. package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -0
  22. package/dist/builtin/workflows/src/runs/foreground/executor.ts +96 -6
  23. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +2 -0
  24. package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +7 -0
  25. package/dist/builtin/workflows/src/runs/shared/worktree.ts +214 -1
  26. package/dist/builtin/workflows/src/sdk-surface.ts +2 -0
  27. package/dist/builtin/workflows/src/shared/types.ts +32 -3
  28. package/dist/builtin/workflows/src/workflows/define-workflow.ts +18 -1
  29. package/dist/core/agent-session-services.d.ts +2 -1
  30. package/dist/core/agent-session-services.d.ts.map +1 -1
  31. package/dist/core/agent-session-services.js +1 -0
  32. package/dist/core/agent-session-services.js.map +1 -1
  33. package/dist/core/agent-session.d.ts +3 -0
  34. package/dist/core/agent-session.d.ts.map +1 -1
  35. package/dist/core/agent-session.js +16 -5
  36. package/dist/core/agent-session.js.map +1 -1
  37. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  38. package/dist/core/atomic-guide-command.js +40 -28
  39. package/dist/core/atomic-guide-command.js.map +1 -1
  40. package/dist/core/sdk.d.ts +9 -1
  41. package/dist/core/sdk.d.ts.map +1 -1
  42. package/dist/core/sdk.js +2 -2
  43. package/dist/core/sdk.js.map +1 -1
  44. package/dist/core/system-prompt.d.ts +2 -0
  45. package/dist/core/system-prompt.d.ts.map +1 -1
  46. package/dist/core/system-prompt.js +22 -13
  47. package/dist/core/system-prompt.js.map +1 -1
  48. package/docs/quickstart.md +13 -5
  49. package/docs/sdk.md +20 -5
  50. package/docs/workflows.md +44 -17
  51. package/examples/sdk/05-tools.ts +22 -1
  52. package/examples/sdk/README.md +7 -3
  53. package/package.json +1 -1
@@ -71,6 +71,24 @@ interface GitResult {
71
71
  stdout: string;
72
72
  stderr: string;
73
73
  status: number | null;
74
+ error?: Error;
75
+ }
76
+
77
+ export interface GitWorktreeSetupOptions {
78
+ gitWorktreeDir: string;
79
+ baseBranch?: string;
80
+ cwd: string;
81
+ }
82
+
83
+ export interface GitWorktreeSetupResult {
84
+ /** Root checkout path that was requested/created/reused. */
85
+ worktreeRoot: string;
86
+ /** Effective workflow cwd, preserving the caller's repo-relative subdirectory inside the worktree. */
87
+ cwd: string;
88
+ /** Invoking checkout root reported by Git. */
89
+ repositoryRoot: string;
90
+ /** Whether this call created a new linked worktree. Existing roots are reused as-is. */
91
+ created: boolean;
74
92
  }
75
93
 
76
94
  interface RepoState {
@@ -80,13 +98,26 @@ interface RepoState {
80
98
  }
81
99
 
82
100
  const DEFAULT_WORKTREE_SETUP_HOOK_TIMEOUT_MS = 30000;
101
+ const DISABLED_GIT_HOOKS_PATH = process.platform === "win32" ? "NUL" : "/dev/null";
83
102
 
84
103
  function runGit(cwd: string, args: string[]): GitResult {
85
- const result = spawnSync("git", ["-C", cwd, ...args], { encoding: "utf-8" });
104
+ const result = spawnSync("git", [
105
+ "-c",
106
+ `core.hooksPath=${DISABLED_GIT_HOOKS_PATH}`,
107
+ "-c",
108
+ "core.fsmonitor=false",
109
+ ...args,
110
+ ], {
111
+ cwd,
112
+ encoding: "utf-8",
113
+ env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" },
114
+ timeout: 5000,
115
+ });
86
116
  return {
87
117
  stdout: result.stdout ?? "",
88
118
  stderr: result.stderr ?? "",
89
119
  status: result.status,
120
+ ...(result.error === undefined ? {} : { error: result.error }),
90
121
  };
91
122
  }
92
123
 
@@ -100,6 +131,188 @@ function runGitChecked(cwd: string, args: string[]): string {
100
131
  return result.stdout;
101
132
  }
102
133
 
134
+ function gitFailureMessage(result: GitResult): string {
135
+ if (result.error !== undefined) return result.error.message;
136
+ return result.stderr.trim() || result.stdout.trim() || `git exited with status ${result.status}`;
137
+ }
138
+
139
+ function quoteShellArg(value: string): string {
140
+ if (process.platform === "win32") return `"${value.replace(/"/g, "\"\"")}"`;
141
+ return `'${value.replace(/'/g, "'\\''")}'`;
142
+ }
143
+
144
+ function worktreeRecoveryCommand(repositoryRoot: string, worktreeDir: string): string {
145
+ return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
146
+ }
147
+
148
+ function hasGrandparent(value: string): boolean {
149
+ const parent = path.dirname(value);
150
+ if (parent === value) return false;
151
+ const grandparent = path.dirname(parent);
152
+ return grandparent !== parent;
153
+ }
154
+
155
+ function pathAncestors(value: string): string[] {
156
+ const ancestors: string[] = [];
157
+ let current = value;
158
+ while (true) {
159
+ ancestors.push(current);
160
+ const parent = path.dirname(current);
161
+ if (parent === current) return ancestors;
162
+ current = parent;
163
+ }
164
+ }
165
+
166
+ function shouldPreserveLogicalPath(logicalPath: string): boolean {
167
+ return pathAncestors(logicalPath).some((ancestor) => {
168
+ try {
169
+ return fs.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
170
+ } catch {
171
+ return false;
172
+ }
173
+ });
174
+ }
175
+
176
+ function canonicalizePreservingSymlinks(value: string): string {
177
+ const logicalPath = path.resolve(value);
178
+ const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
179
+ try {
180
+ const canonical = fs.realpathSync.native(logicalPath);
181
+ return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
182
+ } catch {
183
+ return logicalPath;
184
+ }
185
+ }
186
+
187
+ function resolveGitWorktreePath(value: string, repoRoot: string): string {
188
+ const trimmed = value.trim();
189
+ if (!trimmed) throw new Error("gitWorktreeDir cannot be empty");
190
+ if (trimmed.includes("\0")) {
191
+ throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
192
+ }
193
+ return canonicalizePreservingSymlinks(path.isAbsolute(trimmed) ? trimmed : path.resolve(repoRoot, trimmed));
194
+ }
195
+
196
+ function comparableRealPath(value: string): string {
197
+ const realpath = fs.realpathSync.native(value).replace(/\\/g, "/");
198
+ return process.platform === "win32" ? realpath.toLowerCase() : realpath;
199
+ }
200
+
201
+ function gitPathFromOutput(value: string, cwd: string): string | undefined {
202
+ const trimmed = value.trim();
203
+ if (!trimmed) return undefined;
204
+ return path.isAbsolute(trimmed) ? path.resolve(trimmed) : path.resolve(cwd, trimmed);
205
+ }
206
+
207
+ function pathExistsSync(value: string): boolean {
208
+ try {
209
+ fs.statSync(value);
210
+ return true;
211
+ } catch (error) {
212
+ const code = error && typeof error === "object" && "code" in error ? (error as { code?: unknown }).code : undefined;
213
+ if (code === "ENOENT" || code === "ENOTDIR") return false;
214
+ throw error;
215
+ }
216
+ }
217
+
218
+ function repositoryRootForGitWorktree(cwd: string): string {
219
+ const result = runGit(cwd, ["rev-parse", "--show-toplevel"]);
220
+ if (result.status !== 0) {
221
+ throw new Error(`gitWorktreeDir requires the workflow to be invoked from inside a Git repository. Start from a Git checkout or omit gitWorktreeDir. Git reported: ${gitFailureMessage(result)}`);
222
+ }
223
+ return result.stdout.trim();
224
+ }
225
+
226
+ function gitTopLevel(cwd: string): string | undefined {
227
+ const result = runGit(cwd, ["rev-parse", "--show-toplevel"]);
228
+ if (result.status !== 0) return undefined;
229
+ return gitPathFromOutput(result.stdout, cwd);
230
+ }
231
+
232
+ function gitCommonDirForWorktree(cwd: string): string {
233
+ const result = runGit(cwd, ["rev-parse", "--git-common-dir"]);
234
+ if (result.status !== 0) throw new Error(gitFailureMessage(result));
235
+ const gitPath = gitPathFromOutput(result.stdout, cwd);
236
+ if (gitPath === undefined) throw new Error("git rev-parse --git-common-dir returned an empty path");
237
+ return gitPath;
238
+ }
239
+
240
+ function dirnameForEachRelativeComponent(base: string, relativePath: string): string | undefined {
241
+ if (relativePath === "") return base;
242
+ let current = base;
243
+ for (const component of relativePath.split(/[\\/]+/).filter(Boolean)) {
244
+ if (component === ".") continue;
245
+ if (component === "..") return undefined;
246
+ current = path.dirname(current);
247
+ }
248
+ return current;
249
+ }
250
+
251
+ function cwdWithinGitRepository(cwd: string, repoRoot: string): { relativeCwd: string; logicalRepoRoot: string } {
252
+ const sourceCwd = fs.realpathSync.native(cwd);
253
+ const sourceRepoRoot = fs.realpathSync.native(repoRoot);
254
+ const relativeCwd = path.relative(sourceRepoRoot, sourceCwd);
255
+ const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path.isAbsolute(relativeCwd) ? "" : relativeCwd;
256
+ const logicalCwd = canonicalizePreservingSymlinks(cwd);
257
+ return {
258
+ relativeCwd: safeRelativeCwd,
259
+ logicalRepoRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot,
260
+ };
261
+ }
262
+
263
+ function workspaceCwdForGitWorktreeRoot(worktreeRoot: string, relativeCwd: string): string {
264
+ return relativeCwd === "" ? worktreeRoot : path.join(worktreeRoot, relativeCwd);
265
+ }
266
+
267
+ function validateExistingGitWorktreeRoot(worktreeRoot: string, repoRoot: string): void {
268
+ const topLevel = gitTopLevel(worktreeRoot);
269
+ if (topLevel === undefined) {
270
+ throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
271
+ }
272
+ if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
273
+ throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
274
+ }
275
+ if (comparableRealPath(gitCommonDirForWorktree(repoRoot)) !== comparableRealPath(gitCommonDirForWorktree(topLevel))) {
276
+ throw new Error(`gitWorktreeDir already exists but does not belong to the invoking Git repository: ${worktreeRoot}`);
277
+ }
278
+ }
279
+
280
+ export function setupGitWorktree(options: GitWorktreeSetupOptions): GitWorktreeSetupResult {
281
+ const repoRoot = repositoryRootForGitWorktree(options.cwd);
282
+ const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
283
+ const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
284
+ if (pathExistsSync(worktreeRoot)) {
285
+ validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
286
+ return {
287
+ worktreeRoot,
288
+ cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
289
+ repositoryRoot: repoRoot,
290
+ created: false,
291
+ };
292
+ }
293
+
294
+ try {
295
+ fs.mkdirSync(path.dirname(worktreeRoot), { recursive: true });
296
+ } catch (error) {
297
+ const message = error instanceof Error ? error.message : String(error);
298
+ throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
299
+ }
300
+ const baseRef = options.baseBranch?.trim() || "HEAD";
301
+ const result = runGit(repoRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
302
+ if (result.status !== 0) {
303
+ throw new Error([
304
+ `Failed to create git worktree at requested gitWorktreeDir ${worktreeRoot} from ${baseRef}. Git reported: ${gitFailureMessage(result)}`,
305
+ `If another process just created this same-repository worktree, rerun the workflow to resume it. If this is an orphaned worktree from an interrupted run, recover or remove it with: ${worktreeRecoveryCommand(repoRoot, worktreeRoot)}`,
306
+ ].join("\n"));
307
+ }
308
+ return {
309
+ worktreeRoot,
310
+ cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
311
+ repositoryRoot: repoRoot,
312
+ created: true,
313
+ };
314
+ }
315
+
103
316
  function resolveRepoState(cwd: string): RepoState {
104
317
  const cwdRelative = resolveRepoCwdRelative(cwd);
105
318
  const toplevel = runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim();
@@ -18,6 +18,8 @@ export type { RunOpts, RunResult, ResolvedInputs } from "./runs/foreground/execu
18
18
  export type { AgentSessionAdapter, StageAdapters } from "./runs/foreground/stage-runner.js";
19
19
  export { GraphFrontierTracker } from "./runs/shared/graph-inference.js";
20
20
  export type { StageNode } from "./runs/shared/graph-inference.js";
21
+ export { setupGitWorktree } from "./runs/shared/worktree.js";
22
+ export type { GitWorktreeSetupOptions, GitWorktreeSetupResult } from "./runs/shared/worktree.js";
21
23
  export { createStore, store } from "./shared/store.js";
22
24
  export type { RunStatus, StageStatus, ToolEvent, StageSnapshot, RunSnapshot, StoreSnapshot, WorkflowNotice, NoticeLevel, WorkflowOverlayAdapter, PromptKind, PendingPrompt } from "./shared/store-types.js";
23
25
 
@@ -140,13 +140,17 @@ export interface StageMcpOptions {
140
140
  /**
141
141
  * Options accepted by WorkflowRunContext.stage(name, options?).
142
142
  * All pi SDK createAgentSession options are forwarded to the stage session;
143
- * `mcp` remains workflow-owned and is stripped before SDK session creation.
143
+ * workflow-owned options such as `mcp` and `gitWorktreeDir` are stripped before SDK session creation.
144
144
  */
145
145
  export interface StageOptions extends Omit<CreateAgentSessionOptions, "model">, WorkflowModelFallbackFields {
146
146
  /** Model id or pi SDK model object used as the primary stage model. */
147
147
  model?: WorkflowModelValue;
148
148
  /** Per-stage MCP server gating. No-op when no WorkflowMcpPort is configured. */
149
149
  mcp?: StageMcpOptions;
150
+ /** Reusable Git worktree root. Defaults this stage cwd to the corresponding worktree cwd unless cwd is explicitly provided. */
151
+ gitWorktreeDir?: string;
152
+ /** Git ref used when creating gitWorktreeDir. Defaults to HEAD. */
153
+ baseBranch?: string;
150
154
  /**
151
155
  * Override the session log directory for this stage.
152
156
  * Converted to a pi SessionManager before createAgentSession() is called.
@@ -271,8 +275,12 @@ export interface WorkflowSharedTaskDefaults extends StageOptions {
271
275
  outputMode?: WorkflowOutputMode;
272
276
  /** Files the task should read before responding; relative paths resolve via chainDir for chains, otherwise cwd. */
273
277
  reads?: readonly string[] | false;
274
- /** Workflow-owned isolation flag; not forwarded to createAgentSession(). */
278
+ /** Workflow-owned temporary isolation flag; not forwarded to createAgentSession(). */
275
279
  worktree?: boolean;
280
+ /** Reusable Git worktree root. Defaults cwd to the corresponding worktree cwd unless cwd is explicitly provided. */
281
+ gitWorktreeDir?: string;
282
+ /** Git ref used when creating gitWorktreeDir. Defaults to HEAD. */
283
+ baseBranch?: string;
276
284
  /** Default output truncation limits for steps that do not set one. */
277
285
  maxOutput?: WorkflowMaxOutput;
278
286
  /** Whether to include debug artifacts such as sessions and worktree diffs. */
@@ -400,8 +408,12 @@ export interface WorkflowTaskSessionFields {
400
408
  output?: string | false;
401
409
  outputMode?: WorkflowOutputMode;
402
410
  reads?: readonly string[] | false;
403
- /** Workflow-owned isolation flag; not forwarded to createAgentSession(). */
411
+ /** Workflow-owned temporary isolation flag; not forwarded to createAgentSession(). */
404
412
  worktree?: boolean;
413
+ /** Reusable Git worktree root. Defaults cwd to the corresponding worktree cwd unless cwd is explicitly provided. */
414
+ gitWorktreeDir?: string;
415
+ /** Git ref used when creating gitWorktreeDir. Defaults to HEAD. */
416
+ baseBranch?: string;
405
417
  maxOutput?: WorkflowMaxOutput;
406
418
  /** Whether to include debug artifacts such as sessions and worktree diffs. */
407
419
  artifacts?: boolean;
@@ -421,6 +433,8 @@ export interface WorkflowParallelChainStep {
421
433
  readonly concurrency?: number;
422
434
  readonly failFast?: boolean;
423
435
  readonly worktree?: boolean;
436
+ readonly gitWorktreeDir?: string;
437
+ readonly baseBranch?: string;
424
438
  }
425
439
 
426
440
  export type WorkflowChainStep = WorkflowDirectTaskItem | WorkflowParallelChainStep;
@@ -438,6 +452,8 @@ export interface WorkflowDirectOptions extends StageOptions {
438
452
  output?: string | false;
439
453
  outputMode?: WorkflowOutputMode;
440
454
  worktree?: boolean;
455
+ gitWorktreeDir?: string;
456
+ baseBranch?: string;
441
457
  maxOutput?: WorkflowMaxOutput;
442
458
  artifacts?: boolean;
443
459
  }
@@ -505,6 +521,8 @@ export interface StageContext {
505
521
  export interface WorkflowRunContext<TInputs extends Record<string, unknown> = Record<string, unknown>> {
506
522
  /** Typed inputs provided by the caller, validated against the input schema. */
507
523
  readonly inputs: TInputs;
524
+ /** Invocation working directory for workflow-owned artifacts. Defaults to the host process cwd when omitted. */
525
+ readonly cwd?: string;
508
526
  /**
509
527
  * Create and register a named stage synchronously. Stage work starts when
510
528
  * a stage method such as prompt() or complete() is awaited; the executor
@@ -571,6 +589,15 @@ export type WorkflowRunFn<TInputs extends Record<string, unknown> = Record<strin
571
589
  // Compiled workflow definition
572
590
  // ---------------------------------------------------------------------------
573
591
 
592
+ export interface WorkflowWorktreeInputBinding {
593
+ readonly gitWorktreeDir: string;
594
+ readonly baseBranch?: string;
595
+ }
596
+
597
+ export interface WorkflowInputBindings {
598
+ readonly worktree?: WorkflowWorktreeInputBinding;
599
+ }
600
+
574
601
  export interface WorkflowDefinition<TInputs extends Record<string, unknown> = Record<string, unknown>> {
575
602
  /** Sentinel consumed by the registry loader to validate the export. */
576
603
  readonly __piWorkflow: true;
@@ -579,5 +606,7 @@ export interface WorkflowDefinition<TInputs extends Record<string, unknown> = Re
579
606
  readonly normalizedName: string;
580
607
  readonly description: string;
581
608
  readonly inputs: Readonly<Record<string, WorkflowInputSchema>>;
609
+ /** Optional input-to-runtime defaults declared by the workflow builder. */
610
+ readonly inputBindings?: WorkflowInputBindings;
582
611
  readonly run: WorkflowRunFn<TInputs>;
583
612
  }
@@ -8,7 +8,7 @@
8
8
  * cross-ref: v0.x packages/atomic-sdk/src/define-workflow.ts
9
9
  */
10
10
 
11
- import type { WorkflowDefinition, WorkflowInputSchema, WorkflowRunFn } from "../shared/types.js";
11
+ import type { WorkflowDefinition, WorkflowInputBindings, WorkflowInputSchema, WorkflowRunFn, WorkflowWorktreeInputBinding } from "../shared/types.js";
12
12
  import { normalizeWorkflowName } from "./identity.js";
13
13
 
14
14
  // ---------------------------------------------------------------------------
@@ -19,6 +19,7 @@ interface BuilderState<TInputs extends Record<string, unknown>> {
19
19
  readonly name: string;
20
20
  readonly description: string;
21
21
  readonly inputs: Readonly<Record<string, WorkflowInputSchema>>;
22
+ readonly inputBindings: WorkflowInputBindings;
22
23
  readonly runFn: WorkflowRunFn<TInputs> | undefined;
23
24
  }
24
25
 
@@ -45,6 +46,8 @@ export interface WorkflowBuilder<TInputs extends Record<string, unknown> = Recor
45
46
  key: K,
46
47
  schema: WorkflowInputSchema,
47
48
  ): WorkflowBuilder<TInputs & Record<K, unknown>>;
49
+ /** Bind workflow inputs to reusable git worktree runtime defaults. */
50
+ worktreeFromInputs(binding: WorkflowWorktreeInputBinding): WorkflowBuilder<TInputs>;
48
51
  /** Seal the run function. Returns a builder on which .compile() is available. */
49
52
  run(fn: WorkflowRunFn<TInputs>): CompletedWorkflowBuilder<TInputs>;
50
53
  }
@@ -59,6 +62,7 @@ export interface CompletedWorkflowBuilder<TInputs extends Record<string, unknown
59
62
  key: K,
60
63
  schema: WorkflowInputSchema,
61
64
  ): CompletedWorkflowBuilder<TInputs & Record<K, unknown>>;
65
+ worktreeFromInputs(binding: WorkflowWorktreeInputBinding): CompletedWorkflowBuilder<TInputs>;
62
66
  run(fn: WorkflowRunFn<TInputs>): CompletedWorkflowBuilder<TInputs>;
63
67
  /** Freeze and return the completed WorkflowDefinition. */
64
68
  compile(): WorkflowDefinition<TInputs>;
@@ -83,6 +87,16 @@ function makeBuilder<TInputs extends Record<string, unknown>>(
83
87
  } as BuilderState<TInputs & Record<K, unknown>>);
84
88
  },
85
89
 
90
+ worktreeFromInputs(binding: WorkflowWorktreeInputBinding) {
91
+ return makeBuilder<TInputs>({
92
+ ...state,
93
+ inputBindings: {
94
+ ...state.inputBindings,
95
+ worktree: { ...binding },
96
+ },
97
+ });
98
+ },
99
+
86
100
  run(fn: WorkflowRunFn<TInputs>) {
87
101
  return makeBuilder<TInputs>({ ...state, runFn: fn });
88
102
  },
@@ -98,6 +112,7 @@ function makeBuilder<TInputs extends Record<string, unknown>>(
98
112
 
99
113
  // Deep-freeze inputs map first, then the top-level definition.
100
114
  const frozenInputs = Object.freeze({ ...state.inputs });
115
+ const inputBindings = Object.freeze({ ...state.inputBindings });
101
116
 
102
117
  const definition: WorkflowDefinition<TInputs> = {
103
118
  __piWorkflow: true,
@@ -105,6 +120,7 @@ function makeBuilder<TInputs extends Record<string, unknown>>(
105
120
  normalizedName,
106
121
  description: state.description,
107
122
  inputs: frozenInputs,
123
+ ...(Object.keys(inputBindings).length > 0 ? { inputBindings } : {}),
108
124
  run: state.runFn,
109
125
  };
110
126
 
@@ -143,6 +159,7 @@ export function defineWorkflow(name: string): WorkflowBuilder {
143
159
  name,
144
160
  description: "",
145
161
  inputs: {},
162
+ inputBindings: {},
146
163
  runFn: undefined,
147
164
  };
148
165
 
@@ -50,7 +50,8 @@ export interface CreateAgentSessionFromServicesOptions {
50
50
  model: Model<Api>;
51
51
  thinkingLevel?: ThinkingLevel;
52
52
  }>;
53
- tools?: string[];
53
+ tools?: CreateAgentSessionOptions["tools"];
54
+ excludeTools?: CreateAgentSessionOptions["excludeTools"];
54
55
  noTools?: CreateAgentSessionOptions["noTools"];
55
56
  customTools?: ToolDefinition[];
56
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-services.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAyB,KAAK,4BAA4B,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrH,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,wBAAwB,EAAsB,MAAM,UAAU,CAAC;AAC7G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iCAAiC;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;IACpD,qBAAqB,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,KAAK,GAAG,UAAU,GAAG,iBAAiB,CAAC,CAAC;CACnG;AAED;;;;;GAKG;AACH,MAAM,WAAW,qCAAqC;IACrD,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,aAAa,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IAC3E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,6BAA6B,EAAE,CAAC;CAC7C;AAkDD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC/C,OAAO,EAAE,iCAAiC,GACxC,OAAO,CAAC,oBAAoB,CAAC,CAuC/B;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CACnD,OAAO,EAAE,qCAAqC,GAC5C,OAAO,CAAC,wBAAwB,CAAC,CAiBnC","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.ts\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<Api>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = resolvePath(options.cwd);\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agent-session-services.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAyB,KAAK,4BAA4B,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrH,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,wBAAwB,EAAsB,MAAM,UAAU,CAAC;AAC7G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iCAAiC;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;IACpD,qBAAqB,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,KAAK,GAAG,UAAU,GAAG,iBAAiB,CAAC,CAAC;CACnG;AAED;;;;;GAKG;AACH,MAAM,WAAW,qCAAqC;IACrD,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,aAAa,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IAC3E,KAAK,CAAC,EAAE,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC3C,YAAY,CAAC,EAAE,yBAAyB,CAAC,cAAc,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,6BAA6B,EAAE,CAAC;CAC7C;AAkDD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC/C,OAAO,EAAE,iCAAiC,GACxC,OAAO,CAAC,oBAAoB,CAAC,CAuC/B;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CACnD,OAAO,EAAE,qCAAqC,GAC5C,OAAO,CAAC,wBAAwB,CAAC,CAkBnC","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.ts\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<Api>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\ttools?: CreateAgentSessionOptions[\"tools\"];\n\texcludeTools?: CreateAgentSessionOptions[\"excludeTools\"];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = resolvePath(options.cwd);\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\ttools: options.tools,\n\t\texcludeTools: options.excludeTools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
@@ -110,6 +110,7 @@ export async function createAgentSessionFromServices(options) {
110
110
  thinkingLevel: options.thinkingLevel,
111
111
  scopedModels: options.scopedModels,
112
112
  tools: options.tools,
113
+ excludeTools: options.excludeTools,
113
114
  noTools: options.noTools,
114
115
  customTools: options.customTools,
115
116
  sessionStartEvent: options.sessionStartEvent,
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-services.js","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.ts\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<Api>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\ttools?: string[];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = resolvePath(options.cwd);\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\ttools: options.tools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
1
+ {"version":3,"file":"agent-session-services.js","sourceRoot":"","sources":["../../src/core/agent-session-services.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport type { SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { DefaultResourceLoader, type DefaultResourceLoaderOptions, type ResourceLoader } from \"./resource-loader.ts\";\nimport { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession } from \"./sdk.ts\";\nimport type { SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * Non-fatal issues collected while creating services or sessions.\n *\n * Runtime creation returns diagnostics to the caller instead of printing or\n * exiting. The app layer decides whether warnings should be shown and whether\n * errors should abort startup.\n */\nexport interface AgentSessionRuntimeDiagnostic {\n\ttype: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\n/**\n * Inputs for creating cwd-bound runtime services.\n *\n * These services are recreated whenever the effective session cwd changes.\n * CLI-provided resource paths should be resolved to absolute paths before they\n * reach this function, so later cwd switches do not reinterpret them.\n */\nexport interface CreateAgentSessionServicesOptions {\n\tcwd: string;\n\tagentDir?: string;\n\tauthStorage?: AuthStorage;\n\tsettingsManager?: SettingsManager;\n\tmodelRegistry?: ModelRegistry;\n\textensionFlagValues?: Map<string, boolean | string>;\n\tresourceLoaderOptions?: Omit<DefaultResourceLoaderOptions, \"cwd\" | \"agentDir\" | \"settingsManager\">;\n}\n\n/**\n * Inputs for creating an AgentSession from already-created services.\n *\n * Use this after services exist and any cwd-bound model/tool/session options\n * have been resolved against those services.\n */\nexport interface CreateAgentSessionFromServicesOptions {\n\tservices: AgentSessionServices;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tmodel?: Model<Api>;\n\tthinkingLevel?: ThinkingLevel;\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\ttools?: CreateAgentSessionOptions[\"tools\"];\n\texcludeTools?: CreateAgentSessionOptions[\"excludeTools\"];\n\tnoTools?: CreateAgentSessionOptions[\"noTools\"];\n\tcustomTools?: ToolDefinition[];\n}\n\n/**\n * Coherent cwd-bound runtime services for one effective session cwd.\n *\n * This is infrastructure only. The AgentSession itself is created separately so\n * session options can be resolved against these services first.\n */\nexport interface AgentSessionServices {\n\tcwd: string;\n\tagentDir: string;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tresourceLoader: ResourceLoader;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nfunction applyExtensionFlagValues(\n\tresourceLoader: ResourceLoader,\n\textensionFlagValues: Map<string, boolean | string> | undefined,\n): AgentSessionRuntimeDiagnostic[] {\n\tif (!extensionFlagValues) {\n\t\treturn [];\n\t}\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tconst registeredFlags = new Map<string, { type: \"boolean\" | \"string\" }>();\n\tfor (const extension of extensionsResult.extensions) {\n\t\tfor (const [name, flag] of extension.flags) {\n\t\t\tregisteredFlags.set(name, { type: flag.type });\n\t\t}\n\t}\n\n\tconst unknownFlags: string[] = [];\n\tfor (const [name, value] of extensionFlagValues) {\n\t\tconst flag = registeredFlags.get(name);\n\t\tif (!flag) {\n\t\t\tunknownFlags.push(name);\n\t\t\tcontinue;\n\t\t}\n\t\tif (flag.type === \"boolean\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\textensionsResult.runtime.flagValues.set(name, value);\n\t\t\tcontinue;\n\t\t}\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Extension flag \"--${name}\" requires a value`,\n\t\t});\n\t}\n\n\tif (unknownFlags.length > 0) {\n\t\tdiagnostics.push({\n\t\t\ttype: \"error\",\n\t\t\tmessage: `Unknown option${unknownFlags.length === 1 ? \"\" : \"s\"}: ${unknownFlags.map((name) => `--${name}`).join(\", \")}`,\n\t\t});\n\t}\n\n\treturn diagnostics;\n}\n\n/**\n * Create cwd-bound runtime services.\n *\n * Returns services plus diagnostics. It does not create an AgentSession.\n */\nexport async function createAgentSessionServices(\n\toptions: CreateAgentSessionServicesOptions,\n): Promise<AgentSessionServices> {\n\tconst cwd = resolvePath(options.cwd);\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();\n\tconst authStorage = options.authStorage ?? AuthStorage.create(join(agentDir, \"auth.json\"));\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, join(agentDir, \"models.json\"));\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\t...(options.resourceLoaderOptions ?? {}),\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t});\n\tawait resourceLoader.reload();\n\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tconst extensionsResult = resourceLoader.getExtensions();\n\tfor (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {\n\t\ttry {\n\t\t\tmodelRegistry.registerProvider(name, config);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `Extension \"${extensionPath}\" error: ${message}`,\n\t\t\t});\n\t\t}\n\t}\n\textensionsResult.runtime.pendingProviderRegistrations = [];\n\tdiagnostics.push(...applyExtensionFlagValues(resourceLoader, options.extensionFlagValues));\n\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tauthStorage,\n\t\tsettingsManager,\n\t\tmodelRegistry,\n\t\tresourceLoader,\n\t\tdiagnostics,\n\t};\n}\n\n/**\n * Create an AgentSession from previously created services.\n *\n * This keeps session creation separate from service creation so callers can\n * resolve model, thinking, tools, and other session inputs against the target\n * cwd before constructing the session.\n */\nexport async function createAgentSessionFromServices(\n\toptions: CreateAgentSessionFromServicesOptions,\n): Promise<CreateAgentSessionResult> {\n\treturn createAgentSession({\n\t\tcwd: options.services.cwd,\n\t\tagentDir: options.services.agentDir,\n\t\tauthStorage: options.services.authStorage,\n\t\tsettingsManager: options.services.settingsManager,\n\t\tmodelRegistry: options.services.modelRegistry,\n\t\tresourceLoader: options.services.resourceLoader,\n\t\tsessionManager: options.sessionManager,\n\t\tmodel: options.model,\n\t\tthinkingLevel: options.thinkingLevel,\n\t\tscopedModels: options.scopedModels,\n\t\ttools: options.tools,\n\t\texcludeTools: options.excludeTools,\n\t\tnoTools: options.noTools,\n\t\tcustomTools: options.customTools,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n}\n"]}
@@ -96,6 +96,8 @@ export interface AgentSessionConfig {
96
96
  initialActiveToolNames?: string[];
97
97
  /** Optional allowlist of tool names. When provided, only these tool names are exposed. */
98
98
  allowedToolNames?: string[];
99
+ /** Optional blocklist of tool names. Matching names are omitted from the final exposed registry. */
100
+ excludedToolNames?: string[];
99
101
  /**
100
102
  * Override base tools (useful for custom runtimes).
101
103
  *
@@ -188,6 +190,7 @@ export declare class AgentSession {
188
190
  private _extensionRunnerRef?;
189
191
  private _initialActiveToolNames?;
190
192
  private _allowedToolNames?;
193
+ private _excludedToolNames?;
191
194
  private _baseToolsOverride?;
192
195
  private _sessionStartEvent;
193
196
  private _extensionUIContext?;