@voidlabs.gg/voidshift-agents 0.4.3 → 0.4.5
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 +52 -4
- package/dist/config.d.ts +65 -6
- package/dist/config.js +114 -16
- package/dist/control.d.ts +3 -1
- package/dist/control.js +69 -39
- package/dist/cron.d.ts +9 -0
- package/dist/cron.js +66 -0
- package/dist/engine.d.ts +1 -0
- package/dist/engine.js +2 -0
- package/dist/git.d.ts +6 -0
- package/dist/git.js +60 -0
- package/dist/index.js +151 -35
- package/dist/linear.d.ts +1 -1
- package/dist/linear.js +3 -3
- package/dist/manage.d.ts +5 -2
- package/dist/manage.js +138 -21
- package/dist/names.d.ts +1 -0
- package/dist/names.js +4 -1
- package/dist/profile.d.ts +10 -0
- package/dist/profile.js +70 -0
- package/dist/runner.d.ts +15 -8
- package/dist/runner.js +219 -98
- package/dist/state.d.ts +7 -2
- package/dist/state.js +15 -0
- package/dist/tracker.d.ts +24 -0
- package/dist/tracker.js +36 -0
- package/dist/voidtrack.d.ts +18 -0
- package/dist/voidtrack.js +89 -0
- package/dist/workflow.d.ts +2 -2
- package/package.json +1 -1
package/dist/tracker.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createLinear } from "./linear.js";
|
|
2
|
+
import { readSecret } from "./secrets.js";
|
|
3
|
+
import { createVoidTrack } from "./voidtrack.js";
|
|
4
|
+
export const TRACKERS = {
|
|
5
|
+
linear: { name: 'Linear', keyHint: 'Linear > Settings > Security & access > API keys' },
|
|
6
|
+
voidtrack: { name: 'VoidTrack', keyHint: 'VoidTrack > Settings > API keys' },
|
|
7
|
+
};
|
|
8
|
+
export function trackersFor(configDir) {
|
|
9
|
+
const open = new Map();
|
|
10
|
+
return (kind) => {
|
|
11
|
+
let t = open.get(kind);
|
|
12
|
+
if (!t) {
|
|
13
|
+
const key = readSecret(configDir, kind);
|
|
14
|
+
if (!key)
|
|
15
|
+
throw new Error(`No ${TRACKERS[kind].name} API key. Run vsf agents key${kind === 'linear' ? '' : ` --${kind}`}`);
|
|
16
|
+
t = kind === 'voidtrack' ? createVoidTrack(key) : createLinear(key);
|
|
17
|
+
open.set(kind, t);
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Stands in for a tracker on a scheduled run, which has no card: reads find
|
|
23
|
+
// nothing and writes go nowhere.
|
|
24
|
+
export const noTracker = {
|
|
25
|
+
viewer: async () => ({ id: '', name: '' }),
|
|
26
|
+
myCardsWithLabel: async () => [],
|
|
27
|
+
card: async (id) => {
|
|
28
|
+
throw new Error(`a scheduled run has no card ${id}`);
|
|
29
|
+
},
|
|
30
|
+
comments: async () => [],
|
|
31
|
+
comment: async () => { },
|
|
32
|
+
setLabels: async (card, next) => {
|
|
33
|
+
card.labels = next;
|
|
34
|
+
},
|
|
35
|
+
moveTo: async () => false,
|
|
36
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Card } from './linear.ts';
|
|
2
|
+
export declare const branchFor: (identifier: string) => string;
|
|
3
|
+
export declare function mapIssue(i: any, web: string): Card;
|
|
4
|
+
export declare function createVoidTrack(apiKey: string, fetcher?: typeof fetch): {
|
|
5
|
+
viewer(): Promise<{
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}>;
|
|
9
|
+
myCardsWithLabel(label: string, team: string): Promise<Card[]>;
|
|
10
|
+
card(identifier: string): Promise<Card>;
|
|
11
|
+
comments(identifier: string): Promise<{
|
|
12
|
+
body: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
}[]>;
|
|
15
|
+
comment(card: Card, body: string): Promise<void>;
|
|
16
|
+
setLabels(card: Card, next: string[]): Promise<void>;
|
|
17
|
+
moveTo(card: Card, stateName: string): Promise<boolean>;
|
|
18
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// VoidTrack over its REST API with a bearer key. Self hosted installs set
|
|
2
|
+
// VOIDTRACK_API_URL; the web app lives at the same address without /api.
|
|
3
|
+
const apiBase = () => (process.env.VOIDTRACK_API_URL ?? 'https://web.voidtrack.app/api').replace(/\/$/, '');
|
|
4
|
+
// One branch per card that survives a retitle: GitHub closes a pull request
|
|
5
|
+
// whose branch is renamed.
|
|
6
|
+
export const branchFor = (identifier) => identifier.toLowerCase();
|
|
7
|
+
export function mapIssue(i, web) {
|
|
8
|
+
return {
|
|
9
|
+
id: i.id,
|
|
10
|
+
identifier: i.identifier,
|
|
11
|
+
title: i.title,
|
|
12
|
+
description: i.description ?? undefined,
|
|
13
|
+
url: `${web}/issue/${i.identifier}`,
|
|
14
|
+
branchName: branchFor(i.identifier),
|
|
15
|
+
teamId: i.team?.id ?? '',
|
|
16
|
+
teamKey: i.team?.key ?? i.identifier.split('-')[0],
|
|
17
|
+
projectName: i.project?.name ?? undefined,
|
|
18
|
+
labels: (i.labels ?? []).map((l) => (typeof l === 'string' ? l : l.name)),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function createVoidTrack(apiKey, fetcher = fetch) {
|
|
22
|
+
const base = apiBase();
|
|
23
|
+
const web = base.replace(/\/api$/, '');
|
|
24
|
+
async function call(method, path, body) {
|
|
25
|
+
let res;
|
|
26
|
+
try {
|
|
27
|
+
res = await fetcher(`${base}${path}`, {
|
|
28
|
+
method,
|
|
29
|
+
signal: AbortSignal.timeout(30_000),
|
|
30
|
+
headers: { Authorization: `Bearer ${apiKey}`, ...(body === undefined ? {} : { 'Content-Type': 'application/json' }) },
|
|
31
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
const cause = err.cause;
|
|
36
|
+
throw new Error(`could not reach VoidTrack (${cause?.code ?? cause?.message ?? err.message})`);
|
|
37
|
+
}
|
|
38
|
+
const text = await res.text();
|
|
39
|
+
if (!res.ok)
|
|
40
|
+
throw Object.assign(new Error(`voidtrack ${method} ${path.split('?')[0]} ${res.status}: ${text.slice(0, 200)}`), { status: res.status });
|
|
41
|
+
return text ? JSON.parse(text) : {};
|
|
42
|
+
}
|
|
43
|
+
const enc = encodeURIComponent;
|
|
44
|
+
return {
|
|
45
|
+
async viewer() {
|
|
46
|
+
const d = await call('GET', '/v1/users');
|
|
47
|
+
const me = (d.users ?? []).find((u) => u.isMe);
|
|
48
|
+
if (!me)
|
|
49
|
+
throw new Error('voidtrack did not say which user this key belongs to');
|
|
50
|
+
return { id: me.id, name: me.name };
|
|
51
|
+
},
|
|
52
|
+
// My open cards in the team carrying the label. The API cannot filter on
|
|
53
|
+
// labels, so that part happens here.
|
|
54
|
+
async myCardsWithLabel(label, team) {
|
|
55
|
+
const d = await call('GET', `/v1/issues?team=${enc(team)}&assignee=me&stateType=backlog,unstarted,started&sort=created&limit=200`);
|
|
56
|
+
return (d.issues ?? []).map((i) => mapIssue(i, web)).filter((c) => c.labels.includes(label));
|
|
57
|
+
},
|
|
58
|
+
async card(identifier) {
|
|
59
|
+
const d = await call('GET', `/v1/issues/${enc(identifier)}`);
|
|
60
|
+
if (!d.issue)
|
|
61
|
+
throw new Error(`voidtrack has no card ${identifier}`);
|
|
62
|
+
return mapIssue(d.issue, web);
|
|
63
|
+
},
|
|
64
|
+
async comments(identifier) {
|
|
65
|
+
const d = await call('GET', `/v1/issues/${enc(identifier)}/comments`);
|
|
66
|
+
return (d.comments ?? []).map((c) => ({ body: c.body, createdAt: c.createdAt }));
|
|
67
|
+
},
|
|
68
|
+
async comment(card, body) {
|
|
69
|
+
await call('POST', `/v1/issues/${enc(card.identifier)}/comments`, { body });
|
|
70
|
+
},
|
|
71
|
+
// Labels are free text on VoidTrack and the list replaces the whole set.
|
|
72
|
+
async setLabels(card, next) {
|
|
73
|
+
await call('PATCH', `/v1/issues/${enc(card.identifier)}`, { labels: next });
|
|
74
|
+
card.labels = next;
|
|
75
|
+
},
|
|
76
|
+
// Move to a named state; false if the team has no such state.
|
|
77
|
+
async moveTo(card, stateName) {
|
|
78
|
+
try {
|
|
79
|
+
await call('PATCH', `/v1/issues/${enc(card.identifier)}`, { state: stateName });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (err.status === 400 || err.status === 404)
|
|
84
|
+
return false;
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
package/dist/workflow.d.ts
CHANGED
|
@@ -47,6 +47,6 @@ export interface PromptInput {
|
|
|
47
47
|
extra?: string;
|
|
48
48
|
}
|
|
49
49
|
export declare function buildPrompt(p: PromptInput): string;
|
|
50
|
-
export declare function verdictBlock<T
|
|
51
|
-
export declare function fixTarget<T
|
|
50
|
+
export declare function verdictBlock<T>(steps: T[], i: number, isVerdict: (s: T) => boolean): [number, number];
|
|
51
|
+
export declare function fixTarget<T>(steps: T[], blockStart: number, isProducer: (s: T) => boolean): number;
|
|
52
52
|
export declare function planBody(output: string): string;
|
package/package.json
CHANGED