@aligndottech/cli 0.67.0 → 0.68.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 (119) hide show
  1. package/README.md +29 -8
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +5 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/capture.d.ts.map +1 -1
  6. package/dist/commands/capture.js +4 -0
  7. package/dist/commands/capture.js.map +1 -1
  8. package/dist/commands/check.d.ts +1 -5
  9. package/dist/commands/check.d.ts.map +1 -1
  10. package/dist/commands/check.js +1 -33
  11. package/dist/commands/check.js.map +1 -1
  12. package/dist/commands/default-action.d.ts.map +1 -1
  13. package/dist/commands/default-action.js +18 -7
  14. package/dist/commands/default-action.js.map +1 -1
  15. package/dist/commands/mcp.d.ts.map +1 -1
  16. package/dist/commands/mcp.js +2 -0
  17. package/dist/commands/mcp.js.map +1 -1
  18. package/dist/commands/setup.d.ts.map +1 -1
  19. package/dist/commands/setup.js +22 -13
  20. package/dist/commands/setup.js.map +1 -1
  21. package/dist/lib/agent/edit-gate.d.ts +30 -0
  22. package/dist/lib/agent/edit-gate.d.ts.map +1 -0
  23. package/dist/lib/agent/edit-gate.js +67 -0
  24. package/dist/lib/agent/edit-gate.js.map +1 -0
  25. package/dist/lib/agent/edit-text.d.ts +14 -0
  26. package/dist/lib/agent/edit-text.d.ts.map +1 -0
  27. package/dist/lib/agent/edit-text.js +34 -0
  28. package/dist/lib/agent/edit-text.js.map +1 -0
  29. package/dist/lib/agent/engines/claude-code-protocol.d.ts +24 -0
  30. package/dist/lib/agent/engines/claude-code-protocol.d.ts.map +1 -0
  31. package/dist/lib/agent/engines/claude-code-protocol.js +123 -0
  32. package/dist/lib/agent/engines/claude-code-protocol.js.map +1 -0
  33. package/dist/lib/agent/engines/claude-code.d.ts +17 -0
  34. package/dist/lib/agent/engines/claude-code.d.ts.map +1 -0
  35. package/dist/lib/agent/engines/claude-code.js +122 -0
  36. package/dist/lib/agent/engines/claude-code.js.map +1 -0
  37. package/dist/lib/agent/engines/pi-models.d.ts +46 -0
  38. package/dist/lib/agent/engines/pi-models.d.ts.map +1 -0
  39. package/dist/lib/agent/engines/pi-models.js +91 -0
  40. package/dist/lib/agent/engines/pi-models.js.map +1 -0
  41. package/dist/lib/agent/engines/pi-sdk.d.ts +39 -0
  42. package/dist/lib/agent/engines/pi-sdk.d.ts.map +1 -0
  43. package/dist/lib/agent/engines/pi-sdk.js +105 -0
  44. package/dist/lib/agent/engines/pi-sdk.js.map +1 -0
  45. package/dist/lib/agent/engines/pi.d.ts +44 -0
  46. package/dist/lib/agent/engines/pi.d.ts.map +1 -0
  47. package/dist/lib/agent/engines/pi.js +185 -0
  48. package/dist/lib/agent/engines/pi.js.map +1 -0
  49. package/dist/lib/agent/graph-tools.d.ts +23 -0
  50. package/dist/lib/agent/graph-tools.d.ts.map +1 -0
  51. package/dist/lib/agent/graph-tools.js +33 -0
  52. package/dist/lib/agent/graph-tools.js.map +1 -0
  53. package/dist/lib/agent/permission-broker.d.ts +25 -0
  54. package/dist/lib/agent/permission-broker.d.ts.map +1 -0
  55. package/dist/lib/agent/permission-broker.js +47 -0
  56. package/dist/lib/agent/permission-broker.js.map +1 -0
  57. package/dist/lib/agent/run-agent-session.d.ts +44 -0
  58. package/dist/lib/agent/run-agent-session.d.ts.map +1 -0
  59. package/dist/lib/agent/run-agent-session.js +137 -0
  60. package/dist/lib/agent/run-agent-session.js.map +1 -0
  61. package/dist/lib/agent/select-engine.d.ts +28 -0
  62. package/dist/lib/agent/select-engine.d.ts.map +1 -0
  63. package/dist/lib/agent/select-engine.js +14 -0
  64. package/dist/lib/agent/select-engine.js.map +1 -0
  65. package/dist/lib/agent/tui/app.d.ts +11 -0
  66. package/dist/lib/agent/tui/app.d.ts.map +1 -0
  67. package/dist/lib/agent/tui/app.js +122 -0
  68. package/dist/lib/agent/tui/app.js.map +1 -0
  69. package/dist/lib/agent/tui/cards.d.ts +16 -0
  70. package/dist/lib/agent/tui/cards.d.ts.map +1 -0
  71. package/dist/lib/agent/tui/cards.js +46 -0
  72. package/dist/lib/agent/tui/cards.js.map +1 -0
  73. package/dist/lib/agent/tui/controller.d.ts +21 -0
  74. package/dist/lib/agent/tui/controller.d.ts.map +1 -0
  75. package/dist/lib/agent/tui/controller.js +29 -0
  76. package/dist/lib/agent/tui/controller.js.map +1 -0
  77. package/dist/lib/agent/tui/theme.d.ts +11 -0
  78. package/dist/lib/agent/tui/theme.d.ts.map +1 -0
  79. package/dist/lib/agent/tui/theme.js +13 -0
  80. package/dist/lib/agent/tui/theme.js.map +1 -0
  81. package/dist/lib/agent/types.d.ts +81 -0
  82. package/dist/lib/agent/types.d.ts.map +1 -0
  83. package/dist/lib/agent/types.js +2 -0
  84. package/dist/lib/agent/types.js.map +1 -0
  85. package/dist/lib/commit-shape.d.ts +3 -1
  86. package/dist/lib/commit-shape.d.ts.map +1 -1
  87. package/dist/lib/commit-shape.js +8 -2
  88. package/dist/lib/commit-shape.js.map +1 -1
  89. package/dist/lib/config.d.ts +4 -0
  90. package/dist/lib/config.d.ts.map +1 -1
  91. package/dist/lib/config.js +17 -0
  92. package/dist/lib/config.js.map +1 -1
  93. package/dist/lib/doctor.d.ts +1 -1
  94. package/dist/lib/doctor.js +2 -2
  95. package/dist/lib/git.d.ts.map +1 -1
  96. package/dist/lib/git.js +4 -1
  97. package/dist/lib/git.js.map +1 -1
  98. package/dist/lib/launch/mcp-child-env.js +1 -1
  99. package/dist/lib/launch/mcp-child-env.js.map +1 -1
  100. package/dist/lib/launch/pi-state.d.ts.map +1 -1
  101. package/dist/lib/launch/pi-state.js +9 -3
  102. package/dist/lib/launch/pi-state.js.map +1 -1
  103. package/dist/lib/personal-import.d.ts +4 -0
  104. package/dist/lib/personal-import.d.ts.map +1 -1
  105. package/dist/lib/personal-import.js +4 -0
  106. package/dist/lib/personal-import.js.map +1 -1
  107. package/dist/lib/scope-real.d.ts +12 -0
  108. package/dist/lib/scope-real.d.ts.map +1 -1
  109. package/dist/lib/sync/real-env.d.ts +12 -0
  110. package/dist/lib/sync/real-env.d.ts.map +1 -1
  111. package/dist/lib/usage-telemetry.d.ts +1 -1
  112. package/dist/lib/usage-telemetry.d.ts.map +1 -1
  113. package/dist/lib/usage-telemetry.js +20 -2
  114. package/dist/lib/usage-telemetry.js.map +1 -1
  115. package/dist/lib/write-confirm.d.ts +13 -4
  116. package/dist/lib/write-confirm.d.ts.map +1 -1
  117. package/dist/lib/write-confirm.js +29 -10
  118. package/dist/lib/write-confirm.js.map +1 -1
  119. package/package.json +5 -2
@@ -0,0 +1,39 @@
1
+ import type { PiSdk } from './pi.js';
2
+ /**
3
+ * Where Align's own engine comes from.
4
+ *
5
+ * The engine is Pi's SDK plus the provider SDKs it pulls in, about 110 MB, so it is not in the
6
+ * npm install (install-smoke caps that at 100 MB; the UI library, ~3 MB, is). It is used from
7
+ * the bundle where there is one (the compiled binary, a dev checkout), else from a copy
8
+ * downloaded earlier, else downloaded once now with the person's yes - the same shape as the
9
+ * on-device embedding runtime. Users on their own Claude Code never download it.
10
+ */
11
+ export declare const PI_ENGINE_PACKAGES: readonly ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai"];
12
+ export declare const PI_ENGINE_VERSION: string;
13
+ export interface PiSdkDeps {
14
+ engineDir: string;
15
+ /** The engine bundled with this build, and its version when it can be read. */
16
+ importBundled: () => Promise<{
17
+ sdk: PiSdk;
18
+ version?: string;
19
+ }>;
20
+ importInstalled: (engineDir: string) => Promise<PiSdk>;
21
+ confirm: (message: string) => Promise<boolean>;
22
+ runNpm: (args: string[]) => Promise<number>;
23
+ out: (line: string) => void;
24
+ }
25
+ export declare function loadPiSdk(deps: PiSdkDeps): Promise<PiSdk>;
26
+ /**
27
+ * How to run npm. On Windows npm is npm.cmd, which needs a shell, and cmd.exe splits an unquoted
28
+ * argument at a space - a home directory like "Jo Smith" would break the install path.
29
+ */
30
+ export declare function npmCommand(platform: string, args: string[]): {
31
+ cmd: string;
32
+ args: string[];
33
+ shell: boolean;
34
+ };
35
+ export declare function defaultPiSdkDeps(o: {
36
+ engineDir: string;
37
+ confirm: (message: string) => Promise<boolean>;
38
+ }): PiSdkDeps;
39
+ //# sourceMappingURL=pi-sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-sdk.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/engines/pi-sdk.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;GAQG;AAEH,eAAO,MAAM,kBAAkB,uEAAwE,CAAC;AAQxG,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,OAAO,CAAC;QAAE,GAAG,EAAE,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAMD,wBAAsB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAgB/D;AA6BD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAG5G;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,CAepH"}
@@ -0,0 +1,105 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
+ import pkg from '../../../../package.json' with { type: 'json' };
6
+ /**
7
+ * Where Align's own engine comes from.
8
+ *
9
+ * The engine is Pi's SDK plus the provider SDKs it pulls in, about 110 MB, so it is not in the
10
+ * npm install (install-smoke caps that at 100 MB; the UI library, ~3 MB, is). It is used from
11
+ * the bundle where there is one (the compiled binary, a dev checkout), else from a copy
12
+ * downloaded earlier, else downloaded once now with the person's yes - the same shape as the
13
+ * on-device embedding runtime. Users on their own Claude Code never download it.
14
+ */
15
+ export const PI_ENGINE_PACKAGES = ['@earendil-works/pi-coding-agent', '@earendil-works/pi-ai'];
16
+ /** The exact versions this CLI was tested against: the devDependencies pins, one writer of each. */
17
+ function pinned(name) {
18
+ const version = pkg.devDependencies[name];
19
+ if (!version)
20
+ throw new Error(`package.json pins no version of ${name}`);
21
+ return version;
22
+ }
23
+ export const PI_ENGINE_VERSION = pinned(PI_ENGINE_PACKAGES[0]);
24
+ const attempt = async (load) => {
25
+ try {
26
+ return await load();
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ };
32
+ export async function loadPiSdk(deps) {
33
+ // A bundled Pi of another version (one installed beside Align, say) may lack what the engine
34
+ // uses, so only the pinned version counts. A build that cannot report its version (the compiled
35
+ // binary) counts when it has the API, so binary users are not sent to download what they have.
36
+ const bundled = await attempt(deps.importBundled);
37
+ const usable = bundled && (bundled.version === PI_ENGINE_VERSION || (bundled.version === undefined && typeof bundled.sdk.ModelRuntime === 'function'));
38
+ const ready = (usable ? bundled.sdk : undefined) ?? (await attempt(() => deps.importInstalled(deps.engineDir)));
39
+ if (ready)
40
+ return ready;
41
+ const yes = await deps.confirm('Align\'s own engine is a one-time download, about 110 MB. Download it now?');
42
+ if (!yes)
43
+ throw new Error('Align\'s own engine was not downloaded. Run align again to download it, or use --engine claude.');
44
+ deps.out(`Downloading Align's engine into ${deps.engineDir} ...`);
45
+ const code = await deps.runNpm(['install', '--prefix', deps.engineDir, '--no-audit', '--no-fund', '--loglevel=error',
46
+ ...PI_ENGINE_PACKAGES.map((name) => `${name}@${pinned(name)}`)]);
47
+ if (code !== 0)
48
+ throw new Error(`The engine download failed (npm exited ${code}). Check your connection and run align again.`);
49
+ return deps.importInstalled(deps.engineDir);
50
+ }
51
+ /** The ESM entry of a package installed under `engineDir`, read from its own exports map. */
52
+ function installedEntry(engineDir, name) {
53
+ const dir = join(engineDir, 'node_modules', ...name.split('/'));
54
+ const manifest = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
55
+ const root = manifest.exports?.['.'];
56
+ const entry = typeof root === 'string' ? root
57
+ : root?.['import'] ?? root?.['default'] ?? manifest.main;
58
+ const file = typeof entry === 'string' ? entry : entry?.['default'];
59
+ if (typeof file !== 'string')
60
+ throw new Error(`${name} in ${engineDir} has no entry point`);
61
+ return join(dir, file);
62
+ }
63
+ /** The version of the bundled engine, read from its package.json; undefined when it cannot be found. */
64
+ function bundledVersion() {
65
+ try {
66
+ let dir = dirname(fileURLToPath(import.meta.resolve(PI_ENGINE_PACKAGES[0])));
67
+ for (let i = 0; i < 6; i++) {
68
+ try {
69
+ const m = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
70
+ if (m.name === PI_ENGINE_PACKAGES[0])
71
+ return m.version;
72
+ }
73
+ catch { /* keep walking up */ }
74
+ dir = dirname(dir);
75
+ }
76
+ }
77
+ catch { /* not resolvable here */ }
78
+ return undefined;
79
+ }
80
+ /**
81
+ * How to run npm. On Windows npm is npm.cmd, which needs a shell, and cmd.exe splits an unquoted
82
+ * argument at a space - a home directory like "Jo Smith" would break the install path.
83
+ */
84
+ export function npmCommand(platform, args) {
85
+ if (platform !== 'win32')
86
+ return { cmd: 'npm', args, shell: false };
87
+ return { cmd: 'npm.cmd', args: args.map((a) => (/[\s"&|<>^]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a)), shell: true };
88
+ }
89
+ export function defaultPiSdkDeps(o) {
90
+ return {
91
+ engineDir: o.engineDir,
92
+ // A literal specifier, so the compiled binary bundles the engine and never downloads it.
93
+ importBundled: async () => ({ sdk: await import('@earendil-works/pi-coding-agent'), version: bundledVersion() }),
94
+ importInstalled: async (dir) => (await import(pathToFileURL(installedEntry(dir, PI_ENGINE_PACKAGES[0])).href)),
95
+ confirm: o.confirm,
96
+ runNpm: (args) => new Promise((resolve) => {
97
+ const npm = npmCommand(process.platform, args);
98
+ const child = spawn(npm.cmd, npm.args, { stdio: 'inherit', shell: npm.shell });
99
+ child.on('error', () => resolve(127));
100
+ child.on('exit', (code) => resolve(code ?? 1));
101
+ }),
102
+ out: (l) => process.stderr.write(`${l}\n`),
103
+ };
104
+ }
105
+ //# sourceMappingURL=pi-sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-sdk.js","sourceRoot":"","sources":["../../../../src/lib/agent/engines/pi-sdk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type * as PiCodingAgent from '@earendil-works/pi-coding-agent';
2
+ import type { DefaultResourceLoader, ExtensionFactory } from '@earendil-works/pi-coding-agent';
3
+ import type { GraphToolSpec } from '../graph-tools.js';
4
+ import type { AgentEngine, BrokerVerdict, ToolAsk } from '../types.js';
5
+ import type { ResolvedPiModel } from './pi-models.js';
6
+ /**
7
+ * The loader the Align engine runs on. A repository is untrusted input: Pi would otherwise load
8
+ * `<cwd>/.pi/extensions`, skills, prompt templates and themes, run them with the user's full
9
+ * permissions, and read `<cwd>/.pi/settings.json` for more. So none of that is discovered. The
10
+ * settings are in-memory as well, so no project or home settings file reaches the session (the
11
+ * hostile-repo test shows noExtensions already covers the settings route; this is the second
12
+ * lock). Context files (AGENTS.md, CLAUDE.md) stay on: they are text, and the agent should
13
+ * follow a repo's own notes.
14
+ */
15
+ /** The parts of Pi's SDK the engine uses. */
16
+ export type PiSdk = Pick<typeof PiCodingAgent, 'DefaultResourceLoader' | 'ModelRuntime' | 'createAgentSession' | 'SessionManager' | 'SettingsManager'>;
17
+ export declare function createAlignResourceLoader(o: {
18
+ sdk: PiSdk;
19
+ cwd: string;
20
+ agentDir: string;
21
+ systemPrompt?: string;
22
+ extensionFactories?: ExtensionFactory[];
23
+ }): DefaultResourceLoader;
24
+ type BrokerFn = (ask: ToolAsk) => Promise<BrokerVerdict>;
25
+ /**
26
+ * The one inline extension: every tool call waits on the broker, and a denial blocks the call with
27
+ * the broker's message, which Pi hands back to the model as the tool result. Fails CLOSED: no broker
28
+ * yet (start() not called) or a broker that throws blocks the call, because "I could not ask" must
29
+ * never read as "allowed".
30
+ */
31
+ export declare function createToolGate(getBroker: () => BrokerFn | undefined, cwd: string): ExtensionFactory;
32
+ export interface PiEngineDeps {
33
+ sdk: PiSdk;
34
+ /** The module boundary tests inject, so nothing calls a provider. */
35
+ createAgentSession?: PiSdk['createAgentSession'];
36
+ }
37
+ export declare function createPiEngine(opts: {
38
+ cwd: string;
39
+ stateDir: string;
40
+ model: ResolvedPiModel;
41
+ tools: GraphToolSpec[];
42
+ }, deps: PiEngineDeps): Promise<AgentEngine>;
43
+ export {};
44
+ //# sourceMappingURL=pi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/engines/pi.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,aAAa,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAkB,MAAM,iCAAiC,CAAC;AAE/G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAgB,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAkBtD;;;;;;;;GAQG;AACH,6CAA6C;AAC7C,MAAM,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,aAAa,EAAE,uBAAuB,GAAG,cAAc,GAAG,oBAAoB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC,CAAC;AAEvJ,wBAAgB,yBAAyB,CAAC,CAAC,EAAE;IAC3C,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACzC,GAAG,qBAAqB,CAYxB;AA0BD,KAAK,QAAQ,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,QAAQ,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAanG;AAkBD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,KAAK,CAAC;IACX,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;CAClD;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,EACvF,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,WAAW,CAAC,CA6FtB"}
@@ -0,0 +1,185 @@
1
+ import { join, resolve } from 'node:path';
2
+ /**
3
+ * Align's engine on Pi. EVERY Pi type stays in this file: Pi's minors break often, and the gate,
4
+ * the broker and the UI only ever see the port in ../types.ts.
5
+ */
6
+ const ALIGN_AGENT_SYSTEM_PROMPT = [
7
+ "You are Align's coding agent. You work in the user's repository with read, bash, edit, write, grep, find and ls.",
8
+ 'You also have tools that read the team\'s decision graph: align_ask, align_search, align_get_topic_timeline and align_get_related_decisions.',
9
+ 'Ask the graph before you change behaviour a past decision may cover. Quote a decision by its title when it matters.',
10
+ 'Every edit is checked against the graph before it is written. If an edit is stopped, read the reason, say what it means, and change course. Do not retry the same edit.',
11
+ 'Follow the repository\'s own notes (AGENTS.md, CLAUDE.md). Keep answers short and plain.',
12
+ ].join('\n');
13
+ const BUILTIN_TOOLS = ['read', 'bash', 'edit', 'write', 'grep', 'find', 'ls'];
14
+ const READ_TOOLS = new Set(['read', 'grep', 'find', 'ls']);
15
+ export function createAlignResourceLoader(o) {
16
+ return new o.sdk.DefaultResourceLoader({
17
+ cwd: o.cwd,
18
+ agentDir: o.agentDir,
19
+ settingsManager: o.sdk.SettingsManager.inMemory(),
20
+ noExtensions: true,
21
+ noSkills: true,
22
+ noPromptTemplates: true,
23
+ noThemes: true,
24
+ systemPrompt: o.systemPrompt,
25
+ extensionFactories: o.extensionFactories,
26
+ });
27
+ }
28
+ const str = (v) => (typeof v === 'string' ? v : undefined);
29
+ /** Pi's tool call, in Align's vocabulary. Paths resolve against the working directory, as Pi's own tools do. */
30
+ function toToolAsk(id, tool, input, cwd) {
31
+ const abs = (p) => (p === undefined ? undefined : resolve(cwd, p));
32
+ if (tool === 'write') {
33
+ const edit = { file_path: abs(str(input['path'])), content: str(input['content']) };
34
+ return { id, tool, kind: 'edit', edit };
35
+ }
36
+ if (tool === 'edit') {
37
+ const edits = Array.isArray(input['edits']) ? input['edits'] : [];
38
+ const edit = {
39
+ file_path: abs(str(input['path'])),
40
+ edits: edits.map((e) => ({ old_string: str(e['oldText']), new_string: str(e['newText']) })),
41
+ };
42
+ return { id, tool, kind: 'edit', edit };
43
+ }
44
+ if (tool === 'bash' || tool === 'powershell')
45
+ return { id, tool, kind: 'command', command: str(input['command']) ?? '' };
46
+ // Align's own graph tools (all named align_*) only read the local graph, so they never interrupt.
47
+ if (READ_TOOLS.has(tool) || tool.startsWith('align_'))
48
+ return { id, tool, kind: 'read' };
49
+ return { id, tool, kind: 'other', detail: JSON.stringify(input) };
50
+ }
51
+ /**
52
+ * The one inline extension: every tool call waits on the broker, and a denial blocks the call with
53
+ * the broker's message, which Pi hands back to the model as the tool result. Fails CLOSED: no broker
54
+ * yet (start() not called) or a broker that throws blocks the call, because "I could not ask" must
55
+ * never read as "allowed".
56
+ */
57
+ export function createToolGate(getBroker, cwd) {
58
+ return (pi) => {
59
+ pi.on('tool_call', async (event) => {
60
+ try {
61
+ const broker = getBroker();
62
+ if (!broker)
63
+ return { block: true, reason: 'Align has not finished starting its edit check, so this call was stopped.' };
64
+ const verdict = await broker(toToolAsk(event.toolCallId, event.toolName, event.input, cwd));
65
+ return verdict.allow ? undefined : { block: true, reason: verdict.message };
66
+ }
67
+ catch (err) {
68
+ return { block: true, reason: `Align's edit check failed (${err instanceof Error ? err.message : String(err)}), so this call was stopped.` };
69
+ }
70
+ });
71
+ };
72
+ }
73
+ function graphToolDefinition(spec) {
74
+ return {
75
+ name: spec.name,
76
+ label: spec.name,
77
+ description: spec.description,
78
+ // The MCP inputSchema is plain JSON Schema, which is what a TypeBox schema is at runtime.
79
+ parameters: spec.parameters,
80
+ async execute(_id, params) {
81
+ const text = await spec.run(params);
82
+ return { content: [{ type: 'text', text }], details: undefined };
83
+ },
84
+ };
85
+ }
86
+ const summaryOf = (args) => str(args?.['command']) ?? str(args?.['path']) ?? str(args?.['file_path']) ?? '';
87
+ export async function createPiEngine(opts, deps) {
88
+ const { sdk } = deps;
89
+ const create = deps.createAgentSession ?? sdk.createAgentSession;
90
+ const agentDir = join(opts.stateDir, 'agent');
91
+ let broker;
92
+ let onEvent = () => { };
93
+ // No network at startup, and no login: the key is set in-process from what the user gave Align.
94
+ // Pi's login is never called, so no subscription sign-in is reachable from here.
95
+ const modelRuntime = await sdk.ModelRuntime.create({
96
+ authPath: join(agentDir, 'auth.json'),
97
+ modelsPath: join(agentDir, 'models.json'),
98
+ refreshOnCreate: false,
99
+ });
100
+ const { provider, modelId, apiKey, baseUrl } = opts.model;
101
+ if (provider === 'ollama') {
102
+ modelRuntime.registerProvider('ollama', {
103
+ baseUrl,
104
+ api: 'openai-completions',
105
+ apiKey: apiKey ?? 'ollama',
106
+ models: [{
107
+ id: modelId, name: modelId, input: ['text'], reasoning: false,
108
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
109
+ contextWindow: 32_768, maxTokens: 8_192,
110
+ }],
111
+ });
112
+ }
113
+ else if (apiKey) {
114
+ await modelRuntime.setRuntimeApiKey(provider, apiKey);
115
+ }
116
+ const model = modelRuntime.getModel(provider, modelId);
117
+ if (!model)
118
+ throw new Error(`Pi does not know the model ${provider}/${modelId}.`);
119
+ const resourceLoader = createAlignResourceLoader({
120
+ sdk,
121
+ cwd: opts.cwd,
122
+ agentDir,
123
+ systemPrompt: ALIGN_AGENT_SYSTEM_PROMPT,
124
+ extensionFactories: [createToolGate(() => broker, opts.cwd)],
125
+ });
126
+ await resourceLoader.reload();
127
+ const { session } = await create({
128
+ cwd: opts.cwd,
129
+ agentDir,
130
+ model,
131
+ modelRuntime,
132
+ resourceLoader,
133
+ settingsManager: sdk.SettingsManager.inMemory(),
134
+ sessionManager: sdk.SessionManager.inMemory(opts.cwd),
135
+ tools: [...BUILTIN_TOOLS, ...opts.tools.map((t) => t.name)],
136
+ customTools: opts.tools.map(graphToolDefinition),
137
+ });
138
+ let turnEnded = false;
139
+ const endTurn = () => { turnEnded = true; onEvent({ type: 'turn-end' }); };
140
+ return {
141
+ label: opts.model.label,
142
+ async start(emit, ask) {
143
+ onEvent = emit;
144
+ broker = ask;
145
+ session.subscribe((e) => {
146
+ if (e.type === 'message_update') {
147
+ if (e.assistantMessageEvent.type === 'text_delta')
148
+ onEvent({ type: 'text', delta: e.assistantMessageEvent.delta });
149
+ }
150
+ else if (e.type === 'tool_execution_start') {
151
+ onEvent({ type: 'tool-start', id: e.toolCallId, tool: e.toolName, summary: summaryOf(e.args) });
152
+ }
153
+ else if (e.type === 'tool_execution_end') {
154
+ onEvent({ type: 'tool-end', id: e.toolCallId, ok: !e.isError });
155
+ }
156
+ else if (e.type === 'agent_end' && !e.willRetry) {
157
+ // A provider failure (bad key, no credit) arrives as a message that ended in error, and
158
+ // without this it would read as an empty turn.
159
+ const last = [...e.messages].reverse().find((m) => m['role'] === 'assistant');
160
+ if (last?.['stopReason'] === 'error')
161
+ onEvent({ type: 'error', message: str(last['errorMessage']) ?? 'The model call failed.' });
162
+ endTurn();
163
+ }
164
+ });
165
+ },
166
+ async prompt(text) {
167
+ turnEnded = false;
168
+ try {
169
+ await session.prompt(text);
170
+ }
171
+ catch (err) {
172
+ onEvent({ type: 'error', message: err instanceof Error ? err.message : String(err) });
173
+ if (!turnEnded)
174
+ endTurn();
175
+ }
176
+ },
177
+ abort() {
178
+ void session.abort();
179
+ },
180
+ async close() {
181
+ session.dispose();
182
+ },
183
+ };
184
+ }
185
+ //# sourceMappingURL=pi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../../../src/lib/agent/engines/pi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { EnvironmentConfig } from '../config.js';
2
+ import type { createGatewayClient } from '../gateway-client.js';
3
+ /**
4
+ * The decision-graph tools the Align engine hands its model, as engine-neutral specs. An engine
5
+ * adapter turns each spec into its own tool type, so no engine's types leak in here.
6
+ *
7
+ * Every tool goes through dispatchTool, the router `align mcp` serves, so an agent asking from
8
+ * inside `align` gets the answers an agent asking over MCP gets. These are the four READ tools
9
+ * an agent reaches for; align_capture and the other writers stay out of the agent's hands.
10
+ */
11
+ export interface GraphToolSpec {
12
+ name: string;
13
+ description: string;
14
+ /** JSON Schema, copied from TOOL_SCHEMAS so there is one writer of what a tool takes. */
15
+ parameters: Record<string, unknown>;
16
+ run(args: Record<string, unknown>): Promise<string>;
17
+ }
18
+ export interface GraphToolDeps {
19
+ client: ReturnType<typeof createGatewayClient>;
20
+ env: EnvironmentConfig;
21
+ }
22
+ export declare function createGraphTools({ client, env }: GraphToolDeps): GraphToolSpec[];
23
+ //# sourceMappingURL=graph-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-tools.d.ts","sourceRoot":"","sources":["../../../src/lib/agent/graph-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGhE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;IAC/C,GAAG,EAAE,iBAAiB,CAAC;CACxB;AAID,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,aAAa,GAAG,aAAa,EAAE,CA2BhF"}
@@ -0,0 +1,33 @@
1
+ import { dispatchTool, isFirstUsefulToolResult, serializeMcpResult, TOOL_SCHEMAS } from '../../commands/mcp.js';
2
+ import { recordFunnelStage } from '../usage-telemetry.js';
3
+ const GRAPH_TOOL_NAMES = ['align_ask', 'align_search', 'align_get_topic_timeline', 'align_get_related_decisions'];
4
+ export function createGraphTools({ client, env }) {
5
+ // One flag per tool set, so first_useful_decision is offered once per session. The
6
+ // once-per-install guard is recordFunnelStage's; this only stops a chatty session re-offering.
7
+ let recordedFirstUseful = false;
8
+ // The local graph has no topic timeline (the local client cannot serve it), so the local
9
+ // engine is not offered a tool that would only fail.
10
+ const names = GRAPH_TOOL_NAMES.filter((n) => !(env.mode === 'local-embedded' && n === 'align_get_topic_timeline'));
11
+ return names.map((name) => {
12
+ const schema = TOOL_SCHEMAS.find((s) => s.name === name);
13
+ if (!schema)
14
+ throw new Error(`graph tool ${name} is not in TOOL_SCHEMAS`);
15
+ return {
16
+ name,
17
+ description: schema.description,
18
+ parameters: schema.inputSchema,
19
+ async run(args) {
20
+ const result = await dispatchTool(name, args, client, env);
21
+ if (!recordedFirstUseful && isFirstUsefulToolResult(name, result)) {
22
+ recordedFirstUseful = true;
23
+ // Not awaited: a tool response never waits on telemetry (same as createCallToolHandler).
24
+ void recordFunnelStage(env, 'first_useful_decision', 'mcp');
25
+ }
26
+ // Any successful graph call is use, as in the MCP handler; recordFunnelStage keeps it to once a day.
27
+ void recordFunnelStage(env, 'agent_active', 'mcp');
28
+ return serializeMcpResult(result);
29
+ },
30
+ };
31
+ });
32
+ }
33
+ //# sourceMappingURL=graph-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-tools.js","sourceRoot":"","sources":["../../../src/lib/agent/graph-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAuB1D,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,cAAc,EAAE,0BAA0B,EAAE,6BAA6B,CAAU,CAAC;AAE3H,MAAM,UAAU,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAiB;IAC7D,mFAAmF;IACnF,+FAA+F;IAC/F,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,yFAAyF;IACzF,qDAAqD;IACrD,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,KAAK,0BAA0B,CAAC,CAAC,CAAC;IACnH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,yBAAyB,CAAC,CAAC;QAC1E,OAAO;YACL,IAAI;YACJ,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,UAAU,EAAE,MAAM,CAAC,WAAsC;YACzD,KAAK,CAAC,GAAG,CAAC,IAAI;gBACZ,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;gBAC3D,IAAI,CAAC,mBAAmB,IAAI,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;oBAClE,mBAAmB,GAAG,IAAI,CAAC;oBAC3B,yFAAyF;oBACzF,KAAK,iBAAiB,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,CAAC,CAAC;gBAC9D,CAAC;gBACD,qGAAqG;gBACrG,KAAK,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;gBACnD,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { BrokerVerdict, GateOutcome, HumanAnswer, ToolAsk } from './types.js';
2
+ /**
3
+ * Who has to approve a tool call, for both engines. Edits go through the edit gate and reach a
4
+ * person only when the gate asks; commands always reach a person unless they allowed that command
5
+ * for this session; reads never do. A denial carries a message written for the MODEL, because the
6
+ * engine hands it back as the tool result - that is how "stop" turns into the agent changing course.
7
+ */
8
+ export type HumanQuestion = {
9
+ kind: 'gate';
10
+ outcome: Extract<GateOutcome, {
11
+ kind: 'ask';
12
+ }>;
13
+ ask: ToolAsk;
14
+ } | {
15
+ kind: 'command';
16
+ command: string;
17
+ ask: ToolAsk;
18
+ };
19
+ export interface BrokerDeps {
20
+ gate: (ask: ToolAsk) => Promise<GateOutcome>;
21
+ askHuman: (q: HumanQuestion) => Promise<HumanAnswer>;
22
+ onGate: (outcome: GateOutcome, ask: ToolAsk) => void;
23
+ }
24
+ export declare function createBroker(deps: BrokerDeps): (ask: ToolAsk) => Promise<BrokerVerdict>;
25
+ //# sourceMappingURL=permission-broker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-broker.d.ts","sourceRoot":"","sources":["../../../src/lib/agent/permission-broker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAgB,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjG;;;;;GAKG;AAEH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD;AAkBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,aAAa,CAAC,CA6BvF"}
@@ -0,0 +1,47 @@
1
+ /** Only an explicit yes allows. An answer this code does not know (a future key, a cancel) is a stop. */
2
+ const allows = (a) => a === 'allow' || a === 'allow-session';
3
+ function decisionLine(d) {
4
+ return [`- ${d.title}`, d.why ? ` - ${d.why}` : '', d.url ? ` (${d.url})` : ''].join('');
5
+ }
6
+ function stopMessage(outcome) {
7
+ const lead = {
8
+ conflict: 'Align: the person stopped this edit. It conflicts with a recorded decision:',
9
+ 'rewrites-decided-lines': 'Align: the person stopped this edit. It changes lines written by a recorded decision:',
10
+ unchecked: 'Align: the person stopped this edit. Align could not read it to check it against the decisions.',
11
+ }[outcome.reason];
12
+ return [lead, ...outcome.cards.map(decisionLine), 'Do not retry this edit. Ask the person how they want to proceed.'].join('\n');
13
+ }
14
+ export function createBroker(deps) {
15
+ // "Yes for this session" remembers the EXACT command, or the tool by name. A prefix match let
16
+ // an allowed `git status` approve `git status; rm -rf ~` (security review).
17
+ const sessionAllowed = new Set();
18
+ return async (ask) => {
19
+ if (ask.kind === 'read')
20
+ return { allow: true };
21
+ if (ask.kind === 'edit') {
22
+ const outcome = await deps.gate(ask);
23
+ deps.onGate(outcome, ask);
24
+ if (outcome.kind === 'allow')
25
+ return { allow: true };
26
+ const answer = await deps.askHuman({ kind: 'gate', outcome, ask });
27
+ return allows(answer) ? { allow: true } : { allow: false, message: stopMessage(outcome) };
28
+ }
29
+ // A command, or a tool this code does not know (WebFetch, an MCP tool, a subagent): a person decides.
30
+ // An unknown tool is approved for its input, not its name: a yes to one URL is not a yes to all.
31
+ // The question shows the WHOLE input: approval covers all of it, so none may hide past a cut.
32
+ const label = ask.kind === 'command' ? (ask.command ?? '') : [ask.tool, ask.detail].filter(Boolean).join(' ');
33
+ const key = ask.kind === 'command' ? `command:${label}` : `other:${ask.tool}:${ask.detail ?? ''}`;
34
+ if (sessionAllowed.has(key))
35
+ return { allow: true };
36
+ const answer = await deps.askHuman({ kind: 'command', command: label, ask });
37
+ if (!allows(answer)) {
38
+ return { allow: false, message: ask.kind === 'command'
39
+ ? `Align: the person declined to run \`${label}\`. Ask them before trying another way.`
40
+ : `Align: the person declined the ${ask.tool} tool. Ask them before trying another way.` };
41
+ }
42
+ if (answer === 'allow-session')
43
+ sessionAllowed.add(key);
44
+ return { allow: true };
45
+ };
46
+ }
47
+ //# sourceMappingURL=permission-broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-broker.js","sourceRoot":"","sources":["../../../src/lib/agent/permission-broker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { type ClaudeCodeOpts } from './engines/claude-code.js';
2
+ import { type ResolvedPiModel } from './engines/pi-models.js';
3
+ import { type GraphToolSpec } from './graph-tools.js';
4
+ import { type EngineName } from './select-engine.js';
5
+ import { type AgentUiOptions } from './tui/app.js';
6
+ import type { AgentEngine, GateOutcome, ToolAsk } from './types.js';
7
+ /**
8
+ * The composition root for Align's own agent: picks the engine, builds the edit gate over the
9
+ * local graph, and hands both to Align's UI. Everything with a side effect is a dependency, so
10
+ * the wiring is tested without a terminal, a provider or a `claude` binary.
11
+ */
12
+ export interface SessionDeps {
13
+ cwd: string;
14
+ env: Record<string, string | undefined>;
15
+ startupEnv: Readonly<Record<string, string | undefined>>;
16
+ out: (line: string) => void;
17
+ getRemembered: () => EngineName | undefined;
18
+ remember: (engine: EngineName) => void;
19
+ resolveModel: () => Promise<ResolvedPiModel | undefined>;
20
+ findClaude: () => string | null;
21
+ projectState: () => {
22
+ projectHasMcp: boolean;
23
+ projectHasBlock: boolean;
24
+ };
25
+ makeGate: () => (ask: ToolAsk) => Promise<GateOutcome>;
26
+ graphTools: () => GraphToolSpec[];
27
+ countDecisions: () => number;
28
+ loadPiEngine: () => Promise<{
29
+ createPiEngine: (o: {
30
+ cwd: string;
31
+ stateDir: string;
32
+ model: ResolvedPiModel;
33
+ tools: GraphToolSpec[];
34
+ }) => Promise<AgentEngine>;
35
+ }>;
36
+ createClaudeCodeEngine: (o: ClaudeCodeOpts) => AgentEngine;
37
+ runAgentUi: (o: AgentUiOptions) => Promise<number>;
38
+ record: (agent: 'align' | 'claude-code') => void;
39
+ }
40
+ export declare function runAgentSession(opts: {
41
+ engine?: EngineName;
42
+ }, deps?: SessionDeps): Promise<number>;
43
+ export declare function defaultSessionDeps(): SessionDeps;
44
+ //# sourceMappingURL=run-agent-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent-session.d.ts","sourceRoot":"","sources":["../../../src/lib/agent/run-agent-session.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,KAAK,cAAc,EAAc,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACzD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,UAAU,GAAG,SAAS,CAAC;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IACzD,UAAU,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;IACzE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,aAAa,EAAE,CAAC;IAClC,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,cAAc,EAAE,CAAC,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,eAAe,CAAC;YAAC,KAAK,EAAE,aAAa,EAAE,CAAA;SAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;KAAE,CAAC,CAAC;IAChK,sBAAsB,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,WAAW,CAAC;IAC3D,UAAU,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,KAAK,IAAI,CAAC;CAClD;AAsBD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,IAAI,GAAE,WAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC9H;AAED,wBAAgB,kBAAkB,IAAI,WAAW,CA8ChD"}