@agent-loom/loom 1.0.1 → 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 +17 -6
  15. package/dist/apply.d.ts.map +1 -1
  16. package/dist/apply.js +85 -47
  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 +628 -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
package/dist/apply.js CHANGED
@@ -1,52 +1,86 @@
1
1
  /**
2
- * Apply resolves a template from a registry and renders it to a target workspace.
2
+ * Apply -- resolves a template from a registry and renders it to a target workspace.
3
+ *
4
+ * Per U6 the manifest pipeline is monolithic: parseManifest +
5
+ * resolveManifest + skillFetcher + workspace-folder expansion run
6
+ * inline here. The legacy ManifestAdapter dispatcher and dobby/loom
7
+ * adapters are gone -- parseManifest natively probes for both
8
+ * manifest.yaml and dobby.yaml and normalizes flat-layout dobby-style
9
+ * input into the canonical contents:-wrapped shape.
3
10
  */
4
- import { join } from 'node:path';
5
- import { parseManifest, resolveManifest, parseAgentManifest, discoverNestedAgents, mergeTeamAndAgentManifests } from './manifest.js';
6
11
  import { renderCopilot } from './renderers/copilot.js';
7
12
  import { renderClaude } from './renderers/claude.js';
8
13
  import { resolveRegistrySkills } from './skill-fetcher.js';
9
- import { cloneManifestRepos } from './repo-clone.js';
14
+ import { cloneManifestRepos, deriveRepoDir } from './repo-clone.js';
15
+ import { parseManifest, resolveManifest } from './manifest.js';
16
+ import { buildRepoNameMap, expandWorkspaceFolder } from './util/workspace-folder.js';
10
17
  /**
11
18
  * Apply a template to a workspace directory.
12
19
  *
13
20
  * Steps:
14
- * 1. Parse manifest.yaml from templateDir
15
- * 2. Resolve all $ref / file references
16
- * 3. Fetch registry skills if a skillFetcher is provided
17
- * 4. Render output files using the appropriate renderer
18
- * 5. Return list of registry skills that need external install (if not fetched)
21
+ * 1. Parse the manifest from templateDir (probes manifest.yaml then dobby.yaml).
22
+ * 2. Resolve all $ref / file / discover references.
23
+ * 3. Filter agents (when --agent was passed).
24
+ * 4. Fetch registry skills if a skillFetcher is provided.
25
+ * 5. Expand ${workspaceFolder:X} placeholders in MCP args/cwd.
26
+ * 6. Render output files using the appropriate renderer.
27
+ * 7. Return list of registry skills that need external install (if not fetched).
19
28
  */
20
29
  export async function applyTemplate(options) {
21
- const { templateDir, registryRoot, outputDir, target, skillFetcher, cloneRepos, cloneMode, execFn, promptFn, linkFn, agents: selectedAgents } = options;
22
- const manifestPath = join(templateDir, 'manifest.yaml');
23
- const teamManifest = await parseManifest(manifestPath);
24
- // Detect nested agents
25
- const nestedAgentIds = await discoverNestedAgents(templateDir);
26
- let manifest = teamManifest;
27
- if (nestedAgentIds.length > 0) {
28
- // Nested template determine which agents to include
29
- const agentIds = selectedAgents && selectedAgents.length > 0
30
- ? selectedAgents.filter((id) => nestedAgentIds.includes(id))
31
- : nestedAgentIds; // All agents if none specified
32
- // Parse agent manifests
33
- const agentManifests = [];
34
- for (const agentId of agentIds) {
35
- const agentManifestPath = join(templateDir, 'agents', agentId, 'manifest.yaml');
36
- const am = await parseAgentManifest(agentManifestPath);
37
- agentManifests.push(am);
38
- }
39
- // Merge team + agent manifests
40
- manifest = mergeTeamAndAgentManifests(teamManifest, agentManifests, agentIds);
30
+ const { templateDir, registryRoot, outputDir, target, skillFetcher, cloneRepos, cloneMode, execFn, promptFn, linkFn, agents: selectedAgents, onProgress } = options;
31
+ const log = onProgress ?? (() => { });
32
+ // 1. Parse + 2. Resolve. parseManifest natively probes for
33
+ // manifest.yaml or dobby.yaml and normalizes flat-layout aliases.
34
+ log('Parsing manifest...');
35
+ const manifest = await parseManifest(templateDir);
36
+ log('Resolving references...');
37
+ let resolved = await resolveManifest(manifest, templateDir, registryRoot, { agents: selectedAgents });
38
+ // 3. --agent filtering: when callers ask for a subset, drop the rest
39
+ // from the resolved list. resolveManifest already populates each
40
+ // ResolvedAgent.mcp from the agent file's frontmatter `mcp-servers:`
41
+ // block (loom#127 / U4.5), so no further per-agent MCP plumbing is
42
+ // needed here.
43
+ if (selectedAgents?.length) {
44
+ const wanted = new Set(selectedAgents);
45
+ resolved = {
46
+ ...resolved,
47
+ agents: resolved.agents.filter((a) => wanted.has(a.agentId)),
48
+ };
49
+ }
50
+ // 4. Fetch registry skills (when a fetcher is provided)
51
+ if (skillFetcher && resolved.skills.length > 0) {
52
+ log(`Fetching ${resolved.skills.length} skill(s)...`);
53
+ const skills = await resolveRegistrySkills(resolved.skills, skillFetcher);
54
+ resolved = { ...resolved, skills };
41
55
  }
42
- const resolved = await resolveManifest(manifest, templateDir, registryRoot);
43
- // Resolve registry skills to local if fetcher is provided
44
- const resolvedSkills = await resolveRegistrySkills(resolved.skills, skillFetcher);
45
- const manifestWithLocalSkills = {
56
+ // 5. Expand ${workspaceFolder:X} in MCP args/cwd. Without this, repo-
57
+ // backed MCP servers (e.g. dotnet projects, scripts referenced from
58
+ // a checked-out path) would emit literal placeholder strings into
59
+ // .mcp.json / .vscode/mcp.json, which the MCP runtime cannot
60
+ // interpret. dirNameFor mirrors what cloneManifestRepos does:
61
+ // deriveRepoDir returns id when set, else the URL basename. Repos
62
+ // are cloned (or junctioned) into <workspace>/<dirName>, so the
63
+ // placeholder resolves to the same path regardless of how the repo
64
+ // was materialized.
65
+ const workDir = outputDir;
66
+ const repoNameMap = buildRepoNameMap(resolved.repos, (r) => deriveRepoDir(r.url ?? '', r.id));
67
+ const expandVar = (s) => expandWorkspaceFolder(s, repoNameMap, workDir);
68
+ const expandMcp = (m) => ({
69
+ ...m,
70
+ args: m.args?.map(expandVar),
71
+ cwd: m.cwd ? expandVar(m.cwd) : undefined,
72
+ });
73
+ // Expand placeholders in BOTH team-level (resolved.mcp) and
74
+ // per-agent (agent.mcp) MCPs -- the placeholder semantics are
75
+ // the same for either scope (loom#127).
76
+ resolved = {
46
77
  ...resolved,
47
- skills: resolvedSkills,
78
+ mcp: resolved.mcp.map(expandMcp),
79
+ agents: resolved.agents.map((a) => a.mcp ? { ...a, mcp: a.mcp.map(expandMcp) } : a),
48
80
  };
49
- // Render
81
+ const manifestWithLocalSkills = resolved;
82
+ // 6. Render
83
+ log(`Rendering ${target} workspace files...`);
50
84
  switch (target) {
51
85
  case 'copilot':
52
86
  await renderCopilot(manifestWithLocalSkills, outputDir);
@@ -55,7 +89,7 @@ export async function applyTemplate(options) {
55
89
  await renderClaude(manifestWithLocalSkills, outputDir);
56
90
  break;
57
91
  case 'cursor':
58
- // Cursor renderer not yet implemented fall back to copilot
92
+ // Cursor renderer not yet implemented -- fall back to copilot
59
93
  await renderCopilot(manifestWithLocalSkills, outputDir);
60
94
  break;
61
95
  default:
@@ -63,11 +97,12 @@ export async function applyTemplate(options) {
63
97
  }
64
98
  // Clone manifest repos if requested
65
99
  let repoCloneResult;
66
- if (cloneRepos && resolved.repos.length > 0) {
100
+ if (cloneRepos && manifestWithLocalSkills.repos.length > 0) {
101
+ log(`Cloning ${manifestWithLocalSkills.repos.length} repo(s)...`);
67
102
  // Apply --clone-mode partial: override repos without explicit cloneStrategy
68
103
  const repos = cloneMode === 'partial'
69
- ? resolved.repos.map((r) => (!r.cloneStrategy && !r.sparse) ? { ...r, cloneStrategy: 'partial' } : r)
70
- : resolved.repos;
104
+ ? manifestWithLocalSkills.repos.map((r) => (!r.cloneStrategy && !r.sparse) ? { ...r, cloneStrategy: 'partial' } : r)
105
+ : manifestWithLocalSkills.repos;
71
106
  repoCloneResult = await cloneManifestRepos({
72
107
  repos,
73
108
  workspaceDir: outputDir === '.' ? process.cwd() : outputDir,
@@ -77,17 +112,20 @@ export async function applyTemplate(options) {
77
112
  linkFn,
78
113
  });
79
114
  }
80
- // Collect registry skills that were NOT fetched (still type='registry')
81
- const registrySkills = resolvedSkills
82
- .filter((s) => s.type === 'registry' && s.registry && s.ref)
115
+ // Skills with registry coordinates fall into two buckets:
116
+ // - registrySkills: registry-rooted, content NOT fetched (caller must install)
117
+ // - localizedSkills: registry-rooted, content fetched (rendered locally)
118
+ // A skill gets `content` only when a SkillFetcher resolved it, so
119
+ // presence of `content` is the discriminator.
120
+ const registrySkills = manifestWithLocalSkills.skills
121
+ .filter((s) => s.registry && s.ref && s.content === undefined)
83
122
  .map((s) => ({ registry: s.registry, ref: s.ref }));
84
- // Collect skills that were fetched and localized
85
- const localizedSkills = resolvedSkills
86
- .filter((s) => s.type === 'local' && s.originalRegistry && s.originalRef)
87
- .map((s) => ({ name: s.name, registry: s.originalRegistry, ref: s.originalRef }));
123
+ const localizedSkills = manifestWithLocalSkills.skills
124
+ .filter((s) => s.registry && s.ref && s.content !== undefined)
125
+ .map((s) => ({ name: s.name ?? s.ref, registry: s.registry, ref: s.ref }));
88
126
  return {
89
127
  target,
90
- template: resolved.template.id,
128
+ template: manifestWithLocalSkills.template.id,
91
129
  filesGenerated: true,
92
130
  registrySkills,
93
131
  localizedSkills,
package/dist/apply.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"apply.js","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * `chat()` -- single-agent interactive session (powers verb-less `loom <agent>`).
3
+ *
4
+ * Composition note: shares the MCP-discovery + bin-resolution + spawn
5
+ * substrate with `src/run/run.ts` via the shared helpers in `src/copilot/`.
6
+ * The key difference from `run` is stdio: `chat` inherits the parent tty so
7
+ * the user talks to Copilot directly; `run` pipes stdio to capture output.
8
+ */
9
+ import type { ResolvedAgentRef } from './resolve-agent.js';
10
+ import type { AgentMetadata } from './frontmatter.js';
11
+ import { type Session } from '../sessions/index.js';
12
+ export type LaunchRuntimeKind = 'copilot' | 'claude';
13
+ export interface ChatOptions {
14
+ /** Agent id to resolve. */
15
+ agentId: string;
16
+ /** Working directory (where to resolve the agent from and launch in). */
17
+ cwd: string;
18
+ /** One-shot prompt. If set with interactive=false, runs non-interactively. */
19
+ prompt?: string;
20
+ /**
21
+ * When true, runs non-interactively (suitable for `--prompt` one-shot or scripting).
22
+ * When false (default), starts interactive mode with stdio inherited.
23
+ */
24
+ interactive?: boolean;
25
+ /** Runtime to launch. Default 'copilot'. */
26
+ runtime?: LaunchRuntimeKind;
27
+ /** Extra args appended to the runtime command line. */
28
+ extraArgs?: string[];
29
+ /**
30
+ * Pre-resolved agent. If provided, skips resolution. Used for tests and
31
+ * for callers that want to resolve via a different strategy.
32
+ */
33
+ resolved?: ResolvedAgentRef;
34
+ /**
35
+ * Optional callback invoked once we have the agent + its metadata, but
36
+ * before spawning the runtime. Defaults to printing a banner to stderr.
37
+ * Pass `() => {}` to suppress.
38
+ */
39
+ onPreLaunch?: (info: PreLaunchInfo) => void;
40
+ /**
41
+ * When false, skip session-dir creation. Default true.
42
+ * Useful for tests and for scripted one-shots that don't want to litter
43
+ * `~/.loom/sessions/` with short-lived records.
44
+ */
45
+ recordSession?: boolean;
46
+ /** Optional friendly label written to session meta.yaml. */
47
+ sessionName?: string;
48
+ /** Origin hint written to the session meta. Default 'workspace'. */
49
+ sessionOrigin?: 'workspace' | 'staged';
50
+ /**
51
+ * Pre-existing session to use instead of creating one. When set, the
52
+ * session is still finalized on exit. Implies `recordSession` was handled
53
+ * by the caller (e.g., registry staging).
54
+ */
55
+ session?: Session;
56
+ }
57
+ export interface PreLaunchInfo {
58
+ agent: ResolvedAgentRef;
59
+ metadata: AgentMetadata;
60
+ runtime: LaunchRuntimeKind;
61
+ interactive: boolean;
62
+ cwd: string;
63
+ /** Session handle if a session was created; null when recordSession=false. */
64
+ session: Session | null;
65
+ }
66
+ export interface ChatResult {
67
+ /** Resolved agent reference used for this launch. */
68
+ agent: ResolvedAgentRef;
69
+ /** Exit code from the runtime process. */
70
+ exitCode: number | null;
71
+ /** Total duration in milliseconds. */
72
+ durationMs: number;
73
+ /** Session record, if one was created. */
74
+ session: Session | null;
75
+ }
76
+ /**
77
+ * Build the command line for a given runtime. Exported for testability.
78
+ */
79
+ export declare function buildChatCommand(params: {
80
+ runtime: LaunchRuntimeKind;
81
+ prompt?: string;
82
+ interactive: boolean;
83
+ agent: ResolvedAgentRef;
84
+ /**
85
+ * The value to pass to copilot's `--agent` flag. Copilot identifies
86
+ * agents by their frontmatter `name:` (e.g. "Live Site"), not by the
87
+ * filename slug (e.g. "live-site"). Callers should pass
88
+ * `metadata.name ?? agent.agentId` so the spawn finds the agent.
89
+ */
90
+ agentDisplayName?: string;
91
+ mcpConfigPath?: string | null;
92
+ extraArgs?: string[];
93
+ }): {
94
+ bin: string;
95
+ args: string[];
96
+ };
97
+ /**
98
+ * Default banner printer. Emits a 3-line summary to stderr before the
99
+ * runtime takes over the terminal. Kept minimal so it doesn't compete with
100
+ * Copilot CLI's own startup output.
101
+ */
102
+ export declare function defaultPreChatBanner(info: PreLaunchInfo): void;
103
+ /**
104
+ * Launch an agent interactively. Binds stdio to the parent tty so the
105
+ * user talks to Copilot directly. Returns when the runtime process exits.
106
+ */
107
+ export declare function chat(options: ChatOptions): Promise<ChatResult>;
108
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/chat/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAItD,OAAO,EAGL,KAAK,OAAO,EACb,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,aAAa,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,KAAK,EAAE,gBAAgB,CAAC;IACxB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAwClC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CA6B9D;AAgCD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAqGpE"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * `chat()` -- single-agent interactive session (powers verb-less `loom <agent>`).
3
+ *
4
+ * Composition note: shares the MCP-discovery + bin-resolution + spawn
5
+ * substrate with `src/run/run.ts` via the shared helpers in `src/copilot/`.
6
+ * The key difference from `run` is stdio: `chat` inherits the parent tty so
7
+ * the user talks to Copilot directly; `run` pipes stdio to capture output.
8
+ */
9
+ import { homedir } from 'node:os';
10
+ import chalk from 'chalk';
11
+ import { resolveAgentInWorkspace } from './resolve-agent.js';
12
+ import { parseAgentFrontmatter } from './frontmatter.js';
13
+ import { resolveCopilotBin } from '../copilot/resolve.js';
14
+ import { buildCopilotMcpConfigJson, materializeTempMcpConfig } from '../copilot/mcp.js';
15
+ import { spawnInteractive } from '../copilot/spawn.js';
16
+ import { createSession, finalizeSession, } from '../sessions/index.js';
17
+ /**
18
+ * Build the command line for a given runtime. Exported for testability.
19
+ */
20
+ export function buildChatCommand(params) {
21
+ const { runtime, prompt, interactive, agent, agentDisplayName, mcpConfigPath, extraArgs = [] } = params;
22
+ switch (runtime) {
23
+ case 'copilot': {
24
+ const bin = resolveCopilotBin();
25
+ const args = [];
26
+ if (prompt) {
27
+ // -p runs non-interactive and exits; -i <prompt> runs the kickoff
28
+ // then keeps the interactive session open. Interactive with no
29
+ // prompt: don't emit -i (it takes a required value and would
30
+ // swallow the next flag as the prompt).
31
+ args.push(interactive ? '-i' : '-p', prompt);
32
+ }
33
+ args.push('--allow-all-tools');
34
+ args.push('--add-dir', agent.workspaceDir);
35
+ // Activate the agent persona (otherwise Copilot just loads the file
36
+ // as a tool but talks back as plain Copilot, with no visible identity).
37
+ // --agent wants the frontmatter name (e.g. "Live Site"), not the
38
+ // filename slug (e.g. "live-site"); fall back to slug if metadata
39
+ // wasn't passed (the spawn will then surface copilot's own
40
+ // "No such agent" error).
41
+ args.push('--agent', agentDisplayName ?? agent.agentId);
42
+ if (mcpConfigPath) {
43
+ // Copilot expects JSON or a file path prefixed with '@'.
44
+ args.push('--additional-mcp-config', `@${mcpConfigPath}`);
45
+ }
46
+ args.push(...extraArgs);
47
+ return { bin, args };
48
+ }
49
+ case 'claude': {
50
+ const bin = 'claude';
51
+ const args = ['--dangerously-skip-permissions'];
52
+ if (prompt)
53
+ args.push('--prompt', prompt);
54
+ args.push(...extraArgs);
55
+ return { bin, args };
56
+ }
57
+ default:
58
+ throw new Error(`Unknown runtime: ${String(runtime)}`);
59
+ }
60
+ }
61
+ /**
62
+ * Default banner printer. Emits a 3-line summary to stderr before the
63
+ * runtime takes over the terminal. Kept minimal so it doesn't compete with
64
+ * Copilot CLI's own startup output.
65
+ */
66
+ export function defaultPreChatBanner(info) {
67
+ const out = process.stderr;
68
+ const agentId = info.agent.agentId;
69
+ const displayName = info.metadata.name ?? agentId;
70
+ const mode = info.interactive ? 'interactive' : 'one-shot';
71
+ const runtimeLabel = `${info.runtime} \u00b7 ${mode}`;
72
+ // Top rule + agent badge
73
+ out.write('\n');
74
+ out.write(` ${chalk.cyan.bold(agentId)} ${chalk.dim(runtimeLabel)}\n`);
75
+ if (displayName !== agentId) {
76
+ out.write(` ${chalk.dim(displayName)}\n`);
77
+ }
78
+ // Description (wrapped to ~80 cols)
79
+ if (info.metadata.description) {
80
+ out.write('\n');
81
+ for (const line of wrapText(info.metadata.description, 76)) {
82
+ out.write(` ${line}\n`);
83
+ }
84
+ }
85
+ // Footer facts
86
+ out.write('\n');
87
+ out.write(` ${chalk.dim('workspace')} ${tildify(info.agent.workspaceDir)}\n`);
88
+ if (info.session) {
89
+ out.write(` ${chalk.dim('session')} ${info.session.meta.id}\n`);
90
+ }
91
+ out.write('\n');
92
+ }
93
+ function tildify(p) {
94
+ const home = homedir();
95
+ if (p === home)
96
+ return '~';
97
+ if (p.toLowerCase().startsWith(home.toLowerCase() + '\\')) {
98
+ return '~\\' + p.slice(home.length + 1);
99
+ }
100
+ if (p.toLowerCase().startsWith(home.toLowerCase() + '/')) {
101
+ return '~/' + p.slice(home.length + 1);
102
+ }
103
+ return p;
104
+ }
105
+ function wrapText(text, width) {
106
+ const words = text.replace(/\s+/g, ' ').trim().split(' ');
107
+ const lines = [];
108
+ let current = '';
109
+ for (const word of words) {
110
+ if (!current) {
111
+ current = word;
112
+ }
113
+ else if (current.length + 1 + word.length <= width) {
114
+ current += ' ' + word;
115
+ }
116
+ else {
117
+ lines.push(current);
118
+ current = word;
119
+ }
120
+ }
121
+ if (current)
122
+ lines.push(current);
123
+ return lines;
124
+ }
125
+ /**
126
+ * Launch an agent interactively. Binds stdio to the parent tty so the
127
+ * user talks to Copilot directly. Returns when the runtime process exits.
128
+ */
129
+ export async function chat(options) {
130
+ const startTime = Date.now();
131
+ const runtime = options.runtime ?? 'copilot';
132
+ const interactive = options.interactive ?? true;
133
+ const agent = options.resolved ?? resolveAgentInWorkspace({
134
+ agentId: options.agentId,
135
+ cwd: options.cwd,
136
+ });
137
+ if (!agent) {
138
+ throw new Error(`Agent "${options.agentId}" not found in workspace.\n` +
139
+ ` Looked for: ${options.cwd}/.github/agents/${options.agentId}.agent.md\n` +
140
+ ` (Installed-shortname and registry resolution layers are not yet implemented.)`);
141
+ }
142
+ const metadata = parseAgentFrontmatter(agent.agentFilePath);
143
+ // Record the session (unless opted out or supplied by caller) before we
144
+ // hand off to the runtime. We want this row to exist even if the spawn
145
+ // itself explodes, so `loom sessions list` can see failed launches too.
146
+ let session = options.session ?? null;
147
+ if (!session && options.recordSession !== false) {
148
+ session = createSession({
149
+ agentId: agent.agentId,
150
+ agentName: metadata.name,
151
+ runtime,
152
+ workspaceDir: agent.workspaceDir,
153
+ origin: options.sessionOrigin ?? 'workspace',
154
+ name: options.sessionName,
155
+ });
156
+ }
157
+ const preLaunch = options.onPreLaunch ?? defaultPreChatBanner;
158
+ preLaunch({ agent, metadata, runtime, interactive, cwd: options.cwd, session });
159
+ // Persist MCP config to a temp file so --additional-mcp-config can reference it.
160
+ // Returns null when the discovered config has zero usable servers; the temp
161
+ // dir is cleaned up in the finally block.
162
+ let tempMcp = null;
163
+ if (runtime === 'copilot') {
164
+ tempMcp = await materializeTempMcpConfig({
165
+ baseConfig: buildCopilotMcpConfigJson(agent.workspaceDir),
166
+ dirPrefix: 'loom-chat-',
167
+ });
168
+ }
169
+ try {
170
+ const { bin, args } = buildChatCommand({
171
+ runtime,
172
+ prompt: options.prompt,
173
+ interactive,
174
+ agent,
175
+ agentDisplayName: metadata.name ?? agent.agentId,
176
+ mcpConfigPath: tempMcp?.path ?? null,
177
+ extraArgs: options.extraArgs,
178
+ });
179
+ // Set the terminal tab title so the user can always see which agent
180
+ // they are in, even after Copilot's alt-screen TUI clears our banner.
181
+ // OSC 0 is supported by Windows Terminal, iTerm2, GNOME Terminal, etc.
182
+ // We can't read the previous title back, so on exit we restore to a
183
+ // neutral "loom" so it's obvious the agent has ended.
184
+ const titleTag = `loom: ${agent.agentId}`;
185
+ const setTitle = (s) => {
186
+ if (process.stderr.isTTY)
187
+ process.stderr.write(`\x1b]0;${s}\x07`);
188
+ };
189
+ setTitle(titleTag);
190
+ const restoreTitle = () => setTitle('loom');
191
+ let exitCode = null;
192
+ let errored = false;
193
+ try {
194
+ const result = await spawnInteractive({ bin, args, cwd: agent.workspaceDir });
195
+ exitCode = result.exitCode;
196
+ }
197
+ catch (err) {
198
+ errored = true;
199
+ restoreTitle();
200
+ if (session) {
201
+ finalizeSession(session, {
202
+ exitCode: null,
203
+ durationMs: Date.now() - startTime,
204
+ status: 'errored',
205
+ });
206
+ }
207
+ throw err;
208
+ }
209
+ restoreTitle();
210
+ const durationMs = Date.now() - startTime;
211
+ if (session && !errored) {
212
+ session = finalizeSession(session, { exitCode, durationMs });
213
+ }
214
+ return { agent, exitCode, durationMs, session };
215
+ }
216
+ finally {
217
+ // Best-effort cleanup of the per-launch MCP-config temp dir.
218
+ tempMcp?.cleanup();
219
+ }
220
+ }
221
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/chat/chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Workspace + agent discovery for `loom <agent>` and `loom agents`.
3
+ *
4
+ * - `findWorkspaceRoot(cwd)`: walk up the directory tree looking for a
5
+ * `.github/agents/` directory. Matches git's "find-root" ergonomics so
6
+ * users don't have to be at the exact workspace root.
7
+ * - `listWorkspaceAgents(workspaceDir)`: enumerate `.agent.md` files under
8
+ * `.github/agents/` with their parsed frontmatter metadata.
9
+ */
10
+ import type { AgentMetadata } from './frontmatter.js';
11
+ export interface WorkspaceAgentInfo {
12
+ /** Agent id (filename stem before `.agent.md`) */
13
+ agentId: string;
14
+ /** Absolute path to the agent file */
15
+ agentFilePath: string;
16
+ /** Frontmatter metadata */
17
+ metadata: AgentMetadata;
18
+ }
19
+ /**
20
+ * Walk up from `cwd` looking for a directory that contains `.github/agents/`.
21
+ * Returns the absolute path of that directory, or null if no such ancestor
22
+ * exists (including the filesystem root).
23
+ */
24
+ export declare function findWorkspaceRoot(cwd: string): string | null;
25
+ /**
26
+ * List all agents in a workspace's `.github/agents/` directory.
27
+ * Returns an empty array if the directory doesn't exist.
28
+ */
29
+ export declare function listWorkspaceAgents(workspaceDir: string): WorkspaceAgentInfo[];
30
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/chat/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB5D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAyB9E"}