@agent-loom/loom 1.0.2 → 1.0.3

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 (145) hide show
  1. package/README.md +69 -0
  2. package/dist/acp/client.d.ts +182 -0
  3. package/dist/acp/client.d.ts.map +1 -0
  4. package/dist/acp/client.js +432 -0
  5. package/dist/acp/client.js.map +1 -0
  6. package/dist/acp/index.d.ts +5 -0
  7. package/dist/acp/index.d.ts.map +1 -0
  8. package/dist/acp/index.js +3 -0
  9. package/dist/acp/index.js.map +1 -0
  10. package/dist/acp/run.d.ts +41 -0
  11. package/dist/acp/run.d.ts.map +1 -0
  12. package/dist/acp/run.js +32 -0
  13. package/dist/acp/run.js.map +1 -0
  14. package/dist/apply.d.ts +15 -6
  15. package/dist/apply.d.ts.map +1 -1
  16. package/dist/apply.js +78 -49
  17. package/dist/apply.js.map +1 -1
  18. package/dist/chat/chat.d.ts +108 -0
  19. package/dist/chat/chat.d.ts.map +1 -0
  20. package/dist/chat/chat.js +221 -0
  21. package/dist/chat/chat.js.map +1 -0
  22. package/dist/chat/discovery.d.ts +30 -0
  23. package/dist/chat/discovery.d.ts.map +1 -0
  24. package/dist/chat/discovery.js +68 -0
  25. package/dist/chat/discovery.js.map +1 -0
  26. package/dist/chat/frontmatter.d.ts +12 -0
  27. package/dist/chat/frontmatter.d.ts.map +1 -0
  28. package/dist/chat/frontmatter.js +11 -0
  29. package/dist/chat/frontmatter.js.map +1 -0
  30. package/dist/chat/index.d.ts +16 -0
  31. package/dist/chat/index.d.ts.map +1 -0
  32. package/dist/chat/index.js +11 -0
  33. package/dist/chat/index.js.map +1 -0
  34. package/dist/chat/registry.d.ts +73 -0
  35. package/dist/chat/registry.d.ts.map +1 -0
  36. package/dist/chat/registry.js +118 -0
  37. package/dist/chat/registry.js.map +1 -0
  38. package/dist/chat/resolve-agent.d.ts +39 -0
  39. package/dist/chat/resolve-agent.d.ts.map +1 -0
  40. package/dist/chat/resolve-agent.js +36 -0
  41. package/dist/chat/resolve-agent.js.map +1 -0
  42. package/dist/chat/suggest.d.ts +20 -0
  43. package/dist/chat/suggest.d.ts.map +1 -0
  44. package/dist/chat/suggest.js +55 -0
  45. package/dist/chat/suggest.js.map +1 -0
  46. package/dist/cli.js +627 -75
  47. package/dist/cli.js.map +1 -1
  48. package/dist/clone.d.ts +21 -3
  49. package/dist/clone.d.ts.map +1 -1
  50. package/dist/clone.js +240 -12
  51. package/dist/clone.js.map +1 -1
  52. package/dist/copilot/mcp.d.ts +48 -0
  53. package/dist/copilot/mcp.d.ts.map +1 -0
  54. package/dist/copilot/mcp.js +146 -0
  55. package/dist/copilot/mcp.js.map +1 -0
  56. package/dist/copilot/resolve.d.ts +33 -0
  57. package/dist/copilot/resolve.d.ts.map +1 -0
  58. package/dist/copilot/resolve.js +96 -0
  59. package/dist/copilot/resolve.js.map +1 -0
  60. package/dist/copilot/spawn.d.ts +51 -0
  61. package/dist/copilot/spawn.d.ts.map +1 -0
  62. package/dist/copilot/spawn.js +132 -0
  63. package/dist/copilot/spawn.js.map +1 -0
  64. package/dist/index.d.ts +19 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +15 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/launch/index.d.ts +10 -0
  69. package/dist/launch/index.d.ts.map +1 -0
  70. package/dist/launch/index.js +9 -0
  71. package/dist/launch/index.js.map +1 -0
  72. package/dist/launch/stage.d.ts +62 -0
  73. package/dist/launch/stage.d.ts.map +1 -0
  74. package/dist/launch/stage.js +108 -0
  75. package/dist/launch/stage.js.map +1 -0
  76. package/dist/manifest.d.ts +165 -18
  77. package/dist/manifest.d.ts.map +1 -1
  78. package/dist/manifest.js +980 -225
  79. package/dist/manifest.js.map +1 -1
  80. package/dist/renderers/claude.d.ts +5 -0
  81. package/dist/renderers/claude.d.ts.map +1 -1
  82. package/dist/renderers/claude.js +17 -3
  83. package/dist/renderers/claude.js.map +1 -1
  84. package/dist/renderers/copilot.d.ts +1 -1
  85. package/dist/renderers/copilot.d.ts.map +1 -1
  86. package/dist/renderers/copilot.js +205 -22
  87. package/dist/renderers/copilot.js.map +1 -1
  88. package/dist/repo-clone.js +17 -11
  89. package/dist/repo-clone.js.map +1 -1
  90. package/dist/resolve-template.d.ts +12 -4
  91. package/dist/resolve-template.d.ts.map +1 -1
  92. package/dist/resolve-template.js +39 -8
  93. package/dist/resolve-template.js.map +1 -1
  94. package/dist/run/index.d.ts +4 -0
  95. package/dist/run/index.d.ts.map +1 -0
  96. package/dist/run/index.js +2 -0
  97. package/dist/run/index.js.map +1 -0
  98. package/dist/run/run.d.ts +143 -0
  99. package/dist/run/run.d.ts.map +1 -0
  100. package/dist/run/run.js +406 -0
  101. package/dist/run/run.js.map +1 -0
  102. package/dist/search-registry.d.ts +10 -3
  103. package/dist/search-registry.d.ts.map +1 -1
  104. package/dist/search-registry.js +16 -16
  105. package/dist/search-registry.js.map +1 -1
  106. package/dist/sessions/index.d.ts +16 -0
  107. package/dist/sessions/index.d.ts.map +1 -0
  108. package/dist/sessions/index.js +15 -0
  109. package/dist/sessions/index.js.map +1 -0
  110. package/dist/sessions/store.d.ts +56 -0
  111. package/dist/sessions/store.d.ts.map +1 -0
  112. package/dist/sessions/store.js +220 -0
  113. package/dist/sessions/store.js.map +1 -0
  114. package/dist/sessions/types.d.ts +62 -0
  115. package/dist/sessions/types.d.ts.map +1 -0
  116. package/dist/sessions/types.js +5 -0
  117. package/dist/sessions/types.js.map +1 -0
  118. package/dist/skill-fetcher.d.ts.map +1 -1
  119. package/dist/skill-fetcher.js +5 -6
  120. package/dist/skill-fetcher.js.map +1 -1
  121. package/dist/types.d.ts +123 -41
  122. package/dist/types.d.ts.map +1 -1
  123. package/dist/types.js +12 -0
  124. package/dist/types.js.map +1 -1
  125. package/dist/util/binary-cache.d.ts +53 -0
  126. package/dist/util/binary-cache.d.ts.map +1 -0
  127. package/dist/util/binary-cache.js +211 -0
  128. package/dist/util/binary-cache.js.map +1 -0
  129. package/dist/util/frontmatter.d.ts +53 -0
  130. package/dist/util/frontmatter.d.ts.map +1 -0
  131. package/dist/util/frontmatter.js +85 -0
  132. package/dist/util/frontmatter.js.map +1 -0
  133. package/dist/util/loom-home.d.ts +19 -0
  134. package/dist/util/loom-home.d.ts.map +1 -0
  135. package/dist/util/loom-home.js +37 -0
  136. package/dist/util/loom-home.js.map +1 -0
  137. package/dist/util/workspace-folder.d.ts +29 -0
  138. package/dist/util/workspace-folder.d.ts.map +1 -0
  139. package/dist/util/workspace-folder.js +43 -0
  140. package/dist/util/workspace-folder.js.map +1 -0
  141. package/dist/validate.d.ts +7 -1
  142. package/dist/validate.d.ts.map +1 -1
  143. package/dist/validate.js +90 -17
  144. package/dist/validate.js.map +1 -1
  145. package/package.json +31 -2
@@ -0,0 +1,146 @@
1
+ /**
2
+ * MCP config discovery, composition, and materialization helpers.
3
+ * Shared across chat/ and run/ without duplicating logic.
4
+ */
5
+ import { existsSync, readFileSync, mkdtempSync, rmSync } from 'node:fs';
6
+ import { writeFile } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { env } from 'node:process';
10
+ /**
11
+ * Discover an MCP configuration in the given workspace and translate it
12
+ * into the Copilot-CLI `mcpServers`-shaped JSON string (suitable for
13
+ * `--additional-mcp-config @<file>`). Returns null if no servers are
14
+ * usable. Also handles auth-bridge wiring for MCP servers that need a
15
+ * browser-acquired token in the spawn env.
16
+ */
17
+ export function buildCopilotMcpConfigJson(cwd) {
18
+ return discoverMcpConfig(cwd);
19
+ }
20
+ function discoverMcpConfig(cwd) {
21
+ const candidates = [
22
+ join(cwd, '.mcp.json'),
23
+ join(cwd, '.vscode', 'mcp.json'),
24
+ join(cwd, 'mcp.json'),
25
+ ];
26
+ for (const candidate of candidates) {
27
+ if (!existsSync(candidate))
28
+ continue;
29
+ try {
30
+ const raw = readFileSync(candidate, 'utf-8');
31
+ const parsed = JSON.parse(raw);
32
+ const servers = parsed.servers ?? parsed.mcpServers ?? {};
33
+ if (Object.keys(servers).length === 0)
34
+ continue;
35
+ const cliConfig = { mcpServers: {} };
36
+ for (const [name, config] of Object.entries(servers)) {
37
+ const entry = config;
38
+ const cliEntry = {};
39
+ // For MCP servers with browser auth, switch to token-from-cache mode
40
+ // so headless specialists can use them without launching browsers.
41
+ const entryEnv = entry.env ?? {};
42
+ if (entryEnv.HOWLER_AUTH_MODE === 'browser') {
43
+ const cachePath = join(env.HOME ?? env.USERPROFILE ?? '', '.icm_mcp_cache', 'icm_token_cache.json');
44
+ if (existsSync(cachePath)) {
45
+ try {
46
+ const cache = JSON.parse(readFileSync(cachePath, 'utf-8'));
47
+ const token = cache?.public?.icm_token;
48
+ if (token) {
49
+ cliEntry.env = { ...entryEnv, HOWLER_AUTH_MODE: 'token', HOWLER_ICM_TOKEN: token };
50
+ }
51
+ else {
52
+ continue;
53
+ }
54
+ }
55
+ catch {
56
+ continue;
57
+ }
58
+ }
59
+ else {
60
+ continue;
61
+ }
62
+ }
63
+ if (entry.type === 'stdio') {
64
+ cliEntry.type = 'stdio';
65
+ if (entry.command)
66
+ cliEntry.command = entry.command;
67
+ if (entry.args)
68
+ cliEntry.args = entry.args;
69
+ if (entry.env && !cliEntry.env)
70
+ cliEntry.env = entry.env;
71
+ }
72
+ else if (entry.type === 'http' || entry.type === 'sse') {
73
+ cliEntry.type = entry.type;
74
+ if (entry.url)
75
+ cliEntry.url = entry.url;
76
+ }
77
+ cliConfig.mcpServers[name] = cliEntry;
78
+ }
79
+ return JSON.stringify(cliConfig);
80
+ }
81
+ catch {
82
+ // skip
83
+ }
84
+ }
85
+ return null;
86
+ }
87
+ /**
88
+ * Compose a merged MCP config from base + extras - removes, then write it to targetPath.
89
+ * Returns true if anything was written (non-zero servers), false otherwise.
90
+ */
91
+ export async function writeMcpConfig(targetPath, opts) {
92
+ const base = opts.baseConfig
93
+ ? JSON.parse(opts.baseConfig)
94
+ : { mcpServers: {} };
95
+ const merged = { ...base.mcpServers };
96
+ for (const name of opts.removeServers ?? []) {
97
+ delete merged[name];
98
+ }
99
+ for (const [name, cfg] of Object.entries(opts.extras ?? {})) {
100
+ merged[name] = cfg;
101
+ }
102
+ if (Object.keys(merged).length === 0)
103
+ return false;
104
+ await writeFile(targetPath, JSON.stringify({ mcpServers: merged }, null, 2), 'utf-8');
105
+ return true;
106
+ }
107
+ /**
108
+ * Create a temporary directory, write the merged MCP config to it, and return
109
+ * the path + a cleanup function. Returns null when the merged config has zero servers.
110
+ *
111
+ * On any failure during the write step (e.g. malformed `baseConfig` JSON),
112
+ * the temp directory is removed before re-throwing — otherwise we'd leak
113
+ * an empty `loom-XXXX/` under tmp every failed run.
114
+ */
115
+ export async function materializeTempMcpConfig(opts) {
116
+ const dir = mkdtempSync(join(tmpdir(), opts.dirPrefix ?? 'loom-'));
117
+ const configPath = join(dir, 'mcp-cli.json');
118
+ let wrote;
119
+ try {
120
+ wrote = await writeMcpConfig(configPath, opts);
121
+ }
122
+ catch (err) {
123
+ try {
124
+ rmSync(dir, { recursive: true, force: true });
125
+ }
126
+ catch { /* ignore */ }
127
+ throw err;
128
+ }
129
+ if (!wrote) {
130
+ try {
131
+ rmSync(dir, { recursive: true, force: true });
132
+ }
133
+ catch { /* ignore */ }
134
+ return null;
135
+ }
136
+ return {
137
+ path: configPath,
138
+ cleanup: () => {
139
+ try {
140
+ rmSync(dir, { recursive: true, force: true });
141
+ }
142
+ catch { /* ignore */ }
143
+ },
144
+ };
145
+ }
146
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/copilot/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copilot binary and agent resolution helpers.
3
+ * Shared across chat/ and run/ without duplicating logic.
4
+ */
5
+ /**
6
+ * Resolve the path to the Copilot CLI binary.
7
+ *
8
+ * Lookup order:
9
+ * 1. ``COPILOT_CLI_PATH`` env var (escape hatch for any setup).
10
+ * 2. WinGet install location (Windows only, where most users land).
11
+ * 3. PATH lookup (``where.exe`` on Windows, ``command -v`` on POSIX).
12
+ * On Windows, when ``where.exe`` returns an npm shim (``.cmd`` /
13
+ * ``.ps1`` / extensionless), the function probes for the
14
+ * platform-packaged ``copilot.exe`` next to the shim dir before
15
+ * surrendering to a bare-name return. This matters because
16
+ * ``spawnCaptured`` needs ``shell: true`` for non-``.exe`` bins,
17
+ * and ``cmd.exe`` mangles quoted-arg values containing spaces
18
+ * (e.g. ``--agent "Loom Dogfood"`` becomes ``--agent Loom Dogfood``,
19
+ * yielding ``error: too many arguments``). Returning the absolute
20
+ * ``.exe`` directly skips the shell entirely.
21
+ * 4. Bare ``'copilot'`` literal.
22
+ *
23
+ * The POSIX PATH branch (N3 from PR #67) matters because ``spawnCaptured``
24
+ * uses ``shell: false`` on POSIX -- without an absolute path, a missing
25
+ * ``copilot`` produces a bare ``ENOENT`` rather than a useful diagnostic.
26
+ */
27
+ export declare function resolveCopilotBin(): string;
28
+ /**
29
+ * Given a path to an .agent.md file, parse its frontmatter and return the
30
+ * agent's display name. Falls back to the filename slug if no `name:` is set.
31
+ */
32
+ export declare function resolveAgentDisplayNameFromPath(agentFilePath: string): Promise<string>;
33
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/copilot/resolve.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA6D1C;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5F"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Copilot binary and agent resolution helpers.
3
+ * Shared across chat/ and run/ without duplicating logic.
4
+ */
5
+ import { existsSync } from 'node:fs';
6
+ import { join, basename, dirname } from 'node:path';
7
+ import { execSync } from 'node:child_process';
8
+ import { env } from 'node:process';
9
+ import { platform } from 'node:os';
10
+ import { parseAgentFrontmatter } from '../util/frontmatter.js';
11
+ /**
12
+ * Resolve the path to the Copilot CLI binary.
13
+ *
14
+ * Lookup order:
15
+ * 1. ``COPILOT_CLI_PATH`` env var (escape hatch for any setup).
16
+ * 2. WinGet install location (Windows only, where most users land).
17
+ * 3. PATH lookup (``where.exe`` on Windows, ``command -v`` on POSIX).
18
+ * On Windows, when ``where.exe`` returns an npm shim (``.cmd`` /
19
+ * ``.ps1`` / extensionless), the function probes for the
20
+ * platform-packaged ``copilot.exe`` next to the shim dir before
21
+ * surrendering to a bare-name return. This matters because
22
+ * ``spawnCaptured`` needs ``shell: true`` for non-``.exe`` bins,
23
+ * and ``cmd.exe`` mangles quoted-arg values containing spaces
24
+ * (e.g. ``--agent "Loom Dogfood"`` becomes ``--agent Loom Dogfood``,
25
+ * yielding ``error: too many arguments``). Returning the absolute
26
+ * ``.exe`` directly skips the shell entirely.
27
+ * 4. Bare ``'copilot'`` literal.
28
+ *
29
+ * The POSIX PATH branch (N3 from PR #67) matters because ``spawnCaptured``
30
+ * uses ``shell: false`` on POSIX -- without an absolute path, a missing
31
+ * ``copilot`` produces a bare ``ENOENT`` rather than a useful diagnostic.
32
+ */
33
+ export function resolveCopilotBin() {
34
+ if (env.COPILOT_CLI_PATH)
35
+ return env.COPILOT_CLI_PATH;
36
+ const isWindows = platform() === 'win32';
37
+ if (isWindows) {
38
+ const wingetPath = join(env.LOCALAPPDATA ?? '', 'Microsoft', 'WinGet', 'Links', 'copilot.exe');
39
+ if (existsSync(wingetPath))
40
+ return wingetPath;
41
+ }
42
+ try {
43
+ if (isWindows) {
44
+ const candidates = execSync('where.exe copilot 2>nul', { encoding: 'utf-8' })
45
+ .split('\n')
46
+ .map((l) => l.trim())
47
+ .filter((l) => l.length > 0 && !l.includes('globalStorage'));
48
+ // Prefer an absolute .exe directly on PATH (e.g. WinGet link
49
+ // promoted earlier in the user's %PATH%).
50
+ const directExe = candidates.find((l) => l.toLowerCase().endsWith('.exe'));
51
+ if (directExe)
52
+ return directExe;
53
+ // npm-installed copilot lays out as:
54
+ // <npm-prefix>\copilot (extensionless POSIX-style shim)
55
+ // <npm-prefix>\copilot.cmd (Windows shim)
56
+ // <npm-prefix>\copilot.ps1 (PowerShell shim)
57
+ // <npm-prefix>\node_modules\@github\copilot\node_modules\@github\copilot-win32-x64\copilot.exe
58
+ // Probe for the platform package next to the shim dir. Returning
59
+ // the .exe means spawnCaptured can use shell: false, side-stepping
60
+ // cmd.exe arg mangling.
61
+ const exeUnderShim = (shim) => join(dirname(shim), 'node_modules', '@github', 'copilot', 'node_modules', '@github', 'copilot-win32-x64', 'copilot.exe');
62
+ for (const shim of candidates) {
63
+ const probed = exeUnderShim(shim);
64
+ if (existsSync(probed))
65
+ return probed;
66
+ }
67
+ // Last resort on Windows: if `where.exe` returned at least one
68
+ // shim path, prefer its absolute form (still a shim, but at least
69
+ // not a bare name -- caller can handle it).
70
+ if (candidates.length > 0)
71
+ return candidates[0];
72
+ }
73
+ else {
74
+ // ``command -v`` is the POSIX-portable equivalent of ``which``;
75
+ // built into every shell, no external binary needed. ``execSync``
76
+ // already wraps the command string in ``/bin/sh -c``, so we can
77
+ // call the shell builtin directly.
78
+ const posixPath = execSync('command -v copilot 2>/dev/null', { encoding: 'utf-8' })
79
+ .trim();
80
+ if (posixPath)
81
+ return posixPath;
82
+ }
83
+ }
84
+ catch { /* not found */ }
85
+ return 'copilot';
86
+ }
87
+ /**
88
+ * Given a path to an .agent.md file, parse its frontmatter and return the
89
+ * agent's display name. Falls back to the filename slug if no `name:` is set.
90
+ */
91
+ export async function resolveAgentDisplayNameFromPath(agentFilePath) {
92
+ const meta = parseAgentFrontmatter(agentFilePath);
93
+ const fallback = basename(agentFilePath).replace(/\.agent\.md$/i, '');
94
+ return meta.name ?? fallback;
95
+ }
96
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/copilot/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Spawn helpers for Copilot CLI processes.
3
+ * Two variants:
4
+ * - spawnInteractive: stdio inherited (TTY pass-through), for interactive chat
5
+ * - spawnCaptured: piped stdio with bounded buffer + timeout, for headless run
6
+ */
7
+ import { spawn as nodeSpawn } from 'node:child_process';
8
+ export interface SpawnInteractiveSpec {
9
+ bin: string;
10
+ args: string[];
11
+ cwd: string;
12
+ env?: Record<string, string>;
13
+ }
14
+ export interface SpawnInteractiveResult {
15
+ exitCode: number;
16
+ durationMs: number;
17
+ }
18
+ /**
19
+ * Spawn a process with stdio: 'inherit' (TTY pass-through). Returns when the
20
+ * process exits. This function is intentionally dumb -- no banner, no session
21
+ * logic, no MCP wiring. All of that lives in the caller (chat.ts).
22
+ */
23
+ export declare function spawnInteractive(spec: SpawnInteractiveSpec): Promise<SpawnInteractiveResult>;
24
+ export interface SpawnCapturedSpec {
25
+ bin: string;
26
+ args: string[];
27
+ cwd: string;
28
+ env?: Record<string, string>;
29
+ }
30
+ export interface SpawnCapturedOpts {
31
+ timeoutMs?: number;
32
+ /** Hard cap on bytes retained in memory per stream. Default 1MB. */
33
+ bufferCapBytes?: number;
34
+ /** Bytes of the captured buffer to include in stdoutTail/stderrTail. Defaults to bufferCapBytes. */
35
+ tailBytes?: number;
36
+ onStdout?: (chunk: string) => void;
37
+ onStderr?: (chunk: string) => void;
38
+ /** Inject spawn function (for tests). Defaults to node:child_process spawn. */
39
+ spawnFn?: typeof nodeSpawn;
40
+ }
41
+ export interface SpawnCapturedResult {
42
+ exitCode: number;
43
+ durationMs: number;
44
+ timedOut: boolean;
45
+ stdout: string;
46
+ stderr: string;
47
+ stdoutTail: string;
48
+ stderrTail: string;
49
+ }
50
+ export declare function spawnCaptured(spec: SpawnCapturedSpec, opts?: SpawnCapturedOpts): Promise<SpawnCapturedResult>;
51
+ //# sourceMappingURL=spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/copilot/spawn.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGxD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AA6BD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAalG;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,+EAA+E;IAC/E,OAAO,CAAC,EAAE,OAAO,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,iBAAiB,EACvB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA6E9B"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Spawn helpers for Copilot CLI processes.
3
+ * Two variants:
4
+ * - spawnInteractive: stdio inherited (TTY pass-through), for interactive chat
5
+ * - spawnCaptured: piped stdio with bounded buffer + timeout, for headless run
6
+ */
7
+ import { spawn as nodeSpawn } from 'node:child_process';
8
+ import { platform } from 'node:os';
9
+ /**
10
+ * Heuristic: do we need `shell: true` to spawn this binary on Windows?
11
+ *
12
+ * Node's `child_process.spawn` on Windows can resolve `.exe` files directly
13
+ * via CreateProcess, but `.cmd` / `.bat` shims (used by every npm-global
14
+ * package — `copilot.cmd`, `claude.cmd`, etc.) require a shell context.
15
+ * Enabling `shell: true` unconditionally works but it (a) drags `cmd.exe`
16
+ * into the call chain, which mangles arg quoting (breaks our tests that
17
+ * pass paths with spaces), and (b) changes exit-code propagation for
18
+ * children that exit non-zero.
19
+ *
20
+ * Compromise: turn `shell` on only when the bin is a bare name OR ends in
21
+ * `.cmd`/`.bat`. Absolute paths to `.exe` files (e.g. `process.execPath`)
22
+ * skip the shell entirely.
23
+ *
24
+ * POSIX always returns false — `.cmd` shims don't exist there.
25
+ */
26
+ function needsShellOnWindows(bin) {
27
+ if (platform() !== 'win32')
28
+ return false;
29
+ const lower = bin.toLowerCase();
30
+ if (lower.endsWith('.exe'))
31
+ return false;
32
+ // Bare names ('copilot', 'claude') OR explicit shim extensions.
33
+ return !bin.includes('\\') && !bin.includes('/')
34
+ || lower.endsWith('.cmd')
35
+ || lower.endsWith('.bat');
36
+ }
37
+ /**
38
+ * Spawn a process with stdio: 'inherit' (TTY pass-through). Returns when the
39
+ * process exits. This function is intentionally dumb -- no banner, no session
40
+ * logic, no MCP wiring. All of that lives in the caller (chat.ts).
41
+ */
42
+ export async function spawnInteractive(spec) {
43
+ const startTime = Date.now();
44
+ const child = nodeSpawn(spec.bin, spec.args, {
45
+ cwd: spec.cwd,
46
+ stdio: 'inherit',
47
+ shell: needsShellOnWindows(spec.bin),
48
+ ...(spec.env ? { env: { ...process.env, ...spec.env } } : {}),
49
+ });
50
+ const exitCode = await new Promise((resolveP, rejectP) => {
51
+ child.on('exit', (code) => resolveP(code));
52
+ child.on('error', (err) => rejectP(err));
53
+ });
54
+ return { exitCode: exitCode ?? 1, durationMs: Date.now() - startTime };
55
+ }
56
+ export function spawnCaptured(spec, opts = {}) {
57
+ return new Promise((resolveP) => {
58
+ const startTime = Date.now();
59
+ const cap = opts.bufferCapBytes ?? 1024 * 1024;
60
+ const spawnFn = opts.spawnFn ?? nodeSpawn;
61
+ // Bounded FIFO buffer: peak memory is at most ~2*cap (during a single
62
+ // chunk merge) before the slice trims back to `cap`. Prevents unbounded
63
+ // growth on agents that produce gigabytes of stdout.
64
+ const append = (current, chunk) => {
65
+ if (chunk.length >= cap)
66
+ return chunk.slice(-cap);
67
+ const overflow = current.length + chunk.length - cap;
68
+ if (overflow <= 0)
69
+ return current + chunk;
70
+ return current.slice(overflow) + chunk;
71
+ };
72
+ const child = spawnFn(spec.bin, spec.args, {
73
+ cwd: spec.cwd,
74
+ // shell:true is only needed on Windows to resolve `.cmd` shims
75
+ // (e.g. copilot.cmd on PATH). On posix it adds an extra `/bin/sh`
76
+ // layer that changes argv semantics and broadens the injection
77
+ // surface for caller-controlled values like options.model.
78
+ shell: platform() === 'win32',
79
+ stdio: ['pipe', 'pipe', 'pipe'],
80
+ ...(spec.env ? { env: { ...process.env, ...spec.env } } : {}),
81
+ });
82
+ let stdout = '';
83
+ let stderr = '';
84
+ let timedOut = false;
85
+ let escalationTimer;
86
+ child.stdout?.on('data', (data) => {
87
+ const chunk = data.toString();
88
+ stdout = append(stdout, chunk);
89
+ opts.onStdout?.(chunk);
90
+ });
91
+ child.stderr?.on('data', (data) => {
92
+ const chunk = data.toString();
93
+ stderr = append(stderr, chunk);
94
+ opts.onStderr?.(chunk);
95
+ });
96
+ const timer = opts.timeoutMs
97
+ ? setTimeout(() => {
98
+ timedOut = true;
99
+ child.kill('SIGTERM');
100
+ // Belt and suspenders: if SIGTERM doesn't take, escalate after 5s.
101
+ escalationTimer = setTimeout(() => {
102
+ if (child.exitCode === null)
103
+ child.kill('SIGKILL');
104
+ }, 5000);
105
+ escalationTimer.unref();
106
+ }, opts.timeoutMs)
107
+ : undefined;
108
+ const finish = (code) => {
109
+ if (timer)
110
+ clearTimeout(timer);
111
+ if (escalationTimer)
112
+ clearTimeout(escalationTimer);
113
+ const durationMs = Date.now() - startTime;
114
+ const tail = opts.tailBytes ?? cap;
115
+ resolveP({
116
+ exitCode: code ?? 1,
117
+ durationMs,
118
+ timedOut,
119
+ stdout,
120
+ stderr,
121
+ stdoutTail: stdout.length > tail ? stdout.slice(-tail) : stdout,
122
+ stderrTail: stderr.length > tail ? stderr.slice(-tail) : stderr,
123
+ });
124
+ };
125
+ child.on('exit', (code) => finish(code));
126
+ child.on('error', (err) => {
127
+ stderr += `\n[loom-run] spawn error: ${err.message}`;
128
+ finish(1);
129
+ });
130
+ });
131
+ }
132
+ //# sourceMappingURL=spawn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/copilot/spawn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Main library entry point for @agent-loom/loom.
3
+ *
4
+ * This is the public SDK surface. CLI entry is `src/cli.ts`.
5
+ *
6
+ * Subpath exports (see `package.json` exports map):
7
+ * - `@agent-loom/loom` (this file — chat + run + staging + types)
8
+ * - `@agent-loom/loom/run` (headless `run()` only)
9
+ * - `@agent-loom/loom/launch` (`stageRegistryAgent` for orchestrators)
10
+ * - `@agent-loom/loom/acp` (`AcpClient` for the planned peers MCP)
11
+ */
12
+ export { chat, buildChatCommand, defaultPreChatBanner } from './chat/index.js';
13
+ export type { ChatOptions, ChatResult, LaunchRuntimeKind, PreLaunchInfo, } from './chat/index.js';
14
+ export { run, DEFAULT_RUN_TIMEOUT_MS } from './run/index.js';
15
+ export type { RunOptions, RunResult } from './run/index.js';
16
+ export { stageRegistryAgent } from './launch/index.js';
17
+ export type { StagedLaunch, StageOptions } from './launch/index.js';
18
+ export type { McpServerConfig } from './copilot/mcp.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,YAAY,EACV,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIpE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Main library entry point for @agent-loom/loom.
3
+ *
4
+ * This is the public SDK surface. CLI entry is `src/cli.ts`.
5
+ *
6
+ * Subpath exports (see `package.json` exports map):
7
+ * - `@agent-loom/loom` (this file — chat + run + staging + types)
8
+ * - `@agent-loom/loom/run` (headless `run()` only)
9
+ * - `@agent-loom/loom/launch` (`stageRegistryAgent` for orchestrators)
10
+ * - `@agent-loom/loom/acp` (`AcpClient` for the planned peers MCP)
11
+ */
12
+ export { chat, buildChatCommand, defaultPreChatBanner } from './chat/index.js';
13
+ export { run, DEFAULT_RUN_TIMEOUT_MS } from './run/index.js';
14
+ export { stageRegistryAgent } from './launch/index.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAQ/E,OAAO,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public exports for the launch module.
3
+ *
4
+ * `launch` is the layer between registry resolution and runtime spawn:
5
+ * it materializes a registry-resolved agent into a session workspace
6
+ * ready for `chat()`, `run()`, or a future `startSpecialist()`.
7
+ */
8
+ export { stageRegistryAgent } from './stage.js';
9
+ export type { StagedLaunch, StageOptions } from './stage.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/launch/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Public exports for the launch module.
3
+ *
4
+ * `launch` is the layer between registry resolution and runtime spawn:
5
+ * it materializes a registry-resolved agent into a session workspace
6
+ * ready for `chat()`, `run()`, or a future `startSpecialist()`.
7
+ */
8
+ export { stageRegistryAgent } from './stage.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/launch/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Staging — materialize a registry-resolved agent into a session workspace.
3
+ *
4
+ * The staging flow:
5
+ * 1. Generate a session id + compute the staged workspace path
6
+ * 2. Create the session record pointing at that workspace
7
+ * 3. Apply the registry template into `<session.dir>/workspace/`
8
+ * 4. Return a `ResolvedAgentRef` pointing at the staged agent file so the
9
+ * launch machinery can spawn against it unchanged.
10
+ *
11
+ * Manifest repos are cloned in `'auto'` mode by default — real-work agents
12
+ * (CRI triage, pool investigations, ...) reference these repos at runtime
13
+ * and a session without them stalls immediately. Lightweight callers can
14
+ * pass `cloneRepos: 'none'` to skip.
15
+ *
16
+ * Located under `src/launch/` (not `src/chat/`) so library consumers like
17
+ * `loom run`, the planned `startSpecialist` (#76), and `loom-peers-mcp`
18
+ * (#77) can stage without pulling in chat-only modules.
19
+ */
20
+ import { type Session, type SessionRuntime } from '../sessions/index.js';
21
+ import type { ResolvedAgentRef } from '../chat/resolve-agent.js';
22
+ import type { RegistryAgentHit } from '../chat/registry.js';
23
+ export interface StagedLaunch {
24
+ /** The session record that owns the staged workspace. */
25
+ session: Session;
26
+ /** The staged agent ref — points inside `<session.dir>/workspace/`. */
27
+ agent: ResolvedAgentRef;
28
+ }
29
+ export interface StageOptions {
30
+ hit: RegistryAgentHit;
31
+ /** Friendly session label. */
32
+ sessionName?: string;
33
+ /**
34
+ * Runtime the staged session will be launched against. Controls both the
35
+ * `runtime:` field on the session record AND the renderer (`target`) used
36
+ * by `applyTemplate`. Defaults to `'copilot'` for back-compat with the
37
+ * pre-multi-runtime callers, but new callers should pass this through
38
+ * from the user's `--runtime` choice.
39
+ */
40
+ runtime?: SessionRuntime;
41
+ /** Progress callback forwarded to applyTemplate. */
42
+ onProgress?: (msg: string) => void;
43
+ /**
44
+ * Manifest repo clone behavior. Defaults to `'auto'` for staged launches
45
+ * because real-work agents reference repos at runtime
46
+ * and a workspace without them is dead-on-arrival. Pass `'none'` for
47
+ * lightweight / smoke-test agents.
48
+ */
49
+ cloneRepos?: 'auto' | 'all' | 'none';
50
+ /** Clone strategy override forwarded to applyTemplate. */
51
+ cloneMode?: 'full' | 'partial';
52
+ /** Interactive prompt for large/ADO repos (forwarded to applyTemplate). */
53
+ promptFn?: (message: string, choices: string[]) => Promise<string>;
54
+ /** Junction/symlink creator (forwarded to applyTemplate). */
55
+ linkFn?: (target: string, linkPath: string) => Promise<void>;
56
+ }
57
+ /**
58
+ * Stage a registry-resolved agent into a new session workspace, ready to launch.
59
+ * Throws if `applyTemplate` fails to produce the expected agent file.
60
+ */
61
+ export declare function stageRegistryAgent(options: StageOptions): Promise<StagedLaunch>;
62
+ //# sourceMappingURL=stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/launch/stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,KAAK,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,gBAAgB,CAAC;IACtB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,oDAAoD;IACpD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA4FrF"}