@agent-relay/factory 0.0.0 → 0.1.1

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 (221) hide show
  1. package/README.md +240 -22
  2. package/bin/factory.mjs +7 -0
  3. package/dist/cli/fleet.d.ts +77 -0
  4. package/dist/cli/fleet.d.ts.map +1 -0
  5. package/dist/cli/fleet.js +500 -0
  6. package/dist/cli/fleet.js.map +1 -0
  7. package/dist/config/schema.d.ts +1313 -0
  8. package/dist/config/schema.d.ts.map +1 -0
  9. package/dist/config/schema.js +309 -0
  10. package/dist/config/schema.js.map +1 -0
  11. package/dist/constants/linear.d.ts +4 -0
  12. package/dist/constants/linear.d.ts.map +1 -0
  13. package/dist/constants/linear.js +15 -0
  14. package/dist/constants/linear.js.map +1 -0
  15. package/dist/constants/slack.d.ts +3 -0
  16. package/dist/constants/slack.d.ts.map +1 -0
  17. package/dist/constants/slack.js +3 -0
  18. package/dist/constants/slack.js.map +1 -0
  19. package/dist/dispatch/templates.d.ts +36 -0
  20. package/dist/dispatch/templates.d.ts.map +1 -0
  21. package/dist/dispatch/templates.js +110 -0
  22. package/dist/dispatch/templates.js.map +1 -0
  23. package/dist/fleet/create-fleet.d.ts +13 -0
  24. package/dist/fleet/create-fleet.d.ts.map +1 -0
  25. package/dist/fleet/create-fleet.js +14 -0
  26. package/dist/fleet/create-fleet.js.map +1 -0
  27. package/dist/fleet/internal-fleet-client.d.ts +85 -0
  28. package/dist/fleet/internal-fleet-client.d.ts.map +1 -0
  29. package/dist/fleet/internal-fleet-client.js +575 -0
  30. package/dist/fleet/internal-fleet-client.js.map +1 -0
  31. package/dist/fleet/relay-fleet-client.d.ts +28 -0
  32. package/dist/fleet/relay-fleet-client.d.ts.map +1 -0
  33. package/dist/fleet/relay-fleet-client.js +33 -0
  34. package/dist/fleet/relay-fleet-client.js.map +1 -0
  35. package/dist/github/index.d.ts +5 -0
  36. package/dist/github/index.d.ts.map +1 -0
  37. package/dist/github/index.js +3 -0
  38. package/dist/github/index.js.map +1 -0
  39. package/dist/github/merge-gate.d.ts +47 -0
  40. package/dist/github/merge-gate.d.ts.map +1 -0
  41. package/dist/github/merge-gate.js +147 -0
  42. package/dist/github/merge-gate.js.map +1 -0
  43. package/dist/github/probe-closer.d.ts +15 -0
  44. package/dist/github/probe-closer.d.ts.map +1 -0
  45. package/dist/github/probe-closer.js +67 -0
  46. package/dist/github/probe-closer.js.map +1 -0
  47. package/dist/index.d.ts +32 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +18 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/issue-key-match.d.ts +3 -0
  52. package/dist/issue-key-match.d.ts.map +1 -0
  53. package/dist/issue-key-match.js +22 -0
  54. package/dist/issue-key-match.js.map +1 -0
  55. package/dist/linear/state-resolver.d.ts +25 -0
  56. package/dist/linear/state-resolver.d.ts.map +1 -0
  57. package/dist/linear/state-resolver.js +221 -0
  58. package/dist/linear/state-resolver.js.map +1 -0
  59. package/dist/mount/local-mount-preflight.d.ts +8 -0
  60. package/dist/mount/local-mount-preflight.d.ts.map +1 -0
  61. package/dist/mount/local-mount-preflight.js +97 -0
  62. package/dist/mount/local-mount-preflight.js.map +1 -0
  63. package/dist/mount/relayfile-binary.d.ts +7 -0
  64. package/dist/mount/relayfile-binary.d.ts.map +1 -0
  65. package/dist/mount/relayfile-binary.js +143 -0
  66. package/dist/mount/relayfile-binary.js.map +1 -0
  67. package/dist/mount/relayfile-cloud-mount-client.d.ts +123 -0
  68. package/dist/mount/relayfile-cloud-mount-client.d.ts.map +1 -0
  69. package/dist/mount/relayfile-cloud-mount-client.js +427 -0
  70. package/dist/mount/relayfile-cloud-mount-client.js.map +1 -0
  71. package/dist/orchestrator/batch-tracker.d.ts +42 -0
  72. package/dist/orchestrator/batch-tracker.d.ts.map +1 -0
  73. package/dist/orchestrator/batch-tracker.js +125 -0
  74. package/dist/orchestrator/batch-tracker.js.map +1 -0
  75. package/dist/orchestrator/factory.d.ts +55 -0
  76. package/dist/orchestrator/factory.d.ts.map +1 -0
  77. package/dist/orchestrator/factory.js +4018 -0
  78. package/dist/orchestrator/factory.js.map +1 -0
  79. package/dist/orchestrator/index.d.ts +5 -0
  80. package/dist/orchestrator/index.d.ts.map +1 -0
  81. package/dist/orchestrator/index.js +4 -0
  82. package/dist/orchestrator/index.js.map +1 -0
  83. package/dist/orchestrator/process-identity.d.ts +23 -0
  84. package/dist/orchestrator/process-identity.d.ts.map +1 -0
  85. package/dist/orchestrator/process-identity.js +122 -0
  86. package/dist/orchestrator/process-identity.js.map +1 -0
  87. package/dist/orchestrator/reaper.d.ts +60 -0
  88. package/dist/orchestrator/reaper.d.ts.map +1 -0
  89. package/dist/orchestrator/reaper.js +293 -0
  90. package/dist/orchestrator/reaper.js.map +1 -0
  91. package/dist/ports/fleet.d.ts +95 -0
  92. package/dist/ports/fleet.d.ts.map +1 -0
  93. package/dist/ports/fleet.js +2 -0
  94. package/dist/ports/fleet.js.map +1 -0
  95. package/dist/ports/index.d.ts +5 -0
  96. package/dist/ports/index.d.ts.map +1 -0
  97. package/dist/ports/index.js +2 -0
  98. package/dist/ports/index.js.map +1 -0
  99. package/dist/ports/mount.d.ts +56 -0
  100. package/dist/ports/mount.d.ts.map +1 -0
  101. package/dist/ports/mount.js +2 -0
  102. package/dist/ports/mount.js.map +1 -0
  103. package/dist/ports/state.d.ts +61 -0
  104. package/dist/ports/state.d.ts.map +1 -0
  105. package/dist/ports/state.js +2 -0
  106. package/dist/ports/state.js.map +1 -0
  107. package/dist/ports/system.d.ts +15 -0
  108. package/dist/ports/system.d.ts.map +1 -0
  109. package/dist/ports/system.js +2 -0
  110. package/dist/ports/system.js.map +1 -0
  111. package/dist/ports/writeback.d.ts +25 -0
  112. package/dist/ports/writeback.d.ts.map +1 -0
  113. package/dist/ports/writeback.js +2 -0
  114. package/dist/ports/writeback.js.map +1 -0
  115. package/dist/safety/factory-scope.d.ts +16 -0
  116. package/dist/safety/factory-scope.d.ts.map +1 -0
  117. package/dist/safety/factory-scope.js +107 -0
  118. package/dist/safety/factory-scope.js.map +1 -0
  119. package/dist/state/in-memory-state-store.d.ts +31 -0
  120. package/dist/state/in-memory-state-store.d.ts.map +1 -0
  121. package/dist/state/in-memory-state-store.js +115 -0
  122. package/dist/state/in-memory-state-store.js.map +1 -0
  123. package/dist/state/index.d.ts +3 -0
  124. package/dist/state/index.d.ts.map +1 -0
  125. package/dist/state/index.js +2 -0
  126. package/dist/state/index.js.map +1 -0
  127. package/dist/state/store.d.ts +29 -0
  128. package/dist/state/store.d.ts.map +1 -0
  129. package/dist/state/store.js +26 -0
  130. package/dist/state/store.js.map +1 -0
  131. package/dist/subscriptions/common.d.ts +7 -0
  132. package/dist/subscriptions/common.d.ts.map +1 -0
  133. package/dist/subscriptions/common.js +59 -0
  134. package/dist/subscriptions/common.js.map +1 -0
  135. package/dist/subscriptions/event-client.d.ts +40 -0
  136. package/dist/subscriptions/event-client.d.ts.map +1 -0
  137. package/dist/subscriptions/event-client.js +234 -0
  138. package/dist/subscriptions/event-client.js.map +1 -0
  139. package/dist/subscriptions/globs.d.ts +5 -0
  140. package/dist/subscriptions/globs.d.ts.map +1 -0
  141. package/dist/subscriptions/globs.js +50 -0
  142. package/dist/subscriptions/globs.js.map +1 -0
  143. package/dist/subscriptions/index.d.ts +8 -0
  144. package/dist/subscriptions/index.d.ts.map +1 -0
  145. package/dist/subscriptions/index.js +5 -0
  146. package/dist/subscriptions/index.js.map +1 -0
  147. package/dist/subscriptions/linear-filter.d.ts +26 -0
  148. package/dist/subscriptions/linear-filter.d.ts.map +1 -0
  149. package/dist/subscriptions/linear-filter.js +143 -0
  150. package/dist/subscriptions/linear-filter.js.map +1 -0
  151. package/dist/subscriptions/specs.d.ts +44 -0
  152. package/dist/subscriptions/specs.d.ts.map +1 -0
  153. package/dist/subscriptions/specs.js +195 -0
  154. package/dist/subscriptions/specs.js.map +1 -0
  155. package/dist/testing/fakes.d.ts +114 -0
  156. package/dist/testing/fakes.d.ts.map +1 -0
  157. package/dist/testing/fakes.js +219 -0
  158. package/dist/testing/fakes.js.map +1 -0
  159. package/dist/testing/index.d.ts +2 -0
  160. package/dist/testing/index.d.ts.map +1 -0
  161. package/dist/testing/index.js +2 -0
  162. package/dist/testing/index.js.map +1 -0
  163. package/dist/triage/heuristic.d.ts +38 -0
  164. package/dist/triage/heuristic.d.ts.map +1 -0
  165. package/dist/triage/heuristic.js +262 -0
  166. package/dist/triage/heuristic.js.map +1 -0
  167. package/dist/triage/index.d.ts +7 -0
  168. package/dist/triage/index.d.ts.map +1 -0
  169. package/dist/triage/index.js +5 -0
  170. package/dist/triage/index.js.map +1 -0
  171. package/dist/triage/llm.d.ts +11 -0
  172. package/dist/triage/llm.d.ts.map +1 -0
  173. package/dist/triage/llm.js +46 -0
  174. package/dist/triage/llm.js.map +1 -0
  175. package/dist/triage/schema.d.ts +240 -0
  176. package/dist/triage/schema.d.ts.map +1 -0
  177. package/dist/triage/schema.js +34 -0
  178. package/dist/triage/schema.js.map +1 -0
  179. package/dist/triage/tiered.d.ts +8 -0
  180. package/dist/triage/tiered.d.ts.map +1 -0
  181. package/dist/triage/tiered.js +40 -0
  182. package/dist/triage/tiered.js.map +1 -0
  183. package/dist/types.d.ts +211 -0
  184. package/dist/types.d.ts.map +1 -0
  185. package/dist/types.js +2 -0
  186. package/dist/types.js.map +1 -0
  187. package/dist/webhook/handler.d.ts +22 -0
  188. package/dist/webhook/handler.d.ts.map +1 -0
  189. package/dist/webhook/handler.js +57 -0
  190. package/dist/webhook/handler.js.map +1 -0
  191. package/dist/webhook/index.d.ts +5 -0
  192. package/dist/webhook/index.d.ts.map +1 -0
  193. package/dist/webhook/index.js +3 -0
  194. package/dist/webhook/index.js.map +1 -0
  195. package/dist/webhook/registrar.d.ts +16 -0
  196. package/dist/webhook/registrar.d.ts.map +1 -0
  197. package/dist/webhook/registrar.js +50 -0
  198. package/dist/webhook/registrar.js.map +1 -0
  199. package/dist/writeback/github.d.ts +6 -0
  200. package/dist/writeback/github.d.ts.map +1 -0
  201. package/dist/writeback/github.js +48 -0
  202. package/dist/writeback/github.js.map +1 -0
  203. package/dist/writeback/index.d.ts +6 -0
  204. package/dist/writeback/index.d.ts.map +1 -0
  205. package/dist/writeback/index.js +4 -0
  206. package/dist/writeback/index.js.map +1 -0
  207. package/dist/writeback/linear.d.ts +41 -0
  208. package/dist/writeback/linear.d.ts.map +1 -0
  209. package/dist/writeback/linear.js +243 -0
  210. package/dist/writeback/linear.js.map +1 -0
  211. package/dist/writeback/shared.d.ts +7 -0
  212. package/dist/writeback/shared.d.ts.map +1 -0
  213. package/dist/writeback/shared.js +29 -0
  214. package/dist/writeback/shared.js.map +1 -0
  215. package/dist/writeback/slack.d.ts +16 -0
  216. package/dist/writeback/slack.d.ts.map +1 -0
  217. package/dist/writeback/slack.js +104 -0
  218. package/dist/writeback/slack.js.map +1 -0
  219. package/package.json +46 -9
  220. package/index.d.ts +0 -2
  221. package/index.js +0 -7
@@ -0,0 +1,221 @@
1
+ import { FACTORY_STATE_ROLES } from '../config/schema';
2
+ // Roles the factory cannot operate without; humanReview is optional (the
3
+ // terminalState falls back to `done` when it is unset).
4
+ const REQUIRED_ROLES = [
5
+ 'readyForAgent',
6
+ 'agentImplementing',
7
+ 'inPlanning',
8
+ 'done',
9
+ ];
10
+ const STATES_INDEX_PATH = '/linear/states/_index.json';
11
+ const stateCanonicalPath = (id) => `/linear/states/${id}.json`;
12
+ // Cap concurrent canonical-record reads so a large states catalog can't flood a
13
+ // remote/cloud mount (rate limits, timeouts, fd exhaustion).
14
+ const CATALOG_READ_CONCURRENCY = 10;
15
+ // Build a resolution from explicit, already-known UUIDs (no mount reads). Used
16
+ // as the back-compat / test path when names aren't configured: the global ids
17
+ // apply to every team. Lenient — unresolved roles only throw when used.
18
+ export function stateResolutionFromIds(stateIds) {
19
+ const roleById = new Map();
20
+ for (const role of FACTORY_STATE_ROLES) {
21
+ const id = stateIds[role];
22
+ if (id)
23
+ roleById.set(id, role);
24
+ }
25
+ return {
26
+ idFor(_teamToken, role) {
27
+ const id = stateIds[role];
28
+ if (!id)
29
+ throw new Error(`No resolved Linear state for role "${role}".`);
30
+ return id;
31
+ },
32
+ optionalIdFor(_teamToken, role) {
33
+ return stateIds[role];
34
+ },
35
+ roleOf(stateId) {
36
+ return stateId ? roleById.get(stateId) : undefined;
37
+ },
38
+ isRole(stateId, role) {
39
+ return Boolean(stateId) && roleById.get(stateId) === role;
40
+ },
41
+ hasHumanReview() {
42
+ return Boolean(stateIds.humanReview);
43
+ },
44
+ };
45
+ }
46
+ const norm = (value) => (value ?? '').trim().toLowerCase();
47
+ const asArray = (value) => {
48
+ if (Array.isArray(value))
49
+ return value;
50
+ if (value && typeof value === 'object') {
51
+ const record = value;
52
+ for (const key of ['entries', 'rows', 'items', 'payload']) {
53
+ if (Array.isArray(record[key]))
54
+ return record[key];
55
+ }
56
+ }
57
+ return [];
58
+ };
59
+ const unwrap = (value) => {
60
+ if (!value || typeof value !== 'object')
61
+ return {};
62
+ const record = value;
63
+ return record.payload && typeof record.payload === 'object'
64
+ ? record.payload
65
+ : record;
66
+ };
67
+ const str = (value) => (typeof value === 'string' && value ? value : undefined);
68
+ // Lazily load and cache the /linear/states catalog. Only invoked when at least
69
+ // one role is configured by name, so explicit-UUID setups never read it.
70
+ class StateCatalog {
71
+ reader;
72
+ #records;
73
+ constructor(reader) {
74
+ this.reader = reader;
75
+ }
76
+ async records() {
77
+ if (this.#records)
78
+ return this.#records;
79
+ let index;
80
+ try {
81
+ index = (await this.reader.readFile(STATES_INDEX_PATH)).content;
82
+ }
83
+ catch (error) {
84
+ throw new Error(`Cannot resolve Linear state names: ${STATES_INDEX_PATH} is unavailable ` +
85
+ `(${error instanceof Error ? error.message : String(error)}). ` +
86
+ `Deploy the workflow-states resource or pin stateIds (UUIDs) in config.`);
87
+ }
88
+ const ids = asArray(index)
89
+ .map((row) => str(row?.id))
90
+ .filter((id) => Boolean(id));
91
+ // Read canonical records in bounded batches — a workspace can have many
92
+ // states, and an unbounded Promise.all would flood a remote/cloud mount.
93
+ const records = [];
94
+ for (let i = 0; i < ids.length; i += CATALOG_READ_CONCURRENCY) {
95
+ const batch = await Promise.all(ids.slice(i, i + CATALOG_READ_CONCURRENCY).map(async (id) => {
96
+ try {
97
+ const rec = unwrap((await this.reader.readFile(stateCanonicalPath(id))).content);
98
+ return { id, name: str(rec.name), teamKey: str(rec.team_key), teamName: str(rec.team_name) };
99
+ }
100
+ catch {
101
+ return { id };
102
+ }
103
+ }));
104
+ records.push(...batch);
105
+ }
106
+ this.#records = records;
107
+ return records;
108
+ }
109
+ // Resolve a state NAME to a UUID, optionally scoped to a team token (matched
110
+ // against team_key or team_name). Throws on no match or ambiguity.
111
+ async resolve(name, teamToken) {
112
+ const records = await this.records();
113
+ let matches = records.filter((rec) => norm(rec.name) === norm(name));
114
+ if (teamToken) {
115
+ // Restrict to states that belong to this team (or are team-less). Never
116
+ // fall back to another team's state of the same name — that would silently
117
+ // mis-route issues across teams. If nothing remains, it's a hard no-match.
118
+ const teamless = (rec) => !rec.teamKey && !rec.teamName;
119
+ const inTeam = (rec) => norm(rec.teamKey) === norm(teamToken) || norm(rec.teamName) === norm(teamToken);
120
+ matches = matches.filter((rec) => inTeam(rec) || teamless(rec));
121
+ const scoped = matches.filter(inTeam);
122
+ if (scoped.length > 0)
123
+ matches = scoped;
124
+ }
125
+ if (matches.length === 0) {
126
+ throw new Error(`No Linear workflow state named "${name}"${teamToken ? ` for team "${teamToken}"` : ''}.`);
127
+ }
128
+ if (matches.length > 1) {
129
+ throw new Error(`Linear workflow state "${name}" is ambiguous (${matches.length} matches)` +
130
+ `${teamToken ? ` for team "${teamToken}"` : ''}; scope it with linear.statesByTeam.`);
131
+ }
132
+ return matches[0].id;
133
+ }
134
+ }
135
+ // Resolve every configured role for every known team to concrete UUIDs, building
136
+ // the forward (team,role)->id map and the reverse id->role map. Throws if a
137
+ // required role cannot be resolved for any team.
138
+ export async function resolveFactoryStates(reader, input) {
139
+ const catalog = new StateCatalog(reader);
140
+ const globalNames = input.states ?? {};
141
+ const explicitIds = input.stateIds ?? {};
142
+ // Normalize statesByTeam keys up front so per-team lookups are case-insensitive
143
+ // and consistent with how byTeam/teamTokens are keyed (avoids a lowercase
144
+ // team token silently missing an uppercase override, then overwriting it).
145
+ const byTeamNames = {};
146
+ for (const [team, names] of Object.entries(input.statesByTeam ?? {})) {
147
+ byTeamNames[norm(team)] = names;
148
+ }
149
+ // Resolve one role for one team token, applying precedence:
150
+ // per-team name > global name > explicit UUID.
151
+ const resolveRole = async (teamToken, role) => {
152
+ const perTeamName = teamToken ? byTeamNames[norm(teamToken)]?.[role] : undefined;
153
+ const name = perTeamName ?? globalNames[role];
154
+ if (name)
155
+ return catalog.resolve(name, teamToken);
156
+ return explicitIds[role];
157
+ };
158
+ // Dedupe team tokens by normalized form while keeping the first original
159
+ // casing for resolution + error messages.
160
+ const teamTokenByNorm = new Map();
161
+ for (const team of [...Object.keys(input.statesByTeam ?? {}), ...(input.teams ?? [])]) {
162
+ const key = norm(team);
163
+ if (key && !teamTokenByNorm.has(key))
164
+ teamTokenByNorm.set(key, team);
165
+ }
166
+ const byTeam = new Map();
167
+ const resolveAllRoles = async (teamToken, enforce) => {
168
+ const resolved = {};
169
+ for (const role of FACTORY_STATE_ROLES) {
170
+ const id = await resolveRole(teamToken, role);
171
+ if (id)
172
+ resolved[role] = id;
173
+ }
174
+ const missing = REQUIRED_ROLES.filter((role) => !resolved[role]);
175
+ if (enforce && missing.length > 0) {
176
+ throw new Error(`Linear state resolution incomplete${teamToken ? ` for team "${teamToken}"` : ''}: ` +
177
+ `missing [${missing.join(', ')}]. Set linear.states / linear.statesByTeam (by name) or stateIds (UUIDs).`);
178
+ }
179
+ return resolved;
180
+ };
181
+ // The team-less default only needs to satisfy required roles when there's
182
+ // global config meant to fill it; a per-team-only setup leaves it best-effort
183
+ // (each subscribed team is enforced below, and idFor() throws at use if an
184
+ // unconfigured team's issue ever appears).
185
+ const hasGlobalConfig = Object.keys(globalNames).length > 0 || Object.keys(explicitIds).length > 0;
186
+ const defaultIds = await resolveAllRoles(undefined, hasGlobalConfig);
187
+ for (const [key, team] of teamTokenByNorm) {
188
+ byTeam.set(key, await resolveAllRoles(team, true));
189
+ }
190
+ const idsFor = (teamToken) => (teamToken ? byTeam.get(norm(teamToken)) : undefined) ?? defaultIds;
191
+ // Reverse map across the default + every team mapping.
192
+ const roleById = new Map();
193
+ for (const ids of [defaultIds, ...byTeam.values()]) {
194
+ for (const role of FACTORY_STATE_ROLES) {
195
+ const id = ids[role];
196
+ if (id)
197
+ roleById.set(id, role);
198
+ }
199
+ }
200
+ return {
201
+ idFor(teamToken, role) {
202
+ const id = idsFor(teamToken)[role];
203
+ if (!id)
204
+ throw new Error(`No resolved Linear state for role "${role}"${teamToken ? ` (team "${teamToken}")` : ''}.`);
205
+ return id;
206
+ },
207
+ optionalIdFor(teamToken, role) {
208
+ return idsFor(teamToken)[role];
209
+ },
210
+ roleOf(stateId) {
211
+ return stateId ? roleById.get(stateId) : undefined;
212
+ },
213
+ isRole(stateId, role) {
214
+ return Boolean(stateId) && roleById.get(stateId) === role;
215
+ },
216
+ hasHumanReview(teamToken) {
217
+ return Boolean(idsFor(teamToken).humanReview);
218
+ },
219
+ };
220
+ }
221
+ //# sourceMappingURL=state-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-resolver.js","sourceRoot":"","sources":["../../src/linear/state-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface EnsureLocalMountOptions {
2
+ stateWaitTimeoutMs?: number;
3
+ stateWaitPollMs?: number;
4
+ acceptableWorkspaceIds?: readonly string[];
5
+ }
6
+ export declare function ensureLocalMount(workspaceId: string, startDir: string, options?: EnsureLocalMountOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=local-mount-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-mount-preflight.d.ts","sourceRoot":"","sources":["../../src/mount/local-mount-preflight.ts"],"names":[],"mappings":"AAQA,UAAU,uBAAuB;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;IAIxB,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC3C;AAED,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CAsBf"}
@@ -0,0 +1,97 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { spawn } from 'node:child_process';
4
+ import { checkMountStaleness, resolveRelayfileMountBinary } from './relayfile-binary';
5
+ const STATE_FILE = '.integrations/.relay/state.json';
6
+ export async function ensureLocalMount(workspaceId, startDir, options = {}) {
7
+ const stateFilePath = join(startDir, STATE_FILE);
8
+ if (!(await isMountStatePresent(stateFilePath))) {
9
+ await spawnMount(workspaceId, startDir);
10
+ await waitForStateFile(stateFilePath, workspaceId, options.stateWaitTimeoutMs, options.stateWaitPollMs, options.acceptableWorkspaceIds);
11
+ return;
12
+ }
13
+ const staleness = checkMountStaleness(stateFilePath, workspaceId, options.acceptableWorkspaceIds);
14
+ if (staleness.stale) {
15
+ const suffix = staleness.reason !== undefined ? ` (${staleness.reason})` : '';
16
+ process.stderr.write(`[factory] local mount is stale${suffix}; writeback may not propagate. Run: relayfile stop && relayfile start ${workspaceId} .integrations --background\n`);
17
+ }
18
+ }
19
+ async function isMountStatePresent(stateFilePath) {
20
+ try {
21
+ const raw = await readFile(stateFilePath, 'utf8');
22
+ JSON.parse(raw);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ async function spawnMount(workspaceId, startDir) {
30
+ const binaryPath = resolveRelayfileMountBinary();
31
+ return new Promise((resolve, reject) => {
32
+ const child = spawn(binaryPath, ['start', workspaceId, '.integrations', '--background', '--rehome'], {
33
+ cwd: startDir,
34
+ stdio: ['ignore', 'ignore', 'pipe'],
35
+ });
36
+ const stderrChunks = [];
37
+ if (child.stderr) {
38
+ child.stderr.on('data', (chunk) => stderrChunks.push(chunk));
39
+ }
40
+ child.on('close', (code) => {
41
+ const stderr = Buffer.concat(stderrChunks).toString('utf8');
42
+ if (isAuthError(stderr)) {
43
+ reject(new Error(`[factory] relayfile mount not authorized — run: relayfile workspace join ${workspaceId} --write`));
44
+ return;
45
+ }
46
+ if (code !== 0) {
47
+ reject(new Error(`[factory] relayfile mount start failed (exit ${code ?? 'null'}): ${stderr.trim()}`));
48
+ return;
49
+ }
50
+ resolve();
51
+ });
52
+ child.on('error', (err) => {
53
+ reject(new Error(`[factory] relayfile mount start error: ${err.message}`));
54
+ });
55
+ });
56
+ }
57
+ async function waitForStateFile(stateFilePath, workspaceId, timeoutMs = 10_000, pollMs = 200, acceptableWorkspaceIds = []) {
58
+ const deadline = Date.now() + timeoutMs;
59
+ let lastInvalidReason = 'state file was not created';
60
+ while (Date.now() < deadline) {
61
+ try {
62
+ const raw = await readFile(stateFilePath, 'utf8');
63
+ const state = JSON.parse(raw);
64
+ if (isValidMountState(state, workspaceId, acceptableWorkspaceIds))
65
+ return;
66
+ lastInvalidReason = `state file is malformed or for another workspace: ${stateFilePath}`;
67
+ }
68
+ catch (error) {
69
+ if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT') {
70
+ lastInvalidReason = 'state file was not created';
71
+ }
72
+ else {
73
+ lastInvalidReason = error instanceof Error ? error.message : String(error);
74
+ }
75
+ // not yet present
76
+ }
77
+ await sleep(pollMs);
78
+ }
79
+ throw new Error(`[factory] relayfile mount did not become ready within ${timeoutMs}ms (${lastInvalidReason})`);
80
+ }
81
+ function isValidMountState(value, workspaceId, acceptableWorkspaceIds = []) {
82
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
83
+ return false;
84
+ const state = value;
85
+ const accepted = new Set([workspaceId, ...acceptableWorkspaceIds]);
86
+ return typeof state.workspaceId === 'string' && accepted.has(state.workspaceId) &&
87
+ typeof state.lastReconcileAt === 'string' &&
88
+ Number.isFinite(Date.parse(state.lastReconcileAt)) &&
89
+ typeof state.pid === 'number' &&
90
+ Number.isInteger(state.pid) &&
91
+ state.pid > 0;
92
+ }
93
+ const isAuthError = (stderr) => stderr.includes('workspace join') ||
94
+ stderr.includes('unauthorized') ||
95
+ stderr.includes('no credentials');
96
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
97
+ //# sourceMappingURL=local-mount-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-mount-preflight.js","sourceRoot":"","sources":["../../src/mount/local-mount-preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function resolveRelayfileMountBinary(startDir?: string): string;
2
+ export declare function checkMountStaleness(stateFilePath: string, workspaceId: string, acceptableWorkspaceIds?: readonly string[]): {
3
+ stale: boolean;
4
+ reason?: string;
5
+ pid?: number;
6
+ };
7
+ //# sourceMappingURL=relayfile-binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relayfile-binary.d.ts","sourceRoot":"","sources":["../../src/mount/relayfile-binary.ts"],"names":[],"mappings":"AA0EA,wBAAgB,2BAA2B,CAAC,QAAQ,SAAY,GAAG,MAAM,CAqBxE;AAED,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAKnB,sBAAsB,GAAE,SAAS,MAAM,EAAO,GAC7C;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CA0DnD"}
@@ -0,0 +1,143 @@
1
+ import { accessSync, constants, readFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ const STALE_RECONCILE_MS = 15 * 60 * 1000;
4
+ const NOT_FOUND_ERROR = '[factory] relayfile-mount binary not found. Install dependencies or run: npm run relayfile-mount:install';
5
+ function canExecute(filePath) {
6
+ if (!filePath)
7
+ return false;
8
+ try {
9
+ accessSync(filePath, constants.X_OK);
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ function devArchSuffix() {
17
+ if (process.platform === 'darwin') {
18
+ return process.arch === 'arm64' ? 'darwin-arm64' : 'darwin-amd64';
19
+ }
20
+ if (process.platform === 'linux') {
21
+ return process.arch === 'arm64' ? 'linux-arm64' : 'linux-amd64';
22
+ }
23
+ return `${process.platform}-${process.arch}`;
24
+ }
25
+ function binaryName() {
26
+ return process.platform === 'win32' ? 'relayfile-mount.exe' : 'relayfile-mount';
27
+ }
28
+ function optionalPackageArchSuffix() {
29
+ return `${process.platform}-${process.arch}`;
30
+ }
31
+ function findPearRoot(startDir) {
32
+ let current = resolve(startDir);
33
+ for (;;) {
34
+ try {
35
+ accessSync(join(current, 'factory.config.json'), constants.R_OK);
36
+ return current;
37
+ }
38
+ catch {
39
+ const parent = dirname(current);
40
+ if (parent === current)
41
+ return null;
42
+ current = parent;
43
+ }
44
+ }
45
+ }
46
+ function devRelayfileCandidates(pearRoot) {
47
+ const distRoot = resolve(process.env.RELAYFILE_DIST_DIR ?? join(pearRoot, '..', 'relayfile', 'dist'));
48
+ const suffix = devArchSuffix();
49
+ return [
50
+ join(distRoot, `relayfile-mount-${suffix}`),
51
+ join(distRoot, suffix, binaryName()),
52
+ ];
53
+ }
54
+ // @relayfile/sdk carries relayfile-mount through per-platform optional
55
+ // dependencies. Prefer that bundled binary so factory start does not depend on
56
+ // a global relayfile install or a manually populated repo bin/ directory.
57
+ function optionalPackageCandidates(pearRoot) {
58
+ const suffix = optionalPackageArchSuffix();
59
+ return [
60
+ join(pearRoot, 'node_modules', '@relayfile', `mount-${suffix}`, 'bin', binaryName()),
61
+ join(pearRoot, 'node_modules', '@relayfile', 'sdk', 'node_modules', '@relayfile', `mount-${suffix}`, 'bin', binaryName()),
62
+ ];
63
+ }
64
+ export function resolveRelayfileMountBinary(startDir = __dirname) {
65
+ if (process.env.RELAYFILE_MOUNT_BIN) {
66
+ const explicitBinary = resolve(process.env.RELAYFILE_MOUNT_BIN);
67
+ if (canExecute(explicitBinary))
68
+ return explicitBinary;
69
+ throw new Error(NOT_FOUND_ERROR);
70
+ }
71
+ const pearRoot = findPearRoot(startDir);
72
+ const candidates = pearRoot
73
+ ? [
74
+ ...optionalPackageCandidates(pearRoot),
75
+ join(pearRoot, 'bin', binaryName()),
76
+ ...devRelayfileCandidates(pearRoot),
77
+ ]
78
+ : [];
79
+ for (const candidate of candidates) {
80
+ if (canExecute(candidate))
81
+ return resolve(candidate);
82
+ }
83
+ throw new Error(NOT_FOUND_ERROR);
84
+ }
85
+ export function checkMountStaleness(stateFilePath, workspaceId,
86
+ // Alternate identifiers that name the SAME workspace (e.g. the cloud-side
87
+ // UUID for a `rw_` handle). The local mount records the cloud UUID in its
88
+ // state.json, so without these aliases a handle-vs-UUID comparison would
89
+ // report a false "workspace mismatch".
90
+ acceptableWorkspaceIds = []) {
91
+ let parsed;
92
+ try {
93
+ parsed = JSON.parse(readFileSync(stateFilePath, 'utf8'));
94
+ }
95
+ catch (error) {
96
+ if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT') {
97
+ return { stale: false };
98
+ }
99
+ return { stale: true, reason: `mount state is unreadable: ${error instanceof Error ? error.message : String(error)}` };
100
+ }
101
+ if (typeof parsed !== 'object' || parsed === null) {
102
+ return { stale: true, reason: 'mount state is unreadable: expected object' };
103
+ }
104
+ const registeredWorkspaceId = typeof parsed.workspaceId === 'string' ? parsed.workspaceId : undefined;
105
+ const accepted = new Set([workspaceId, ...acceptableWorkspaceIds]);
106
+ if (registeredWorkspaceId === undefined || !accepted.has(registeredWorkspaceId)) {
107
+ return {
108
+ stale: true,
109
+ reason: `workspace mismatch: registered=${registeredWorkspaceId ?? 'unknown'} expected=${[...accepted].join('|')}`,
110
+ };
111
+ }
112
+ const pid = typeof parsed.pid === 'number' && Number.isInteger(parsed.pid) && parsed.pid > 0
113
+ ? parsed.pid
114
+ : undefined;
115
+ const lastReconcileAt = typeof parsed.lastReconcileAt === 'string'
116
+ ? Date.parse(parsed.lastReconcileAt)
117
+ : NaN;
118
+ if (!Number.isFinite(lastReconcileAt)) {
119
+ return { stale: true, reason: 'last reconcile timestamp is missing', pid };
120
+ }
121
+ const ageMs = Date.now() - lastReconcileAt;
122
+ if (ageMs > STALE_RECONCILE_MS) {
123
+ return {
124
+ stale: true,
125
+ reason: `last reconcile ${Math.floor(ageMs / 60000)}m ago`,
126
+ pid,
127
+ };
128
+ }
129
+ if (pid === undefined) {
130
+ return { stale: true, reason: 'mount process pid is missing' };
131
+ }
132
+ try {
133
+ process.kill(pid, 0);
134
+ }
135
+ catch (error) {
136
+ if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'EPERM') {
137
+ return { stale: false, pid };
138
+ }
139
+ return { stale: true, reason: `mount process (pid ${pid}) is not running`, pid };
140
+ }
141
+ return { stale: false, pid };
142
+ }
143
+ //# sourceMappingURL=relayfile-binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relayfile-binary.js","sourceRoot":"","sources":["../../src/mount/relayfile-binary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import { type ActiveWorkspaceDescriptor, type CloudSession, type CloudSessionOptions } from '@agent-relay/cloud';
2
+ import { type ChangeEvent, type DeleteFileInput, type EventFeedResponse, type FileReadResponse, type GetEventsOptions, type ListTreeOptions, type ResourceAtEventResult, type OperationStatusResponse, type Subscription, type TreeResponse, type WriteFileInput, type WriteQueuedResponse } from '@relayfile/sdk';
3
+ import type { EventPage, MountClient, ProviderSyncStatus, SubscribeOptions } from '../ports';
4
+ import { type RelayfileEventClient, type TokenProvider } from '../subscriptions';
5
+ export declare const FACTORY_RELAYFILE_SCOPES: readonly ["relayfile:fs:read:/linear/issues/**", "relayfile:fs:write:/linear/issues/**", "relayfile:fs:read:/github/repos/**", "relayfile:fs:read:/slack/channels/**", "relayfile:fs:write:/slack/channels/**", "relayfile:fs:read:/slack/users/**"];
6
+ export type CloudSessionProvider = (options?: CloudSessionOptions) => Promise<CloudSession>;
7
+ export type ActiveWorkspaceResolver = (options?: {
8
+ interactive?: boolean;
9
+ }) => Promise<ActiveWorkspaceDescriptor>;
10
+ export interface ResolvedFactoryWorkspace {
11
+ /** Relayfile workspace handle (e.g. `rw_7ccfea89`) — what the mount/config use. */
12
+ workspaceId: string;
13
+ /**
14
+ * Cloud-side UUID for the same workspace (e.g. `50587328-…`). The local
15
+ * relayfile mount records this form in its state.json, so it is passed to the
16
+ * staleness check as an accepted alias to avoid a spurious "workspace
17
+ * mismatch" warning when handle and UUID refer to the same workspace.
18
+ */
19
+ cloudWorkspaceId?: string;
20
+ }
21
+ /**
22
+ * Derive the factory's workspace from the active cloud session rather than a
23
+ * hardcoded config value. `resolveActiveWorkspace()` resolves the locally
24
+ * pinned workspace against the cloud API and returns both identifier forms.
25
+ * Falls back to the built-in default when resolution fails (offline / no
26
+ * session), so callers always get a usable handle.
27
+ */
28
+ export declare function resolveFactoryWorkspace(resolver?: ActiveWorkspaceResolver): Promise<ResolvedFactoryWorkspace>;
29
+ export interface RelayfileWorkspaceHandleLike {
30
+ info: {
31
+ relayfileUrl: string;
32
+ };
33
+ client(): RelayFileClientLike;
34
+ getToken(): Promise<string> | string;
35
+ }
36
+ export type RelayfileSetupFactory = (options: {
37
+ cloudApiUrl: string;
38
+ tokenProvider: () => Promise<string>;
39
+ }) => {
40
+ joinWorkspace(workspaceId: string, options?: {
41
+ agentName?: string;
42
+ scopes?: string[];
43
+ }): Promise<RelayfileWorkspaceHandleLike>;
44
+ };
45
+ export interface RelayfileCloudMountClientConfig {
46
+ backend?: 'relayfile-cloud';
47
+ workspaceId?: string;
48
+ cloudApiUrl?: string;
49
+ cloudSessionProvider?: CloudSessionProvider;
50
+ cloudSessionRefreshTimeoutMs?: number;
51
+ cloudSessionEnv?: NodeJS.ProcessEnv;
52
+ relayfileSetupFactory?: RelayfileSetupFactory;
53
+ agentName?: string;
54
+ scopes?: string[];
55
+ client?: RelayFileClientLike;
56
+ tokenProvider?: TokenProvider;
57
+ baseUrl?: string;
58
+ eventClient?: RelayfileEventClient;
59
+ isAllowedDraft?: (path: string, content: unknown, opts?: {
60
+ guarded?: boolean;
61
+ }) => boolean | Promise<boolean>;
62
+ isAllowedDelete?: (path: string, currentContent: unknown) => boolean | Promise<boolean>;
63
+ }
64
+ export type RelayFileClientLike = {
65
+ readFile(workspaceId: string, path: string): Promise<FileReadResponse>;
66
+ writeFile(input: WriteFileInput): Promise<WriteQueuedResponse>;
67
+ deleteFile(input: DeleteFileInput): Promise<WriteQueuedResponse>;
68
+ listTree(workspaceId: string, options?: ListTreeOptions): Promise<TreeResponse>;
69
+ getEvents(workspaceId: string, options?: GetEventsOptions): Promise<EventFeedResponse>;
70
+ listLastNChanges?(limit: number, context?: {
71
+ workspaceId: string;
72
+ token?: string;
73
+ }): Promise<{
74
+ events: ChangeEvent[];
75
+ }>;
76
+ getResourceAtEvent(eventId: string, context?: {
77
+ workspaceId: string;
78
+ token?: string;
79
+ }): Promise<ResourceAtEventResult>;
80
+ getOp?(workspaceId: string, opId: string): Promise<OperationStatusResponse>;
81
+ getSyncStatus?(workspaceId: string, options?: {
82
+ provider?: string;
83
+ }): Promise<unknown>;
84
+ getToken?(): Promise<string> | string;
85
+ getBaseUrl?(): string;
86
+ };
87
+ export declare class RelayfileCloudMountClient implements MountClient {
88
+ #private;
89
+ readonly workspaceId: string;
90
+ readonly writebackTransport = "relayfile-cloud";
91
+ constructor(config?: RelayfileCloudMountClientConfig);
92
+ setDefaultAllowedDraftPredicate(predicate: (path: string, content: unknown, opts?: {
93
+ guarded?: boolean;
94
+ }) => boolean | Promise<boolean>): void;
95
+ static fromConfig(config?: RelayfileCloudMountClientConfig): Promise<RelayfileCloudMountClient>;
96
+ readFile(path: string): Promise<{
97
+ content: unknown;
98
+ revision?: string;
99
+ }>;
100
+ writeFile(path: string, content: unknown, opts?: {
101
+ guarded?: boolean;
102
+ }): Promise<void>;
103
+ deleteFile(path: string): Promise<void>;
104
+ listTree(prefix: string): Promise<string[]>;
105
+ subscribe(globs: string[], onChange: (event: ChangeEvent) => void, opts?: SubscribeOptions): Subscription;
106
+ getEvents(opts: {
107
+ cursor?: string;
108
+ limit?: number;
109
+ provider?: string;
110
+ last?: number;
111
+ }): Promise<EventPage>;
112
+ getEventHighWatermark(opts?: {
113
+ provider?: string;
114
+ }): Promise<string | undefined>;
115
+ getSyncStatus(provider: string): Promise<ProviderSyncStatus | undefined>;
116
+ confirmWrite(path: string, opts?: {
117
+ timeoutMs?: number;
118
+ }): Promise<'acked' | 'pending' | 'failed' | 'timeout'>;
119
+ ensureSubRoot(prefix: string, _opts?: {
120
+ timeoutMs?: number;
121
+ }): Promise<'ready' | 'absent'>;
122
+ }
123
+ //# sourceMappingURL=relayfile-cloud-mount-client.d.ts.map