@voidlabs.gg/voidshift-agents 0.5.0 → 0.6.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.
- package/README.md +16 -2
- package/dist/config.d.ts +19 -0
- package/dist/config.js +43 -0
- package/dist/control.d.ts +14 -2
- package/dist/control.js +91 -48
- package/dist/index.js +132 -10
- package/dist/manage.d.ts +2 -1
- package/dist/manage.js +46 -1
- package/dist/runner.d.ts +25 -2
- package/dist/runner.js +192 -56
- package/dist/state.d.ts +11 -1
- package/dist/state.js +57 -3
- package/dist/workflow.d.ts +4 -0
- package/dist/workflow.js +15 -0
- package/pack/vs-plan/SKILL.md +4 -1
- package/pack/vs-plan-review/SKILL.md +3 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from 'node:os';
|
|
|
4
4
|
import { basename, dirname, join, resolve, sep } from 'node:path';
|
|
5
5
|
import { parseArgs } from 'node:util';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { AGENTS, AGENT_FILE, STEPS, TEMPLATES, isProducer, agentFolders, agentsDir, describeSteps, describeTrigger, describeTriggers, describeWorkflow, stepEnabled, stepId, visibleAgents, readAgentsConfig, writeAgentsConfig, DEFAULTS } from "./config.js";
|
|
7
|
+
import { AGENTS, AGENT_FILE, STEPS, TEMPLATES, isProducer, agentFolders, agentsDir, describeSteps, describeTrigger, describeTriggers, describeWorkflow, stepEnabled, stepId, visibleAgents, readAgentsConfig, writeAgentsConfig, workspaceOf, DEFAULTS, DEFAULT_WORKSPACE, WORKSPACE_NAME } from "./config.js";
|
|
8
8
|
import { controlChecks, controlCommands, controlUsage } from "./control.js";
|
|
9
9
|
import { keyStore, looksLikeLinearKey, readLinearKey, readSecret, storeLinearKey, storeSecret } from "./secrets.js";
|
|
10
10
|
import { TRACKERS } from "./tracker.js";
|
|
@@ -14,7 +14,7 @@ import { trackersInUse } from "./control.js";
|
|
|
14
14
|
import { runnerService } from "./service.js";
|
|
15
15
|
import { initProfile, profileChecks, profileDir, readRules, renderClaudeSettings, CLAUDE_SETTINGS, RULES_FILE } from "./profile.js";
|
|
16
16
|
import { createLinear } from "./linear.js";
|
|
17
|
-
import { TRIGGER_FORMS, duplicateTriggerWarnings, moveKey, parseTrigger, renameKey, sameTrigger, validateAgentFolder, validateConfig, validateWorkflow, workflowsUsing } from "./manage.js";
|
|
17
|
+
import { TRIGGER_FORMS, duplicateTriggerWarnings, moveKey, parseTrigger, projectProblems, renameKey, sameTrigger, validateAgentFolder, validateConfig, validateWorkflow, workflowsUsing } from "./manage.js";
|
|
18
18
|
import { parseStep, resolveName, stepNames } from "./names.js";
|
|
19
19
|
import { findRepos } from "./repos.js";
|
|
20
20
|
import { defaultBranch, sh } from "./git.js";
|
|
@@ -239,7 +239,8 @@ async function promptProject(ui, config, current = {}, edit = false, allowExisti
|
|
|
239
239
|
const describeProject = (config, name) => {
|
|
240
240
|
const p = config.projects[name];
|
|
241
241
|
const used = workflowsUsing(config, name);
|
|
242
|
-
|
|
242
|
+
const where = [p.workspace ? `workspace ${p.workspace}` : '', p.match?.length ? `matches ${p.match.join(', ')}` : ''].filter(Boolean);
|
|
243
|
+
return `${name} ${tilde(p.path)}, PRs into ${p.base ?? 'the default branch'}, ${where.map((w) => `${w}, `).join('')}${used.length ? `used by ${used.join(', ')}` : 'not used by any workflow'}`;
|
|
243
244
|
};
|
|
244
245
|
// Named local repos the workflows run in. Triggers point at them by name.
|
|
245
246
|
async function setupProjects(ui, config, log) {
|
|
@@ -366,11 +367,14 @@ const USAGE = [
|
|
|
366
367
|
['workflow rm NAME [--yes]', 'Delete a workflow'],
|
|
367
368
|
['workflow move NAME (--first | --last | --before OTHER | --after OTHER)', 'Change the match order'],
|
|
368
369
|
['projects [--json]', 'List projects'],
|
|
369
|
-
['project add [NAME] [--path P] [--base B]', 'Add a project; prompts for what is missing'],
|
|
370
|
+
['project add [NAME] [--path P] [--base B] [--workspace W] [--match NAME]...', 'Add a project; prompts for what is missing. --match routes cards of that tracker project here, whatever the workflow says'],
|
|
370
371
|
['project show NAME [--json]', 'Show one project'],
|
|
371
|
-
['project edit NAME [--path P] [--base B]', 'Change a project; no flags asks'],
|
|
372
|
+
['project edit NAME [--path P] [--base B] [--workspace W] [--match NAME]...', 'Change a project; no flags asks. An empty --workspace or --match clears it'],
|
|
372
373
|
['project rename OLD NEW', 'Rename a project and the workflows that use it'],
|
|
373
374
|
['project rm NAME [--yes]', 'Delete a project nothing uses'],
|
|
375
|
+
['workspace add NAME --root DIR [--context FILE]', 'Add a workspace: a folder of repos with its own run queue. Steps carry FILE, or DIR/CONTEXT.md'],
|
|
376
|
+
['workspace list [--json]', 'List workspaces and their projects'],
|
|
377
|
+
['workspace rm NAME', 'Delete a workspace no project uses'],
|
|
374
378
|
['homes [--json]', 'Show where the agents are linked'],
|
|
375
379
|
['link DIR [--claude | --codex]', 'Link the agents into a config folder'],
|
|
376
380
|
['unlink DIR', 'Remove the agents from a config folder'],
|
|
@@ -789,9 +793,31 @@ function pickProject(config, input, ctx) {
|
|
|
789
793
|
}
|
|
790
794
|
return r.name;
|
|
791
795
|
}
|
|
796
|
+
const PROJECT_FLAGS = { path: { type: 'string' }, base: { type: 'string' }, workspace: { type: 'string' }, match: { type: 'string', multiple: true } };
|
|
797
|
+
// Applies --workspace and --match to a project. An empty value clears either.
|
|
798
|
+
// Returns a complaint when the workspace or a match does not fit.
|
|
799
|
+
function applyWorkspaceFlags(config, name, project, v) {
|
|
800
|
+
if (v.workspace !== undefined) {
|
|
801
|
+
const ws = String(v.workspace).trim();
|
|
802
|
+
if (ws && ws !== DEFAULT_WORKSPACE && !config.workspaces[ws])
|
|
803
|
+
return `No workspace named ${ws}. vsf agents workspace add creates it.`;
|
|
804
|
+
if (ws && ws !== DEFAULT_WORKSPACE)
|
|
805
|
+
project.workspace = ws;
|
|
806
|
+
else
|
|
807
|
+
delete project.workspace;
|
|
808
|
+
}
|
|
809
|
+
if (v.match !== undefined) {
|
|
810
|
+
const match = v.match.map((m) => m.trim()).filter(Boolean);
|
|
811
|
+
if (match.length)
|
|
812
|
+
project.match = match;
|
|
813
|
+
else
|
|
814
|
+
delete project.match;
|
|
815
|
+
}
|
|
816
|
+
return projectProblems({ ...config.projects, [name]: project }, config.workspaces)[0] ?? null;
|
|
817
|
+
}
|
|
792
818
|
const projectSubs = {
|
|
793
819
|
async add(args, ctx) {
|
|
794
|
-
const p = begin('project add', args,
|
|
820
|
+
const p = begin('project add', args, PROJECT_FLAGS, ctx);
|
|
795
821
|
if (typeof p === 'number')
|
|
796
822
|
return p;
|
|
797
823
|
if (p.positionals.length > 1) {
|
|
@@ -838,6 +864,11 @@ const projectSubs = {
|
|
|
838
864
|
name = r.name;
|
|
839
865
|
project = r.project;
|
|
840
866
|
}
|
|
867
|
+
const bad = applyWorkspaceFlags(config, name, project, p.values);
|
|
868
|
+
if (bad) {
|
|
869
|
+
ctx.log(bad);
|
|
870
|
+
return 1;
|
|
871
|
+
}
|
|
841
872
|
config.projects[name] = project;
|
|
842
873
|
save(ctx, config);
|
|
843
874
|
ctx.log(`Project ${name}: ${tilde(project.path)}${project.base ? `, PRs into ${project.base}` : ''}`);
|
|
@@ -861,12 +892,15 @@ const projectSubs = {
|
|
|
861
892
|
ctx.log(`Project ${name}`);
|
|
862
893
|
ctx.log(`Path: ${tilde(proj.path)}`);
|
|
863
894
|
ctx.log(`PRs into: ${proj.base ?? 'the default branch'}`);
|
|
895
|
+
ctx.log(`Workspace: ${workspaceOf(proj)}`);
|
|
896
|
+
if (proj.match?.length)
|
|
897
|
+
ctx.log(`Matches: ${proj.match.join(', ')}`);
|
|
864
898
|
ctx.log(`Used by: ${used.length ? used.join(', ') : 'no workflows'}`);
|
|
865
899
|
}
|
|
866
900
|
return 0;
|
|
867
901
|
},
|
|
868
902
|
async edit(args, ctx) {
|
|
869
|
-
const p = begin('project edit', args,
|
|
903
|
+
const p = begin('project edit', args, PROJECT_FLAGS, ctx);
|
|
870
904
|
if (typeof p === 'number')
|
|
871
905
|
return p;
|
|
872
906
|
if (!needArgs(p, 1, 'project edit', ctx))
|
|
@@ -877,9 +911,9 @@ const projectSubs = {
|
|
|
877
911
|
return 1;
|
|
878
912
|
const current = config.projects[name];
|
|
879
913
|
const v = p.values;
|
|
880
|
-
if (v.path === undefined && v.base === undefined) {
|
|
914
|
+
if (v.path === undefined && v.base === undefined && v.workspace === undefined && v.match === undefined) {
|
|
881
915
|
if (!interactive()) {
|
|
882
|
-
ctx.log('Nothing to change. Give --path or --
|
|
916
|
+
ctx.log('Nothing to change. Give --path, --base, --workspace or --match, or run this in a terminal to be asked.');
|
|
883
917
|
ctx.log(usageOf('project edit'));
|
|
884
918
|
return 2;
|
|
885
919
|
}
|
|
@@ -887,7 +921,8 @@ const projectSubs = {
|
|
|
887
921
|
}
|
|
888
922
|
else {
|
|
889
923
|
const path = v.path !== undefined ? resolve(expandHome(v.path)) : current.path;
|
|
890
|
-
|
|
924
|
+
// Only a new path needs checking; a workspace or match change keeps the repo.
|
|
925
|
+
if (v.path !== undefined && !isRepo(path)) {
|
|
891
926
|
ctx.log(`${tilde(path)} is not a git repository.`);
|
|
892
927
|
return 1;
|
|
893
928
|
}
|
|
@@ -899,6 +934,11 @@ const projectSubs = {
|
|
|
899
934
|
else
|
|
900
935
|
delete next.base;
|
|
901
936
|
}
|
|
937
|
+
const bad = applyWorkspaceFlags(config, name, next, v);
|
|
938
|
+
if (bad) {
|
|
939
|
+
ctx.log(bad);
|
|
940
|
+
return 1;
|
|
941
|
+
}
|
|
902
942
|
config.projects[name] = next;
|
|
903
943
|
}
|
|
904
944
|
save(ctx, config);
|
|
@@ -960,6 +1000,87 @@ const projectSubs = {
|
|
|
960
1000
|
return 0;
|
|
961
1001
|
},
|
|
962
1002
|
};
|
|
1003
|
+
// ---- workspaces ----
|
|
1004
|
+
const projectsIn = (config, ws) => Object.entries(config.projects).filter(([, p]) => workspaceOf(p) === ws).map(([n]) => n);
|
|
1005
|
+
const workspaceSubs = {
|
|
1006
|
+
async add(args, ctx) {
|
|
1007
|
+
const p = begin('workspace add', args, { root: { type: 'string' }, context: { type: 'string' } }, ctx);
|
|
1008
|
+
if (typeof p === 'number')
|
|
1009
|
+
return p;
|
|
1010
|
+
if (!needArgs(p, 1, 'workspace add', ctx))
|
|
1011
|
+
return 2;
|
|
1012
|
+
const name = p.positionals[0].trim();
|
|
1013
|
+
if (!WORKSPACE_NAME.test(name)) {
|
|
1014
|
+
ctx.log('A workspace name is letters, digits, dashes and underscores.');
|
|
1015
|
+
return 2;
|
|
1016
|
+
}
|
|
1017
|
+
if (!p.values.root) {
|
|
1018
|
+
ctx.log('Missing --root.');
|
|
1019
|
+
ctx.log(usageOf('workspace add'));
|
|
1020
|
+
return 2;
|
|
1021
|
+
}
|
|
1022
|
+
const config = readAgentsConfig(ctx.configDir);
|
|
1023
|
+
if (config.workspaces[name]) {
|
|
1024
|
+
ctx.log(`A workspace named ${name} already exists.`);
|
|
1025
|
+
return 1;
|
|
1026
|
+
}
|
|
1027
|
+
const root = resolve(expandHome(p.values.root));
|
|
1028
|
+
if (!existsSync(root)) {
|
|
1029
|
+
ctx.log(`${tilde(root)} does not exist.`);
|
|
1030
|
+
return 1;
|
|
1031
|
+
}
|
|
1032
|
+
const context = p.values.context ? resolve(root, expandHome(p.values.context)) : undefined;
|
|
1033
|
+
if (context && !existsSync(context)) {
|
|
1034
|
+
ctx.log(`${tilde(context)} does not exist.`);
|
|
1035
|
+
return 1;
|
|
1036
|
+
}
|
|
1037
|
+
config.workspaces[name] = { root, ...(context ? { context } : {}) };
|
|
1038
|
+
save(ctx, config);
|
|
1039
|
+
ctx.log(`Workspace ${name}: ${tilde(root)}. vsf agents project edit P --workspace ${name} puts a project in it.`);
|
|
1040
|
+
return 0;
|
|
1041
|
+
},
|
|
1042
|
+
async list(args, ctx) {
|
|
1043
|
+
const p = begin('workspace list', args, { json: { type: 'boolean' } }, ctx);
|
|
1044
|
+
if (typeof p === 'number')
|
|
1045
|
+
return p;
|
|
1046
|
+
const config = readAgentsConfig(ctx.configDir);
|
|
1047
|
+
const names = [...new Set([...Object.keys(config.workspaces), ...Object.values(config.projects).map(workspaceOf)])];
|
|
1048
|
+
if (p.values.json) {
|
|
1049
|
+
out(ctx, names.map((name) => ({ name, ...config.workspaces[name], projects: projectsIn(config, name) })));
|
|
1050
|
+
return 0;
|
|
1051
|
+
}
|
|
1052
|
+
if (!names.length)
|
|
1053
|
+
ctx.log('No workspaces yet. Every project runs in the default one; vsf agents workspace add creates another.');
|
|
1054
|
+
for (const name of names) {
|
|
1055
|
+
const w = config.workspaces[name];
|
|
1056
|
+
const projects = projectsIn(config, name);
|
|
1057
|
+
ctx.log(`${name} ${w ? tilde(w.root) : 'no root'}${w?.context ? `, context ${tilde(w.context)}` : ''}, ${projects.length ? projects.join(', ') : 'no projects'}`);
|
|
1058
|
+
}
|
|
1059
|
+
return 0;
|
|
1060
|
+
},
|
|
1061
|
+
async rm(args, ctx) {
|
|
1062
|
+
const p = begin('workspace rm', args, {}, ctx);
|
|
1063
|
+
if (typeof p === 'number')
|
|
1064
|
+
return p;
|
|
1065
|
+
if (!needArgs(p, 1, 'workspace rm', ctx))
|
|
1066
|
+
return 2;
|
|
1067
|
+
const config = readAgentsConfig(ctx.configDir);
|
|
1068
|
+
const name = p.positionals[0].trim();
|
|
1069
|
+
if (!config.workspaces[name]) {
|
|
1070
|
+
ctx.log(`No workspace named ${name}.`);
|
|
1071
|
+
return 1;
|
|
1072
|
+
}
|
|
1073
|
+
const used = projectsIn(config, name);
|
|
1074
|
+
if (used.length) {
|
|
1075
|
+
ctx.log(`Used by ${used.join(', ')}. Move those projects first: vsf agents project edit P --workspace OTHER.`);
|
|
1076
|
+
return 1;
|
|
1077
|
+
}
|
|
1078
|
+
delete config.workspaces[name];
|
|
1079
|
+
save(ctx, config);
|
|
1080
|
+
ctx.log(`Deleted workspace ${name}.`);
|
|
1081
|
+
return 0;
|
|
1082
|
+
},
|
|
1083
|
+
};
|
|
963
1084
|
// ---- homes ----
|
|
964
1085
|
// Per enabled agent: ours, taken by something else, or missing.
|
|
965
1086
|
function homeReport(config, h) {
|
|
@@ -1242,6 +1363,7 @@ const agents = {
|
|
|
1242
1363
|
return 0;
|
|
1243
1364
|
},
|
|
1244
1365
|
project: (args, ctx) => group('project', projectSubs, args, ctx),
|
|
1366
|
+
workspace: (args, ctx) => group('workspace', workspaceSubs, args, ctx),
|
|
1245
1367
|
homes: homeCommands.homes,
|
|
1246
1368
|
link: homeCommands.link,
|
|
1247
1369
|
unlink: homeCommands.unlink,
|
package/dist/manage.d.ts
CHANGED
|
@@ -18,4 +18,5 @@ export type Place = {
|
|
|
18
18
|
};
|
|
19
19
|
export declare function moveKey<T>(record: Record<string, T>, name: string, place: Place): Record<string, T>;
|
|
20
20
|
export declare const workflowsUsing: (config: Pick<AgentsConfig, "workflows">, project: string) => string[];
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function projectProblems(projects: AgentsConfig['projects'], workspaces: AgentsConfig['workspaces']): string[];
|
|
22
|
+
export declare function validateConfig(value: unknown, saved?: Pick<AgentsConfig, 'projects' | 'workflows'> & Partial<Pick<AgentsConfig, 'workspaces'>>): string[];
|
package/dist/manage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { basename, join, resolve } from 'node:path';
|
|
3
|
-
import { AGENTS, AGENT_FILE, OUTPUTS, STEP_ID, isBuiltin, readAgentFolder, stepFile, describeTrigger, triggerSpec } from "./config.js";
|
|
3
|
+
import { AGENTS, AGENT_FILE, DEFAULT_WORKSPACE, OUTPUTS, STEP_ID, WORKSPACE_NAME, isBuiltin, readAgentFolder, stepFile, describeTrigger, triggerSpec } from "./config.js";
|
|
4
4
|
import { parseCron } from "./cron.js";
|
|
5
5
|
const isInt = (v, min, max) => typeof v === 'number' && Number.isInteger(v) && v >= min && v <= max;
|
|
6
6
|
// The line a step's prompt must ask for, so the runner can read the result.
|
|
@@ -185,6 +185,34 @@ export function moveKey(record, name, place) {
|
|
|
185
185
|
}
|
|
186
186
|
export const workflowsUsing = (config, project) => Object.entries(config.workflows).filter(([, w]) => w.project === project).map(([n]) => n);
|
|
187
187
|
const isObj = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
188
|
+
// What is wrong with the projects' workspaces and matches: a workspace that
|
|
189
|
+
// does not exist, or a tracker project name two projects both claim.
|
|
190
|
+
export function projectProblems(projects, workspaces) {
|
|
191
|
+
const problems = [];
|
|
192
|
+
const claimed = new Map();
|
|
193
|
+
for (const [name, p] of Object.entries(projects)) {
|
|
194
|
+
if (!isObj(p))
|
|
195
|
+
continue;
|
|
196
|
+
if (p.workspace !== undefined && (typeof p.workspace !== 'string' || (p.workspace !== DEFAULT_WORKSPACE && !Object.hasOwn(workspaces, p.workspace)))) {
|
|
197
|
+
problems.push(`Project ${name}: workspace ${String(p.workspace)} does not exist. vsf agents workspace add creates it.`);
|
|
198
|
+
}
|
|
199
|
+
if (p.match === undefined)
|
|
200
|
+
continue;
|
|
201
|
+
if (!Array.isArray(p.match) || p.match.some((m) => typeof m !== 'string' || !m.trim())) {
|
|
202
|
+
problems.push(`Project ${name}: match must list tracker project names.`);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
for (const m of p.match) {
|
|
206
|
+
const key = m.trim().toLowerCase();
|
|
207
|
+
const other = claimed.get(key);
|
|
208
|
+
if (other && other !== name)
|
|
209
|
+
problems.push(`Projects ${other} and ${name} both match ${m}.`);
|
|
210
|
+
else
|
|
211
|
+
claimed.set(key, name);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return problems;
|
|
215
|
+
}
|
|
188
216
|
// Everything wrong with a whole agents config, e.g. one edited by hand.
|
|
189
217
|
// `saved` is the config on disk: only what the write changes is checked, so a
|
|
190
218
|
// moved folder or a retired agent elsewhere does not block an unrelated edit.
|
|
@@ -209,6 +237,23 @@ export function validateConfig(value, saved) {
|
|
|
209
237
|
else if (saved?.projects?.[name]?.path !== p.path && !existsSync(join(p.path, '.git')))
|
|
210
238
|
problems.push(`Project ${name}: ${p.path} is not a git repository.`);
|
|
211
239
|
}
|
|
240
|
+
// Older configs have no workspaces: every project is in the default one.
|
|
241
|
+
const workspaces = value.workspaces === undefined ? {} : isObj(value.workspaces) ? value.workspaces : null;
|
|
242
|
+
if (!workspaces)
|
|
243
|
+
problems.push('workspaces must be an object.');
|
|
244
|
+
for (const [name, w] of Object.entries(workspaces ?? {})) {
|
|
245
|
+
if (!WORKSPACE_NAME.test(name))
|
|
246
|
+
problems.push(`Workspace ${name} must be letters, digits, dashes and underscores.`);
|
|
247
|
+
if (!isObj(w) || typeof w.root !== 'string' || !w.root)
|
|
248
|
+
problems.push(`Workspace ${name} needs a root folder.`);
|
|
249
|
+
else {
|
|
250
|
+
if (saved?.workspaces?.[name]?.root !== w.root && !existsSync(w.root))
|
|
251
|
+
problems.push(`Workspace ${name}: ${w.root} does not exist.`);
|
|
252
|
+
if (w.context !== undefined && typeof w.context !== 'string')
|
|
253
|
+
problems.push(`Workspace ${name} context must be a file name.`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
problems.push(...projectProblems((projects ?? {}), (workspaces ?? {})));
|
|
212
257
|
if (!Array.isArray(value.enabled) || value.enabled.some((a) => typeof a !== 'string' || !(a in AGENTS)))
|
|
213
258
|
problems.push(`enabled must list agents from: ${Object.keys(AGENTS).join(', ')}.`);
|
|
214
259
|
if (value.commits !== undefined && (!isObj(value.commits) || Object.entries(value.commits).some(([k, v]) => !['signOff', 'dropAiTrailers'].includes(k) || typeof v !== 'boolean')))
|
package/dist/runner.d.ts
CHANGED
|
@@ -16,15 +16,38 @@ type Job = {
|
|
|
16
16
|
card: Card;
|
|
17
17
|
trigger: Trigger;
|
|
18
18
|
workflow: string;
|
|
19
|
+
workspace: string;
|
|
19
20
|
};
|
|
20
21
|
export declare function cronCard(workflow: string, task: string, at: Date): Card;
|
|
21
|
-
export
|
|
22
|
+
export interface JobQuery {
|
|
23
|
+
only?: string;
|
|
24
|
+
workflow?: string;
|
|
25
|
+
schedule?: string;
|
|
22
26
|
force?: boolean;
|
|
27
|
+
busy?: Set<string>;
|
|
28
|
+
skip?: Set<string>;
|
|
29
|
+
limit?: number;
|
|
23
30
|
now?: Date;
|
|
24
|
-
}
|
|
31
|
+
}
|
|
32
|
+
export declare function findJobs(rc: RunContext, q?: JobQuery): Promise<Job[]>;
|
|
33
|
+
export declare function nextJob(rc: RunContext, only?: string, workflowName?: string, opts?: Omit<JobQuery, 'only' | 'workflow' | 'limit'>): Promise<Job | null>;
|
|
25
34
|
export declare function cancelCard(tracker: Tracker, configDir: string, cardId: string, label: string, source?: 'linear' | 'voidtrack'): Promise<boolean>;
|
|
26
35
|
export declare function tick(rc: RunContext, only?: string, opts?: {
|
|
27
36
|
workflow?: string;
|
|
28
37
|
from?: string;
|
|
38
|
+
schedule?: string;
|
|
39
|
+
child?: boolean;
|
|
29
40
|
}): Promise<number>;
|
|
41
|
+
export interface ChildRun {
|
|
42
|
+
kill(signal: NodeJS.Signals): unknown;
|
|
43
|
+
once(event: 'exit' | 'error', listener: (err?: Error) => void): unknown;
|
|
44
|
+
exitCode: number | null;
|
|
45
|
+
}
|
|
46
|
+
export interface DispatchDeps {
|
|
47
|
+
start: (args: string[]) => ChildRun;
|
|
48
|
+
waitMs: number;
|
|
49
|
+
reload?: () => AgentsConfig;
|
|
50
|
+
}
|
|
51
|
+
export declare const jobArgs: (job: Job) => string[];
|
|
52
|
+
export declare function dispatch(rc: RunContext, over?: Partial<DispatchDeps>): Promise<number>;
|
|
30
53
|
export {};
|