@brainervirus/workit-opencode 8.22.3 → 8.23.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.
|
@@ -20,14 +20,14 @@ units of ~100+ lines each. Coupled work stays with one owner. Workit never spawn
|
|
|
20
20
|
PR (`references/orchestration.md`).
|
|
21
21
|
2. **Record standing orders** (`workit ledger standing add "<order>"`): every
|
|
22
22
|
user directive all workers share. Directives decay across resumes.
|
|
23
|
-
3. **Brief each worker verbatim
|
|
24
|
-
|
|
23
|
+
3. **Brief each worker verbatim**: `workit fanout worktree create <slice>`
|
|
24
|
+
(every host), then `workit fanout brief <slice>` (WORKTREE, SCRATCH, rules).
|
|
25
25
|
Never hand-edit it; change the plan or the standing orders and render again.
|
|
26
26
|
4. **Spawn in a rolling window**, in the background, each in its own worktree:
|
|
27
27
|
keep 4-6 in flight and refill from `spawnable` in `workit fanout status` as
|
|
28
28
|
each one finishes. Model: the brief's `model:` line, else TIER
|
|
29
|
-
(`references/orchestration.md`). Claude Code: the `implementer` agent
|
|
30
|
-
|
|
29
|
+
(`references/orchestration.md`). Claude Code: the `implementer` agent, never
|
|
30
|
+
with `isolation: "worktree"`; Workit's hooks confine it to its WORKTREE.
|
|
31
31
|
5. **Judge liveness by side effects only:** `workit fanout status` (head age,
|
|
32
32
|
PR, CI, verdict, landed; STUCK past the TIMEBOX). Stop a stuck worker and
|
|
33
33
|
observe that it exited (a timeout is not proof). Removing a worktree drops
|
|
@@ -25,6 +25,7 @@ REPORT: branch, head SHA, files changed, each VERIFY command with its exit code,
|
|
|
25
25
|
each ACCEPTANCE line met / not met, rulings you made (`workit ledger ruling`),
|
|
26
26
|
anything out of scope as a follow-up, not a diff.
|
|
27
27
|
STANDING: <the standing orders, verbatim: `workit ledger standing add` records each one>
|
|
28
|
+
WORKTREE: <the path `workit fanout worktree create <slice>` made; the worker runs `workit --cwd <it> …` there>
|
|
28
29
|
<identity line, per the lead's host: see "Identity and git rules per host" below>
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -48,6 +49,7 @@ FORBIDDEN: no edits outside SCOPE; no schema migration; no new packages
|
|
|
48
49
|
FAN-IN: one PR per slice. Never rebase, retarget, merge or force-push: the lead owns topology.
|
|
49
50
|
REPORT: as in the template
|
|
50
51
|
STANDING: conventional commits; no comments that restate code; ask nothing, record rulings instead
|
|
52
|
+
WORKTREE: ../app-wt/usage-endpoint (made by `workit fanout worktree create usage-endpoint`; yours alone)
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
## Plan file
|
|
@@ -106,25 +108,29 @@ lead's host (`WORKIT_HOST`, or the host's own session variable):
|
|
|
106
108
|
|
|
107
109
|
| Lead's host | Identity line | RULES 1 and 3 |
|
|
108
110
|
| --- | --- | --- |
|
|
109
|
-
| Claude Code | `Session: your env already has WORKIT_SESSION_ID (the lead's id)`; no `export`, no hand-minted id (SubagentStart issues `<lead>:<agent id>` only to verifiers and reviewers, never to an implementer, so the worker's commits carry the lead's id) |
|
|
111
|
+
| Claude Code | `Session: your env already has WORKIT_SESSION_ID (the lead's id)`; no `export`, no hand-minted id (SubagentStart issues `<lead>:<agent id>` only to verifiers and reviewers, never to an implementer, so the worker's commits carry the lead's id) | `workit git branch <branch> --base <base>`, `workit git commit -m <msg> -- <paths in SCOPE>`: the implementer runs without Claude Code's worktree isolation, which refused every `workit git` form |
|
|
110
112
|
| OpenCode, Pi, Codex | `Session: your host already sets WORKIT_SESSION_ID in your shell`; export nothing (the host derives the id and an export cannot replace it) | `workit git branch <branch> --base <base>`, `workit git commit -m <msg> -- <paths in SCOPE>` |
|
|
111
113
|
| Cursor, CI, a plain terminal | `export WORKIT_SESSION_ID=<lead>-w-<slice>` (`+try<n>` for a race attempt): declared, not checked | the same `workit git` forms |
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
Once `workit fanout worktree create <slice>` made the worktree, the brief's
|
|
116
|
+
WORKTREE line names it and RULES 1 and 3 run against it on every host:
|
|
117
|
+
`workit --cwd <worktree> git commit …`, `workit --cwd <worktree> check <name>`,
|
|
118
|
+
one verb per call. The worktree is already on the branch (MODE new or resume),
|
|
119
|
+
so no branch command comes first. Without one, `MODE: resume` is
|
|
120
|
+
`git switch <branch>` (the branch exists), then continue from its head. A race
|
|
121
|
+
attempt (`--attempt <n>`) follows its host's row with the branch
|
|
122
|
+
`<branch>-try<n>`.
|
|
117
123
|
|
|
118
124
|
## Worker rules (`workit fanout brief` appends them as RULES)
|
|
119
125
|
|
|
120
|
-
1.
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
1. Work only in WORKTREE, already on the branch, one verb per call against it
|
|
127
|
+
(`workit --cwd <worktree> …`); Workit's hooks deny an implementer's change
|
|
128
|
+
outside it. With no worktree made yet: create the branch (`MODE: new`) or
|
|
129
|
+
`git switch` to it (`MODE: resume`), as the table above says.
|
|
123
130
|
2. Decide ambiguities yourself and record them:
|
|
124
131
|
`workit ledger ruling "<what>" --why "<why>" --cost-if-wrong "<cost>"`.
|
|
125
132
|
Stop only for an irreversible action, a security-sensitive one, or a side
|
|
126
133
|
effect outside the worktree.
|
|
127
|
-
3. Commit
|
|
128
|
-
|
|
129
|
-
so.
|
|
134
|
+
3. Commit with `workit --cwd <worktree> git commit -m "<msg>" -- <paths in SCOPE>`;
|
|
135
|
+
push only if the brief says so.
|
|
130
136
|
4. Never record a verdict on your own work.
|
|
@@ -35,8 +35,8 @@ parent is verified, appears there by itself.
|
|
|
35
35
|
|
|
36
36
|
A slice is retried when it is STUCK, its worker exits without meeting
|
|
37
37
|
ACCEPTANCE, or its verdict fails. Stop the worker and observe that it exited.
|
|
38
|
-
Release its worktree: `workit fanout worktree release <slice>` (
|
|
39
|
-
|
|
38
|
+
Release its worktree: `workit fanout worktree release <slice>` (it records
|
|
39
|
+
`git status` first), and create it again for the retry. Then spawn one fresh
|
|
40
40
|
worker with `workit fanout brief <slice> --mode resume`: same branch, and the
|
|
41
41
|
brief points at its head and its ledger rows (last report, verdicts,
|
|
42
42
|
rulings). If the retry fails too, escalate instead of a third worker:
|
|
@@ -69,9 +69,9 @@ list. The fixer applies that list once, then one focused recheck follows.
|
|
|
69
69
|
When a hard slice has an uncertain approach and a cheap VERIFY, run 2-3
|
|
70
70
|
attempts at once instead of retrying in series. `workit fanout brief <slice>
|
|
71
71
|
--attempt <n>` gives each attempt its own branch (`<branch>-try<n>`), session
|
|
72
|
-
and scratch dir. Each attempt needs its own worktree
|
|
73
|
-
`
|
|
74
|
-
|
|
72
|
+
and scratch dir. Each attempt needs its own worktree, and `fanout worktree
|
|
73
|
+
create` makes only the slice's own one, so run the attempts one after another
|
|
74
|
+
there on every host.
|
|
75
75
|
Verify every attempt, keep the one with the best verdict (accepted first,
|
|
76
76
|
then the fewest changed files, then the earliest), point the slice branch at
|
|
77
77
|
it (`git branch <branch> <winner>`), have the verifier record the verdict on
|
|
@@ -109,7 +109,7 @@ Which session id a verdict carries, per host:
|
|
|
109
109
|
`WORKIT_SESSION_ID=<lead>:verifier-<random hex>`, a fresh suffix per
|
|
110
110
|
verifier. Cursor cannot check it: it is declared, not derived.
|
|
111
111
|
- A worker's commits: on Claude Code the lead's `WORKIT_SESSION_ID` already in
|
|
112
|
-
its env (SubagentStart issues no implementer id;
|
|
112
|
+
its env (SubagentStart issues no implementer id; no export, so the
|
|
113
113
|
lead authored those commits: a verifier or reviewer records the verdict, not
|
|
114
114
|
the lead); on OpenCode, Pi and Codex the id the host already
|
|
115
115
|
puts in its shell; on Cursor, CI and a plain terminal the brief's
|
|
@@ -47,6 +47,8 @@ description: Build a requested change in small verified steps - follow local pat
|
|
|
47
47
|
`workit verify-delivery push`).
|
|
48
48
|
|
|
49
49
|
Independent slices that could run in parallel: fan them out (call the skill tool with `workit-fanout`).
|
|
50
|
+
One `implementer` slice: `workit fanout worktree create <slice>` before spawning,
|
|
51
|
+
then `workit fanout brief <slice>`; no host isolation (Workit's hooks confine it).
|
|
50
52
|
|
|
51
53
|
Stay inline by default (workspace `delegation: inline-first`). Hand work off
|
|
52
54
|
only past the thresholds: an explorer after about 3 tool calls or 10k tokens
|
package/dist/plugin.js
CHANGED
|
@@ -16219,6 +16219,24 @@ function workitInvocations(command, dialect = "posix", depth = 0) {
|
|
|
16219
16219
|
}
|
|
16220
16220
|
return found;
|
|
16221
16221
|
}
|
|
16222
|
+
var WORKIT_GLOBAL = /^--(?:cwd|session|token|as)(=|$)/;
|
|
16223
|
+
function skipWorkitGlobals(args) {
|
|
16224
|
+
let cwd = null;
|
|
16225
|
+
let at = 0;
|
|
16226
|
+
for (;at < args.length; at++) {
|
|
16227
|
+
const match = WORKIT_GLOBAL.exec(args[at]);
|
|
16228
|
+
if (match?.[1] === "=") {
|
|
16229
|
+
if (args[at].startsWith("--cwd="))
|
|
16230
|
+
cwd = args[at].slice(6);
|
|
16231
|
+
} else if (match && args[at + 1] !== undefined) {
|
|
16232
|
+
if (args[at] === "--cwd")
|
|
16233
|
+
cwd = args[at + 1];
|
|
16234
|
+
at++;
|
|
16235
|
+
} else if (args[at] !== "--json")
|
|
16236
|
+
break;
|
|
16237
|
+
}
|
|
16238
|
+
return { rest: args.slice(at), cwd };
|
|
16239
|
+
}
|
|
16222
16240
|
var PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
|
|
16223
16241
|
var CURRENT_BRANCH = /^\$\(\s*git\s+(?:branch\s+--show-current|rev-parse\s+--abbrev-ref\s+HEAD|symbolic-ref\s+--short\s+HEAD)\s*\)$/;
|
|
16224
16242
|
var pushDestination = (destination) => {
|
|
@@ -21349,7 +21367,7 @@ function heavyGate(cwd, command, options) {
|
|
|
21349
21367
|
}
|
|
21350
21368
|
}
|
|
21351
21369
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
21352
|
-
import { realpathSync as realpathSync6 } from "node:fs";
|
|
21370
|
+
import { existsSync as existsSync9, realpathSync as realpathSync6 } from "node:fs";
|
|
21353
21371
|
import os10 from "node:os";
|
|
21354
21372
|
import path31 from "node:path";
|
|
21355
21373
|
|
|
@@ -21578,7 +21596,7 @@ var exempt = (cwd, root, file, plans) => {
|
|
|
21578
21596
|
const segments = posix.split("/");
|
|
21579
21597
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
21580
21598
|
};
|
|
21581
|
-
var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
|
|
21599
|
+
var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs", "busybox"]);
|
|
21582
21600
|
var operands = (words) => words.filter((item) => !item.startsWith("-"));
|
|
21583
21601
|
var SCRIPT_SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
|
|
21584
21602
|
var wrappedScript = (input) => {
|
|
@@ -21590,9 +21608,9 @@ var wrappedScript = (input) => {
|
|
|
21590
21608
|
return null;
|
|
21591
21609
|
if ("script" in tail)
|
|
21592
21610
|
return tail.script;
|
|
21593
|
-
const
|
|
21594
|
-
if (SCRIPT_SHELLS.has((
|
|
21595
|
-
return script
|
|
21611
|
+
const script = shellScript2(tail.argv);
|
|
21612
|
+
if (SCRIPT_SHELLS.has((tail.argv[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()) && script)
|
|
21613
|
+
return script;
|
|
21596
21614
|
return tail.argv.map(quoteWord2).join(" ");
|
|
21597
21615
|
};
|
|
21598
21616
|
var editsOf = (input) => {
|
|
@@ -21671,6 +21689,94 @@ var editsOf = (input) => {
|
|
|
21671
21689
|
return [];
|
|
21672
21690
|
}
|
|
21673
21691
|
};
|
|
21692
|
+
var shellScript2 = (words) => {
|
|
21693
|
+
if (!SCRIPT_SHELLS.has((words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()))
|
|
21694
|
+
return null;
|
|
21695
|
+
for (let index = 1;index < words.length; index++) {
|
|
21696
|
+
const word = words[index];
|
|
21697
|
+
if (/^-[a-z]*c$/.test(word))
|
|
21698
|
+
return words[index + 1] ?? null;
|
|
21699
|
+
if (/^[-+][oO]$/.test(word))
|
|
21700
|
+
index++;
|
|
21701
|
+
else if (!/^[-+]/.test(word))
|
|
21702
|
+
return null;
|
|
21703
|
+
}
|
|
21704
|
+
return null;
|
|
21705
|
+
};
|
|
21706
|
+
var XARGS_VALUE = /^-[IinLPdsEa]$/;
|
|
21707
|
+
var runsWriter = (words) => {
|
|
21708
|
+
const filled = [...words.filter((word) => word !== "{}" && word !== ";" && word !== "+"), "x"];
|
|
21709
|
+
const edits = editsOf(filled);
|
|
21710
|
+
return edits === null || edits.length > 0 || opaqueWrites(filled) !== null;
|
|
21711
|
+
};
|
|
21712
|
+
var opaqueWrites = (input) => {
|
|
21713
|
+
let words = input;
|
|
21714
|
+
while (words.length && (PREFIXES2.has(words[0]) || /^\w+=/.test(words[0]))) {
|
|
21715
|
+
if (words[0] === "xargs") {
|
|
21716
|
+
let at = 1;
|
|
21717
|
+
while (words[at]?.startsWith("-"))
|
|
21718
|
+
at += XARGS_VALUE.test(words[at]) ? 2 : 1;
|
|
21719
|
+
return runsWriter(words.slice(at)) ? ["."] : null;
|
|
21720
|
+
}
|
|
21721
|
+
words = words.slice(1);
|
|
21722
|
+
}
|
|
21723
|
+
const [verb, ...args] = words;
|
|
21724
|
+
const name = (verb?.split(/[\\/]/).at(-1) ?? "").toLowerCase();
|
|
21725
|
+
const files = operands(args);
|
|
21726
|
+
const has = (pattern) => args.some((arg) => pattern.test(arg));
|
|
21727
|
+
const listed = (named) => named.length ? named : ["."];
|
|
21728
|
+
if (name === "unlink" || name === "shred")
|
|
21729
|
+
return listed(files);
|
|
21730
|
+
if (/^(?:chmod|chown|chgrp|chattr)$/.test(name))
|
|
21731
|
+
return listed(has(/^--reference/) ? files : files.slice(1));
|
|
21732
|
+
if (name === "rsync") {
|
|
21733
|
+
const dest = files.at(-1);
|
|
21734
|
+
const remote = /^[\w.@-]*:/.test(dest ?? "") && !/^[A-Za-z]:[\\/]/.test(dest ?? "");
|
|
21735
|
+
return dest === undefined ? ["."] : remote ? [] : [dest];
|
|
21736
|
+
}
|
|
21737
|
+
if (name === "find") {
|
|
21738
|
+
const exec = args.findIndex((arg) => /^-(?:exec|execdir|ok|okdir)$/.test(arg));
|
|
21739
|
+
const writes = has(/^-(?:delete|fprint\w*|fls)$/) || exec >= 0 && runsWriter(args.slice(exec + 1));
|
|
21740
|
+
const end = args.findIndex((arg) => /^[-(!]/.test(arg));
|
|
21741
|
+
return writes ? listed(end < 0 ? args : args.slice(0, end)) : null;
|
|
21742
|
+
}
|
|
21743
|
+
if (/^g?awk$/.test(name)) {
|
|
21744
|
+
if (!has(/^-i|^--include/))
|
|
21745
|
+
return null;
|
|
21746
|
+
const named = [];
|
|
21747
|
+
let program = !has(/^-f$|^--file/);
|
|
21748
|
+
for (let index = 0;index < args.length; index++)
|
|
21749
|
+
if (/^(?:-[ifvF]|--(?:include|file|assign|field-separator))$/.test(args[index]))
|
|
21750
|
+
index++;
|
|
21751
|
+
else if (args[index].startsWith("-"))
|
|
21752
|
+
continue;
|
|
21753
|
+
else if (program)
|
|
21754
|
+
program = false;
|
|
21755
|
+
else
|
|
21756
|
+
named.push(args[index]);
|
|
21757
|
+
return listed(named);
|
|
21758
|
+
}
|
|
21759
|
+
if (name === "perl")
|
|
21760
|
+
return has(/^-[a-zA-Z]*[eE]/) ? ["."] : null;
|
|
21761
|
+
if (/^(?:python[\d.]*|node|bun|deno|ruby|php)$/.test(name))
|
|
21762
|
+
return has(/^-[a-zA-Z]*[ce]$|^--eval$|^-p$/) ? ["."] : null;
|
|
21763
|
+
return shellScript2(words) === null ? null : ["."];
|
|
21764
|
+
};
|
|
21765
|
+
var linkSources = (args, at) => {
|
|
21766
|
+
const names = operands([...args]);
|
|
21767
|
+
const into = args.indexOf("-t");
|
|
21768
|
+
const dest = into >= 0 ? args[into + 1] : names.length > 1 ? names.at(-1) : ".";
|
|
21769
|
+
const sources = names.filter((name, index) => into >= 0 ? name !== dest : index < names.length - 1 || names.length === 1);
|
|
21770
|
+
const target = dest === undefined ? null : at(dest);
|
|
21771
|
+
const symbolic = args.some((arg) => /^-[a-zA-Z]*s|^--symbolic$/.test(arg));
|
|
21772
|
+
const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync9(target) || /[\\/]$/.test(dest ?? "") ? target : path31.dirname(target);
|
|
21773
|
+
return sources.flatMap((source) => {
|
|
21774
|
+
if (symbolic && base !== null && !path31.isAbsolute(homeExpanded(source)))
|
|
21775
|
+
return [path31.resolve(base, source)];
|
|
21776
|
+
const resolved = at(source);
|
|
21777
|
+
return resolved ? [resolved] : [];
|
|
21778
|
+
});
|
|
21779
|
+
};
|
|
21674
21780
|
var shellWrites = (command, depth = 0) => {
|
|
21675
21781
|
const targets = [];
|
|
21676
21782
|
let unknown = false;
|
|
@@ -21780,11 +21886,15 @@ var gitMutationDirs = (cwd, command, dialect) => {
|
|
|
21780
21886
|
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
21781
21887
|
var PUSHD2 = new Set(["pushd", "push-location"]);
|
|
21782
21888
|
var POPD2 = new Set(["popd", "pop-location"]);
|
|
21783
|
-
var
|
|
21889
|
+
var UNKNOWN_DIR = path31.resolve(path31.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
21890
|
+
var cdInto = (dir, words, strict = false) => {
|
|
21891
|
+
const lost = strict ? UNKNOWN_DIR : undefined;
|
|
21784
21892
|
const named = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
|
|
21785
21893
|
const target = named === undefined ? undefined : homeExpanded(named);
|
|
21786
|
-
if (
|
|
21787
|
-
return;
|
|
21894
|
+
if (target === "-" || target && /^~|[$`*?]/.test(target))
|
|
21895
|
+
return lost;
|
|
21896
|
+
if (dir === undefined)
|
|
21897
|
+
return lost;
|
|
21788
21898
|
return target === undefined ? os10.homedir() : path31.resolve(dir, target);
|
|
21789
21899
|
};
|
|
21790
21900
|
var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
|
|
@@ -21792,7 +21902,7 @@ var homeExpanded = (file) => {
|
|
|
21792
21902
|
const match = /^(?:~|\$HOME|\$\{HOME\})(?=\/|$)/.exec(file);
|
|
21793
21903
|
return match ? (process.env.HOME || os10.homedir()) + file.slice(match[0].length) : file;
|
|
21794
21904
|
};
|
|
21795
|
-
var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
21905
|
+
var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
21796
21906
|
const targets = [];
|
|
21797
21907
|
let dir = cwd;
|
|
21798
21908
|
let stack = [];
|
|
@@ -21816,21 +21926,35 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
|
21816
21926
|
const words = lead < 0 ? [] : segment.words.slice(lead);
|
|
21817
21927
|
const name = (words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase();
|
|
21818
21928
|
if (CD2.has(name)) {
|
|
21819
|
-
dir = cdInto(dir, words);
|
|
21929
|
+
dir = cdInto(dir, words, strict);
|
|
21820
21930
|
continue;
|
|
21821
21931
|
}
|
|
21822
21932
|
if (PUSHD2.has(name)) {
|
|
21823
21933
|
stack.push(dir);
|
|
21824
|
-
dir = cdInto(dir, words);
|
|
21934
|
+
dir = cdInto(dir, words, strict);
|
|
21825
21935
|
continue;
|
|
21826
21936
|
}
|
|
21827
21937
|
if (POPD2.has(name)) {
|
|
21828
|
-
dir = stack.length ? stack.pop() : undefined;
|
|
21938
|
+
dir = stack.length ? stack.pop() : strict ? UNKNOWN_DIR : undefined;
|
|
21829
21939
|
continue;
|
|
21830
21940
|
}
|
|
21831
|
-
const inner = depth < 4 ? wrappedScript(words) : null;
|
|
21941
|
+
const inner = depth < 4 ? wrappedScript(words) ?? (strict ? shellScript2(words) : null) : null;
|
|
21832
21942
|
if (inner !== null && dir !== undefined)
|
|
21833
|
-
targets.push(...segmentTargets(dir, inner, "posix", depth + 1));
|
|
21943
|
+
targets.push(...segmentTargets(dir, inner, "posix", depth + 1, strict));
|
|
21944
|
+
if (strict && dir !== undefined) {
|
|
21945
|
+
const runIn = dir;
|
|
21946
|
+
for (const sub of depth < 4 ? segment.subs ?? [] : [])
|
|
21947
|
+
targets.push(...segmentTargets(runIn, sub, dialect, depth + 1, true));
|
|
21948
|
+
const opaque = segment.unanalyzable ? ["."] : inner === null ? opaqueWrites(words) : null;
|
|
21949
|
+
for (const file of opaque ?? []) {
|
|
21950
|
+
const resolved = at(file);
|
|
21951
|
+
if (resolved)
|
|
21952
|
+
targets.push(file === "." ? path31.join(resolved, DIR_TARGET) : resolved);
|
|
21953
|
+
}
|
|
21954
|
+
const ln = words.findIndex((word) => /^ln$/i.test(word.split(/[\\/]/).at(-1) ?? ""));
|
|
21955
|
+
if (ln >= 0 && words.slice(0, ln).every((word) => PREFIXES2.has(word)))
|
|
21956
|
+
targets.push(...linkSources(words.slice(ln + 1), at));
|
|
21957
|
+
}
|
|
21834
21958
|
for (const file of segment.redirects)
|
|
21835
21959
|
if (!/^\/dev\/(?:null|stdout|stderr|tty)$/.test(file)) {
|
|
21836
21960
|
const resolved = at(file);
|
|
@@ -21847,11 +21971,29 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
|
21847
21971
|
if (resolved)
|
|
21848
21972
|
targets.push(resolved);
|
|
21849
21973
|
}
|
|
21850
|
-
if (dir !== undefined
|
|
21851
|
-
|
|
21974
|
+
if (dir !== undefined)
|
|
21975
|
+
for (const invocation of workitInvocations(segment.words.map(quoteWord2).join(" "), "posix")) {
|
|
21976
|
+
const { at: runsIn, args } = workitCwd(dir, invocation);
|
|
21977
|
+
if (args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), ""))
|
|
21978
|
+
targets.push(path31.join(runsIn, DIR_TARGET));
|
|
21979
|
+
}
|
|
21852
21980
|
}
|
|
21853
21981
|
return targets;
|
|
21854
21982
|
};
|
|
21983
|
+
var workitCwd = (dir, args) => {
|
|
21984
|
+
const { rest, cwd } = skipWorkitGlobals(args);
|
|
21985
|
+
return { at: cwd === null ? dir : path31.resolve(dir, homeExpanded(cwd)), args: rest };
|
|
21986
|
+
};
|
|
21987
|
+
var shellMutationTargets = (cwd, command, dialect = "posix", strict = false) => {
|
|
21988
|
+
try {
|
|
21989
|
+
return [
|
|
21990
|
+
...segmentTargets(cwd, command, dialect, 0, strict),
|
|
21991
|
+
...gitMutationDirs(cwd, command, dialect).map((dir) => path31.join(dir, DIR_TARGET))
|
|
21992
|
+
];
|
|
21993
|
+
} catch {
|
|
21994
|
+
return [];
|
|
21995
|
+
}
|
|
21996
|
+
};
|
|
21855
21997
|
var overridden = (command, dialect) => {
|
|
21856
21998
|
const segments = segmentsOf(command, dialect);
|
|
21857
21999
|
if (segments.length !== 1 || segments[0].group || segments[0].subs?.length)
|
|
@@ -21957,16 +22099,8 @@ function shellGate(cwd, command, owner, dialect = "posix", deps) {
|
|
|
21957
22099
|
} catch {}
|
|
21958
22100
|
const writes = shellWrites(command);
|
|
21959
22101
|
let targets = [];
|
|
21960
|
-
if (owner)
|
|
21961
|
-
|
|
21962
|
-
targets = [
|
|
21963
|
-
...segmentTargets(cwd, command, dialect),
|
|
21964
|
-
...gitMutationDirs(cwd, command, dialect).map((dir) => path31.join(dir, DIR_TARGET))
|
|
21965
|
-
];
|
|
21966
|
-
} catch {
|
|
21967
|
-
targets = [];
|
|
21968
|
-
}
|
|
21969
|
-
}
|
|
22102
|
+
if (owner)
|
|
22103
|
+
targets = shellMutationTargets(cwd, command, dialect);
|
|
21970
22104
|
if (owner && targets.length) {
|
|
21971
22105
|
const live = liveGate(owner, targets, deps);
|
|
21972
22106
|
if (live.kind !== "none") {
|
|
@@ -22544,6 +22678,19 @@ var standingSinceStart = (input) => {
|
|
|
22544
22678
|
// packages/workit-core/src/hooks/cwd-normalize.ts
|
|
22545
22679
|
var FILTERS = new Set(["tail", "head", "grep"]);
|
|
22546
22680
|
|
|
22681
|
+
// packages/workit-core/src/hooks/worktree-confine.ts
|
|
22682
|
+
var CASE_INSENSITIVE2 = process.platform === "darwin" || process.platform === "win32";
|
|
22683
|
+
var MUTATING_REMOTE = new Set([
|
|
22684
|
+
"add",
|
|
22685
|
+
"remove",
|
|
22686
|
+
"rm",
|
|
22687
|
+
"rename",
|
|
22688
|
+
"set-url",
|
|
22689
|
+
"set-head",
|
|
22690
|
+
"set-branches",
|
|
22691
|
+
"prune"
|
|
22692
|
+
]);
|
|
22693
|
+
|
|
22547
22694
|
// packages/workit-core/src/hooks/handle.ts
|
|
22548
22695
|
var offered = new Set;
|
|
22549
22696
|
var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
|
|
@@ -22652,7 +22799,7 @@ var OPENCODE_DESCRIPTOR = {
|
|
|
22652
22799
|
import path37 from "node:path";
|
|
22653
22800
|
|
|
22654
22801
|
// packages/workit-core/src/core/gitignore.ts
|
|
22655
|
-
import { existsSync as
|
|
22802
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22656
22803
|
import path33 from "node:path";
|
|
22657
22804
|
var GITIGNORE_ENTRIES = [
|
|
22658
22805
|
"# workit: SDD working state (never commit)",
|
|
@@ -22674,7 +22821,7 @@ var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
22674
22821
|
if (!confirmed)
|
|
22675
22822
|
return { ok: false, error: "confirmed: true required" };
|
|
22676
22823
|
const file = path33.join(workspaceRoot, ".gitignore");
|
|
22677
|
-
const existing =
|
|
22824
|
+
const existing = existsSync10(file) ? readFileSync6(file, "utf8") : "";
|
|
22678
22825
|
const existingLines = new Set(existing.split(`
|
|
22679
22826
|
`).map((l) => l.trim()).filter(Boolean));
|
|
22680
22827
|
const added = [];
|
|
@@ -22693,19 +22840,19 @@ var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
22693
22840
|
` : "") + append.join(`
|
|
22694
22841
|
`) + `
|
|
22695
22842
|
`, "utf8");
|
|
22696
|
-
} else if (!
|
|
22843
|
+
} else if (!existsSync10(file)) {
|
|
22697
22844
|
writeFileSync4(file, "", "utf8");
|
|
22698
22845
|
}
|
|
22699
22846
|
return { ok: true, path: file, added };
|
|
22700
22847
|
};
|
|
22701
22848
|
|
|
22702
22849
|
// packages/workit-core/src/core/hygiene.ts
|
|
22703
|
-
import { existsSync as
|
|
22850
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22704
22851
|
import path34 from "node:path";
|
|
22705
22852
|
var repoRoot3 = assetRoot();
|
|
22706
22853
|
var templatesDir = () => path34.join(repoRoot3, "templates", "hygiene");
|
|
22707
22854
|
var packageJson = (root) => {
|
|
22708
|
-
if (!
|
|
22855
|
+
if (!existsSync11(path34.join(root, "package.json")))
|
|
22709
22856
|
return null;
|
|
22710
22857
|
try {
|
|
22711
22858
|
return JSON.parse(readFileSync7(path34.join(root, "package.json"), "utf8"));
|
|
@@ -22714,7 +22861,7 @@ var packageJson = (root) => {
|
|
|
22714
22861
|
}
|
|
22715
22862
|
};
|
|
22716
22863
|
var isOpenSource = (root) => {
|
|
22717
|
-
if (
|
|
22864
|
+
if (existsSync11(path34.join(root, "LICENSE")))
|
|
22718
22865
|
return true;
|
|
22719
22866
|
const pkg = packageJson(root);
|
|
22720
22867
|
if (pkg && !pkg.private)
|
|
@@ -22742,10 +22889,10 @@ var planHygieneFiles = (root, opts = {}) => {
|
|
|
22742
22889
|
files.push("LICENSE", "CONTRIBUTING.md");
|
|
22743
22890
|
const planned = [];
|
|
22744
22891
|
for (const file of files) {
|
|
22745
|
-
if (
|
|
22892
|
+
if (existsSync11(path34.join(root, file)))
|
|
22746
22893
|
continue;
|
|
22747
22894
|
const tpl = path34.join(templatesDir(), file);
|
|
22748
|
-
if (!
|
|
22895
|
+
if (!existsSync11(tpl))
|
|
22749
22896
|
continue;
|
|
22750
22897
|
const content = readFileSync7(tpl, "utf8").replace(/<PROJECT>/g, path34.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
22751
22898
|
planned.push({ path: path34.join(root, file), content });
|
|
@@ -23290,7 +23437,7 @@ import path41 from "node:path";
|
|
|
23290
23437
|
|
|
23291
23438
|
// packages/workit-core/src/git/ops.ts
|
|
23292
23439
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
23293
|
-
import { existsSync as
|
|
23440
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
|
|
23294
23441
|
import path40 from "node:path";
|
|
23295
23442
|
|
|
23296
23443
|
// packages/workit-core/src/forge/redact.ts
|
|
@@ -23339,11 +23486,11 @@ function operationInProgress(cwd) {
|
|
|
23339
23486
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
23340
23487
|
for (const [index, [, operation]] of markers.entries()) {
|
|
23341
23488
|
const marker = found[index];
|
|
23342
|
-
if (!marker || !
|
|
23489
|
+
if (!marker || !existsSync12(marker))
|
|
23343
23490
|
continue;
|
|
23344
|
-
if (index === 1 &&
|
|
23491
|
+
if (index === 1 && existsSync12(path40.join(marker, "applying")))
|
|
23345
23492
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
23346
|
-
if (index === 0 &&
|
|
23493
|
+
if (index === 0 && existsSync12(path40.join(marker, "amend")) && !conflicted()) {
|
|
23347
23494
|
let headName = "";
|
|
23348
23495
|
try {
|
|
23349
23496
|
headName = readFileSync9(path40.join(marker, "head-name"), "utf8").trim();
|
|
@@ -24638,11 +24785,11 @@ var createStopControl = (root, port) => {
|
|
|
24638
24785
|
};
|
|
24639
24786
|
|
|
24640
24787
|
// packages/workit-opencode/src/v2/registry.ts
|
|
24641
|
-
import { existsSync as
|
|
24788
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10 } from "node:fs";
|
|
24642
24789
|
import path45 from "node:path";
|
|
24643
24790
|
|
|
24644
24791
|
// packages/workit-opencode/src/shared/assets.ts
|
|
24645
|
-
import { existsSync as
|
|
24792
|
+
import { existsSync as existsSync13, realpathSync as realpathSync9 } from "node:fs";
|
|
24646
24793
|
import path44 from "node:path";
|
|
24647
24794
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24648
24795
|
var moduleDir = () => {
|
|
@@ -24659,7 +24806,7 @@ var packageRoot2 = () => {
|
|
|
24659
24806
|
path44.resolve(dir, "..", ".."),
|
|
24660
24807
|
path44.resolve(dir, "..", "..", "..")
|
|
24661
24808
|
]) {
|
|
24662
|
-
if (
|
|
24809
|
+
if (existsSync13(path44.join(candidate, "package.json")))
|
|
24663
24810
|
return candidate;
|
|
24664
24811
|
}
|
|
24665
24812
|
return path44.resolve(dir, "..");
|
|
@@ -24667,7 +24814,7 @@ var packageRoot2 = () => {
|
|
|
24667
24814
|
var skillsRoot = () => {
|
|
24668
24815
|
const root = packageRoot2();
|
|
24669
24816
|
const canonical = path44.resolve(root, "..", "workit-core", "skills");
|
|
24670
|
-
if (
|
|
24817
|
+
if (existsSync13(path44.join(root, "src")) && existsSync13(canonical))
|
|
24671
24818
|
return canonical;
|
|
24672
24819
|
return path44.join(root, "assets", "skills");
|
|
24673
24820
|
};
|
|
@@ -24693,7 +24840,7 @@ var parseFrontmatter = (markdown) => {
|
|
|
24693
24840
|
};
|
|
24694
24841
|
var registerSkills = async (ctx) => {
|
|
24695
24842
|
const skillsDir = skillsRoot();
|
|
24696
|
-
if (!
|
|
24843
|
+
if (!existsSync14(skillsDir))
|
|
24697
24844
|
return new Set;
|
|
24698
24845
|
const listed = await ctx.skill.list().catch(() => ({ data: [] }));
|
|
24699
24846
|
const own = (skill) => typeof skill.path === "string" && path45.resolve(skill.path).startsWith(skillsDir + path45.sep);
|
|
@@ -24701,7 +24848,7 @@ var registerSkills = async (ctx) => {
|
|
|
24701
24848
|
const packaged = new Map;
|
|
24702
24849
|
for (const id of WORKIT_METHOD_SKILLS) {
|
|
24703
24850
|
const file = path45.join(skillsDir, id, "SKILL.md");
|
|
24704
|
-
if (!userSkills.has(id) &&
|
|
24851
|
+
if (!userSkills.has(id) && existsSync14(file))
|
|
24705
24852
|
packaged.set(id, file);
|
|
24706
24853
|
}
|
|
24707
24854
|
await ctx.skill.transform((editor) => {
|
|
@@ -24747,11 +24894,11 @@ var registerCommands = async (ctx, registeredSkills) => {
|
|
|
24747
24894
|
};
|
|
24748
24895
|
|
|
24749
24896
|
// packages/workit-opencode/src/stale-sources.ts
|
|
24750
|
-
import { existsSync as
|
|
24897
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6 } from "node:fs";
|
|
24751
24898
|
import path46 from "node:path";
|
|
24752
24899
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
24753
24900
|
var typescriptFiles = (directory) => {
|
|
24754
|
-
if (!
|
|
24901
|
+
if (!existsSync15(directory))
|
|
24755
24902
|
return [];
|
|
24756
24903
|
return readdirSync6(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
24757
24904
|
const file = path46.join(directory, entry.name);
|
|
@@ -24765,7 +24912,7 @@ var pluginSourceFiles = [
|
|
|
24765
24912
|
path46.join(packageRoot2(), "..", "workit-core", "src", "core.ts"),
|
|
24766
24913
|
...typescriptFiles(path46.join(packageRoot2(), "..", "workit-core", "src", "core"))
|
|
24767
24914
|
])
|
|
24768
|
-
].filter((file) =>
|
|
24915
|
+
].filter((file) => existsSync15(file)).toSorted();
|
|
24769
24916
|
|
|
24770
24917
|
// packages/workit-opencode/src/v2/plugin.ts
|
|
24771
24918
|
var sessionFacts = async (ctx, sessionID) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-opencode",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.23.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit OpenCode plugin — native tools, adaptive policy, and sixteen method skills",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typecheck": "tsc --noEmit"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@brainervirus/workit-core": "^8.
|
|
42
|
+
"@brainervirus/workit-core": "^8.23.0",
|
|
43
43
|
"@opencode/plugin": "2.0.18"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|