@gaia-ai/gaia 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/bin/gaia +1 -1
  2. package/dist/src/plugins-barrel.d.ts +1 -0
  3. package/dist/src/plugins-barrel.js +1 -0
  4. package/package.json +10 -16
  5. package/dist/src/cli/gaia.d.ts +0 -24
  6. package/dist/src/cli/gaia.js +0 -572
  7. package/dist/src/cli/init.d.ts +0 -74
  8. package/dist/src/cli/init.js +0 -220
  9. package/dist/src/cli/local-registry.d.ts +0 -14
  10. package/dist/src/cli/local-registry.js +0 -56
  11. package/dist/src/config.d.ts +0 -13
  12. package/dist/src/config.js +0 -186
  13. package/dist/src/core/conductor-id.d.ts +0 -1
  14. package/dist/src/core/conductor-id.js +0 -8
  15. package/dist/src/core/conductor.d.ts +0 -47
  16. package/dist/src/core/conductor.js +0 -287
  17. package/dist/src/core/exec.d.ts +0 -33
  18. package/dist/src/core/exec.js +0 -65
  19. package/dist/src/core/logger.d.ts +0 -31
  20. package/dist/src/core/logger.js +0 -36
  21. package/dist/src/core/slug.d.ts +0 -9
  22. package/dist/src/core/slug.js +0 -18
  23. package/dist/src/index.d.ts +0 -16
  24. package/dist/src/index.js +0 -9
  25. package/dist/src/plugin-api.d.ts +0 -7
  26. package/dist/src/plugin-api.js +0 -3
  27. package/dist/src/plugins/agent/agent.d.ts +0 -20
  28. package/dist/src/plugins/agent/agent.js +0 -1
  29. package/dist/src/plugins/auth/basic.d.ts +0 -11
  30. package/dist/src/plugins/auth/basic.js +0 -35
  31. package/dist/src/plugins/executor/executor.d.ts +0 -61
  32. package/dist/src/plugins/executor/executor.js +0 -1
  33. package/dist/src/plugins/plugins.d.ts +0 -38
  34. package/dist/src/plugins/plugins.js +0 -16
  35. package/dist/src/plugins/registry-exports.d.ts +0 -6
  36. package/dist/src/plugins/registry-exports.js +0 -6
  37. package/dist/src/plugins/remote/drupal.d.ts +0 -47
  38. package/dist/src/plugins/remote/drupal.js +0 -337
  39. package/dist/src/plugins/remote/fake.d.ts +0 -81
  40. package/dist/src/plugins/remote/fake.js +0 -203
  41. package/dist/src/plugins/remote/remote.d.ts +0 -143
  42. package/dist/src/plugins/remote/remote.js +0 -1
  43. package/dist/src/plugins/workspace/fake.d.ts +0 -9
  44. package/dist/src/plugins/workspace/fake.js +0 -19
  45. package/dist/src/plugins/workspace/git.d.ts +0 -53
  46. package/dist/src/plugins/workspace/git.js +0 -113
  47. package/dist/src/plugins/workspace/instructions.d.ts +0 -6
  48. package/dist/src/plugins/workspace/instructions.js +0 -16
  49. package/dist/src/plugins/workspace/workspace.d.ts +0 -33
  50. package/dist/src/plugins/workspace/workspace.js +0 -1
  51. package/dist/src/types.d.ts +0 -51
  52. package/dist/src/types.js +0 -1
@@ -1,287 +0,0 @@
1
- import { conductorId } from './conductor-id.js';
2
- function sleep(ms, signal) {
3
- return new Promise((resolve) => {
4
- if (signal?.aborted) {
5
- resolve();
6
- return;
7
- }
8
- const timer = setTimeout(() => {
9
- signal?.removeEventListener('abort', onAbort);
10
- resolve();
11
- }, ms);
12
- const onAbort = () => {
13
- clearTimeout(timer);
14
- resolve();
15
- };
16
- signal?.addEventListener('abort', onAbort, { once: true });
17
- });
18
- }
19
- /**
20
- * Formats a ticket's comments into the `{comments}` prompt block, oldest first.
21
- * The conductor injects this so a review→coding bounce reaches the coder with the
22
- * review summary in hand, independent of whether the agent remembers to fetch it.
23
- *
24
- * The body is the raw gaia_rich markup — the agent reads HTML fine, so we don't
25
- * strip it (a tag/entity stripper is a maintenance footgun that buys nothing for
26
- * an LLM reader).
27
- */
28
- function renderComments(comments) {
29
- if (comments.length === 0) {
30
- return '(no comments on this ticket yet)';
31
- }
32
- return comments
33
- .map((c, i) => {
34
- const when = c.created ? ` (${c.created})` : '';
35
- return `[#${i + 1}] type=${c.type}${when}\n${c.body}`;
36
- })
37
- .join('\n\n---\n\n');
38
- }
39
- function renderPrompt(template, values) {
40
- return template
41
- .replaceAll('{identifier}', values.identifier)
42
- .replaceAll('{state}', values.state)
43
- .replaceAll('{runUuid}', values.runUuid)
44
- .replaceAll('{comments}', renderComments(values.comments));
45
- }
46
- export class Conductor {
47
- config;
48
- remote;
49
- executor;
50
- workspace;
51
- agent;
52
- logger;
53
- checkoutRoot;
54
- uuid = null;
55
- constructor(config, remote, executor, workspace, agent, logger, checkoutRoot = process.cwd()) {
56
- this.config = config;
57
- this.remote = remote;
58
- this.executor = executor;
59
- this.workspace = workspace;
60
- this.agent = agent;
61
- this.logger = logger;
62
- this.checkoutRoot = checkoutRoot;
63
- }
64
- get id() {
65
- return this.config.machine_id ?? conductorId(this.checkoutRoot);
66
- }
67
- /** This conductor's registration payload, built from config. */
68
- registration() {
69
- return {
70
- id: this.id,
71
- project: this.config.project,
72
- states: this.config.states,
73
- workspace: this.checkoutRoot,
74
- label: this.config.label,
75
- max_parallel: this.config.max_parallel,
76
- };
77
- }
78
- async start() {
79
- this.uuid = await this.remote.registerConductor(this.registration());
80
- this.logger.info({ conductorId: this.id, uuid: this.uuid, project: this.config.project }, 'conductor started');
81
- }
82
- async tick() {
83
- if (!this.uuid)
84
- throw new Error('not started');
85
- let count = await this.remote.activeRunCount(this.id);
86
- // A heartbeat is the server-side self-heal: it upserts by machine_id (so it
87
- // never 404s and recreates a vanished registration) and refreshes the lease
88
- // — no client-side re-register, no separate status read.
89
- await this.remote.heartbeat(this.registration(), count, this.config.lease_seconds);
90
- this.logger.info({ conductorId: this.id, active: count }, 'conductor tick');
91
- await this.finalizeDoneRuns();
92
- await this.cleanupDoneTickets();
93
- let claimed = 0;
94
- while (count < this.config.max_parallel) {
95
- const run = await this.remote.claimNext({
96
- leaseSeconds: this.config.lease_seconds,
97
- conductorId: this.id,
98
- });
99
- if (!run)
100
- break;
101
- this.logger.info({ conductorId: this.id, run: run.runUuid, ticket: run.ticketUuid }, 'claimed run');
102
- try {
103
- await this.dispatch(run);
104
- }
105
- catch (err) {
106
- // A failed dispatch must NOT terminalise the run. The run lifecycle is
107
- // server-owned; a client-side releaseRun('done') here fabricated a
108
- // terminal state on failure, which reopened the ticket for claiming and
109
- // re-dispatched it every tick — the GAIA-41 runaway. Leaving the run
110
- // `claimed` lets the server's same-state claim conflict
111
- // (TicketClaimService::retireSupersededRuns) block a re-claim of the
112
- // same ticket, so we just log and move on. A run stuck `claimed` on a
113
- // persistently-failing dispatch is freed by the lease-expiry reaper
114
- // (separate follow-up), not here.
115
- this.logger.error({ run: run.runUuid, err: String(err) }, 'dispatch failed');
116
- }
117
- count += 1;
118
- claimed += 1;
119
- }
120
- if (claimed === 0) {
121
- this.logger.info({
122
- conductorId: this.id,
123
- active: count,
124
- capacity: this.config.max_parallel,
125
- }, count >= this.config.max_parallel
126
- ? 'at capacity, nothing claimed'
127
- : 'idle, nothing to claim');
128
- }
129
- }
130
- /**
131
- * One-shot finalisation: for each of this conductor's runs that is
132
- * state=done but not yet closed, read the agent transcript from its worktree
133
- * and write it as the final log, then mark the run closed. Keyed off the
134
- * durable `state=done AND closed=false` query — no in-memory state, so a
135
- * restarted conductor still finalises any unclosed done run on its next tick.
136
- */
137
- async finalizeDoneRuns() {
138
- const runs = await this.remote.fetchFinalizableRuns(this.id);
139
- for (const r of runs) {
140
- try {
141
- // Ask the agent to exit gracefully (/exit) before capturing its log.
142
- // Best-effort and gated on the persistent capability (only hosted
143
- // executors have a live agent pane) — mirrors removeWorktree's gate.
144
- // A stop failure must never block finalisation.
145
- if (this.executor.capabilities().persistent) {
146
- const branch = await this.remote.getRunTicketBranchName(r.runUuid);
147
- if (branch) {
148
- try {
149
- await this.executor.stopAgent(branch);
150
- }
151
- catch (err) {
152
- this.logger.warn({ run: r.runUuid, err: String(err) }, 'agent stop failed');
153
- }
154
- }
155
- }
156
- const log = r.worktreePath
157
- ? await this.agent.getRunLog(r.worktreePath)
158
- : '';
159
- await this.remote.finalizeRun(r.runUuid, log);
160
- this.logger.info({ run: r.runUuid }, 'run finalised');
161
- }
162
- catch (err) {
163
- this.logger.warn({ run: r.runUuid, err: String(err) }, 'run finalise failed');
164
- }
165
- }
166
- }
167
- /**
168
- * One-shot ticket cleanup, symmetric to {@link finalizeDoneRuns} on the
169
- * ticket axis: for each of this conductor's tickets that is state=done but not
170
- * yet closed, run the workspace's `after_done` hook in the ticket's worktree,
171
- * tear the worktree down (herdr), then mark the ticket closed. Keyed off the
172
- * durable `state=done AND closed=false` query — no in-memory state, so a
173
- * restarted conductor still cleans up.
174
- *
175
- * Error handling mirrors finalise: each ticket is isolated in a try/catch so
176
- * one failure never wedges the tick. The `after_done` hook itself is
177
- * best-effort — its failure is logged but does not block the teardown/close
178
- * (reclaiming the worktree matters more than a clean environment teardown).
179
- */
180
- async cleanupDoneTickets() {
181
- const tickets = await this.remote.fetchFinalizableTickets(this.id);
182
- for (const t of tickets) {
183
- try {
184
- if (t.worktreePath) {
185
- try {
186
- await this.workspace.afterDone(t.worktreePath);
187
- }
188
- catch (err) {
189
- this.logger.warn({ ticket: t.ticketUuid, err: String(err) }, 'ticket after_done hook failed');
190
- }
191
- }
192
- // Only persistent executors host a workspace to tear down; the abstract
193
- // capability keeps this executor-agnostic (mirrors the release path).
194
- // Pass the stable worktreePath so the executor resolves the worktree by
195
- // path, not by the mutable checked-out branch (which the coding agent
196
- // may have renamed). Teardown is idempotent: a worktree herdr no longer
197
- // tracks is a no-op (already gone) or a direct on-disk reclaim, not a
198
- // failure — foreign worktrees in herdr's machine-global list are never
199
- // surfaced. A genuine teardown failure is best-effort like after_done:
200
- // logged but must not block the close (a still-closed ticket beats a
201
- // wedged cleanup loop).
202
- if (this.executor.capabilities().persistent) {
203
- try {
204
- await this.executor.removeWorktree(t.branchName, t.worktreePath || undefined);
205
- }
206
- catch (err) {
207
- this.logger.warn({
208
- ticket: t.ticketUuid,
209
- branch: t.branchName,
210
- worktreePath: t.worktreePath,
211
- err: String(err),
212
- }, 'worktree teardown failed');
213
- }
214
- }
215
- await this.remote.closeTicket(t.ticketUuid);
216
- this.logger.info({ ticket: t.ticketUuid }, 'ticket cleaned up');
217
- }
218
- catch (err) {
219
- this.logger.warn({ ticket: t.ticketUuid, err: String(err) }, 'ticket cleanup failed');
220
- }
221
- }
222
- }
223
- async dispatch(run) {
224
- const t = await this.remote.getTicket(run.ticketUuid);
225
- const baseRef = t.baseBranch ? `origin/${t.baseBranch}` : undefined;
226
- const ws = await this.workspace.ensure(t.identifier, t.branchName, baseRef);
227
- await this.workspace.beforeRun(ws.path);
228
- await this.executor.retire(t.branchName);
229
- const prompt = ws.instructions
230
- ? renderPrompt(this.config.prompt, {
231
- identifier: t.identifier,
232
- state: t.state || 'triage',
233
- runUuid: run.runUuid,
234
- comments: t.comments,
235
- })
236
- : '';
237
- await this.executor.startRun({
238
- ticket: {
239
- uuid: t.uuid,
240
- identifier: t.identifier,
241
- title: t.title,
242
- branchName: t.branchName,
243
- state: t.state,
244
- ...(t.issueUrl ? { url: t.issueUrl } : {}),
245
- },
246
- run: { uuid: run.runUuid, id: run.runId, handler: run.handler },
247
- workspacePath: ws.path,
248
- instructions: ws.instructions,
249
- command: this.agent.launchCommand(prompt),
250
- env: {
251
- GAIA_URL: this.config.site.base_url,
252
- GAIA_ID: run.ticketUuid,
253
- GAIA_RUN_UUID: run.runUuid,
254
- WORKSPACE_ROOT: this.checkoutRoot,
255
- ...(t.issueUrl ? { TICKET_URL: t.issueUrl } : {}),
256
- },
257
- });
258
- this.logger.info({
259
- ticket: t.identifier,
260
- run: run.runUuid,
261
- state: t.state,
262
- workspace: ws.path,
263
- }, 'dispatched run');
264
- // The conductor — not the agent — knows the per-run git worktree path, so
265
- // it persists `worktree_path` to gaia_run here alongside the running state.
266
- await this.remote.markRunning(run.runUuid, { worktree_path: ws.path });
267
- }
268
- async serve(signal) {
269
- await this.pollLoop(signal);
270
- }
271
- async pollLoop(signal) {
272
- while (!signal?.aborted) {
273
- try {
274
- await this.tick();
275
- }
276
- catch (err) {
277
- this.logger.error({ conductorId: this.id, err: String(err) }, 'tick failed');
278
- }
279
- await sleep(this.config.poll_interval_ms, signal);
280
- }
281
- // NB: the poll loop never writes status=offline itself. A graceful stop
282
- // (`gaia conductor stop`) writes offline directly server-side; a crash or
283
- // hard-kill leaves a stale lease that the Drupal cron reaper flips to
284
- // offline (gaia_core cron → ConductorReaper). Liveness is thus always
285
- // derived from status + last_seen/lease_expires_at, never from the loop.
286
- }
287
- }
@@ -1,33 +0,0 @@
1
- import type { ConductorLogger } from './logger.js';
2
- export declare class ExecError extends Error {
3
- readonly file: string;
4
- readonly args: string[];
5
- readonly exitCode: number | null;
6
- readonly stderr: string;
7
- constructor(file: string, args: string[], exitCode: number | null, stderr: string, options?: {
8
- cause?: unknown;
9
- });
10
- }
11
- export declare class CommandRunner {
12
- private readonly logger;
13
- constructor(logger: ConductorLogger);
14
- run(file: string, args: string[], opts?: {
15
- cwd?: string;
16
- }): Promise<string>;
17
- }
18
- /**
19
- * Replace the module-level singleton runner used by {@link exec}.
20
- *
21
- * Note: out-of-package plugins (e.g. `@gaia-ai/plugin-herdr`) import `exec` via
22
- * the `@gaia-ai/gaia/plugin` barrel, which resolves to the built `dist/`
23
- * copy of this module. This means `setDefaultCommandRunner` only shares the
24
- * runner with those plugins when the conductor itself runs from `dist`
25
- * (production / after `pnpm build`). Under `tsx`/dev, the entry point loads
26
- * this module from source while the plugin loads it from dist — two separate
27
- * module instances — so plugin exec calls fall back to the noop logger.
28
- * This is functionally harmless; logging only.
29
- */
30
- export declare function setDefaultCommandRunner(r: CommandRunner): void;
31
- export declare function exec(file: string, args: string[], opts?: {
32
- cwd?: string;
33
- }): Promise<string>;
@@ -1,65 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- const execFileAsync = promisify(execFile);
4
- export class ExecError extends Error {
5
- file;
6
- args;
7
- exitCode;
8
- stderr;
9
- constructor(file, args, exitCode, stderr, options) {
10
- super(`exec failed: ${file}`, options);
11
- this.file = file;
12
- this.args = args;
13
- this.exitCode = exitCode;
14
- this.stderr = stderr;
15
- this.name = 'ExecError';
16
- }
17
- }
18
- export class CommandRunner {
19
- logger;
20
- constructor(logger) {
21
- this.logger = logger;
22
- }
23
- async run(file, args, opts = {}) {
24
- try {
25
- const { stdout } = await execFileAsync(file, args, {
26
- encoding: 'utf8',
27
- ...opts,
28
- });
29
- this.logger.debug({ file, args, cwd: opts.cwd }, 'exec ok');
30
- return stdout;
31
- }
32
- catch (err) {
33
- const e = err;
34
- const exitCode = typeof e.code === 'number' ? e.code : null;
35
- const stderr = e.stderr ?? '';
36
- this.logger.error({ file, args, cwd: opts.cwd, exitCode, stderr }, 'exec failed');
37
- throw new ExecError(file, args, exitCode, stderr, { cause: err });
38
- }
39
- }
40
- }
41
- const noopLogger = {
42
- debug() { },
43
- info() { },
44
- warn() { },
45
- error() { },
46
- };
47
- let defaultRunner = new CommandRunner(noopLogger);
48
- /**
49
- * Replace the module-level singleton runner used by {@link exec}.
50
- *
51
- * Note: out-of-package plugins (e.g. `@gaia-ai/plugin-herdr`) import `exec` via
52
- * the `@gaia-ai/gaia/plugin` barrel, which resolves to the built `dist/`
53
- * copy of this module. This means `setDefaultCommandRunner` only shares the
54
- * runner with those plugins when the conductor itself runs from `dist`
55
- * (production / after `pnpm build`). Under `tsx`/dev, the entry point loads
56
- * this module from source while the plugin loads it from dist — two separate
57
- * module instances — so plugin exec calls fall back to the noop logger.
58
- * This is functionally harmless; logging only.
59
- */
60
- export function setDefaultCommandRunner(r) {
61
- defaultRunner = r;
62
- }
63
- export function exec(file, args, opts = {}) {
64
- return defaultRunner.run(file, args, opts);
65
- }
@@ -1,31 +0,0 @@
1
- export type LogSink = {
2
- kind: 'stdout';
3
- } | {
4
- kind: 'file';
5
- path: string;
6
- };
7
- export interface ConductorLogger {
8
- debug(obj: object, msg?: string): void;
9
- info(obj: object, msg?: string): void;
10
- warn(obj: object, msg?: string): void;
11
- error(obj: object, msg?: string): void;
12
- }
13
- /**
14
- * Pick the log sink. Precedence: explicit CLI override (`sink`) > the
15
- * GAIA_CONDUCTOR_LOG env var > TTY default (stdout on a TTY, file otherwise).
16
- */
17
- export declare function resolveSink(env: NodeJS.ProcessEnv, isTTY: boolean, checkoutRoot: string, override?: string): LogSink;
18
- /**
19
- * Pick the log level. Precedence: explicit CLI override (`level`) >
20
- * the GAIA_LOG_LEVEL env var > info.
21
- */
22
- export declare function resolveLevel(env: NodeJS.ProcessEnv, override?: string): string;
23
- export declare function createLogger(opts: {
24
- checkoutRoot: string;
25
- isTTY?: boolean;
26
- env?: NodeJS.ProcessEnv;
27
- /** CLI override for the level — beats env + default. */
28
- level?: string;
29
- /** CLI override for the sink — beats env + default. */
30
- sink?: string;
31
- }): ConductorLogger;
@@ -1,36 +0,0 @@
1
- import { join } from 'node:path';
2
- import pino from 'pino';
3
- import pretty from 'pino-pretty';
4
- /**
5
- * Pick the log sink. Precedence: explicit CLI override (`sink`) > the
6
- * GAIA_CONDUCTOR_LOG env var > TTY default (stdout on a TTY, file otherwise).
7
- */
8
- export function resolveSink(env, isTTY, checkoutRoot, override) {
9
- const fileSink = {
10
- kind: 'file',
11
- path: join(checkoutRoot, 'log.txt'),
12
- };
13
- const choice = override ?? env.GAIA_CONDUCTOR_LOG;
14
- if (choice === 'stdout')
15
- return { kind: 'stdout' };
16
- if (choice === 'file')
17
- return fileSink;
18
- return isTTY ? { kind: 'stdout' } : fileSink;
19
- }
20
- /**
21
- * Pick the log level. Precedence: explicit CLI override (`level`) >
22
- * the GAIA_LOG_LEVEL env var > info.
23
- */
24
- export function resolveLevel(env, override) {
25
- return override ?? env.GAIA_LOG_LEVEL ?? 'info';
26
- }
27
- export function createLogger(opts) {
28
- const env = opts.env ?? process.env;
29
- const isTTY = opts.isTTY ?? Boolean(process.stdout.isTTY);
30
- const level = resolveLevel(env, opts.level);
31
- const sink = resolveSink(env, isTTY, opts.checkoutRoot, opts.sink);
32
- if (sink.kind === 'stdout') {
33
- return pino({ level }, pretty({ colorize: true, sync: true }));
34
- }
35
- return pino({ level }, pino.destination({ dest: sink.path, append: true, mkdir: true }));
36
- }
@@ -1,9 +0,0 @@
1
- /** Default cap for a title slug — keeps tab labels and branch names short. */
2
- export declare const DEFAULT_SLUG_MAX_LENGTH = 40;
3
- /**
4
- * Turn free text (a ticket title) into a short, ref-safe slug:
5
- * lowercase, non-alphanumeric runs collapsed to `-`, trimmed, and capped to
6
- * `maxLength` characters without leaving a trailing separator. Returns `''`
7
- * for input that has no usable characters.
8
- */
9
- export declare function slugify(text: string, maxLength?: number): string;
@@ -1,18 +0,0 @@
1
- /** Default cap for a title slug — keeps tab labels and branch names short. */
2
- export const DEFAULT_SLUG_MAX_LENGTH = 40;
3
- /**
4
- * Turn free text (a ticket title) into a short, ref-safe slug:
5
- * lowercase, non-alphanumeric runs collapsed to `-`, trimmed, and capped to
6
- * `maxLength` characters without leaving a trailing separator. Returns `''`
7
- * for input that has no usable characters.
8
- */
9
- export function slugify(text, maxLength = DEFAULT_SLUG_MAX_LENGTH) {
10
- const slug = text
11
- .toLowerCase()
12
- .replace(/[^a-z0-9]+/g, '-')
13
- .replace(/^-+|-+$/g, '');
14
- if (slug.length <= maxLength) {
15
- return slug;
16
- }
17
- return slug.slice(0, maxLength).replace(/-+$/g, '');
18
- }
@@ -1,16 +0,0 @@
1
- export type { GaiaCliDeps } from './cli/gaia.js';
2
- export { main, runGaiaCli } from './cli/gaia.js';
3
- export type { ConductorRegistryEntry } from './cli/local-registry.js';
4
- export { DEFAULT_AGENT_PROMPT, loadConductorConfig } from './config.js';
5
- export { Conductor } from './core/conductor.js';
6
- export { conductorId } from './core/conductor-id.js';
7
- export type { GaiaExecutor } from './plugins/executor/executor.js';
8
- export type { ExecutorPlugin, RemotePlugin, WorkspacePlugin, } from './plugins/plugins.js';
9
- export { selectExecutor, selectRemote, selectWorkspace, } from './plugins/plugins.js';
10
- export { DrupalGaiaRemote, drupalRemote } from './plugins/remote/drupal.js';
11
- export { FakeGaiaRemote, fakeRemote } from './plugins/remote/fake.js';
12
- export type { GaiaRemote } from './plugins/remote/remote.js';
13
- export { FakeWorkspace, fakeWorkspace } from './plugins/workspace/fake.js';
14
- export { GitWorkspace, gitWorkspace } from './plugins/workspace/git.js';
15
- export type { GaiaWorkspace } from './plugins/workspace/workspace.js';
16
- export type * from './types.js';
package/dist/src/index.js DELETED
@@ -1,9 +0,0 @@
1
- export { main, runGaiaCli } from './cli/gaia.js';
2
- export { DEFAULT_AGENT_PROMPT, loadConductorConfig } from './config.js';
3
- export { Conductor } from './core/conductor.js';
4
- export { conductorId } from './core/conductor-id.js';
5
- export { selectExecutor, selectRemote, selectWorkspace, } from './plugins/plugins.js';
6
- export { DrupalGaiaRemote, drupalRemote } from './plugins/remote/drupal.js';
7
- export { FakeGaiaRemote, fakeRemote } from './plugins/remote/fake.js';
8
- export { FakeWorkspace, fakeWorkspace } from './plugins/workspace/fake.js';
9
- export { GitWorkspace, gitWorkspace } from './plugins/workspace/git.js';
@@ -1,7 +0,0 @@
1
- export { CommandRunner, ExecError, exec, setDefaultCommandRunner, } from './core/exec.js';
2
- export { DEFAULT_SLUG_MAX_LENGTH, slugify } from './core/slug.js';
3
- export type { GaiaAgent } from './plugins/agent/agent.js';
4
- export type * from './plugins/executor/executor.js';
5
- export type { AgentPlugin, ExecutorPlugin, RemotePlugin, WorkspacePlugin, } from './plugins/plugins.js';
6
- export { loadInstructions } from './plugins/workspace/instructions.js';
7
- export type { EnsuredWorkspace, GaiaWorkspace, } from './plugins/workspace/workspace.js';
@@ -1,3 +0,0 @@
1
- export { CommandRunner, ExecError, exec, setDefaultCommandRunner, } from './core/exec.js';
2
- export { DEFAULT_SLUG_MAX_LENGTH, slugify } from './core/slug.js';
3
- export { loadInstructions } from './plugins/workspace/instructions.js';
@@ -1,20 +0,0 @@
1
- /**
2
- * A GAIA agent: the program the conductor runs to work a ticket (e.g. claude).
3
- * It knows how it is launched (CLI + model + flags) and where its per-run
4
- * transcript/log lives — so the conductor stays agent-agnostic and the CLI can
5
- * attach the run log on release without agent-specific knowledge.
6
- */
7
- export interface GaiaAgent {
8
- /** Stable id, e.g. 'claude'. */
9
- readonly id: string;
10
- /**
11
- * Build the full agent CLI invocation for a GAIA prompt. With an empty
12
- * prompt, returns the bare launch command (no prompt argument).
13
- */
14
- launchCommand(prompt: string): string;
15
- /**
16
- * Locate and read this agent's run transcript for a run that executed in
17
- * `worktreePath`. MUST return '' (never throw) when nothing is found.
18
- */
19
- getRunLog(worktreePath: string): Promise<string>;
20
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,11 +0,0 @@
1
- /**
2
- * Static HTTP Basic auth provider built from an inline base64 `user:pass` token
3
- * (conductor.config.local.js `auth.basic`, or the GAIA_E2E_BASIC env for tests).
4
- * Returns the `{ id, authProvider }` plugin shape that dropsh's resolveAuth reads
5
- * from `config.plugins`. Replaces the per-file basicAuthProvider that used to be
6
- * hand-written into each dropsh.config.js.
7
- */
8
- export declare function basicAuthProvider(tokenBase64: string): {
9
- id: string;
10
- authProvider: unknown;
11
- };
@@ -1,35 +0,0 @@
1
- /**
2
- * Static HTTP Basic auth provider built from an inline base64 `user:pass` token
3
- * (conductor.config.local.js `auth.basic`, or the GAIA_E2E_BASIC env for tests).
4
- * Returns the `{ id, authProvider }` plugin shape that dropsh's resolveAuth reads
5
- * from `config.plugins`. Replaces the per-file basicAuthProvider that used to be
6
- * hand-written into each dropsh.config.js.
7
- */
8
- export function basicAuthProvider(tokenBase64) {
9
- const authProvider = {
10
- id: 'basic_auth',
11
- displayName: 'HTTP Basic (inline)',
12
- capabilities: { login: false, logout: false, status: true },
13
- async login() {
14
- throw new Error('GAIA uses static inline HTTP Basic auth.');
15
- },
16
- async logout() { },
17
- async status() {
18
- return { loggedIn: true, provider: 'basic_auth' };
19
- },
20
- createAdapter() {
21
- return {
22
- async apply(req) {
23
- return {
24
- ...req,
25
- headers: {
26
- ...(req.headers ?? {}),
27
- Authorization: `Basic ${tokenBase64}`,
28
- },
29
- };
30
- },
31
- };
32
- },
33
- };
34
- return { id: 'gaia-basic-auth', authProvider };
35
- }
@@ -1,61 +0,0 @@
1
- export interface SpawnedSession {
2
- sessionRef: string;
3
- }
4
- export interface ExecutorCapabilities {
5
- persistent: boolean;
6
- }
7
- export interface SpawnRunInput {
8
- ticket: {
9
- uuid: string;
10
- identifier: string;
11
- title: string;
12
- branchName: string;
13
- state: string;
14
- url?: string;
15
- };
16
- run: {
17
- uuid: string;
18
- id: number;
19
- handler: string;
20
- };
21
- workspacePath: string;
22
- instructions: {
23
- path: string;
24
- sha256: string;
25
- text: string;
26
- } | null;
27
- command?: string;
28
- env?: Record<string, string>;
29
- }
30
- export interface GaiaExecutor {
31
- id: string;
32
- capabilities(): ExecutorCapabilities;
33
- startRun(input: SpawnRunInput): Promise<SpawnedSession>;
34
- /** Send C-c to every open (non-`(done)`) tab in the branch workspace and
35
- * append ` (done)` to its label. Best-effort, non-destructive: tabs stay open
36
- * for the human to close. */
37
- retire(branch: string): Promise<void>;
38
- /**
39
- * Ask the agent in each open (non-`(done)`) tab of the branch workspace to
40
- * exit gracefully by typing `/exit` + Enter into its pane — a clean shutdown
41
- * vs {@link retire}'s C-c SIGINT. Called by the conductor's run-finalise pass
42
- * once a run is done. Best-effort and non-destructive (tabs stay open); a
43
- * no-op for non-persistent executors (no hosted agent pane), so the conductor
44
- * gates the call on `capabilities().persistent`.
45
- */
46
- stopAgent(branch: string): Promise<void>;
47
- /**
48
- * Tear down the branch's entire worktree (git worktree + hosted workspace),
49
- * reclaiming its disk. Called by the conductor's ticket-cleanup pass once a
50
- * ticket is done. A no-op for non-persistent executors (no hosted workspace);
51
- * the conductor gates the call on `capabilities().persistent`.
52
- *
53
- * `worktreePath` is the stable, identifier-derived worktree path (from the
54
- * ticket's latest run). Prefer it over `branch` to resolve the worktree: the
55
- * checked-out branch is mutable (the coding agent may rename/switch it), the
56
- * path is not. Implementations MUST NOT silently succeed when no worktree
57
- * matches — surface the miss (throw with the wanted branch/path and what the
58
- * executor actually lists) so it is visible rather than a silent skip.
59
- */
60
- removeWorktree(branch: string, worktreePath?: string): Promise<void>;
61
- }
@@ -1 +0,0 @@
1
- export {};