@phnx-labs/agents-cli 1.20.88 → 1.20.89
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.
- package/CHANGELOG.md +263 -0
- package/README.md +9 -1
- package/dist/bin/agents +0 -0
- package/dist/commands/commands.js +7 -7
- package/dist/commands/factory.js +26 -2
- package/dist/commands/funnel.js +16 -1
- package/dist/commands/menubar.js +117 -34
- package/dist/commands/routines.js +23 -1
- package/dist/commands/secrets-rotate-passphrase.d.ts +17 -0
- package/dist/commands/secrets-rotate-passphrase.js +96 -0
- package/dist/commands/secrets.js +2 -0
- package/dist/commands/sessions.d.ts +7 -1
- package/dist/commands/sessions.js +39 -12
- package/dist/commands/webhook.js +7 -2
- package/dist/lib/commands.js +9 -1
- package/dist/lib/daemon.d.ts +29 -0
- package/dist/lib/daemon.js +58 -4
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/factory/snapshot.d.ts +78 -0
- package/dist/lib/factory/snapshot.js +209 -0
- package/dist/lib/fs-atomic.d.ts +14 -1
- package/dist/lib/fs-atomic.js +35 -3
- package/dist/lib/funnel.d.ts +1 -0
- package/dist/lib/funnel.js +8 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -2
- package/dist/lib/menubar/install-menubar.d.ts +53 -2
- package/dist/lib/menubar/install-menubar.js +183 -28
- package/dist/lib/platform/process.d.ts +2 -0
- package/dist/lib/platform/process.js +5 -3
- package/dist/lib/resources.d.ts +8 -0
- package/dist/lib/resources.js +34 -1
- package/dist/lib/routines-placement.d.ts +2 -1
- package/dist/lib/routines-placement.js +8 -4
- package/dist/lib/routines.d.ts +57 -1
- package/dist/lib/routines.js +74 -1
- package/dist/lib/runner.d.ts +2 -0
- package/dist/lib/runner.js +21 -8
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/bundles.js +9 -34
- package/dist/lib/secrets/filestore.d.ts +152 -34
- package/dist/lib/secrets/filestore.js +676 -123
- package/dist/lib/session/remote-active.d.ts +4 -1
- package/dist/lib/session/remote-active.js +8 -2
- package/dist/lib/session/viewing-in.d.ts +31 -0
- package/dist/lib/session/viewing-in.js +47 -0
- package/dist/lib/state.d.ts +17 -0
- package/dist/lib/state.js +30 -2
- package/dist/lib/triggers/handlers.d.ts +95 -0
- package/dist/lib/triggers/handlers.js +384 -0
- package/dist/lib/triggers/webhook.d.ts +10 -2
- package/dist/lib/triggers/webhook.js +65 -11
- package/package.json +1 -1
|
@@ -9,7 +9,10 @@ export declare const NO_FANOUT_ENV = "AGENTS_SESSIONS_LOCAL";
|
|
|
9
9
|
* Parse a peer's `--active --json` stdout into active sessions, tagging each
|
|
10
10
|
* with `machine`. Defensive against version skew / partial output: non-JSON or
|
|
11
11
|
* a non-array yields `[]`, and non-object entries are dropped rather than
|
|
12
|
-
* throwing.
|
|
12
|
+
* throwing. `viewingIn` arrives as a display string from a current peer and as
|
|
13
|
+
* an `{app, tab}` object from one that predates the flattening, so it is
|
|
14
|
+
* normalized here — the single boundary where a foreign row becomes internal.
|
|
15
|
+
* Exported for unit testing without a live tailnet.
|
|
13
16
|
*/
|
|
14
17
|
export declare function parseRemoteActive(stdout: string, machine: string): ActiveSession[];
|
|
15
18
|
export interface RemoteActiveResult {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* `spawn`, not the sync `sshExec`) so N peers cost one round-trip, not N.
|
|
16
16
|
*/
|
|
17
17
|
import { gatherRemoteAgentsJson } from '../remote-agents-json.js';
|
|
18
|
+
import { parseViewingIn } from './viewing-in.js';
|
|
18
19
|
/**
|
|
19
20
|
* Recursion guard, passed as an env var (not a CLI flag) so an OLDER remote
|
|
20
21
|
* `agents` that predates this feature ignores it harmlessly instead of erroring
|
|
@@ -25,7 +26,10 @@ export const NO_FANOUT_ENV = 'AGENTS_SESSIONS_LOCAL';
|
|
|
25
26
|
* Parse a peer's `--active --json` stdout into active sessions, tagging each
|
|
26
27
|
* with `machine`. Defensive against version skew / partial output: non-JSON or
|
|
27
28
|
* a non-array yields `[]`, and non-object entries are dropped rather than
|
|
28
|
-
* throwing.
|
|
29
|
+
* throwing. `viewingIn` arrives as a display string from a current peer and as
|
|
30
|
+
* an `{app, tab}` object from one that predates the flattening, so it is
|
|
31
|
+
* normalized here — the single boundary where a foreign row becomes internal.
|
|
32
|
+
* Exported for unit testing without a live tailnet.
|
|
29
33
|
*/
|
|
30
34
|
export function parseRemoteActive(stdout, machine) {
|
|
31
35
|
let parsed;
|
|
@@ -40,7 +44,9 @@ export function parseRemoteActive(stdout, machine) {
|
|
|
40
44
|
const out = [];
|
|
41
45
|
for (const x of parsed) {
|
|
42
46
|
if (x && typeof x === 'object' && !Array.isArray(x)) {
|
|
43
|
-
|
|
47
|
+
const row = { ...x, machine };
|
|
48
|
+
row.viewingIn = parseViewingIn(x.viewingIn);
|
|
49
|
+
out.push(row);
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
return out;
|
|
@@ -27,6 +27,37 @@ export interface ViewingIn {
|
|
|
27
27
|
/** 1-based tab number within that app, when it can be resolved. */
|
|
28
28
|
tab?: number;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* The one display form of "where is this session being watched" — `'codium tab 3'`
|
|
32
|
+
* when a client is attached, the bare app name when the tab can't be resolved, and
|
|
33
|
+
* `'detached'` when the pane is live but nobody is looking at it (the terminal that
|
|
34
|
+
* displayed it was closed or crashed).
|
|
35
|
+
*
|
|
36
|
+
* `undefined` means **we do not know**, and it covers two different situations that
|
|
37
|
+
* must not be confused with `'detached'`: a session that isn't tmux-hosted (no pane
|
|
38
|
+
* to attach to, so it isn't on this axis at all), and a tmux session whose pane the
|
|
39
|
+
* locator could not resolve (`mapPanesToTargets` returned nothing for this socket,
|
|
40
|
+
* or the row was never enriched). {@link resolveViewingIn} answers `undefined` for
|
|
41
|
+
* BOTH "no client attached" and "could not locate the pane", so the pane's resolved
|
|
42
|
+
* `tmuxTarget` is what separates them: without it there is no evidence of absence,
|
|
43
|
+
* only absence of evidence. Claiming `'detached'` there would invent an orphaned
|
|
44
|
+
* session — and a consumer acts on that claim (Factory's picker pre-ticks every
|
|
45
|
+
* detached row for rescue), so the wrong answer resumes a session nobody asked for.
|
|
46
|
+
*
|
|
47
|
+
* Shared by the `--active` row renderer and the `--json` serializer so a machine
|
|
48
|
+
* consumer reads exactly the string a human sees, instead of re-deriving "detached"
|
|
49
|
+
* from an absent field.
|
|
50
|
+
*/
|
|
51
|
+
export declare function viewingInLabel(s: Pick<ActiveSession, 'provenance' | 'viewingIn' | 'tmuxTarget'>): string | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Wire form -> internal form for a row arriving from another machine's
|
|
54
|
+
* `--active --json`. The fan-out reaches peers whose CLI may predate
|
|
55
|
+
* {@link viewingInLabel} and still emit the `{app, tab}` object, so this boundary
|
|
56
|
+
* normalizes both shapes into one — the ONLY place either shape is accepted.
|
|
57
|
+
* `'detached'` maps to undefined, which is what "no attached client" means
|
|
58
|
+
* internally; {@link viewingInLabel} regenerates the word from the pane.
|
|
59
|
+
*/
|
|
60
|
+
export declare function parseViewingIn(raw: unknown): ViewingIn | undefined;
|
|
30
61
|
/** Injection seams so `resolveViewingIn` is unit-testable without a live tmux/ps/osascript. */
|
|
31
62
|
export interface ViewingInDeps {
|
|
32
63
|
/** Ghostty surfaces (window/tab/cwd/title). Enumerated once by the caller and shared. */
|
|
@@ -26,6 +26,53 @@ import { hostFromPid } from './active.js';
|
|
|
26
26
|
import { enumerateGhosttyTabs, assignGhosttyTabs } from './ghostty-tabs.js';
|
|
27
27
|
import { getTerminalsDir } from '../state.js';
|
|
28
28
|
const execFileAsync = promisify(execFile);
|
|
29
|
+
/**
|
|
30
|
+
* The one display form of "where is this session being watched" — `'codium tab 3'`
|
|
31
|
+
* when a client is attached, the bare app name when the tab can't be resolved, and
|
|
32
|
+
* `'detached'` when the pane is live but nobody is looking at it (the terminal that
|
|
33
|
+
* displayed it was closed or crashed).
|
|
34
|
+
*
|
|
35
|
+
* `undefined` means **we do not know**, and it covers two different situations that
|
|
36
|
+
* must not be confused with `'detached'`: a session that isn't tmux-hosted (no pane
|
|
37
|
+
* to attach to, so it isn't on this axis at all), and a tmux session whose pane the
|
|
38
|
+
* locator could not resolve (`mapPanesToTargets` returned nothing for this socket,
|
|
39
|
+
* or the row was never enriched). {@link resolveViewingIn} answers `undefined` for
|
|
40
|
+
* BOTH "no client attached" and "could not locate the pane", so the pane's resolved
|
|
41
|
+
* `tmuxTarget` is what separates them: without it there is no evidence of absence,
|
|
42
|
+
* only absence of evidence. Claiming `'detached'` there would invent an orphaned
|
|
43
|
+
* session — and a consumer acts on that claim (Factory's picker pre-ticks every
|
|
44
|
+
* detached row for rescue), so the wrong answer resumes a session nobody asked for.
|
|
45
|
+
*
|
|
46
|
+
* Shared by the `--active` row renderer and the `--json` serializer so a machine
|
|
47
|
+
* consumer reads exactly the string a human sees, instead of re-deriving "detached"
|
|
48
|
+
* from an absent field.
|
|
49
|
+
*/
|
|
50
|
+
export function viewingInLabel(s) {
|
|
51
|
+
if (s.provenance?.mux?.kind !== 'tmux' || !s.provenance.mux.pane)
|
|
52
|
+
return undefined;
|
|
53
|
+
if (!s.viewingIn)
|
|
54
|
+
return s.tmuxTarget ? 'detached' : undefined;
|
|
55
|
+
return s.viewingIn.tab != null ? `${s.viewingIn.app} tab ${s.viewingIn.tab}` : s.viewingIn.app;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wire form -> internal form for a row arriving from another machine's
|
|
59
|
+
* `--active --json`. The fan-out reaches peers whose CLI may predate
|
|
60
|
+
* {@link viewingInLabel} and still emit the `{app, tab}` object, so this boundary
|
|
61
|
+
* normalizes both shapes into one — the ONLY place either shape is accepted.
|
|
62
|
+
* `'detached'` maps to undefined, which is what "no attached client" means
|
|
63
|
+
* internally; {@link viewingInLabel} regenerates the word from the pane.
|
|
64
|
+
*/
|
|
65
|
+
export function parseViewingIn(raw) {
|
|
66
|
+
if (raw && typeof raw === 'object') {
|
|
67
|
+
const app = raw.app;
|
|
68
|
+
const tab = raw.tab;
|
|
69
|
+
return typeof app === 'string' ? { app, tab: typeof tab === 'number' ? tab : undefined } : undefined;
|
|
70
|
+
}
|
|
71
|
+
if (typeof raw !== 'string' || !raw || raw === 'detached')
|
|
72
|
+
return undefined;
|
|
73
|
+
const m = raw.match(/^(.+?) tab (\d+)$/);
|
|
74
|
+
return m ? { app: m[1], tab: parseInt(m[2], 10) } : { app: raw };
|
|
75
|
+
}
|
|
29
76
|
/** Apps whose tab index is published by the extension via live-terminals.json. */
|
|
30
77
|
const EDITOR_APPS = new Set(['code', 'cursor', 'codium', 'windsurf']);
|
|
31
78
|
/** The tmux session name a session's pane belongs to, from `session:window.pane`. */
|
package/dist/lib/state.d.ts
CHANGED
|
@@ -109,6 +109,12 @@ export declare function getCacheDir(): string;
|
|
|
109
109
|
export declare function getPackagesDir(): string;
|
|
110
110
|
/** Path to routine YAML definitions (~/.agents/routines/). */
|
|
111
111
|
export declare function getRoutinesDir(): string;
|
|
112
|
+
/**
|
|
113
|
+
* Path to webhook handler YAML definitions (~/.agents/webhooks/). Handlers are
|
|
114
|
+
* one-off triggers for agents/workflows/commands/routines, layered the same way
|
|
115
|
+
* as routines (project > user > system).
|
|
116
|
+
*/
|
|
117
|
+
export declare function getWebhooksDir(): string;
|
|
112
118
|
/**
|
|
113
119
|
* Path to built-in routine definitions shipped in the system repo
|
|
114
120
|
* (`~/.agents/.system/routines/`). Unioned under the user routines dir by
|
|
@@ -117,6 +123,11 @@ export declare function getRoutinesDir(): string;
|
|
|
117
123
|
* disables the built-in). The daemon fires these; the directory need not exist.
|
|
118
124
|
*/
|
|
119
125
|
export declare function getSystemRoutinesDir(): string;
|
|
126
|
+
/**
|
|
127
|
+
* Path to built-in webhook handler definitions shipped in the system repo
|
|
128
|
+
* (`~/.agents/.system/webhooks/`). Layered under user handlers by `listHandlers()`.
|
|
129
|
+
*/
|
|
130
|
+
export declare function getSystemWebhooksDir(): string;
|
|
120
131
|
/**
|
|
121
132
|
* Path to a project-scoped routines directory (`<project>/.agents/routines/`),
|
|
122
133
|
* or null when no project `.agents/` is found by walking up from cwd.
|
|
@@ -130,6 +141,12 @@ export declare function getSystemRoutinesDir(): string;
|
|
|
130
141
|
* it does not auto-enable firing. See `lib/routines-project.ts`.
|
|
131
142
|
*/
|
|
132
143
|
export declare function getProjectRoutinesDir(cwd?: string): string | null;
|
|
144
|
+
/**
|
|
145
|
+
* Path to a project-scoped webhook handlers directory
|
|
146
|
+
* (`<project>/.agents/webhooks/`), or null when no project `.agents/` is found
|
|
147
|
+
* by walking up from cwd.
|
|
148
|
+
*/
|
|
149
|
+
export declare function getProjectWebhooksDir(cwd?: string): string | null;
|
|
133
150
|
/** Path to routine execution logs (~/.agents/.history/runs/). */
|
|
134
151
|
export declare function getRunsDir(): string;
|
|
135
152
|
/** Path to monitor YAML definitions (~/.agents/monitors/). */
|
package/dist/lib/state.js
CHANGED
|
@@ -72,6 +72,7 @@ const SYSTEM_PLUGINS_DIR = path.join(SYSTEM_AGENTS_DIR, 'plugins');
|
|
|
72
72
|
// Unioned under user routines by listJobs()/readJob() so a routine shipped here
|
|
73
73
|
// fires for every install, while a user routine of the same name overrides it.
|
|
74
74
|
const SYSTEM_ROUTINES_DIR = path.join(SYSTEM_AGENTS_DIR, 'routines');
|
|
75
|
+
const SYSTEM_WEBHOOKS_DIR = path.join(SYSTEM_AGENTS_DIR, 'webhooks');
|
|
75
76
|
const SYSTEM_PROMPTCUTS_FILE = path.join(SYSTEM_AGENTS_DIR, 'hooks', 'promptcuts.yaml');
|
|
76
77
|
const SYSTEM_MCP_CONFIG_FILE = path.join(SYSTEM_AGENTS_DIR, 'mcp.json');
|
|
77
78
|
const SYSTEM_INSTRUCTIONS_FILE = path.join(SYSTEM_AGENTS_DIR, 'instructions.md');
|
|
@@ -82,6 +83,7 @@ const HISTORY_DIR = path.join(USER_AGENTS_DIR, '.history');
|
|
|
82
83
|
const CACHE_DIR = path.join(USER_AGENTS_DIR, '.cache');
|
|
83
84
|
// Top-level user dirs (config/definitions only — runtime moves into .history/.cache).
|
|
84
85
|
const ROUTINES_DIR = path.join(USER_AGENTS_DIR, 'routines');
|
|
86
|
+
const WEBHOOKS_DIR = path.join(USER_AGENTS_DIR, 'webhooks');
|
|
85
87
|
// Monitor definitions (event-triggered watchers). Sibling of ROUTINES_DIR: a
|
|
86
88
|
// monitor is a routine whose trigger is a watched source instead of a clock.
|
|
87
89
|
const MONITORS_DIR = path.join(USER_AGENTS_DIR, 'monitors');
|
|
@@ -306,7 +308,13 @@ export function getCacheDir() { return CACHE_DIR; }
|
|
|
306
308
|
/** Path to cloned packages (~/.agents/.cache/packages/). */
|
|
307
309
|
export function getPackagesDir() { return PACKAGES_DIR; }
|
|
308
310
|
/** Path to routine YAML definitions (~/.agents/routines/). */
|
|
309
|
-
export function getRoutinesDir() { return ROUTINES_DIR; }
|
|
311
|
+
export function getRoutinesDir() { return process.env.AGENTS_ROUTINES_DIR ?? ROUTINES_DIR; }
|
|
312
|
+
/**
|
|
313
|
+
* Path to webhook handler YAML definitions (~/.agents/webhooks/). Handlers are
|
|
314
|
+
* one-off triggers for agents/workflows/commands/routines, layered the same way
|
|
315
|
+
* as routines (project > user > system).
|
|
316
|
+
*/
|
|
317
|
+
export function getWebhooksDir() { return process.env.AGENTS_WEBHOOKS_DIR ?? WEBHOOKS_DIR; }
|
|
310
318
|
/**
|
|
311
319
|
* Path to built-in routine definitions shipped in the system repo
|
|
312
320
|
* (`~/.agents/.system/routines/`). Unioned under the user routines dir by
|
|
@@ -314,7 +322,12 @@ export function getRoutinesDir() { return ROUTINES_DIR; }
|
|
|
314
322
|
* user routine of the same name overrides it (a user copy with `enabled: false`
|
|
315
323
|
* disables the built-in). The daemon fires these; the directory need not exist.
|
|
316
324
|
*/
|
|
317
|
-
export function getSystemRoutinesDir() { return SYSTEM_ROUTINES_DIR; }
|
|
325
|
+
export function getSystemRoutinesDir() { return process.env.AGENTS_SYSTEM_ROUTINES_DIR ?? SYSTEM_ROUTINES_DIR; }
|
|
326
|
+
/**
|
|
327
|
+
* Path to built-in webhook handler definitions shipped in the system repo
|
|
328
|
+
* (`~/.agents/.system/webhooks/`). Layered under user handlers by `listHandlers()`.
|
|
329
|
+
*/
|
|
330
|
+
export function getSystemWebhooksDir() { return process.env.AGENTS_SYSTEM_WEBHOOKS_DIR ?? SYSTEM_WEBHOOKS_DIR; }
|
|
318
331
|
/**
|
|
319
332
|
* Path to a project-scoped routines directory (`<project>/.agents/routines/`),
|
|
320
333
|
* or null when no project `.agents/` is found by walking up from cwd.
|
|
@@ -333,6 +346,17 @@ export function getProjectRoutinesDir(cwd = process.cwd()) {
|
|
|
333
346
|
return null;
|
|
334
347
|
return path.join(projectAgentsDir, 'routines');
|
|
335
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* Path to a project-scoped webhook handlers directory
|
|
351
|
+
* (`<project>/.agents/webhooks/`), or null when no project `.agents/` is found
|
|
352
|
+
* by walking up from cwd.
|
|
353
|
+
*/
|
|
354
|
+
export function getProjectWebhooksDir(cwd = process.cwd()) {
|
|
355
|
+
const projectAgentsDir = getProjectAgentsDir(cwd);
|
|
356
|
+
if (!projectAgentsDir)
|
|
357
|
+
return null;
|
|
358
|
+
return path.join(projectAgentsDir, 'webhooks');
|
|
359
|
+
}
|
|
336
360
|
/** Path to routine execution logs (~/.agents/.history/runs/). */
|
|
337
361
|
export function getRunsDir() { return RUNS_DIR; }
|
|
338
362
|
/** Path to monitor YAML definitions (~/.agents/monitors/). */
|
|
@@ -506,6 +530,8 @@ export function ensureAgentsDir() {
|
|
|
506
530
|
fs.mkdirSync(PACKAGES_DIR, opts);
|
|
507
531
|
if (!fs.existsSync(ROUTINES_DIR))
|
|
508
532
|
fs.mkdirSync(ROUTINES_DIR, opts);
|
|
533
|
+
if (!fs.existsSync(WEBHOOKS_DIR))
|
|
534
|
+
fs.mkdirSync(WEBHOOKS_DIR, opts);
|
|
509
535
|
if (!fs.existsSync(RUNS_DIR))
|
|
510
536
|
fs.mkdirSync(RUNS_DIR, opts);
|
|
511
537
|
if (!fs.existsSync(VERSIONS_DIR))
|
|
@@ -524,6 +550,8 @@ export function ensureAgentsDir() {
|
|
|
524
550
|
fs.mkdirSync(SYSTEM_PERMISSIONS_DIR, opts);
|
|
525
551
|
if (!fs.existsSync(SYSTEM_SUBAGENTS_DIR))
|
|
526
552
|
fs.mkdirSync(SYSTEM_SUBAGENTS_DIR, opts);
|
|
553
|
+
if (!fs.existsSync(SYSTEM_WEBHOOKS_DIR))
|
|
554
|
+
fs.mkdirSync(SYSTEM_WEBHOOKS_DIR, opts);
|
|
527
555
|
try {
|
|
528
556
|
fs.chmodSync(SYSTEM_AGENTS_DIR, 0o700);
|
|
529
557
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook handler config layer.
|
|
3
|
+
*
|
|
4
|
+
* Handlers are one-off triggers stored in `~/.agents/webhooks/*.yml` (plus
|
|
5
|
+
* project/system layers). They complement routine triggers: a matching webhook
|
|
6
|
+
* can run an agent, workflow, shell command, or delegate to a routine.
|
|
7
|
+
*/
|
|
8
|
+
import type { JobConfig, RunMeta, WebhookContext } from '../routines.js';
|
|
9
|
+
import type { AgentId } from '../types.js';
|
|
10
|
+
import type { IncomingWebhook, WebhookSource } from './webhook.js';
|
|
11
|
+
export interface WebhookHandler {
|
|
12
|
+
name: string;
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
devices?: string[];
|
|
15
|
+
source: WebhookSource;
|
|
16
|
+
event?: string;
|
|
17
|
+
action?: string;
|
|
18
|
+
stateTo?: string;
|
|
19
|
+
stateFrom?: string;
|
|
20
|
+
teamKey?: string;
|
|
21
|
+
label?: string;
|
|
22
|
+
repo?: string;
|
|
23
|
+
branch?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Where to run the action. A device name (`yosemite-s0`) runs there over SSH;
|
|
26
|
+
* `fleet` picks any eligible online worker; `fleet/<platform>` (or
|
|
27
|
+
* `<platform>/fleet`, or a bare `linux`/`macos`/`windows`) restricts that pick
|
|
28
|
+
* to one platform. Omitted runs locally.
|
|
29
|
+
*/
|
|
30
|
+
host?: string;
|
|
31
|
+
run?: {
|
|
32
|
+
agent?: AgentId;
|
|
33
|
+
workflow?: string;
|
|
34
|
+
command?: string;
|
|
35
|
+
prompt?: string;
|
|
36
|
+
/** Environment variables injected into the spawned process. */
|
|
37
|
+
env?: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
routine?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface FiredHandler {
|
|
42
|
+
handlerName: string;
|
|
43
|
+
runId?: string;
|
|
44
|
+
exitCode?: number;
|
|
45
|
+
output?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface HandlerHostResolution {
|
|
48
|
+
/** Resolved execution host, or undefined to run locally. */
|
|
49
|
+
host?: string;
|
|
50
|
+
/** Strategy that should be set on the JobConfig. */
|
|
51
|
+
hostStrategy?: 'host' | 'fleet';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a handler `host` expression to a concrete host or local execution.
|
|
55
|
+
*
|
|
56
|
+
* - Specific device name (e.g. `yosemite-s0`) → run there over SSH, or locally
|
|
57
|
+
* if it names this machine.
|
|
58
|
+
* - `fleet` → pick any online worker device.
|
|
59
|
+
* - `fleet/<platform>` or `<platform>/fleet` (e.g. `fleet/linux`, `linux/fleet`)
|
|
60
|
+
* → pick any online worker on that platform. `linux` alone is accepted as a
|
|
61
|
+
* shorthand for `fleet/linux`.
|
|
62
|
+
*
|
|
63
|
+
* Throws when a fleet expression matches no eligible device, rather than
|
|
64
|
+
* silently falling back to this machine — `fleet/linux` must never land on a
|
|
65
|
+
* macOS box.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveHandlerHost(host: string | undefined): HandlerHostResolution;
|
|
68
|
+
/**
|
|
69
|
+
* List all webhook handlers, scanning project > user > system webhook dirs.
|
|
70
|
+
* Higher layers shadow lower ones of the same name (first-seen wins).
|
|
71
|
+
*/
|
|
72
|
+
export declare function listHandlers(cwd?: string): WebhookHandler[];
|
|
73
|
+
/** Pure matcher: does this handler match the incoming webhook? */
|
|
74
|
+
export declare function handlerMatchesWebhook(handler: WebhookHandler, webhook: IncomingWebhook): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Build the variable-substitution context for a webhook. Linear events expose
|
|
77
|
+
* `issue` and `updatedFrom`; GitHub events expose `repository`, `pull_request`,
|
|
78
|
+
* and `issue`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function buildWebhookContext(webhook: IncomingWebhook): WebhookContext;
|
|
81
|
+
export interface ExecuteHandlerOptions {
|
|
82
|
+
dispatchAgent?: (config: JobConfig) => Promise<RunMeta>;
|
|
83
|
+
dispatchWorkflow?: (config: JobConfig) => Promise<RunMeta>;
|
|
84
|
+
execCommand?: (command: string) => Promise<{
|
|
85
|
+
exitCode: number;
|
|
86
|
+
output: string;
|
|
87
|
+
}>;
|
|
88
|
+
dispatchRoutine?: (config: JobConfig) => Promise<RunMeta>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Execute a handler's action. Runs the configured agent/workflow/command or
|
|
92
|
+
* delegates to a routine, substituting `{{...}}` placeholders from the webhook
|
|
93
|
+
* context.
|
|
94
|
+
*/
|
|
95
|
+
export declare function executeHandler(handler: WebhookHandler, webhook: IncomingWebhook, opts?: ExecuteHandlerOptions): Promise<FiredHandler>;
|