@workit-dev/claude-code 0.0.1 → 1.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.
Files changed (54) hide show
  1. package/.claude-plugin/plugin.json +19 -0
  2. package/README.md +35 -31
  3. package/agents/implementer.md +56 -0
  4. package/agents/reviewer.md +33 -0
  5. package/agents/verifier.md +40 -0
  6. package/assets/templates/headers.md +3 -0
  7. package/assets/templates/hygiene/.editorconfig +8 -0
  8. package/assets/templates/hygiene/.gitattributes +3 -0
  9. package/assets/templates/hygiene/CHANGELOG.md +14 -0
  10. package/assets/templates/hygiene/CONTRIBUTING.md +3 -0
  11. package/assets/templates/hygiene/LICENSE +21 -0
  12. package/assets/templates/hygiene/README.md +3 -0
  13. package/assets/templates/issue-update.md +5 -0
  14. package/assets/templates/plan-template.md +26 -0
  15. package/assets/templates/spec-template.md +64 -0
  16. package/assets/templates/workit-contract.md +13 -0
  17. package/bin/node-resolve.mjs +249 -0
  18. package/bin/workit +82 -0
  19. package/bin/workit-hook.mjs +552 -0
  20. package/bin/workit-paths.mjs +242 -0
  21. package/dist/workit-hook.js +248 -0
  22. package/dist/workit.js +122606 -0
  23. package/hooks/hooks.json +147 -0
  24. package/package.json +45 -6
  25. package/skills/architecture/SKILL.md +72 -0
  26. package/skills/architecture/agents/openai.yaml +3 -0
  27. package/skills/architecture/references/instruction-files.md +52 -0
  28. package/skills/architecture/references/vocabulary.md +53 -0
  29. package/skills/bdd/SKILL.md +53 -0
  30. package/skills/continue/SKILL.md +54 -0
  31. package/skills/debug/SKILL.md +45 -0
  32. package/skills/deslop/SKILL.md +58 -0
  33. package/skills/fanout/SKILL.md +71 -0
  34. package/skills/fanout/references/brief.md +141 -0
  35. package/skills/fanout/references/orchestration.md +169 -0
  36. package/skills/implement/SKILL.md +71 -0
  37. package/skills/retro/SKILL.md +72 -0
  38. package/skills/retro/agents/openai.yaml +3 -0
  39. package/skills/retro/references/sources.md +35 -0
  40. package/skills/retro/references/steering.md +39 -0
  41. package/skills/review/SKILL.md +66 -0
  42. package/skills/review/references/impact.md +24 -0
  43. package/skills/shape/SKILL.md +71 -0
  44. package/skills/shape/references/diagrams.md +17 -0
  45. package/skills/shape/references/knowledge.md +61 -0
  46. package/skills/shape/references/mockups.md +15 -0
  47. package/skills/shape/references/slicing.md +44 -0
  48. package/skills/ship/SKILL.md +71 -0
  49. package/skills/ship/references/changelog.md +44 -0
  50. package/skills/ship/references/pr-body.md +32 -0
  51. package/skills/ship/references/release.md +39 -0
  52. package/skills/test-audit/SKILL.md +54 -0
  53. package/skills/verify-app/SKILL.md +68 -0
  54. package/skills/verify-app/references/template.md +51 -0
@@ -0,0 +1,242 @@
1
+ // The one resolver for every Workit file location (docs/agents/file-locations.md).
2
+ // Kinds: config, state, data, cache and runtime. Linux and macOS follow the
3
+ // XDG Base Directory spec; Windows uses %APPDATA% (config, roaming) and
4
+ // %LOCALAPPDATA% (state, data, cache). An absolute XDG_*_HOME wins on every
5
+ // platform; a relative one is ignored, as the spec says.
6
+ //
7
+ // Plain JavaScript with node: builtins only and no syntax newer than Node 16:
8
+ // TypeScript imports it, and the hook launchers carry a byte-equal copy
9
+ // (claude-code bin/, codex bin/, cursor hooks/; a test holds them equal). The
10
+ // POSIX shell launchers embed the *_SH functions below verbatim, and a test
11
+ // runs them against the JavaScript for the same environment.
12
+ // Side-effect free on import; only migrateLegacyDirs touches the disk.
13
+ import { existsSync, lstatSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
14
+ import os from "node:os";
15
+ import path from "node:path";
16
+
17
+ /** Every location kind the resolver knows. */
18
+ export const WORKIT_DIR_KINDS = ["config", "state", "data", "cache", "runtime"];
19
+
20
+ /** Environment overrides per kind, first non-empty wins; each names the directory itself. */
21
+ export const WORKIT_DIR_OVERRIDES = {
22
+ config: ["WORKIT_CONFIG", "WORKIT_CONFIG_DIR"],
23
+ state: ["WORKIT_STATE_DIR"],
24
+ data: [],
25
+ cache: [],
26
+ runtime: [],
27
+ };
28
+
29
+ /** The XDG base variable each kind follows (`<base>/workit`). */
30
+ export const WORKIT_DIR_XDG = {
31
+ config: "XDG_CONFIG_HOME",
32
+ state: "XDG_STATE_HOME",
33
+ data: "XDG_DATA_HOME",
34
+ cache: "XDG_CACHE_HOME",
35
+ runtime: "XDG_RUNTIME_DIR",
36
+ };
37
+
38
+ /** The XDG defaults under $HOME when the base variable is unset. */
39
+ const XDG_DEFAULTS = {
40
+ config: [".config"],
41
+ state: [".local", "state"],
42
+ data: [".local", "share"],
43
+ cache: [".cache"],
44
+ };
45
+
46
+ /**
47
+ * The user's home: $HOME, else %USERPROFILE%, else the OS record.
48
+ * @param {NodeJS.ProcessEnv} env
49
+ */
50
+ export const userHome = (env) => env.HOME || env.USERPROFILE || os.homedir();
51
+
52
+ /**
53
+ * The kind's XDG base when set to an absolute path (the spec ignores a relative one).
54
+ * @param {string} kind @param {NodeJS.ProcessEnv} env
55
+ */
56
+ const xdgBase = (kind, env) => {
57
+ const base = env[WORKIT_DIR_XDG[kind]];
58
+ return base && path.isAbsolute(base) ? base : "";
59
+ };
60
+
61
+ /**
62
+ * Where one kind of Workit file lives.
63
+ * @param {"config" | "state" | "data" | "cache" | "runtime"} kind
64
+ * @param {NodeJS.ProcessEnv} [env]
65
+ * @param {string} [platform]
66
+ * @returns {string}
67
+ */
68
+ export const workitDir = (kind, env = process.env, platform = process.platform) => {
69
+ for (const name of WORKIT_DIR_OVERRIDES[kind]) if (env[name]) return String(env[name]);
70
+ const base = xdgBase(kind, env);
71
+ if (base) return path.join(base, "workit");
72
+ if (kind === "runtime") {
73
+ if (platform === "win32") return path.join(env.TEMP || env.TMP || os.tmpdir(), "workit");
74
+ const uid = typeof process.getuid === "function" ? process.getuid() : os.userInfo().username;
75
+ return path.join(env.TMPDIR || os.tmpdir(), `workit-${uid}`);
76
+ }
77
+ const home = userHome(env);
78
+ if (platform !== "win32") return path.join(home, ...XDG_DEFAULTS[kind], "workit");
79
+ if (kind === "config")
80
+ return path.join(env.APPDATA || path.join(home, "AppData", "Roaming"), "workit");
81
+ const local = path.join(env.LOCALAPPDATA || path.join(home, "AppData", "Local"), "workit");
82
+ return kind === "cache" ? path.join(local, "cache") : local;
83
+ };
84
+
85
+ /** @param {NodeJS.ProcessEnv} [env] @param {string} [platform] */
86
+ export const configDir = (env, platform) => workitDir("config", env, platform);
87
+ /** @param {NodeJS.ProcessEnv} [env] @param {string} [platform] */
88
+ export const stateDir = (env, platform) => workitDir("state", env, platform);
89
+ /** @param {NodeJS.ProcessEnv} [env] @param {string} [platform] */
90
+ export const dataDir = (env, platform) => workitDir("data", env, platform);
91
+ /** @param {NodeJS.ProcessEnv} [env] @param {string} [platform] */
92
+ export const cacheDir = (env, platform) => workitDir("cache", env, platform);
93
+ /** @param {NodeJS.ProcessEnv} [env] @param {string} [platform] */
94
+ export const runtimeDir = (env, platform) => workitDir("runtime", env, platform);
95
+
96
+ /**
97
+ * Where Workit keeps the worktrees it manages: `<state>/worktrees/<repo>/<slug>`.
98
+ * State, not cache: a worktree holds uncommitted work.
99
+ * @param {NodeJS.ProcessEnv} [env] @param {string} [platform]
100
+ */
101
+ export const worktreesDir = (env, platform) => path.join(stateDir(env, platform), "worktrees");
102
+
103
+ /**
104
+ * The managed worktree root before it moved to worktreesDir:
105
+ * `$XDG_CACHE_HOME/workit-wt`, else `~/.cache/workit-wt` (on every platform).
106
+ * Never moved (a session may be using a worktree there); cleanup still sweeps it.
107
+ * @param {NodeJS.ProcessEnv} [env]
108
+ */
109
+ export const legacyWorktreesDir = (env = process.env) =>
110
+ path.join(xdgBase("cache", env) || path.join(userHome(env), ".cache"), "workit-wt");
111
+
112
+ /**
113
+ * The POSIX shell form of stateDir, embedded verbatim by the shell launchers
114
+ * (claude-code bin/workit, the owned launcher `workit upgrade` writes).
115
+ */
116
+ export const STATE_DIR_SH = `workit_state_dir() {
117
+ if [ -n "\${WORKIT_STATE_DIR:-}" ]; then printf '%s\\n' "$WORKIT_STATE_DIR"; return; fi
118
+ case "\${XDG_STATE_HOME:-}" in /*) printf '%s\\n' "$XDG_STATE_HOME/workit"; return ;; esac
119
+ case "$(uname -s 2>/dev/null)" in
120
+ MINGW*|MSYS*|CYGWIN*) printf '%s\\n' "\${LOCALAPPDATA:-$HOME/AppData/Local}/workit" ;;
121
+ *) printf '%s\\n' "$HOME/.local/state/workit" ;;
122
+ esac
123
+ }`;
124
+
125
+ /** The POSIX shell form of configDir, embedded verbatim by scripts/lib/config-dir.sh. */
126
+ export const CONFIG_DIR_SH = `workit_config_dir() {
127
+ if [ -n "\${WORKIT_CONFIG:-}" ]; then printf '%s\\n' "$WORKIT_CONFIG"; return; fi
128
+ if [ -n "\${WORKIT_CONFIG_DIR:-}" ]; then printf '%s\\n' "$WORKIT_CONFIG_DIR"; return; fi
129
+ case "\${XDG_CONFIG_HOME:-}" in /*) printf '%s\\n' "$XDG_CONFIG_HOME/workit"; return ;; esac
130
+ case "$(uname -s 2>/dev/null)" in
131
+ MINGW*|MSYS*|CYGWIN*) printf '%s\\n' "\${APPDATA:-$HOME/AppData/Roaming}/workit" ;;
132
+ *) printf '%s\\n' "$HOME/.config/workit" ;;
133
+ esac
134
+ }`;
135
+
136
+ /** The POSIX shell form of dataDir, embedded verbatim by scripts/lib/config-dir.sh. */
137
+ export const DATA_DIR_SH = `workit_data_dir() {
138
+ case "\${XDG_DATA_HOME:-}" in /*) printf '%s\\n' "$XDG_DATA_HOME/workit"; return ;; esac
139
+ case "$(uname -s 2>/dev/null)" in
140
+ MINGW*|MSYS*|CYGWIN*) printf '%s\\n' "\${LOCALAPPDATA:-$HOME/AppData/Local}/workit" ;;
141
+ *) printf '%s\\n' "$HOME/.local/share/workit" ;;
142
+ esac
143
+ }`;
144
+
145
+ /**
146
+ * The POSIX shell form of runtimeDir, embedded verbatim by scripts/lib/config-dir.sh.
147
+ * `os.tmpdir()` drops a trailing slash from TMPDIR; so does this.
148
+ */
149
+ export const RUNTIME_DIR_SH = `workit_runtime_dir() {
150
+ case "\${XDG_RUNTIME_DIR:-}" in /*) printf '%s\\n' "$XDG_RUNTIME_DIR/workit"; return ;; esac
151
+ case "$(uname -s 2>/dev/null)" in
152
+ MINGW*|MSYS*|CYGWIN*) printf '%s\\n' "\${TEMP:-\${TMP:-/tmp}}/workit" ;;
153
+ *) set -- "\${TMPDIR:-/tmp}"; printf '%s\\n' "\${1%/}/workit-$(id -u)" ;;
154
+ esac
155
+ }`;
156
+
157
+ /**
158
+ * Locations older Workit versions used, per kind, that migrateLegacyDirs moves
159
+ * to the resolver's default: macOS state lived in ~/Library/Application
160
+ * Support/workit, Windows config in ~\.config\workit. Only while the kind has
161
+ * no override or XDG variable (then the default is in use).
162
+ * @param {NodeJS.ProcessEnv} [env] @param {string} [platform]
163
+ * @returns {Array<{ kind: "config" | "state", legacy: string, target: string }>}
164
+ */
165
+ export const legacyDirs = (env = process.env, platform = process.platform) => {
166
+ const home = userHome(env);
167
+ /** @type {Array<{ kind: "config" | "state", legacy: string }>} */
168
+ const old = [];
169
+ if (platform === "darwin")
170
+ old.push({
171
+ kind: "state",
172
+ legacy: path.join(home, "Library", "Application Support", "workit"),
173
+ });
174
+ if (platform === "win32")
175
+ old.push({ kind: "config", legacy: path.join(home, ".config", "workit") });
176
+ return old
177
+ .filter(
178
+ (entry) =>
179
+ !WORKIT_DIR_OVERRIDES[entry.kind].some((name) => env[name]) && !xdgBase(entry.kind, env),
180
+ )
181
+ .map((entry) => ({
182
+ kind: entry.kind,
183
+ legacy: entry.legacy,
184
+ target: workitDir(entry.kind, env, platform),
185
+ }));
186
+ };
187
+
188
+ /** The marker a move leaves beside the old location: `<legacy>.moved-<stamp>`. */
189
+ export const LEGACY_MARKER_INFIX = ".moved-";
190
+
191
+ /**
192
+ * A real directory, never a symlink to one: a migration must not move a link
193
+ * the user made (the data behind it would stay where the link pointed).
194
+ * @param {string} file
195
+ */
196
+ export const isRealDir = (file) => {
197
+ try {
198
+ return lstatSync(file).isDirectory();
199
+ } catch {
200
+ return false;
201
+ }
202
+ };
203
+
204
+ /**
205
+ * One-time move of each legacy location whose new location does not exist yet.
206
+ * Leaves `<legacy>.moved-<UTC stamp>` naming the new location; a second run
207
+ * finds no legacy directory and does nothing. Never throws: a failed move
208
+ * leaves both places as they were, and `workit doctor` (legacy_dirs) names the
209
+ * command that finishes it.
210
+ * @param {{ env?: NodeJS.ProcessEnv, platform?: string, now?: Date }} [options]
211
+ * @returns {Array<{ kind: string, legacy: string, target: string, marker: string }>}
212
+ */
213
+ export const migrateLegacyDirs = (options = {}) => {
214
+ const env = options.env || process.env;
215
+ const platform = options.platform || process.platform;
216
+ const stamp = (options.now || new Date())
217
+ .toISOString()
218
+ .replace(/[-:]/g, "")
219
+ .replace(/\..*$/, "Z");
220
+ /** @type {Array<{ kind: string, legacy: string, target: string, marker: string }>} */
221
+ const moved = [];
222
+ for (const entry of legacyDirs(env, platform)) {
223
+ if (!isRealDir(entry.legacy) || existsSync(entry.target)) continue;
224
+ const marker = `${entry.legacy}${LEGACY_MARKER_INFIX}${stamp}`;
225
+ try {
226
+ mkdirSync(path.dirname(entry.target), { recursive: true });
227
+ renameSync(entry.legacy, entry.target);
228
+ } catch {
229
+ continue;
230
+ }
231
+ try {
232
+ writeFileSync(
233
+ marker,
234
+ `Workit moved this ${entry.kind} directory to ${entry.target} at ${stamp}.\n`,
235
+ );
236
+ } catch {
237
+ // the move is done; a missing marker only loses the note
238
+ }
239
+ moved.push({ kind: entry.kind, legacy: entry.legacy, target: entry.target, marker });
240
+ }
241
+ return moved;
242
+ };