@voidlabs.gg/voidshift 0.4.3 → 0.4.4
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
CHANGED
|
@@ -50,15 +50,24 @@ Five agents, installed into Claude Code (and Codex if you use it):
|
|
|
50
50
|
| QA | CI, then code review, then a usability check in a headless browser |
|
|
51
51
|
|
|
52
52
|
Use them yourself (`/vs-plan ENG-123` in Claude Code), or let a **workflow**
|
|
53
|
-
run them. A workflow starts when one of your Linear cards gets a
|
|
54
|
-
agents in order in a project (a repo on your
|
|
55
|
-
step that made it when a check fails:
|
|
53
|
+
run them. A workflow starts when one of your Linear or VoidTrack cards gets a
|
|
54
|
+
label, or on a schedule, runs agents in order in a project (a repo on your
|
|
55
|
+
machine), and sends work back to the step that made it when a check fails:
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
when ENG + vs-plan: Dev → QA in tether-relay
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
Triggers, as `--trigger` takes them:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
ENG:vs-plan # a Linear card in ENG assigned to you gets vs-plan
|
|
65
|
+
voidtrack:ORG:vs-start # the same for VoidTrack (vsf agents key --voidtrack)
|
|
66
|
+
"cron:0 5 * * 1:Update dependencies" # every Monday 05:00, no card, on its own branch
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
A schedule fires once when due (a missed one is made up within a day) and
|
|
70
|
+
`vsf agents run --workflow NAME` fires it now. The runner checks every minute, works in its own copy of the repo so
|
|
62
71
|
your checkout is never touched, and keeps two labels on the card as it goes: the
|
|
63
72
|
stage (`vs-planning`, `vs-plan-review`, `vs-dev`, `vs-qa`, then `vs-qa-verified`
|
|
64
73
|
or `vs-parked`) and the round (`vs-v1`, `vs-v2`). On Linear it posts the plan and
|
package/dist/tui/data.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { useBackGuard, useEquivalent, useHints, useKeys, useScreen } from "../co
|
|
|
8
8
|
import { theme } from "../theme.js";
|
|
9
9
|
import { Panel, Select, TextInput } from "../widgets.js";
|
|
10
10
|
import { tilde } from "../format.js";
|
|
11
|
-
import { matchWarnings, stepLabel, stepName, triggerText, warningText, sameTriggerLike } from "./workflows.js";
|
|
11
|
+
import { matchWarnings, stepLabel, stepName, triggerSpec, triggerText, warningText, sameTriggerLike } from "./workflows.js";
|
|
12
12
|
const h = React.createElement;
|
|
13
13
|
export function formReducer(s, a) {
|
|
14
14
|
switch (a.type) {
|
|
@@ -38,7 +38,7 @@ export function formReducer(s, a) {
|
|
|
38
38
|
}
|
|
39
39
|
export function initialForm(w, name, projects) {
|
|
40
40
|
if (w)
|
|
41
|
-
return { name, triggers: w.triggers.map((t) => ({
|
|
41
|
+
return { name, triggers: w.triggers.map((t) => ({ ...t })), steps: [...w.steps], project: w.project, rounds: w.maxRounds };
|
|
42
42
|
return { name: '', triggers: [], steps: [], project: projects.length === 1 ? projects[0] : '', rounds: 3 };
|
|
43
43
|
}
|
|
44
44
|
const FALLBACK_PRODUCERS = ['vs-plan', 'vs-dev'];
|
|
@@ -95,7 +95,7 @@ export function saveArgs(s, isNew, catalog) {
|
|
|
95
95
|
'workflow',
|
|
96
96
|
isNew ? 'add' : 'edit',
|
|
97
97
|
s.name.trim(),
|
|
98
|
-
...s.triggers.flatMap((t) => ['--trigger',
|
|
98
|
+
...s.triggers.flatMap((t) => ['--trigger', triggerSpec(t)]),
|
|
99
99
|
'--steps',
|
|
100
100
|
s.steps.map((id) => stepName(catalog, id)).join(','),
|
|
101
101
|
'--project',
|
|
@@ -105,17 +105,19 @@ export function saveArgs(s, isNew, catalog) {
|
|
|
105
105
|
];
|
|
106
106
|
}
|
|
107
107
|
export const renameArgs = (from, to) => ['agents', 'workflow', 'rename', from, to];
|
|
108
|
-
// A trigger from the two text fields, or a complaint.
|
|
108
|
+
// A trigger from the two text fields, or a complaint. A team written as
|
|
109
|
+
// voidtrack:ORG is a VoidTrack team; schedules are added with the CLI.
|
|
109
110
|
export function makeTrigger(team, label) {
|
|
110
|
-
const
|
|
111
|
+
const voidtrack = /^voidtrack:/i.test(team.trim());
|
|
112
|
+
const t = team.trim().replace(/^voidtrack:/i, '').toUpperCase();
|
|
111
113
|
const l = label.trim();
|
|
112
114
|
if (!t)
|
|
113
|
-
return { error: 'Give the
|
|
115
|
+
return { error: 'Give the team, like ENG, or voidtrack:ORG for VoidTrack.' };
|
|
114
116
|
if (t.includes(':') || /\s/.test(t))
|
|
115
|
-
return { error: 'The team is a short key like ENG.' };
|
|
117
|
+
return { error: 'The team is a short key like ENG, or voidtrack:ORG.' };
|
|
116
118
|
if (!l)
|
|
117
119
|
return { error: 'Give the label, like vs-plan.' };
|
|
118
|
-
return { trigger: { team: t, label: l } };
|
|
120
|
+
return { trigger: { source: voidtrack ? 'voidtrack' : 'linear', team: t, label: l } };
|
|
119
121
|
}
|
|
120
122
|
// Warnings for triggers this workflow shares with another. In place when
|
|
121
123
|
// editing, last in order when new.
|
|
@@ -348,7 +350,7 @@ function WorkflowForm(props) {
|
|
|
348
350
|
// Triggers
|
|
349
351
|
h(Box, null, h(Label, { text: 'Starts when', focused: where === 'triggers' }), h(Box, { flexDirection: 'column', flexGrow: 1 }, form.triggers.length === 0 ? h(Text, { color: theme.dim }, ' no trigger yet') : null, ...form.triggers.map((t, i) => {
|
|
350
352
|
const on = where === 'triggers' && i === tCursor && adding === null;
|
|
351
|
-
return h(Text, { key:
|
|
353
|
+
return h(Text, { key: triggerSpec(t), backgroundColor: on ? theme.selected : undefined, bold: on, color: on ? theme.bold : undefined }, ` ${triggerText(t)} `);
|
|
352
354
|
}), adding !== null
|
|
353
355
|
? h(Box, { flexDirection: 'column' }, h(Box, null, h(Text, { color: theme.dim }, ' team '), h(TextInput, { value: newTeam, onChange: setNewTeam, focus: adding === 'team', placeholder: 'ENG', onSubmit: () => setAdding('label') }), h(Text, { color: theme.dim }, ' label '), h(TextInput, { value: newLabel, onChange: setNewLabel, focus: adding === 'label', placeholder: 'vs-plan', onSubmit: commitTrigger })), addError ? h(Text, { color: theme.red }, ` ${addError}`) : null)
|
|
354
356
|
: null), h(Box, { flexShrink: 0, marginLeft: 2 }, h(Text, { color: theme.dim }, where === 'triggers' ? 'a add trigger · x remove' : ''))), h(Text, null, ' '),
|
|
@@ -4,10 +4,14 @@ import type { Screen } from '../screens.ts';
|
|
|
4
4
|
export declare function stepLabel(catalog: StepsCatalog | null, id: string): string;
|
|
5
5
|
export declare function stepName(catalog: StepsCatalog | null, id: string): string;
|
|
6
6
|
export interface TriggerLike {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
source?: string;
|
|
8
|
+
team?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
schedule?: string;
|
|
11
|
+
task?: string;
|
|
9
12
|
}
|
|
10
13
|
export declare const triggerText: (t: TriggerLike) => string;
|
|
14
|
+
export declare const triggerSpec: (t: TriggerLike) => string;
|
|
11
15
|
export declare const triggersText: (triggers: TriggerLike[]) => string;
|
|
12
16
|
export declare const sameTriggerLike: (a: TriggerLike, b: TriggerLike) => boolean;
|
|
13
17
|
export declare const stepsText: (catalog: StepsCatalog | null, steps: string[]) => string;
|
|
@@ -28,9 +28,11 @@ export function stepLabel(catalog, id) {
|
|
|
28
28
|
export function stepName(catalog, id) {
|
|
29
29
|
return catalog?.steps.find((s) => s.id === id)?.name ?? id.replace(/^vs-/, '');
|
|
30
30
|
}
|
|
31
|
-
export const triggerText = (t) => `${t.team} + ${t.label}`;
|
|
31
|
+
export const triggerText = (t) => t.source === 'cron' ? `cron ${t.schedule}` : `${t.source === 'voidtrack' ? 'VoidTrack ' : ''}${t.team} + ${t.label}`;
|
|
32
|
+
// The form `--trigger` takes.
|
|
33
|
+
export const triggerSpec = (t) => t.source === 'cron' ? `cron:${t.schedule}:${t.task}` : t.source === 'voidtrack' ? `voidtrack:${t.team}:${t.label}` : `${t.team}:${t.label}`;
|
|
32
34
|
export const triggersText = (triggers) => triggers.map(triggerText).join(', ');
|
|
33
|
-
export const sameTriggerLike = (a, b) => a
|
|
35
|
+
export const sameTriggerLike = (a, b) => triggerSpec(a) === triggerSpec(b);
|
|
34
36
|
export const stepsText = (catalog, steps) => steps.map((s) => stepLabel(catalog, s)).join(' → ');
|
|
35
37
|
// Two workflows that start on the same TEAM:LABEL: only the first in order
|
|
36
38
|
// starts the card. One entry per (loser, winner) pair.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidlabs.gg/voidshift",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "One CLI for the Void dev tools: keep your Mac awake, run agents in the background, shared skills and memory for Claude Code and Codex.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|