@brainervirus/workit-claude-code 6.0.0 → 7.0.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/.claude-plugin/plugin.json +1 -1
- package/README.md +8 -5
- package/bin/workit-hook.mjs +62 -4
- package/dist/workit-hook.js +69 -60
- package/dist/workit.js +58190 -57713
- package/hooks/hooks.json +12 -3
- package/package.json +3 -3
- package/skills/deslop/SKILL.md +1 -1
- package/skills/implement/SKILL.md +9 -4
- package/skills/review/SKILL.md +2 -0
- package/skills/shape/SKILL.md +1 -1
- package/skills/ship/SKILL.md +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workit",
|
|
3
3
|
"displayName": "Workit",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7.0.0",
|
|
5
5
|
"description": "Workflow rails for agentic coding: task context on every session, branch policy on shell commands, and the workit method skills",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "BrainerVirus"
|
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @brainervirus/workit-claude-code
|
|
2
2
|
|
|
3
3
|
[](https://github.com/BrainerVirus/workit/actions/workflows/ci.yml)
|
|
4
|
-
[](
|
|
4
|
+
[](https://github.com/BrainerVirus/workit/blob/main/LICENSE)
|
|
5
5
|
|
|
6
|
-
Workit plugin for Claude Code: task context on session start and per turn,
|
|
7
|
-
branch policy on `git` shell commands,
|
|
6
|
+
[Workit](https://github.com/BrainerVirus/workit) plugin for Claude Code: task context on session start and per turn,
|
|
7
|
+
branch policy on `git` shell commands, the before-write gate on edits and shell
|
|
8
|
+
writes, eleven method skills (`/workit:<name>`),
|
|
8
9
|
and `verifier`, `reviewer` and `implementer` agents.
|
|
9
10
|
|
|
10
11
|
## Install
|
|
@@ -36,11 +37,13 @@ export CLAUDE_CODE_PLUGIN_DIRS="$HOME/path/to/workit/packages/workit-claude-code
|
|
|
36
37
|
| Path | Purpose |
|
|
37
38
|
| --- | --- |
|
|
38
39
|
| `.claude-plugin/plugin.json` | Manifest (version synced at release) |
|
|
39
|
-
| `hooks/hooks.json` | SessionStart (startup/resume/clear/compact/fork), UserPromptSubmit, PreToolUse (Bash
|
|
40
|
-
| `bin/workit-hook.mjs` | Hook launcher: source with Bun in a checkout, `dist/workit-hook.js` when installed; fails open (`{}` + one stderr line) when neither can run |
|
|
40
|
+
| `hooks/hooks.json` | SessionStart (startup/resume/clear/compact/fork), UserPromptSubmit, PreToolUse (Bash, PowerShell, Edit/Write/MultiEdit/NotebookEdit), SubagentStart |
|
|
41
|
+
| `bin/workit-hook.mjs` | Hook launcher: source with Bun in a checkout, `dist/workit-hook.js` when installed; answers plain shell commands and edits in task-less checkouts with `{}` before loading the runtime; fails open (`{}` + one stderr line) when neither can run |
|
|
41
42
|
| `bin/workit` | `workit` on the Bash tool's PATH (same source/dist switch) |
|
|
42
43
|
| `agents/` | `verifier`, `reviewer` (read-only), `implementer` (`isolation: worktree`) |
|
|
43
44
|
| `skills/` | Generated by `scripts/build.ts` from `packages/workit-core/skills` (not committed) |
|
|
44
45
|
| `evals/` | Opt-in `claude plugin eval` suite (nightly / `eval` label, not a PR gate) |
|
|
45
46
|
|
|
46
47
|
Requires Node.js 24+ (installed plugin) or Bun (local pin).
|
|
48
|
+
|
|
49
|
+
Full guide: [Claude Code](https://github.com/BrainerVirus/workit/blob/main/docs/guides/claude-code.md).
|
package/bin/workit-hook.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// proceeds as if no Workit hook were installed (no context, no branch
|
|
13
13
|
// policy): a broken hook must never brick the host.
|
|
14
14
|
import { spawnSync } from "node:child_process";
|
|
15
|
-
import { existsSync } from "node:fs";
|
|
15
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
18
|
|
|
@@ -31,9 +31,67 @@ const failOpen = (reason) => {
|
|
|
31
31
|
process.stdout.write("{}\n");
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
// Every Bash/PowerShell call and every file edit reaches this hook (branch
|
|
35
|
+
// policy and the before-write gate). Two fast paths answer `{}` before the
|
|
36
|
+
// runtime loads: a shell command with no git, no redirect and no writing verb
|
|
37
|
+
// can need neither; and with no Workit task store for the checkout there is
|
|
38
|
+
// no task to gate a non-git edit on.
|
|
39
|
+
let payload = "";
|
|
40
|
+
for await (const chunk of process.stdin) payload += String(chunk);
|
|
41
|
+
const MAYBE_GATED =
|
|
42
|
+
/\bgit\b|>|\b(?:tee|touch|mkdir|rm|rmdir|mv|cp|truncate|install|ln|patch|dd|sed|perl|set-content|add-content|out-file|new-item|ni|remove-item|del|copy-item|move-item)\b/i;
|
|
43
|
+
const SHELLS = new Set(["Bash", "PowerShell"]);
|
|
44
|
+
const EDITS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
45
|
+
|
|
46
|
+
/** `<git-common-dir>/workit` (or `<dir>/.workit` outside git) holds tasks. */
|
|
47
|
+
const hasTaskStore = (cwd) => {
|
|
48
|
+
try {
|
|
49
|
+
for (let dir = path.resolve(cwd); ; dir = path.dirname(dir)) {
|
|
50
|
+
const dotGit = path.join(dir, ".git");
|
|
51
|
+
if (existsSync(dotGit)) {
|
|
52
|
+
let gitDir = dotGit;
|
|
53
|
+
if (statSync(dotGit).isFile()) {
|
|
54
|
+
const target = /^gitdir:\s*(.+)$/m.exec(readFileSync(dotGit, "utf8"))?.[1]?.trim();
|
|
55
|
+
if (!target) return true;
|
|
56
|
+
gitDir = path.resolve(dir, target);
|
|
57
|
+
const common = path.join(gitDir, "commondir");
|
|
58
|
+
if (existsSync(common))
|
|
59
|
+
gitDir = path.resolve(gitDir, readFileSync(common, "utf8").trim());
|
|
60
|
+
}
|
|
61
|
+
const store = path.join(gitDir, "workit");
|
|
62
|
+
return (
|
|
63
|
+
existsSync(path.join(store, "tasks")) || existsSync(path.join(store, "task-index.json"))
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (existsSync(path.join(dir, ".workit"))) return true;
|
|
67
|
+
if (path.dirname(dir) === dir) return false;
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const fastAllow = (() => {
|
|
75
|
+
try {
|
|
76
|
+
const value = JSON.parse(payload);
|
|
77
|
+
if (value?.hook_event_name !== "PreToolUse") return false;
|
|
78
|
+
const command = value?.tool_input?.command;
|
|
79
|
+
if (SHELLS.has(value.tool_name) && typeof command === "string") {
|
|
80
|
+
if (!MAYBE_GATED.test(command)) return true;
|
|
81
|
+
return !/\bgit\b/.test(command) && !hasTaskStore(String(value.cwd ?? "."));
|
|
82
|
+
}
|
|
83
|
+
return EDITS.has(value.tool_name) && !hasTaskStore(String(value.cwd ?? "."));
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
})();
|
|
88
|
+
|
|
89
|
+
if (fastAllow) {
|
|
90
|
+
process.stdout.write("{}\n");
|
|
91
|
+
} else if (fromSource) {
|
|
35
92
|
const run = spawnSync(process.env.WORKIT_BUN ?? "bun", [source], {
|
|
36
|
-
|
|
93
|
+
input: payload,
|
|
94
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
37
95
|
windowsHide: true,
|
|
38
96
|
});
|
|
39
97
|
if (run.error) failOpen(`bun is required for the local pin (${run.error.message})`);
|
|
@@ -45,7 +103,7 @@ if (fromSource) {
|
|
|
45
103
|
} catch (error) {
|
|
46
104
|
failOpen(`cannot load ${dist} (${error instanceof Error ? error.message : String(error)})`);
|
|
47
105
|
}
|
|
48
|
-
if (runClaudeHook) process.exitCode = await runClaudeHook(
|
|
106
|
+
if (runClaudeHook) process.exitCode = await runClaudeHook([payload], process.stdout);
|
|
49
107
|
} else {
|
|
50
108
|
failOpen(`${dist} is missing; run \`bun scripts/build.ts\` in ${root}`);
|
|
51
109
|
}
|