@cat-factory/integrations 0.69.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,145 @@
1
+ import { classifyComposePs, composeExecArgs, healthGateIntervalMs, healthGateTimeoutMs, matchesHttpExpectation, recipeStepIntervalMs, recipeStepTimeoutMs, tailOutput, waitFileExecArgs, } from './compose-environment.logic.js';
2
+ /** Run one recipe setup/teardown step, returning a normalized verdict (never throws). */
3
+ export async function runRecipeStep(step, ctx) {
4
+ const { runtime, scope, env, project } = ctx;
5
+ const timeoutMs = recipeStepTimeoutMs(step);
6
+ try {
7
+ switch (step.kind) {
8
+ case 'compose-exec': {
9
+ const res = await runtime.compose(composeExecArgs(scope, step), {
10
+ env,
11
+ timeoutMs,
12
+ ...(step.stdinFile ? { stdin: { project, checkoutFile: step.stdinFile } } : {}),
13
+ });
14
+ return res.code === 0
15
+ ? { ok: true }
16
+ : { ok: false, error: tailOutput(res.stderr || res.stdout) || `exit ${res.code}` };
17
+ }
18
+ case 'copy-file': {
19
+ if (!runtime.copyCheckoutFile)
20
+ return { ok: false, error: 'runtime cannot copy checkout files' };
21
+ await runtime.copyCheckoutFile(project, step.from, step.to);
22
+ return { ok: true };
23
+ }
24
+ case 'wait-http':
25
+ return pollUntil(timeoutMs, recipeStepIntervalMs(step), () => probeHttp(step.url, step));
26
+ case 'wait-file':
27
+ return pollUntil(timeoutMs, recipeStepIntervalMs(step), () => probeFile(step, ctx));
28
+ case 'host-command': {
29
+ if (!runtime.hostCommand)
30
+ return { ok: false, error: 'runtime cannot run host commands' };
31
+ const res = await runtime.hostCommand(project, step.command, {
32
+ ...(step.workdir ? { workdir: step.workdir } : {}),
33
+ env,
34
+ timeoutMs,
35
+ });
36
+ return res.code === 0
37
+ ? { ok: true }
38
+ : { ok: false, error: tailOutput(res.stderr || res.stdout) || `exit ${res.code}` };
39
+ }
40
+ default:
41
+ // A structural guard elsewhere validates the recipe, so a stale/hand-edited config can
42
+ // carry an unknown step kind. Return a clean verdict rather than falling off the switch.
43
+ return {
44
+ ok: false,
45
+ error: `unsupported recipe step kind '${step.kind ?? 'unknown'}'`,
46
+ };
47
+ }
48
+ }
49
+ catch (err) {
50
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
51
+ }
52
+ }
53
+ /**
54
+ * Run the terminal health gate until it passes or its budget elapses (never throws). The gate's own
55
+ * timeout/interval are derived from `gate` here (via {@link healthGateTimeoutMs}/{@link
56
+ * healthGateIntervalMs}), so callers pass only `shortTimeoutMs` — the bound for the individual
57
+ * compose/HTTP probe calls the gate makes — rather than re-deriving the budget at every call site.
58
+ */
59
+ export async function runHealthGate(gate, ctx, shortTimeoutMs) {
60
+ const { runtime, scope, env } = ctx;
61
+ const timeoutMs = healthGateTimeoutMs(gate);
62
+ const intervalMs = healthGateIntervalMs(gate);
63
+ if (gate.kind === 'http') {
64
+ return pollUntil(timeoutMs, intervalMs, () => probeHttp(gate.url, gate, shortTimeoutMs));
65
+ }
66
+ if (gate.kind === 'compose-exec') {
67
+ return pollUntil(timeoutMs, intervalMs, async () => {
68
+ const res = await runtime.compose(composeExecArgs(scope, { service: gate.service, command: gate.command }), { env, timeoutMs: shortTimeoutMs });
69
+ return {
70
+ done: res.code === 0,
71
+ error: tailOutput(res.stderr || res.stdout) || `exit ${res.code}`,
72
+ };
73
+ });
74
+ }
75
+ // compose-healthy: poll `ps` until the stack is ready / a service crashed.
76
+ return pollUntil(timeoutMs, intervalMs, async () => {
77
+ const ps = await runtime.compose([...scope, 'ps', '-a', '--format', 'json'], {
78
+ env,
79
+ timeoutMs: shortTimeoutMs,
80
+ });
81
+ const status = ps.code === 0 ? classifyComposePs(ps.stdout) : 'provisioning';
82
+ if (status === 'ready')
83
+ return { done: true };
84
+ if (status === 'failed')
85
+ return { done: false, fatal: true, error: 'a service is unhealthy or crashed' };
86
+ return { done: false, error: 'stack not healthy yet' };
87
+ });
88
+ }
89
+ /** Probe a URL once for a `wait-http` step / `http` gate; a network error is a non-fatal retry. */
90
+ async function probeHttp(url, opts, timeoutMs = 60_000) {
91
+ try {
92
+ const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
93
+ // Read the body only when a substring is required; otherwise release it so the poll doesn't
94
+ // leave an unconsumed body pinning the connection on every re-probe.
95
+ let body = '';
96
+ if (opts.expectBodyContains)
97
+ body = await res.text();
98
+ else
99
+ await res.body?.cancel();
100
+ return matchesHttpExpectation(res.status, body, opts)
101
+ ? { done: true }
102
+ : { done: false, error: `HTTP ${res.status}` };
103
+ }
104
+ catch (err) {
105
+ return { done: false, error: err instanceof Error ? err.message : String(err) };
106
+ }
107
+ }
108
+ /** Probe a `wait-file` step once — in a container (`test -f`) or the checkout. */
109
+ async function probeFile(step, ctx, shortTimeoutMs = 60_000) {
110
+ const { runtime, scope, env, project } = ctx;
111
+ if (step.service) {
112
+ const res = await runtime.compose(waitFileExecArgs(scope, step.service, step.path), {
113
+ env,
114
+ timeoutMs: shortTimeoutMs,
115
+ });
116
+ return res.code === 0 ? { done: true } : { done: false, error: `not present yet` };
117
+ }
118
+ const exists = (await runtime.checkoutFileExists?.(project, step.path)) ?? false;
119
+ return exists ? { done: true } : { done: false, error: `not present yet` };
120
+ }
121
+ /**
122
+ * Poll `attempt` until it reports `done` (success) or `fatal` (a definitive failure — stop early),
123
+ * or the budget elapses (timeout failure). Attempts at least once; sleeps `intervalMs` between tries.
124
+ */
125
+ async function pollUntil(timeoutMs, intervalMs, attempt) {
126
+ const deadline = Date.now() + timeoutMs;
127
+ let lastError = 'timed out';
128
+ for (;;) {
129
+ const res = await attempt();
130
+ if (res.done)
131
+ return { ok: true };
132
+ if (res.fatal)
133
+ return { ok: false, error: res.error ?? 'failed' };
134
+ lastError = res.error ?? lastError;
135
+ if (Date.now() + intervalMs >= deadline) {
136
+ return { ok: false, error: `timed out after ${timeoutMs}ms (${lastError})` };
137
+ }
138
+ await sleep(intervalMs);
139
+ }
140
+ }
141
+ /** Sleep `ms` between poll attempts (host-side; recipe execution is local-facade only). */
142
+ function sleep(ms) {
143
+ return new Promise((resolve) => setTimeout(resolve, ms));
144
+ }
145
+ //# sourceMappingURL=recipe-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe-runner.js","sourceRoot":"","sources":["../../../src/modules/compose/recipe-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { Clock, CreateSharedStackInput, IdGenerator, RecipeStepRecorder, SharedStack, SharedStackRepository, UpdateSharedStackInput, WorkspaceRepository } from '@cat-factory/kernel';
2
+ import { type ComposeRuntime } from '../compose/compose-environment.logic.js';
3
+ export interface SharedStackServiceDependencies {
4
+ sharedStackRepository: SharedStackRepository;
5
+ workspaceRepository: WorkspaceRepository;
6
+ idGenerator: IdGenerator;
7
+ clock: Clock;
8
+ /**
9
+ * The host Docker seam used to bring a stack UP / tear it DOWN. Wired ONLY on a facade with a
10
+ * host daemon (the local facade); absent on the Worker / plain Node, where CRUD still works but
11
+ * `ensureUp`/`teardown` refuse with a clear "requires the local Docker runtime" error (the
12
+ * documented compose runtime-binding exception — persistence stays symmetric, execution does not).
13
+ */
14
+ composeRuntime?: ComposeRuntime;
15
+ /**
16
+ * Optional VCS token used to CLONE a stack's repo during bring-up (threaded to the runtime's
17
+ * `checkout` as `token`). Wired on the local facade from the same source-control PAT the agent
18
+ * containers push with, so a shared stack whose `cloneUrl` is a PRIVATE repo can be brought up.
19
+ * Absent ⇒ the clone runs unauthenticated (public repos only), exactly as before.
20
+ */
21
+ cloneToken?: string;
22
+ /**
23
+ * Optional per-step provisioning-log recorder factory: given a stack, returns a recorder the
24
+ * bring-up streams per-step verdicts through (clone, network, env-file, up, each setup step,
25
+ * health gate), so the Infrastructure "View logs" drawer shows which step ran/died. Absent ⇒ no
26
+ * per-step logging (the status/lastError on the record are still updated).
27
+ */
28
+ provisioningLog?: (stack: SharedStack) => RecipeStepRecorder;
29
+ }
30
+ /**
31
+ * Lifecycle for a workspace's SHARED STACKS — long-lived compose infra a per-PR consumer
32
+ * environment attaches to over an external network (the acme-shared-services pilot). CRUD is
33
+ * runtime-neutral persistence (works on every facade); the bring-up (`ensureUp`) / teardown drive a
34
+ * host Docker daemon through the injected {@link ComposeRuntime}, so they run ONLY on the local
35
+ * facade.
36
+ *
37
+ * A shared stack is NEVER swept with a run and NEVER TTL-reaped — teardown is a deliberate action.
38
+ * Unlike a per-PR preview env, its committed compose files run AS AUTHORED (host ports kept, no
39
+ * isolation rewrite): it is the operator's own trusted infra, so the trust boundary is configuring
40
+ * the stack, not sandboxing it. `ensureUp` is idempotent + coalesces concurrent callers onto one
41
+ * in-flight bring-up per stack id.
42
+ */
43
+ export declare class SharedStackService {
44
+ private readonly stacks;
45
+ private readonly workspaceRepository;
46
+ private readonly idGenerator;
47
+ private readonly clock;
48
+ private readonly runtime;
49
+ private readonly cloneToken;
50
+ private readonly provisioningLog;
51
+ private readonly inflight;
52
+ constructor(deps: SharedStackServiceDependencies);
53
+ /** List a workspace's shared stacks (ordered by creation). */
54
+ list(workspaceId: string): Promise<SharedStack[]>;
55
+ /** A single shared stack by id. */
56
+ get(workspaceId: string, id: string): Promise<SharedStack>;
57
+ /** Create a new shared stack (initially `stopped`). */
58
+ create(workspaceId: string, input: CreateSharedStackInput): Promise<SharedStack>;
59
+ /** Patch a shared stack's config. A running stack cannot be reconfigured — tear it down first. */
60
+ update(workspaceId: string, id: string, patch: UpdateSharedStackInput): Promise<SharedStack>;
61
+ /** Remove a shared stack. A running stack must be torn down first (never silently killed). */
62
+ remove(workspaceId: string, id: string): Promise<void>;
63
+ /**
64
+ * Bring a shared stack up (idempotent). Already-`running` ⇒ a no-op returning the record.
65
+ * Otherwise: clone/refresh the repo, create its managed networks, `up -d` under its profiles,
66
+ * materialize env-file templates, run the ordered setup steps, then poll the terminal health gate
67
+ * — persisting `running` / `failed` (+ `lastError`) at the end. Concurrent callers coalesce onto
68
+ * one in-flight bring-up. Requires the host Docker runtime (local facade).
69
+ */
70
+ ensureUp(workspaceId: string, id: string): Promise<SharedStack>;
71
+ /** Tear a shared stack down (`down -v`). A deliberate action; the stack row is preserved. */
72
+ teardown(workspaceId: string, id: string): Promise<SharedStack>;
73
+ /** The stable compose project name for a shared stack (long-lived, NOT per-PR). */
74
+ private projectName;
75
+ /**
76
+ * Is the stack's compose project ACTUALLY up on the daemon right now? A project-name-scoped
77
+ * `compose ps` (no checkout / `-f` needed) classified as `ready`. Used to reconcile a stored
78
+ * `running` against reality before `ensureUp` short-circuits — a failed probe (daemon gone,
79
+ * containers pruned) reads as not-live so the caller re-provisions. Never throws.
80
+ */
81
+ private isStackLive;
82
+ /** Drive the full bring-up, persisting the terminal `running`/`failed` verdict. */
83
+ private bringUp;
84
+ /**
85
+ * Refuse a stack's `host-command` setup steps unless it opted in (`allowHostCommands`) AND the
86
+ * runtime can run host commands. Returns a blocking message, or null when allowed / none declared.
87
+ */
88
+ private checkHostCommands;
89
+ /** Write a stack's lifecycle transition (status + lastError, bumping updatedAt) and return it. */
90
+ private persist;
91
+ /** Best-effort per-step provisioning-log entry (never throws; no-op when no recorder is wired). */
92
+ private logStep;
93
+ }
94
+ //# sourceMappingURL=SharedStackService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedStackService.d.ts","sourceRoot":"","sources":["../../../src/modules/sharedStack/SharedStackService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,sBAAsB,EACtB,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,yCAAyC,CAAA;AAGhD,MAAM,WAAW,8BAA8B;IAC7C,qBAAqB,EAAE,qBAAqB,CAAA;IAC5C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ;;;;;OAKG;IACH,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,kBAAkB,CAAA;CAC7D;AAOD;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0D;IAG1F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0C;IAEnE,YAAY,IAAI,EAAE,8BAA8B,EAQ/C;IAED,8DAA8D;IACxD,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAGtD;IAED,mCAAmC;IAC7B,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAG/D;IAED,uDAAuD;IACjD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuBrF;IAED,kGAAkG;IAC5F,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,WAAW,CAAC,CAwBtB;IAED,8FAA8F;IACxF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3D;IAED;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBpE;IAED,6FAA6F;IACvF,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAcpE;IAID,mFAAmF;IACnF,OAAO,CAAC,WAAW;IAOnB;;;;;OAKG;YACW,WAAW;IAYzB,mFAAmF;YACrE,OAAO;IA8HrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB,kGAAkG;YACpF,OAAO;IAerB,mGAAmG;YACrF,OAAO;CAmBtB"}
@@ -0,0 +1,340 @@
1
+ import { assertFound, ConflictError, requireWorkspace, ValidationError } from '@cat-factory/kernel';
2
+ import { classifyComposePs, composeFileDir, DEFAULT_RECIPE_HEALTH_GATE, tailOutput, } from '../compose/compose-environment.logic.js';
3
+ import { runHealthGate, runRecipeStep } from '../compose/recipe-runner.js';
4
+ // Bound (ms) for the plain compose calls (network / down / version) so a wedged daemon can't hang
5
+ // a bring-up/teardown forever; `up` clears its own health-gate budget separately.
6
+ const SHORT_TIMEOUT_MS = 60_000;
7
+ const UP_TIMEOUT_MS = 330_000;
8
+ /**
9
+ * Lifecycle for a workspace's SHARED STACKS — long-lived compose infra a per-PR consumer
10
+ * environment attaches to over an external network (the acme-shared-services pilot). CRUD is
11
+ * runtime-neutral persistence (works on every facade); the bring-up (`ensureUp`) / teardown drive a
12
+ * host Docker daemon through the injected {@link ComposeRuntime}, so they run ONLY on the local
13
+ * facade.
14
+ *
15
+ * A shared stack is NEVER swept with a run and NEVER TTL-reaped — teardown is a deliberate action.
16
+ * Unlike a per-PR preview env, its committed compose files run AS AUTHORED (host ports kept, no
17
+ * isolation rewrite): it is the operator's own trusted infra, so the trust boundary is configuring
18
+ * the stack, not sandboxing it. `ensureUp` is idempotent + coalesces concurrent callers onto one
19
+ * in-flight bring-up per stack id.
20
+ */
21
+ export class SharedStackService {
22
+ stacks;
23
+ workspaceRepository;
24
+ idGenerator;
25
+ clock;
26
+ runtime;
27
+ cloneToken;
28
+ provisioningLog;
29
+ // Coalesce concurrent `ensureUp` for the same stack onto one in-flight bring-up (a second caller
30
+ // must not start a duplicate `up` / re-run non-idempotent setup steps).
31
+ inflight = new Map();
32
+ constructor(deps) {
33
+ this.stacks = deps.sharedStackRepository;
34
+ this.workspaceRepository = deps.workspaceRepository;
35
+ this.idGenerator = deps.idGenerator;
36
+ this.clock = deps.clock;
37
+ this.runtime = deps.composeRuntime;
38
+ this.cloneToken = deps.cloneToken;
39
+ this.provisioningLog = deps.provisioningLog;
40
+ }
41
+ /** List a workspace's shared stacks (ordered by creation). */
42
+ async list(workspaceId) {
43
+ await requireWorkspace(this.workspaceRepository, workspaceId);
44
+ return this.stacks.list(workspaceId);
45
+ }
46
+ /** A single shared stack by id. */
47
+ async get(workspaceId, id) {
48
+ await requireWorkspace(this.workspaceRepository, workspaceId);
49
+ return assertFound(await this.stacks.get(workspaceId, id), 'SharedStack', id);
50
+ }
51
+ /** Create a new shared stack (initially `stopped`). */
52
+ async create(workspaceId, input) {
53
+ await requireWorkspace(this.workspaceRepository, workspaceId);
54
+ const now = this.clock.now();
55
+ const stack = {
56
+ id: this.idGenerator.next('ss'),
57
+ workspaceId,
58
+ name: input.name,
59
+ cloneUrl: input.cloneUrl,
60
+ gitRef: input.gitRef ?? null,
61
+ composeFiles: input.composeFiles,
62
+ composeProfiles: input.composeProfiles,
63
+ envFiles: input.envFiles,
64
+ managedNetworks: input.managedNetworks,
65
+ setupSteps: input.setupSteps,
66
+ healthGate: input.healthGate ?? null,
67
+ allowHostCommands: input.allowHostCommands,
68
+ status: 'stopped',
69
+ lastError: null,
70
+ createdAt: now,
71
+ updatedAt: now,
72
+ };
73
+ await this.stacks.upsert(workspaceId, stack);
74
+ return stack;
75
+ }
76
+ /** Patch a shared stack's config. A running stack cannot be reconfigured — tear it down first. */
77
+ async update(workspaceId, id, patch) {
78
+ await requireWorkspace(this.workspaceRepository, workspaceId);
79
+ const existing = assertFound(await this.stacks.get(workspaceId, id), 'SharedStack', id);
80
+ if (existing.status === 'running' || existing.status === 'starting') {
81
+ throw new ConflictError('Tear the shared stack down before reconfiguring it.');
82
+ }
83
+ const updated = {
84
+ ...existing,
85
+ ...(patch.name !== undefined ? { name: patch.name } : {}),
86
+ ...(patch.cloneUrl !== undefined ? { cloneUrl: patch.cloneUrl } : {}),
87
+ ...(patch.gitRef !== undefined ? { gitRef: patch.gitRef } : {}),
88
+ ...(patch.composeFiles !== undefined ? { composeFiles: patch.composeFiles } : {}),
89
+ ...(patch.composeProfiles !== undefined ? { composeProfiles: patch.composeProfiles } : {}),
90
+ ...(patch.envFiles !== undefined ? { envFiles: patch.envFiles } : {}),
91
+ ...(patch.managedNetworks !== undefined ? { managedNetworks: patch.managedNetworks } : {}),
92
+ ...(patch.setupSteps !== undefined ? { setupSteps: patch.setupSteps } : {}),
93
+ ...(patch.healthGate !== undefined ? { healthGate: patch.healthGate } : {}),
94
+ ...(patch.allowHostCommands !== undefined
95
+ ? { allowHostCommands: patch.allowHostCommands }
96
+ : {}),
97
+ updatedAt: this.clock.now(),
98
+ };
99
+ await this.stacks.upsert(workspaceId, updated);
100
+ return updated;
101
+ }
102
+ /** Remove a shared stack. A running stack must be torn down first (never silently killed). */
103
+ async remove(workspaceId, id) {
104
+ await requireWorkspace(this.workspaceRepository, workspaceId);
105
+ const existing = await this.stacks.get(workspaceId, id);
106
+ if (existing && (existing.status === 'running' || existing.status === 'starting')) {
107
+ throw new ConflictError('Tear the shared stack down before deleting it.');
108
+ }
109
+ await this.stacks.remove(workspaceId, id);
110
+ }
111
+ /**
112
+ * Bring a shared stack up (idempotent). Already-`running` ⇒ a no-op returning the record.
113
+ * Otherwise: clone/refresh the repo, create its managed networks, `up -d` under its profiles,
114
+ * materialize env-file templates, run the ordered setup steps, then poll the terminal health gate
115
+ * — persisting `running` / `failed` (+ `lastError`) at the end. Concurrent callers coalesce onto
116
+ * one in-flight bring-up. Requires the host Docker runtime (local facade).
117
+ */
118
+ async ensureUp(workspaceId, id) {
119
+ await requireWorkspace(this.workspaceRepository, workspaceId);
120
+ const stack = assertFound(await this.stacks.get(workspaceId, id), 'SharedStack', id);
121
+ if (!this.runtime) {
122
+ throw new ValidationError('Bringing a shared stack up requires the local Docker runtime (unavailable on this deployment).');
123
+ }
124
+ // Idempotent no-op ONLY when the daemon actually still has the stack up. The stored `running`
125
+ // is intent, not liveness — after a host reboot / `docker system prune` the row still says
126
+ // `running` while nothing is up, so trust-but-verify with a cheap `compose ps` before
127
+ // short-circuiting; a stale `running` falls through and re-provisions instead of wedging.
128
+ if (stack.status === 'running' && (await this.isStackLive(stack)))
129
+ return stack;
130
+ const existing = this.inflight.get(id);
131
+ if (existing)
132
+ return existing;
133
+ const run = this.bringUp(workspaceId, stack).finally(() => this.inflight.delete(id));
134
+ this.inflight.set(id, run);
135
+ return run;
136
+ }
137
+ /** Tear a shared stack down (`down -v`). A deliberate action; the stack row is preserved. */
138
+ async teardown(workspaceId, id) {
139
+ await requireWorkspace(this.workspaceRepository, workspaceId);
140
+ const stack = assertFound(await this.stacks.get(workspaceId, id), 'SharedStack', id);
141
+ if (!this.runtime) {
142
+ throw new ValidationError('Tearing a shared stack down requires the local Docker runtime (unavailable on this deployment).');
143
+ }
144
+ const project = this.projectName(stack);
145
+ await this.runtime
146
+ .compose(['-p', project, 'down', '-v', '--remove-orphans'], { timeoutMs: SHORT_TIMEOUT_MS })
147
+ .catch(() => { });
148
+ await this.runtime.cleanupProject?.(project);
149
+ return this.persist(workspaceId, stack, { status: 'stopped', lastError: null });
150
+ }
151
+ // --- internals ----------------------------------------------------------
152
+ /** The stable compose project name for a shared stack (long-lived, NOT per-PR). */
153
+ projectName(stack) {
154
+ return `cf-stack-${stack.id}`
155
+ .toLowerCase()
156
+ .replace(/[^a-z0-9_-]+/g, '-')
157
+ .slice(0, 63);
158
+ }
159
+ /**
160
+ * Is the stack's compose project ACTUALLY up on the daemon right now? A project-name-scoped
161
+ * `compose ps` (no checkout / `-f` needed) classified as `ready`. Used to reconcile a stored
162
+ * `running` against reality before `ensureUp` short-circuits — a failed probe (daemon gone,
163
+ * containers pruned) reads as not-live so the caller re-provisions. Never throws.
164
+ */
165
+ async isStackLive(stack) {
166
+ const runtime = this.runtime;
167
+ if (!runtime)
168
+ return false;
169
+ const ps = await runtime
170
+ .compose(['-p', this.projectName(stack), 'ps', '-a', '--format', 'json'], {
171
+ timeoutMs: SHORT_TIMEOUT_MS,
172
+ })
173
+ .catch(() => null);
174
+ if (!ps || ps.code !== 0)
175
+ return false;
176
+ return classifyComposePs(ps.stdout) === 'ready';
177
+ }
178
+ /** Drive the full bring-up, persisting the terminal `running`/`failed` verdict. */
179
+ async bringUp(workspaceId, stack) {
180
+ const runtime = this.runtime;
181
+ const record = this.provisioningLog?.(stack);
182
+ await this.persist(workspaceId, stack, { status: 'starting', lastError: null });
183
+ const project = this.projectName(stack);
184
+ if (!runtime.checkout || !runtime.copyCheckoutFile) {
185
+ return this.persist(workspaceId, stack, {
186
+ status: 'failed',
187
+ lastError: 'The runtime cannot clone + write a checkout (shared stacks need a host daemon).',
188
+ });
189
+ }
190
+ // A `host-command` setup step is refused unless the stack opted in AND the runtime supports it.
191
+ const hostCmdIssue = this.checkHostCommands(stack);
192
+ if (hostCmdIssue) {
193
+ return this.persist(workspaceId, stack, { status: 'failed', lastError: hostCmdIssue });
194
+ }
195
+ // Clone/refresh the stack repo into its own long-lived working tree.
196
+ const cloneStarted = this.clock.now();
197
+ let checkoutDir;
198
+ try {
199
+ ;
200
+ ({ dir: checkoutDir } = await runtime.checkout(project, {
201
+ cloneUrl: stack.cloneUrl,
202
+ ref: stack.gitRef ?? 'HEAD',
203
+ ...(this.cloneToken ? { token: this.cloneToken } : {}),
204
+ }));
205
+ await this.logStep(record, 'clone repo', cloneStarted, { ok: true });
206
+ }
207
+ catch (err) {
208
+ const message = `Could not clone the stack repo: ${err instanceof Error ? err.message : String(err)}`;
209
+ await this.logStep(record, 'clone repo', cloneStarted, { ok: false, error: message });
210
+ return this.persist(workspaceId, stack, { status: 'failed', lastError: message });
211
+ }
212
+ // Create the managed networks the stack owns (its consumers attach to these as external).
213
+ for (const network of stack.managedNetworks) {
214
+ const started = this.clock.now();
215
+ const res = (await runtime.ensureNetwork?.(network)) ?? {
216
+ code: 1,
217
+ stdout: '',
218
+ stderr: 'runtime cannot manage networks',
219
+ };
220
+ const ok = res.code === 0;
221
+ await this.logStep(record, `network: ${network}`, started, {
222
+ ok,
223
+ ...(ok ? {} : { error: tailOutput(res.stderr || res.stdout) || `exit ${res.code}` }),
224
+ });
225
+ if (!ok) {
226
+ return this.persist(workspaceId, stack, {
227
+ status: 'failed',
228
+ lastError: `Could not create network '${network}': ${tailOutput(res.stderr || res.stdout)}`,
229
+ });
230
+ }
231
+ }
232
+ // Materialize env-file templates BEFORE `up`, each a logged step.
233
+ for (const envFile of stack.envFiles) {
234
+ const started = this.clock.now();
235
+ try {
236
+ await runtime.copyCheckoutFile(project, envFile.template, envFile.target);
237
+ await this.logStep(record, `env-file: ${envFile.target}`, started, { ok: true });
238
+ }
239
+ catch (err) {
240
+ const message = `Could not materialize env file '${envFile.target}': ${err instanceof Error ? err.message : String(err)}`;
241
+ await this.logStep(record, `env-file: ${envFile.target}`, started, {
242
+ ok: false,
243
+ error: message,
244
+ });
245
+ return this.persist(workspaceId, stack, { status: 'failed', lastError: message });
246
+ }
247
+ }
248
+ // The stack runs its committed compose files AS AUTHORED (host ports kept — it is trusted infra,
249
+ // not an isolated per-PR preview). `--project-directory` is the first file's dir so its relative
250
+ // build contexts / binds / env_files resolve as written.
251
+ const composeDir = composeFileDir(stack.composeFiles[0]);
252
+ const projectDir = composeDir ? `${checkoutDir}/${composeDir}` : checkoutDir;
253
+ const files = stack.composeFiles.flatMap((f) => ['-f', `${checkoutDir}/${f}`]);
254
+ const scope = ['-p', project, '--project-directory', projectDir, ...files];
255
+ const env = stack.composeProfiles.length
256
+ ? { COMPOSE_PROFILES: stack.composeProfiles.join(',') }
257
+ : {};
258
+ const upStarted = this.clock.now();
259
+ const up = await runtime.compose([...scope, 'up', '-d'], { env, timeoutMs: UP_TIMEOUT_MS });
260
+ const upOk = up.code === 0;
261
+ await this.logStep(record, 'compose up', upStarted, {
262
+ ok: upOk,
263
+ ...(upOk ? {} : { error: tailOutput(up.stderr || up.stdout) }),
264
+ });
265
+ if (!upOk) {
266
+ return this.persist(workspaceId, stack, {
267
+ status: 'failed',
268
+ lastError: tailOutput(up.stderr || up.stdout) || 'docker compose up failed',
269
+ });
270
+ }
271
+ // Ordered setup steps (users sync, connector registration, seed import, …).
272
+ for (const step of stack.setupSteps) {
273
+ const started = this.clock.now();
274
+ const result = await runRecipeStep(step, { runtime, scope, env, project });
275
+ await this.logStep(record, step.name, started, result);
276
+ if (!result.ok) {
277
+ return this.persist(workspaceId, stack, {
278
+ status: 'failed',
279
+ lastError: `Setup step '${step.name}' failed: ${result.error}`,
280
+ });
281
+ }
282
+ }
283
+ // Terminal health gate.
284
+ const gate = stack.healthGate ?? DEFAULT_RECIPE_HEALTH_GATE;
285
+ const gateStarted = this.clock.now();
286
+ const gateResult = await runHealthGate(gate, { runtime, scope, env }, SHORT_TIMEOUT_MS);
287
+ await this.logStep(record, `health gate (${gate.kind})`, gateStarted, gateResult);
288
+ if (!gateResult.ok) {
289
+ return this.persist(workspaceId, stack, {
290
+ status: 'failed',
291
+ lastError: `Health gate did not pass: ${gateResult.error}`,
292
+ });
293
+ }
294
+ return this.persist(workspaceId, stack, { status: 'running', lastError: null });
295
+ }
296
+ /**
297
+ * Refuse a stack's `host-command` setup steps unless it opted in (`allowHostCommands`) AND the
298
+ * runtime can run host commands. Returns a blocking message, or null when allowed / none declared.
299
+ */
300
+ checkHostCommands(stack) {
301
+ if (!stack.setupSteps.some((s) => s.kind === 'host-command'))
302
+ return null;
303
+ if (!stack.allowHostCommands) {
304
+ return "This stack declares host-command step(s), but host commands are not enabled for it (set 'Allow host commands').";
305
+ }
306
+ if (!this.runtime?.hostCommand) {
307
+ return 'This stack declares host-command step(s), but the runtime cannot run host commands.';
308
+ }
309
+ return null;
310
+ }
311
+ /** Write a stack's lifecycle transition (status + lastError, bumping updatedAt) and return it. */
312
+ async persist(workspaceId, stack, change) {
313
+ const updated = {
314
+ ...stack,
315
+ status: change.status,
316
+ lastError: change.lastError,
317
+ updatedAt: this.clock.now(),
318
+ };
319
+ await this.stacks.upsert(workspaceId, updated);
320
+ return updated;
321
+ }
322
+ /** Best-effort per-step provisioning-log entry (never throws; no-op when no recorder is wired). */
323
+ async logStep(record, name, startedAt, result) {
324
+ if (!record)
325
+ return;
326
+ try {
327
+ await record({
328
+ name,
329
+ outcome: result.ok ? 'success' : 'failure',
330
+ durationMs: this.clock.now() - startedAt,
331
+ ...(result.detail ? { detail: result.detail } : {}),
332
+ ...(result.error ? { error: result.error } : {}),
333
+ });
334
+ }
335
+ catch {
336
+ // best-effort: a log-write failure must never break the bring-up.
337
+ }
338
+ }
339
+ }
340
+ //# sourceMappingURL=SharedStackService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SharedStackService.js","sourceRoot":"","sources":["../../../src/modules/sharedStack/SharedStackService.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/integrations",
3
- "version": "0.69.0",
3
+ "version": "0.70.0",
4
4
  "description": "External-system integration domain logic for the Agent Architecture Board (GitHub, documents, tasks, environments, runners).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,14 +24,14 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "ai": "^6.0.214",
27
+ "ai": "^6.0.219",
28
28
  "yaml": "^2.9.0",
29
- "@cat-factory/contracts": "0.101.1",
30
- "@cat-factory/kernel": "0.92.0"
29
+ "@cat-factory/contracts": "0.103.0",
30
+ "@cat-factory/kernel": "0.94.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "typescript": "7.0.1-rc",
34
- "undici": "^8.5.0",
34
+ "undici": "^8.7.0",
35
35
  "vitest": "^4.1.9"
36
36
  },
37
37
  "scripts": {