@brainervirus/workit-opencode 0.9.0 → 0.10.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.
@@ -19,7 +19,7 @@ Never ask for or accept tokens in chat. For missing YouTrack configuration, prev
19
19
 
20
20
  When the user wants to personalize the toolkit (locale, timezone, branch policy), ask native questions one at a time:
21
21
 
22
- 1. **Locale** — present a combobox of `localeOptions` (en, es-CL, es-MX, es-AR, pt-BR) + custom answer; validate the answer against BCP-47 (`^[a-z]{2,3}(-[A-Z]{2})?$`) before passing it.
22
+ 1. **Locale** — present a combobox of `localeOptions` (en, es-CL, es-MX, es-AR, pt-BR) + custom answer; validate the answer against BCP-47 (`^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$`, so `es-419` is valid) before passing it.
23
23
  2. **Timezone** — e.g. `America/Santiago`, custom allowed.
24
24
  3. **Branch policy preset** — gitflow / github-flow / trunk-based / custom.
25
25
  4. **Custom branch lists** (only when preset = custom): allowed patterns (`feature/*`, `codex/*`, …) and protected names (`main`, …).
package/dist/plugin.js CHANGED
@@ -14,7 +14,7 @@ var __export = (target, all) => {
14
14
  };
15
15
 
16
16
  // packages/workit-opencode/src/plugin.ts
17
- import { existsSync as existsSync21, readdirSync as readdirSync12 } from "node:fs";
17
+ import { existsSync as existsSync22, readdirSync as readdirSync13 } from "node:fs";
18
18
  import path39 from "node:path";
19
19
  import { fileURLToPath as fileURLToPath3 } from "node:url";
20
20
 
@@ -125,7 +125,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
125
125
  return dir;
126
126
  };
127
127
  var configDir = () => ensureConfigDir();
128
- var LOCALE_RE = /^[a-z]{2,3}(-[A-Z]{2})?$/;
128
+ var LOCALE_RE = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
129
129
  var DEFAULTS = {
130
130
  locale: "en",
131
131
  localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
@@ -455,7 +455,7 @@ var shouldInjectConfigGuard = (currentText) => !currentText.includes(CONFIG_GUAR
455
455
  var shouldInjectIssueRail = (currentText) => !currentText.includes(ISSUE_RAIL_TEXT);
456
456
 
457
457
  // packages/workit-core/src/core/detector.ts
458
- import { existsSync as existsSync16, readdirSync as readdirSync7, readFileSync as readFileSync17 } from "node:fs";
458
+ import { existsSync as existsSync17, readdirSync as readdirSync8, readFileSync as readFileSync17 } from "node:fs";
459
459
  import path23 from "node:path";
460
460
 
461
461
  // packages/workit-core/src/core/init.ts
@@ -2115,8 +2115,21 @@ import path13 from "node:path";
2115
2115
  import { spawnSync as spawnSync3 } from "node:child_process";
2116
2116
 
2117
2117
  // packages/workit-core/src/core/branch.ts
2118
- import { readFileSync as readFileSync10, mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
2118
+ import {
2119
+ copyFileSync as copyFileSync3,
2120
+ cpSync as cpSync3,
2121
+ existsSync as existsSync9,
2122
+ mkdirSync as mkdirSync5,
2123
+ readFileSync as readFileSync10,
2124
+ readdirSync as readdirSync5,
2125
+ renameSync as renameSync2,
2126
+ rmSync as rmSync2,
2127
+ statSync as statSync4,
2128
+ writeFileSync as writeFileSync8
2129
+ } from "node:fs";
2119
2130
  import { execFileSync as execFileSync2 } from "node:child_process";
2131
+ import { createHash } from "node:crypto";
2132
+ import { tmpdir } from "node:os";
2120
2133
  import path12 from "node:path";
2121
2134
 
2122
2135
  // packages/workit-core/src/core/git.ts
@@ -2200,6 +2213,7 @@ var baseBranch = (cwd) => {
2200
2213
  };
2201
2214
  var DECLARE_RE = /^\s*\*+Branch:\*+\s*`?([^`\s|]+)`?\s*$/gim;
2202
2215
  var USE_CURRENT_RE = /^\s*\*+Branch:\*+\s*use-current\s*$/im;
2216
+ var toPosix = (p) => p.split(path12.sep).join("/");
2203
2217
  var readSafe2 = (p) => {
2204
2218
  try {
2205
2219
  return readFileSync10(p, "utf8");
@@ -2335,10 +2349,7 @@ var docsBranch = ({
2335
2349
  }
2336
2350
  return { error: `cannot resolve docs branch from HEAD ${JSON.stringify(current)}` };
2337
2351
  };
2338
- var ensureBaseBranch = (cwd, base) => {
2339
- const git = gitContext(cwd);
2340
- if (!git.branch || git.branch === "unknown")
2341
- return { ok: false, error: "not in a git repository" };
2352
+ var originBaseReady = (cwd, base) => {
2342
2353
  const run2 = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
2343
2354
  try {
2344
2355
  try {
@@ -2346,20 +2357,28 @@ var ensureBaseBranch = (cwd, base) => {
2346
2357
  } catch {
2347
2358
  run2(["fetch", "origin", "--prune"]);
2348
2359
  }
2349
- let hasOriginBase = true;
2350
2360
  try {
2351
2361
  execFileSync2("git", ["show-ref", "--verify", "--quiet", `refs/remotes/origin/${base}`], {
2352
2362
  cwd,
2353
2363
  stdio: "pipe"
2354
2364
  });
2355
2365
  } catch {
2356
- hasOriginBase = false;
2357
- }
2358
- if (!hasOriginBase)
2359
2366
  return {
2360
2367
  ok: false,
2361
2368
  error: `origin/${base} missing — push ${base} before creating feature/* or bugfix/* branches`
2362
2369
  };
2370
+ }
2371
+ return { ok: true };
2372
+ } catch (error) {
2373
+ return {
2374
+ ok: false,
2375
+ error: error instanceof Error ? error.message : "ensure-base-branch failed"
2376
+ };
2377
+ }
2378
+ };
2379
+ var fastForwardBase = (cwd, base) => {
2380
+ const run2 = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
2381
+ try {
2363
2382
  let hasLocalBase = true;
2364
2383
  try {
2365
2384
  execFileSync2("git", ["show-ref", "--verify", "--quiet", `refs/heads/${base}`], {
@@ -2385,12 +2404,95 @@ var ensureBaseBranch = (cwd, base) => {
2385
2404
  };
2386
2405
  }
2387
2406
  };
2407
+ var ensureBaseBranch = (cwd, base) => {
2408
+ const git = gitContext(cwd);
2409
+ if (!git.branch || git.branch === "unknown")
2410
+ return { ok: false, error: "not in a git repository" };
2411
+ const ready = originBaseReady(cwd, base);
2412
+ if (!ready.ok)
2413
+ return ready;
2414
+ return fastForwardBase(cwd, base);
2415
+ };
2416
+ var purgeStaleFlowGuardRoots = (now) => {
2417
+ const cutoff = now - 24 * 3600000;
2418
+ let entries;
2419
+ try {
2420
+ entries = readdirSync5(tmpdir());
2421
+ } catch {
2422
+ return;
2423
+ }
2424
+ for (const entry of entries) {
2425
+ if (!entry.startsWith("workit-flow-guard-"))
2426
+ continue;
2427
+ try {
2428
+ if (statSync4(path12.join(tmpdir(), entry)).mtimeMs < cutoff)
2429
+ rmSync2(path12.join(tmpdir(), entry), { recursive: true, force: true });
2430
+ } catch {}
2431
+ }
2432
+ };
2433
+ var snapshotFlowState = (cwd) => {
2434
+ purgeStaleFlowGuardRoots(Date.now());
2435
+ const root2 = path12.join(tmpdir(), `workit-flow-guard-${createHash("sha256").update(path12.resolve(cwd)).digest("hex").slice(0, 16)}.${process.pid}.${process.hrtime.bigint()}`);
2436
+ mkdirSync5(root2, { recursive: true });
2437
+ const docsDir = path12.join(path12.resolve(cwd), "docs");
2438
+ let slugs = [];
2439
+ try {
2440
+ slugs = readdirSync5(docsDir);
2441
+ } catch {
2442
+ return root2;
2443
+ }
2444
+ for (const slug of slugs) {
2445
+ for (const rel of [["sdd", "flow.json"], ["spec.md"], ["plan.md"]]) {
2446
+ const src = path12.join(docsDir, slug, ...rel);
2447
+ try {
2448
+ if (!statSync4(src).isFile())
2449
+ continue;
2450
+ } catch {
2451
+ continue;
2452
+ }
2453
+ const dest = path12.join(root2, "docs", slug, ...rel);
2454
+ mkdirSync5(path12.dirname(dest), { recursive: true });
2455
+ cpSync3(src, dest);
2456
+ }
2457
+ }
2458
+ return root2;
2459
+ };
2460
+ var restoreFlowSnapshot = (snapDir, cwd) => {
2461
+ const walk = (dir, rel) => readdirSync5(dir, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? walk(path12.join(dir, entry.name), path12.join(rel, entry.name)) : [path12.join(rel, entry.name)]);
2462
+ const restored = [];
2463
+ try {
2464
+ const workspace = path12.resolve(cwd);
2465
+ for (const rel of walk(snapDir, "")) {
2466
+ const dest = path12.join(workspace, rel);
2467
+ if (existsSync9(dest))
2468
+ continue;
2469
+ mkdirSync5(path12.dirname(dest), { recursive: true });
2470
+ const tmpDest = `${dest}.tmp-${process.pid}`;
2471
+ try {
2472
+ copyFileSync3(path12.join(snapDir, rel), tmpDest);
2473
+ renameSync2(tmpDest, dest);
2474
+ } catch (error) {
2475
+ rmSync2(tmpDest, { force: true });
2476
+ throw error;
2477
+ }
2478
+ restored.push(toPosix(rel));
2479
+ }
2480
+ rmSync2(snapDir, { recursive: true, force: true });
2481
+ return { restored };
2482
+ } catch (error) {
2483
+ return {
2484
+ restored,
2485
+ warning: `flow state snapshot restore failed: ${error instanceof Error ? error.message : String(error)}`
2486
+ };
2487
+ }
2488
+ };
2388
2489
  var branchSetup = ({
2389
2490
  action,
2390
2491
  sdd_dir,
2391
2492
  target_branch,
2392
2493
  stash,
2393
- workspace_root
2494
+ workspace_root,
2495
+ log
2394
2496
  }) => {
2395
2497
  const cwd = path12.resolve(workspace_root);
2396
2498
  const exec = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
@@ -2409,20 +2511,74 @@ var branchSetup = ({
2409
2511
  };
2410
2512
  const writeManifest = (data) => writeFileSync8(manifestPath, JSON.stringify(data, null, 2) + `
2411
2513
  `, "utf8");
2514
+ let snapDir = null;
2515
+ const journal = (message) => log?.(`flow-guard: ${message}`);
2516
+ const snapshotRelPaths = () => {
2517
+ const dir = snapDir;
2518
+ if (!dir)
2519
+ return [];
2520
+ try {
2521
+ const walk = (from, rel) => readdirSync5(from, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? walk(path12.join(from, entry.name), path12.join(rel, entry.name)) : [path12.join(rel, entry.name)]);
2522
+ return walk(dir, "").map(toPosix);
2523
+ } catch {
2524
+ return [];
2525
+ }
2526
+ };
2527
+ const journalSnapshot = () => {
2528
+ const dir = snapDir;
2529
+ if (!dir || !log)
2530
+ return;
2531
+ const rels = snapshotRelPaths();
2532
+ journal(`snapshot: ${rels.length} file(s)`);
2533
+ for (const rel of rels) {
2534
+ let shortHash = "";
2535
+ try {
2536
+ shortHash = createHash("sha256").update(readFileSync10(path12.join(dir, rel))).digest("hex").slice(0, 8);
2537
+ } catch {}
2538
+ journal(`snapshot: ${rel} sha=${shortHash}`);
2539
+ }
2540
+ };
2541
+ const journalPresence = (phase) => {
2542
+ for (const rel of snapshotRelPaths()) {
2543
+ journal(`${phase}: ${rel} ${existsSync9(path12.join(cwd, rel)) ? "present" : "MISSING"}`);
2544
+ }
2545
+ };
2546
+ const restoreWithWarning = (dir) => {
2547
+ if (!dir)
2548
+ return { restored: [], warnings: [] };
2549
+ const total = log ? snapshotRelPaths().length : 0;
2550
+ const { restored, warning } = restoreFlowSnapshot(dir, cwd);
2551
+ if (log)
2552
+ journal(`restore: restored=${restored.length} skipped=${total - restored.length}${warning ? ` warning: ${warning}` : ""}`);
2553
+ else if (warning)
2554
+ journal(`restore warning: ${warning}`);
2555
+ return { restored, warnings: warning ? [warning] : [] };
2556
+ };
2412
2557
  if (action === "reapply_stash") {
2413
- const manifest2 = readManifest();
2414
- const ref = manifest2.stash_ref;
2558
+ const manifest = readManifest();
2559
+ const ref = manifest.stash_ref;
2415
2560
  if (!ref)
2416
2561
  return { error: "no stash_ref in manifest" };
2562
+ snapDir = snapshotFlowState(cwd);
2563
+ journalSnapshot();
2564
+ journal(`pre-pop: ${String(ref)}`);
2417
2565
  try {
2418
2566
  exec(["stash", "pop", String(ref)]);
2419
2567
  } catch (error) {
2420
- return { error: error instanceof Error ? error.message : "stash pop failed" };
2568
+ journal("pop: failed");
2569
+ const {
2570
+ warnings: [warning]
2571
+ } = restoreWithWarning(snapDir);
2572
+ return {
2573
+ error: `${error instanceof Error ? error.message : "stash pop failed"}${warning ? `; ${warning}` : ""}`
2574
+ };
2421
2575
  }
2422
- delete manifest2.stash_ref;
2423
- delete manifest2.stash_created_at;
2424
- writeManifest(manifest2);
2425
- return { action: "reapply_stash", ok: true };
2576
+ journal("pop: ok");
2577
+ delete manifest.stash_ref;
2578
+ delete manifest.stash_created_at;
2579
+ writeManifest(manifest);
2580
+ const { warnings: warnings2 } = restoreWithWarning(snapDir);
2581
+ return { action: "reapply_stash", ok: true, ...warnings2.length > 0 ? { warnings: warnings2 } : {} };
2426
2582
  }
2427
2583
  const target = target_branch ?? "";
2428
2584
  if (!target)
@@ -2431,61 +2587,141 @@ var branchSetup = ({
2431
2587
  return { error: `protected branch ${target}` };
2432
2588
  if (!allowedBranch(cwd, target))
2433
2589
  return { error: `target branch ${target} is not allowed by the branch policy` };
2590
+ let base;
2591
+ let targetExists = true;
2592
+ try {
2593
+ exec(["rev-parse", "--verify", "--quiet", `refs/heads/${target}`]);
2594
+ } catch {
2595
+ targetExists = false;
2596
+ }
2597
+ if (!targetExists) {
2598
+ const baseResolved = baseBranch(cwd);
2599
+ if ("error" in baseResolved)
2600
+ return { error: baseResolved.error };
2601
+ base = baseResolved.base;
2602
+ }
2603
+ journal(`entry: current=${current} target=${target} base=${base ?? "-"}`);
2434
2604
  let stash_ref;
2605
+ const failAfterStash = (message) => {
2606
+ let suffix = "";
2607
+ if (stash_ref) {
2608
+ journal(`pre-pop: ${stash_ref}`);
2609
+ try {
2610
+ exec(["stash", "pop", stash_ref]);
2611
+ stash_ref = undefined;
2612
+ journal("pop: ok");
2613
+ } catch {
2614
+ journal("pop: failed");
2615
+ suffix = " (changes preserved in stash)";
2616
+ }
2617
+ }
2618
+ const {
2619
+ warnings: [warning]
2620
+ } = restoreWithWarning(snapDir);
2621
+ return { error: `${message}${suffix}${warning ? `; ${warning}` : ""}` };
2622
+ };
2435
2623
  if (current !== target) {
2436
2624
  const dirty = Boolean(gitContext(cwd).status_short.trim());
2625
+ if (dirty && stash !== "yes") {
2626
+ return {
2627
+ error: "dirty working tree — ask with native question, then call workit_branch_setup with stash=yes"
2628
+ };
2629
+ }
2630
+ let validatedBase;
2631
+ if (!targetExists && base !== undefined) {
2632
+ const ready = originBaseReady(cwd, base);
2633
+ if (!ready.ok)
2634
+ return { error: ready.error ?? "ensure-base-branch failed" };
2635
+ validatedBase = base;
2636
+ }
2437
2637
  if (dirty) {
2438
- if (stash !== "yes") {
2439
- return {
2440
- error: "dirty working tree — ask with native question, then call workit_branch_setup with stash=yes"
2441
- };
2442
- }
2443
2638
  try {
2639
+ snapDir = snapshotFlowState(cwd);
2640
+ journalSnapshot();
2444
2641
  exec(["stash", "push", "-u", "-m", `workit: pre-checkout ${target}`, "--", ":!docs/*/sdd"]);
2445
2642
  } catch (error) {
2446
2643
  return { error: error instanceof Error ? error.message : "stash push failed" };
2447
2644
  }
2448
2645
  stash_ref = "stash@{0}";
2646
+ journal(`stash push: ${stash_ref}`);
2449
2647
  }
2450
2648
  try {
2451
2649
  exec(["checkout", target]);
2650
+ journalPresence("post-checkout");
2452
2651
  } catch (error) {
2453
2652
  const message = error instanceof Error ? error.message : "checkout failed";
2454
2653
  if (/worktree/i.test(message)) {
2455
- return {
2456
- error: `branch ${target} is locked by an existing git worktree — remove it first (we do not use worktrees)`
2457
- };
2654
+ return failAfterStash(`branch ${target} is locked by an existing git worktree — remove it first (we do not use worktrees)`);
2458
2655
  }
2459
2656
  try {
2460
- const baseResolved = baseBranch(cwd);
2461
- if ("error" in baseResolved)
2462
- return { error: baseResolved.error };
2463
- const baseResult = ensureBaseBranch(cwd, baseResolved.base);
2657
+ let effectiveBase = base;
2658
+ if (effectiveBase === undefined) {
2659
+ const lateResolved = baseBranch(cwd);
2660
+ if ("error" in lateResolved)
2661
+ return failAfterStash(lateResolved.error);
2662
+ effectiveBase = lateResolved.base;
2663
+ }
2664
+ const baseResult = validatedBase !== undefined ? fastForwardBase(cwd, effectiveBase) : ensureBaseBranch(cwd, effectiveBase);
2464
2665
  if (!baseResult.ok)
2465
- return { error: baseResult.error };
2666
+ return failAfterStash(baseResult.error ?? "ensure-base-branch failed");
2466
2667
  exec(["checkout", "-b", target]);
2668
+ journalPresence("post-create");
2467
2669
  } catch (createError) {
2468
- return {
2469
- error: createError instanceof Error ? createError.message : "branch create failed"
2470
- };
2670
+ return failAfterStash(createError instanceof Error ? createError.message : "branch create failed");
2471
2671
  }
2472
2672
  }
2473
2673
  }
2474
- const manifest = readManifest();
2475
- manifest.branch = target;
2476
- manifest.previous_branch = current;
2477
- if (stash_ref) {
2478
- manifest.stash_ref = stash_ref;
2479
- manifest.stash_created_at = new Date().toISOString();
2674
+ try {
2675
+ const manifest = readManifest();
2676
+ manifest.branch = target;
2677
+ manifest.previous_branch = current;
2678
+ if (stash_ref) {
2679
+ manifest.stash_ref = stash_ref;
2680
+ manifest.stash_created_at = new Date().toISOString();
2681
+ }
2682
+ writeManifest(manifest);
2683
+ } catch (error) {
2684
+ const result = failAfterStash(error instanceof Error ? `manifest update failed: ${error.message}` : "manifest update failed");
2685
+ if (stash_ref === undefined && gitContext(cwd).branch !== current) {
2686
+ try {
2687
+ exec(["checkout", current]);
2688
+ } catch {}
2689
+ }
2690
+ return result;
2691
+ }
2692
+ const { restored: restoredRels, warnings } = restoreWithWarning(snapDir);
2693
+ if (stash_ref && snapDir && warnings.length === 0) {
2694
+ const covered = new Set(restoredRels.map(toPosix));
2695
+ try {
2696
+ const stashed = exec([
2697
+ "stash",
2698
+ "show",
2699
+ "--include-untracked",
2700
+ "--name-only",
2701
+ String(stash_ref)
2702
+ ]).split(`
2703
+ `).map((line) => toPosix(line.trim())).filter(Boolean);
2704
+ if (stashed.length > 0 && stashed.every((p) => covered.has(p))) {
2705
+ exec(["stash", "drop", String(stash_ref)]);
2706
+ stash_ref = undefined;
2707
+ journal("dropped redundant stash (fully covered by snapshot restore)");
2708
+ const manifest = readManifest();
2709
+ delete manifest.stash_ref;
2710
+ delete manifest.stash_created_at;
2711
+ writeManifest(manifest);
2712
+ } else {
2713
+ journal(`kept stash ref ${stash_ref} (not fully covered by actual restores)`);
2714
+ }
2715
+ } catch {}
2480
2716
  }
2481
- writeManifest(manifest);
2482
2717
  return {
2483
2718
  action: "setup",
2484
2719
  ok: true,
2485
2720
  branch: target,
2486
2721
  previous_branch: current,
2487
2722
  stash_ref: stash_ref ?? null,
2488
- manifest: manifestPath
2723
+ manifest: manifestPath,
2724
+ ...warnings.length > 0 ? { warnings } : {}
2489
2725
  };
2490
2726
  };
2491
2727
 
@@ -2792,13 +3028,13 @@ import fs3 from "node:fs";
2792
3028
  import path15 from "node:path";
2793
3029
 
2794
3030
  // packages/workit-core/src/core/templates.ts
2795
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
3031
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
2796
3032
  import path14 from "node:path";
2797
3033
  var repoRoot2 = assetRoot();
2798
3034
  var templatePath = (name) => path14.join(configDir(), "templates", `${name}.md`);
2799
3035
  var readTemplate = (name) => {
2800
3036
  const cfg = templatePath(name);
2801
- if (existsSync9(cfg))
3037
+ if (existsSync10(cfg))
2802
3038
  return { source: "config", content: readFileSync11(cfg, "utf8") };
2803
3039
  return {
2804
3040
  source: "repo",
@@ -2816,9 +3052,9 @@ var writeTemplate = (name, content, confirmed) => {
2816
3052
  var listTemplates = () => ["issue-update", "greeting", "headers"].map((name) => {
2817
3053
  const cfg = templatePath(name);
2818
3054
  const repoFile = path14.join(repoRoot2, "templates", `${name}.md`);
2819
- if (existsSync9(cfg))
3055
+ if (existsSync10(cfg))
2820
3056
  return { name, source: "config", path: cfg };
2821
- if (existsSync9(repoFile))
3057
+ if (existsSync10(repoFile))
2822
3058
  return { name, source: "repo", path: repoFile };
2823
3059
  return { name, source: "missing", path: cfg };
2824
3060
  });
@@ -3868,29 +4104,29 @@ function configGuardError(missing) {
3868
4104
  // packages/workit-core/src/core/flow-state.ts
3869
4105
  import {
3870
4106
  closeSync,
3871
- existsSync as existsSync15,
4107
+ existsSync as existsSync16,
3872
4108
  fstatSync,
3873
4109
  fsyncSync,
3874
4110
  mkdirSync as mkdirSync9,
3875
4111
  openSync,
3876
- readdirSync as readdirSync6,
4112
+ readdirSync as readdirSync7,
3877
4113
  readFileSync as readFileSync16,
3878
- renameSync as renameSync2,
3879
- rmSync as rmSync2,
3880
- statSync as statSync7,
4114
+ renameSync as renameSync3,
4115
+ rmSync as rmSync3,
4116
+ statSync as statSync8,
3881
4117
  unlinkSync as unlinkSync2,
3882
4118
  writeFileSync as writeFileSync11
3883
4119
  } from "node:fs";
3884
- import { createHash } from "node:crypto";
4120
+ import { createHash as createHash2 } from "node:crypto";
3885
4121
  import path22 from "node:path";
3886
4122
 
3887
4123
  // packages/workit-core/src/core/docs-validate.ts
3888
- import { existsSync as existsSync11, readFileSync as readFileSync12 } from "node:fs";
4124
+ import { existsSync as existsSync12, readFileSync as readFileSync12 } from "node:fs";
3889
4125
  import { execFileSync as execFileSync3 } from "node:child_process";
3890
4126
  import path18 from "node:path";
3891
4127
 
3892
4128
  // packages/workit-core/src/core/docs-layout.ts
3893
- import { existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync7, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
4129
+ import { existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync7, realpathSync as realpathSync2, statSync as statSync5 } from "node:fs";
3894
4130
  import path17 from "node:path";
3895
4131
  var SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
3896
4132
  var LEGACY_SLUG = "superpowers";
@@ -3898,7 +4134,7 @@ var posix = (p) => p.split(path17.sep).join("/");
3898
4134
  var canonicalize = (base, candidate) => {
3899
4135
  const abs = path17.resolve(base, candidate);
3900
4136
  let ancestor = abs;
3901
- while (!existsSync10(ancestor))
4137
+ while (!existsSync11(ancestor))
3902
4138
  ancestor = path17.dirname(ancestor);
3903
4139
  let real;
3904
4140
  try {
@@ -3929,8 +4165,8 @@ var buildLayout = (workspace, slug) => {
3929
4165
  };
3930
4166
  };
3931
4167
  var probeLegacyDocs = (workspace) => ({
3932
- legacy_sdd: existsSync10(path17.join(workspace, ".superpowers", "sdd")),
3933
- superpowers_dir: existsSync10(path17.join(workspace, "docs", LEGACY_SLUG))
4168
+ legacy_sdd: existsSync11(path17.join(workspace, ".superpowers", "sdd")),
4169
+ superpowers_dir: existsSync11(path17.join(workspace, "docs", LEGACY_SLUG))
3934
4170
  });
3935
4171
  var resolveCanonicalLayout = (input) => {
3936
4172
  const { workspace_root, slug, spec_path, plan_path } = input;
@@ -4025,11 +4261,11 @@ var prepareDocsLayout = (input) => {
4025
4261
  const { layout } = resolved;
4026
4262
  const created = [];
4027
4263
  const ensure = (dir) => {
4028
- if (!existsSync10(dir)) {
4264
+ if (!existsSync11(dir)) {
4029
4265
  mkdirSync7(dir, { recursive: true });
4030
4266
  const rel = posix(path17.relative(layout.workspace, dir));
4031
4267
  created.push(rel || ".");
4032
- } else if (!statSync4(dir).isDirectory()) {
4268
+ } else if (!statSync5(dir).isDirectory()) {
4033
4269
  throw new Error(`path exists but is not a directory: ${posix(path17.relative(layout.workspace, dir))}`);
4034
4270
  }
4035
4271
  };
@@ -4353,7 +4589,7 @@ var qualitySpec = (text) => {
4353
4589
  };
4354
4590
  var sddIgnored = (cwd, slug) => {
4355
4591
  const sddDir = path18.join(cwd, "docs", slug, "sdd");
4356
- if (!existsSync11(sddDir))
4592
+ if (!existsSync12(sddDir))
4357
4593
  return true;
4358
4594
  try {
4359
4595
  execFileSync3("git", ["-C", cwd, "rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
@@ -4371,10 +4607,10 @@ var sddIgnored = (cwd, slug) => {
4371
4607
  // packages/workit-core/src/core/sdd.ts
4372
4608
  import {
4373
4609
  appendFileSync,
4374
- existsSync as existsSync12,
4610
+ existsSync as existsSync13,
4375
4611
  mkdirSync as mkdirSync8,
4376
4612
  readFileSync as readFileSync13,
4377
- statSync as statSync5,
4613
+ statSync as statSync6,
4378
4614
  writeFileSync as writeFileSync10
4379
4615
  } from "node:fs";
4380
4616
  import { execFileSync as execFileSync4 } from "node:child_process";
@@ -4399,7 +4635,7 @@ function ledgerCompletion(root2, slug) {
4399
4635
  let started = false;
4400
4636
  const completed = [];
4401
4637
  const absProgress = path19.join(root2, "docs", slug, "sdd", "progress.md");
4402
- if (existsSync12(absProgress)) {
4638
+ if (existsSync13(absProgress)) {
4403
4639
  try {
4404
4640
  for (const line of readFileSync13(absProgress, "utf8").split(`
4405
4641
  `)) {
@@ -4415,7 +4651,7 @@ function ledgerCompletion(root2, slug) {
4415
4651
  const required = [];
4416
4652
  try {
4417
4653
  const absPlan = path19.join(root2, "docs", slug, "plan.md");
4418
- if (existsSync12(absPlan)) {
4654
+ if (existsSync13(absPlan)) {
4419
4655
  for (const task of parseTasksFromPlan(readFileSync13(absPlan, "utf8")))
4420
4656
  required.push(task.id);
4421
4657
  }
@@ -4448,7 +4684,7 @@ function sddContext({
4448
4684
  let progress_lines = [];
4449
4685
  let completed_task_ids = [];
4450
4686
  const absProgress = path19.join(resolved.layout.sdd, "progress.md");
4451
- if (existsSync12(absProgress)) {
4687
+ if (existsSync13(absProgress)) {
4452
4688
  progress_lines = readFileSync13(absProgress, "utf8").split(`
4453
4689
  `).map((ln) => ln.trim()).filter(Boolean);
4454
4690
  const pat = /^Task\s+(\d+):\s+complete\b/i;
@@ -4456,7 +4692,7 @@ function sddContext({
4456
4692
  }
4457
4693
  let manifest = {};
4458
4694
  const absManifest = path19.join(resolved.layout.sdd, "manifest.json");
4459
- if (existsSync12(absManifest)) {
4695
+ if (existsSync13(absManifest)) {
4460
4696
  try {
4461
4697
  manifest = JSON.parse(readFileSync13(absManifest, "utf8"));
4462
4698
  } catch {
@@ -4464,7 +4700,7 @@ function sddContext({
4464
4700
  }
4465
4701
  }
4466
4702
  const legacy_path = path19.join(cwd, ".superpowers/sdd");
4467
- const legacy_exists = existsSync12(legacy_path);
4703
+ const legacy_exists = existsSync13(legacy_path);
4468
4704
  let todos = [];
4469
4705
  let task_count = 0;
4470
4706
  if (plan_path) {
@@ -4495,7 +4731,7 @@ function sddContext({
4495
4731
  progress_lines,
4496
4732
  completed_task_ids,
4497
4733
  manifest,
4498
- created: existsSync12(path19.join(cwd, sdd_dir)),
4734
+ created: existsSync13(path19.join(cwd, sdd_dir)),
4499
4735
  forbidden_legacy_path: ".superpowers/sdd",
4500
4736
  legacy_sdd_exists: legacy_exists,
4501
4737
  warning: legacy_exists ? "Ignore .superpowers/sdd — use sdd_dir from this tool only" : undefined,
@@ -4579,7 +4815,7 @@ function sddAppendProgress({
4579
4815
  if (!match || match[1].toLowerCase() === match[2].toLowerCase()) {
4580
4816
  return { error: "invalid progress line format" };
4581
4817
  }
4582
- if (existsSync12(path_) && statSync5(path_).isDirectory()) {
4818
+ if (existsSync13(path_) && statSync6(path_).isDirectory()) {
4583
4819
  return { error: `progress path is a directory: ${progress_path}` };
4584
4820
  }
4585
4821
  mkdirSync8(path19.dirname(path_), { recursive: true });
@@ -4627,7 +4863,7 @@ function sddAppendAdvisory({
4627
4863
  if (!contained.ok)
4628
4864
  return { error: contained.error, code: "advisory_path_invalid" };
4629
4865
  const abs = contained.path;
4630
- if (existsSync12(abs) && statSync5(abs).isDirectory()) {
4866
+ if (existsSync13(abs) && statSync6(abs).isDirectory()) {
4631
4867
  return {
4632
4868
  error: `advisory target is a directory: ${advisories_path}`,
4633
4869
  code: "advisory_target_invalid"
@@ -4643,12 +4879,12 @@ function sddAppendAdvisory({
4643
4879
 
4644
4880
  // packages/workit-core/src/core/verify-project.ts
4645
4881
  import { spawnSync as spawnSync5 } from "node:child_process";
4646
- import { existsSync as existsSync14, readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
4882
+ import { existsSync as existsSync15, readFileSync as readFileSync15, statSync as statSync7 } from "node:fs";
4647
4883
  import path21 from "node:path";
4648
4884
 
4649
4885
  // packages/workit-core/src/core/repo-context.ts
4650
4886
  import { spawnSync as spawnSync4 } from "node:child_process";
4651
- import { existsSync as existsSync13, readFileSync as readFileSync14, readdirSync as readdirSync5 } from "node:fs";
4887
+ import { existsSync as existsSync14, readFileSync as readFileSync14, readdirSync as readdirSync6 } from "node:fs";
4652
4888
  import path20 from "node:path";
4653
4889
  var runGit = (cwd, args) => {
4654
4890
  const result = spawnSync4("git", args, { cwd, encoding: "utf8" });
@@ -4738,7 +4974,7 @@ var printSection = (title) => `
4738
4974
  `;
4739
4975
  var probeCaseInsensitive = (dir, wanted) => {
4740
4976
  try {
4741
- for (const entry of readdirSync5(dir)) {
4977
+ for (const entry of readdirSync6(dir)) {
4742
4978
  if (entry.toLowerCase() === wanted.toLowerCase())
4743
4979
  return entry;
4744
4980
  }
@@ -4790,7 +5026,7 @@ var diffStatForRange = (cwd, range) => {
4790
5026
  };
4791
5027
  var packageScripts = (cwd, keys) => {
4792
5028
  const pkgPath = path20.join(cwd, "package.json");
4793
- if (!existsSync13(pkgPath))
5029
+ if (!existsSync14(pkgPath))
4794
5030
  return [];
4795
5031
  try {
4796
5032
  const pkg = JSON.parse(readFileSync14(pkgPath, "utf8"));
@@ -4807,7 +5043,7 @@ var documentationFiles = (cwd) => {
4807
5043
  return;
4808
5044
  let entries;
4809
5045
  try {
4810
- entries = readdirSync5(dir, { withFileTypes: true });
5046
+ entries = readdirSync6(dir, { withFileTypes: true });
4811
5047
  } catch {
4812
5048
  return;
4813
5049
  }
@@ -4825,7 +5061,7 @@ var documentationFiles = (cwd) => {
4825
5061
  return matches.sort().slice(0, 200);
4826
5062
  };
4827
5063
  var readTrimmed = (file, maxLines) => {
4828
- if (!existsSync13(file))
5064
+ if (!existsSync14(file))
4829
5065
  return "";
4830
5066
  const lines = readFileSync14(file, "utf8").split(`
4831
5067
  `);
@@ -4899,7 +5135,7 @@ ${status.stderr}` : "");
4899
5135
  stdout += `
4900
5136
  `;
4901
5137
  stdout += printSection("Recent Validation Signals");
4902
- if (existsSync13(path20.join(cwd, "package.json"))) {
5138
+ if (existsSync14(path20.join(cwd, "package.json"))) {
4903
5139
  stdout += `package.json detected. Common scripts:
4904
5140
  `;
4905
5141
  const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
@@ -4908,7 +5144,7 @@ ${status.stderr}` : "");
4908
5144
  `) + `
4909
5145
  `;
4910
5146
  }
4911
- if (existsSync13(path20.join(cwd, "Cargo.toml")) || existsSync13(path20.join(cwd, "src-tauri/Cargo.toml"))) {
5147
+ if (existsSync14(path20.join(cwd, "Cargo.toml")) || existsSync14(path20.join(cwd, "src-tauri/Cargo.toml"))) {
4912
5148
  stdout += `Rust project detected.
4913
5149
  `;
4914
5150
  }
@@ -4956,7 +5192,7 @@ function changelogContext(root2, range) {
4956
5192
  `;
4957
5193
  stdout += printSection("Existing CHANGELOG.md");
4958
5194
  const changelogPath = path20.join(cwd, "CHANGELOG.md");
4959
- if (existsSync13(changelogPath)) {
5195
+ if (existsSync14(changelogPath)) {
4960
5196
  stdout += readTrimmed(changelogPath, 260) + `
4961
5197
  `;
4962
5198
  } else {
@@ -4994,7 +5230,7 @@ function docsRefreshContext(root2, range) {
4994
5230
  `;
4995
5231
  stdout += printSection("README Preview");
4996
5232
  const readme = path20.join(cwd, "README.md");
4997
- if (existsSync13(readme)) {
5233
+ if (existsSync14(readme)) {
4998
5234
  stdout += readTrimmed(readme, 220) + `
4999
5235
  `;
5000
5236
  } else {
@@ -5003,7 +5239,7 @@ function docsRefreshContext(root2, range) {
5003
5239
  }
5004
5240
  stdout += printSection("Package Scripts");
5005
5241
  const pkgPath = path20.join(cwd, "package.json");
5006
- if (existsSync13(pkgPath)) {
5242
+ if (existsSync14(pkgPath)) {
5007
5243
  try {
5008
5244
  const pkg = JSON.parse(readFileSync14(pkgPath, "utf8"));
5009
5245
  stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
@@ -5050,7 +5286,7 @@ function releaseNotesContext(root2, rangeOrTag) {
5050
5286
  `;
5051
5287
  stdout += printSection("Existing Release Files");
5052
5288
  for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
5053
- if (existsSync13(path20.join(cwd, rel)))
5289
+ if (existsSync14(path20.join(cwd, rel)))
5054
5290
  stdout += rel + `
5055
5291
  `;
5056
5292
  }
@@ -5067,9 +5303,9 @@ var commandOnPath2 = (name) => {
5067
5303
  for (const candidateName of names) {
5068
5304
  const candidate = path21.join(dir, candidateName);
5069
5305
  try {
5070
- statSync6(candidate);
5306
+ statSync7(candidate);
5071
5307
  if (process.platform !== "win32") {
5072
- const mode = statSync6(candidate).mode & 73;
5308
+ const mode = statSync7(candidate).mode & 73;
5073
5309
  if (mode === 0)
5074
5310
  continue;
5075
5311
  }
@@ -5081,7 +5317,7 @@ var commandOnPath2 = (name) => {
5081
5317
  };
5082
5318
  var hasScript = (cwd, name) => {
5083
5319
  const pkgPath = path21.join(cwd, "package.json");
5084
- if (!existsSync14(pkgPath))
5320
+ if (!existsSync15(pkgPath))
5085
5321
  return false;
5086
5322
  try {
5087
5323
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
@@ -5091,10 +5327,10 @@ var hasScript = (cwd, name) => {
5091
5327
  }
5092
5328
  };
5093
5329
  var packageRunner = (cwd) => {
5094
- if (existsSync14(path21.join(cwd, "pnpm-lock.yaml")))
5330
+ if (existsSync15(path21.join(cwd, "pnpm-lock.yaml")))
5095
5331
  return "pnpm";
5096
5332
  const pkgPath = path21.join(cwd, "package.json");
5097
- if (existsSync14(pkgPath)) {
5333
+ if (existsSync15(pkgPath)) {
5098
5334
  try {
5099
5335
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
5100
5336
  if (typeof pkg.packageManager === "string" && pkg.packageManager.startsWith("pnpm")) {
@@ -5102,7 +5338,7 @@ var packageRunner = (cwd) => {
5102
5338
  }
5103
5339
  } catch {}
5104
5340
  }
5105
- if (existsSync14(path21.join(cwd, "yarn.lock")))
5341
+ if (existsSync15(path21.join(cwd, "yarn.lock")))
5106
5342
  return "yarn";
5107
5343
  return "npm";
5108
5344
  };
@@ -5163,7 +5399,7 @@ root: ${cwd}
5163
5399
  lines.push(`dry_run: ${String(dryRun)}
5164
5400
  `);
5165
5401
  const pkgPath = path21.join(cwd, "package.json");
5166
- if (existsSync14(pkgPath)) {
5402
+ if (existsSync15(pkgPath)) {
5167
5403
  const runner = packageRunner(cwd);
5168
5404
  for (const script of ["lint", "format:check", "test", "build"]) {
5169
5405
  if (hasScript(cwd, script)) {
@@ -5178,7 +5414,7 @@ root: ${cwd}
5178
5414
  } else {
5179
5415
  skipCheck("javascript", "package.json not found");
5180
5416
  }
5181
- const cargoManifest = existsSync14(path21.join(cwd, "Cargo.toml")) ? "Cargo.toml" : existsSync14(path21.join(cwd, "src-tauri/Cargo.toml")) ? "src-tauri/Cargo.toml" : "";
5417
+ const cargoManifest = existsSync15(path21.join(cwd, "Cargo.toml")) ? "Cargo.toml" : existsSync15(path21.join(cwd, "src-tauri/Cargo.toml")) ? "src-tauri/Cargo.toml" : "";
5182
5418
  if (cargoManifest) {
5183
5419
  runCheck("cargo fmt", "cargo", ["fmt", "--manifest-path", cargoManifest, "--", "--check"]);
5184
5420
  runCheck("cargo clippy", "cargo", [
@@ -5194,7 +5430,7 @@ root: ${cwd}
5194
5430
  } else {
5195
5431
  skipCheck("rust", "Cargo.toml not found");
5196
5432
  }
5197
- if (existsSync14(path21.join(cwd, "pyproject.toml")) || existsSync14(path21.join(cwd, "pytest.ini")) || existsSync14(path21.join(cwd, "tests"))) {
5433
+ if (existsSync15(path21.join(cwd, "pyproject.toml")) || existsSync15(path21.join(cwd, "pytest.ini")) || existsSync15(path21.join(cwd, "tests"))) {
5198
5434
  if (commandOnPath2("pytest"))
5199
5435
  runCheck("pytest", "pytest", []);
5200
5436
  else
@@ -5216,7 +5452,7 @@ root: ${cwd}
5216
5452
  lines.push(`status: skipped (dry run)
5217
5453
  `);
5218
5454
  skipped += 1;
5219
- } else if (existsSync14(changelogPath)) {
5455
+ } else if (existsSync15(changelogPath)) {
5220
5456
  if (/## \[Unreleased\]/i.test(readFileSync15(changelogPath, "utf8"))) {
5221
5457
  lines.push(`status: pass
5222
5458
  `);
@@ -5330,7 +5566,7 @@ var emptyState = (slug) => ({
5330
5566
  });
5331
5567
  var readFlowState = (root2, slug) => {
5332
5568
  const file = flowPath(root2, slug);
5333
- if (!existsSync15(file))
5569
+ if (!existsSync16(file))
5334
5570
  return emptyState(slug);
5335
5571
  try {
5336
5572
  return normalizeState(JSON.parse(readFileSync16(file, "utf8")), slug);
@@ -5472,7 +5708,7 @@ var validateState = (parsed, slug) => {
5472
5708
  var readFlowStrict = (root2, slug) => {
5473
5709
  const file = flowPath(root2, slug);
5474
5710
  const rel = path22.posix.join("docs", slug, "sdd", "flow.json");
5475
- if (!existsSync15(file)) {
5711
+ if (!existsSync16(file)) {
5476
5712
  return err2("flow_not_activated", `flow not activated for ${slug} — run workit_flow_status first`);
5477
5713
  }
5478
5714
  let text;
@@ -5509,15 +5745,15 @@ var writeFlowFileAtomic = (file, state) => {
5509
5745
  fsyncSync(fd);
5510
5746
  closeSync(fd);
5511
5747
  fd = null;
5512
- renameSync2(tmp, file);
5748
+ renameSync3(tmp, file);
5513
5749
  } finally {
5514
5750
  try {
5515
5751
  if (fd !== null)
5516
5752
  closeSync(fd);
5517
5753
  } catch {}
5518
5754
  try {
5519
- if (existsSync15(tmp))
5520
- rmSync2(tmp, { force: true });
5755
+ if (existsSync16(tmp))
5756
+ rmSync3(tmp, { force: true });
5521
5757
  } catch {}
5522
5758
  }
5523
5759
  };
@@ -5525,14 +5761,14 @@ var MAX_WRITE_ATTEMPTS = 5;
5525
5761
  var STALE_LOCK_MS = 1000;
5526
5762
  var lockMtimeMs = (lock) => {
5527
5763
  try {
5528
- return statSync7(lock).mtimeMs;
5764
+ return statSync8(lock).mtimeMs;
5529
5765
  } catch {
5530
5766
  return null;
5531
5767
  }
5532
5768
  };
5533
5769
  var lockOwnedBy = (fd, lock) => {
5534
5770
  try {
5535
- return fstatSync(fd).ino === statSync7(lock).ino;
5771
+ return fstatSync(fd).ino === statSync8(lock).ino;
5536
5772
  } catch {
5537
5773
  return false;
5538
5774
  }
@@ -5548,7 +5784,7 @@ var writeFlowStateIfCurrent = (root2, expected, next) => {
5548
5784
  const tmp = uniqueTempPath(file);
5549
5785
  let fd = null;
5550
5786
  try {
5551
- const currentText = existsSync15(file) ? readFileSync16(file, "utf8") : null;
5787
+ const currentText = existsSync16(file) ? readFileSync16(file, "utf8") : null;
5552
5788
  if (currentText !== expectedText)
5553
5789
  return { ok: false, conflict: true };
5554
5790
  mkdirSync9(path22.dirname(file), { recursive: true });
@@ -5557,10 +5793,10 @@ var writeFlowStateIfCurrent = (root2, expected, next) => {
5557
5793
  fsyncSync(fd);
5558
5794
  closeSync(fd);
5559
5795
  fd = null;
5560
- const reRead = existsSync15(file) ? readFileSync16(file, "utf8") : null;
5796
+ const reRead = existsSync16(file) ? readFileSync16(file, "utf8") : null;
5561
5797
  if (reRead !== expectedText)
5562
5798
  return { ok: false, conflict: true };
5563
- renameSync2(tmp, file);
5799
+ renameSync3(tmp, file);
5564
5800
  return { ok: true };
5565
5801
  } catch (error) {
5566
5802
  return { ok: false, io_error: error instanceof Error ? error.message : String(error) };
@@ -5570,8 +5806,8 @@ var writeFlowStateIfCurrent = (root2, expected, next) => {
5570
5806
  closeSync(fd);
5571
5807
  } catch {}
5572
5808
  try {
5573
- if (existsSync15(tmp))
5574
- rmSync2(tmp, { force: true });
5809
+ if (existsSync16(tmp))
5810
+ rmSync3(tmp, { force: true });
5575
5811
  } catch {}
5576
5812
  }
5577
5813
  };
@@ -5592,7 +5828,7 @@ var readCanonicalDigest = (root2, rel) => {
5592
5828
  } catch {
5593
5829
  return { ok: false, code: "document_unreadable" };
5594
5830
  }
5595
- return { ok: true, text, digest: createHash("sha256").update(bytes).digest("hex") };
5831
+ return { ok: true, text, digest: createHash2("sha256").update(bytes).digest("hex") };
5596
5832
  };
5597
5833
  var resetForSpecDrift = (state) => ({
5598
5834
  ...state,
@@ -5668,11 +5904,11 @@ var normalizeCompatibility = (root2, slug, parsed, state) => {
5668
5904
  };
5669
5905
  var withFlowLock = (file, fn) => {
5670
5906
  const lock = `${file}.lock`;
5671
- if (!existsSync15(path22.dirname(file)))
5907
+ if (!existsSync16(path22.dirname(file)))
5672
5908
  return { locked: true, value: fn() };
5673
5909
  try {
5674
- if (existsSync15(`${lock}.stale`))
5675
- rmSync2(`${lock}.stale`, { force: true });
5910
+ if (existsSync16(`${lock}.stale`))
5911
+ rmSync3(`${lock}.stale`, { force: true });
5676
5912
  } catch {}
5677
5913
  const wait = new Int32Array(new SharedArrayBuffer(4));
5678
5914
  let fd = null;
@@ -5691,7 +5927,7 @@ var withFlowLock = (file, fn) => {
5691
5927
  const mtime = lockMtimeMs(lock);
5692
5928
  if (mtime !== null && Date.now() - mtime > STALE_LOCK_MS) {
5693
5929
  try {
5694
- renameSync2(lock, `${lock}.stale`);
5930
+ renameSync3(lock, `${lock}.stale`);
5695
5931
  unlinkSync2(`${lock}.stale`);
5696
5932
  } catch {}
5697
5933
  try {
@@ -5727,7 +5963,7 @@ var withFlowLock = (file, fn) => {
5727
5963
  } finally {
5728
5964
  try {
5729
5965
  if (fd !== null && lockOwnedBy(fd, lock))
5730
- rmSync2(lock, { force: true });
5966
+ rmSync3(lock, { force: true });
5731
5967
  } catch {}
5732
5968
  try {
5733
5969
  if (fd !== null)
@@ -6044,7 +6280,7 @@ var prepareFlowState = (root2, slug, opts = {}, ctx) => {
6044
6280
  const planPath = path22.posix.join("docs", slug, "plan.md");
6045
6281
  const file = flowPath(root2, slug);
6046
6282
  const locked = withFlowLock(file, () => {
6047
- if (!existsSync15(file)) {
6283
+ if (!existsSync16(file)) {
6048
6284
  writeFlowFileAtomic(file, {
6049
6285
  slug,
6050
6286
  activated: true,
@@ -6085,7 +6321,7 @@ var transitionSpec = (root2, slug, specPath, evidence, ctx) => {
6085
6321
  return err2("path_invalid", doc.error);
6086
6322
  const relPath = path22.posix.join("docs", slug, "spec.md");
6087
6323
  return readModifyWrite(root2, slug, (state) => {
6088
- if (!existsSync15(doc.path))
6324
+ if (!existsSync16(doc.path))
6089
6325
  return err2("spec_missing", `spec not found: ${specPath}`);
6090
6326
  if (state.spec.status === "draft" || state.spec.status === "self_reviewed") {
6091
6327
  const digest = readCanonicalDigest(root2, relPath);
@@ -6130,7 +6366,7 @@ var transitionPlan = (root2, slug, planPath, evidence, ctx) => {
6130
6366
  return err2("path_invalid", doc.error);
6131
6367
  const relPath = path22.posix.join("docs", slug, "plan.md");
6132
6368
  return readModifyWrite(root2, slug, (state) => {
6133
- if (!existsSync15(doc.path))
6369
+ if (!existsSync16(doc.path))
6134
6370
  return err2("plan_missing", `plan not found: ${planPath}`);
6135
6371
  if (state.spec.status !== "approved") {
6136
6372
  return err2("spec_not_approved", "spec must be approved before the plan can be approved");
@@ -6796,7 +7032,7 @@ var subagentDrivenInterception = (input) => {
6796
7032
  var findActiveSubagentDrivenContexts = (root2) => {
6797
7033
  let entries = [];
6798
7034
  try {
6799
- entries = readdirSync6(path22.join(root2, "docs"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
7035
+ entries = readdirSync7(path22.join(root2, "docs"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
6800
7036
  } catch {
6801
7037
  return [];
6802
7038
  }
@@ -6910,7 +7146,7 @@ var detectBacktickDocRefs = (text) => {
6910
7146
  };
6911
7147
  var scanActiveSubagentDrivenPlans = (root2) => {
6912
7148
  const docsDir = path23.join(root2, "docs");
6913
- if (!existsSync16(docsDir))
7149
+ if (!existsSync17(docsDir))
6914
7150
  return { slugs: [], read_errors: [] };
6915
7151
  const slugs = [];
6916
7152
  const readErrors = [];
@@ -6931,9 +7167,9 @@ var scanActiveSubagentDrivenPlans = (root2) => {
6931
7167
  if (exec.status === "active" && exec.mode === "subagent-driven")
6932
7168
  slugs.push(slug);
6933
7169
  };
6934
- for (const slug of readdirSync7(docsDir)) {
7170
+ for (const slug of readdirSync8(docsDir)) {
6935
7171
  const file = path23.join(docsDir, slug, "sdd", "flow.json");
6936
- if (!existsSync16(file))
7172
+ if (!existsSync17(file))
6937
7173
  continue;
6938
7174
  let raw;
6939
7175
  try {
@@ -19276,7 +19512,7 @@ function tool(input) {
19276
19512
  tool.schema = exports_external;
19277
19513
  // packages/workit-core/src/core.ts
19278
19514
  import { spawnSync as spawnSync6 } from "node:child_process";
19279
- import { existsSync as existsSync17, realpathSync as realpathSync3 } from "node:fs";
19515
+ import { existsSync as existsSync18, realpathSync as realpathSync3 } from "node:fs";
19280
19516
  import path24 from "node:path";
19281
19517
  var ok = (data) => ({ ok: true, data, error: null });
19282
19518
  var fail = (error45, data = null) => ({
@@ -19316,7 +19552,7 @@ function resolveInside(root2, candidate) {
19316
19552
  throw new Error("path must stay inside repository root");
19317
19553
  }
19318
19554
  let ancestor = target;
19319
- while (!existsSync17(ancestor))
19555
+ while (!existsSync18(ancestor))
19320
19556
  ancestor = path24.dirname(ancestor);
19321
19557
  const canonicalAncestor = realpathSync3(ancestor);
19322
19558
  if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path24.sep)) {
@@ -19926,12 +20162,14 @@ function createRepoTools(runtime = defaultRuntime) {
19926
20162
  } catch (error45) {
19927
20163
  return output(fail(error45 instanceof Error ? error45.message : "invalid SDD path"));
19928
20164
  }
20165
+ const diagnostic = getDiagnosticLogger();
19929
20166
  const result = branchSetup({
19930
20167
  action,
19931
20168
  sdd_dir: resolvedSdd,
19932
20169
  target_branch,
19933
20170
  stash,
19934
- workspace_root: context2.directory
20171
+ workspace_root: context2.directory,
20172
+ log: diagnostic ? (message) => diagnostic.info(message) : undefined
19935
20173
  });
19936
20174
  return output(legacyScriptResult({
19937
20175
  stdout: JSON.stringify(result),
@@ -20056,7 +20294,7 @@ function createRepoTools(runtime = defaultRuntime) {
20056
20294
  return output(result.ok ? ok(result) : fail(result.error));
20057
20295
  }
20058
20296
  if (action === "config") {
20059
- const LOCALE_RE2 = /^[a-z]{2,3}(-[A-Z]{2})?$/;
20297
+ const LOCALE_RE2 = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
20060
20298
  if (locale !== undefined && !LOCALE_RE2.test(locale)) {
20061
20299
  return output(fail(`invalid locale: ${JSON.stringify(locale)} — expected BCP-47 like en or es-CL`));
20062
20300
  }
@@ -20562,12 +20800,12 @@ import path32 from "node:path";
20562
20800
  import path31 from "node:path";
20563
20801
 
20564
20802
  // packages/workit-core/src/core/handoff-context.ts
20565
- import { existsSync as existsSync18, readFileSync as readFileSync20, readdirSync as readdirSync8, statSync as statSync8 } from "node:fs";
20803
+ import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync9, statSync as statSync9 } from "node:fs";
20566
20804
  import path30 from "node:path";
20567
20805
  var DOC_RE = /docs\/([A-Za-z0-9][A-Za-z0-9._-]*)\/(spec|plan)\.md/g;
20568
20806
  var listMd = (dir) => {
20569
20807
  try {
20570
- return readdirSync8(dir).filter((f) => f.endsWith(".md")).sort();
20808
+ return readdirSync9(dir).filter((f) => f.endsWith(".md")).sort();
20571
20809
  } catch {
20572
20810
  return [];
20573
20811
  }
@@ -20583,7 +20821,7 @@ var resolveFromMessagePaths = (root2, message) => {
20583
20821
  const slug = slugs[0];
20584
20822
  const plan = `docs/${slug}/plan.md`;
20585
20823
  const spec = `docs/${slug}/spec.md`;
20586
- if (!existsSync18(path30.join(root2, plan)) || !existsSync18(path30.join(root2, spec))) {
20824
+ if (!existsSync19(path30.join(root2, plan)) || !existsSync19(path30.join(root2, spec))) {
20587
20825
  return { error: `docs/${slug}/ must contain both plan.md and spec.md` };
20588
20826
  }
20589
20827
  return { spec, plan, source: "message_paths" };
@@ -20593,7 +20831,7 @@ var resolveActivePair = (root2) => {
20593
20831
  let best = null;
20594
20832
  let entries = [];
20595
20833
  try {
20596
- entries = readdirSync8(docsDir);
20834
+ entries = readdirSync9(docsDir);
20597
20835
  } catch {
20598
20836
  return { error: "no pair" };
20599
20837
  }
@@ -20602,9 +20840,9 @@ var resolveActivePair = (root2) => {
20602
20840
  continue;
20603
20841
  const plan = path30.join("docs", slug, "plan.md");
20604
20842
  const spec = path30.join("docs", slug, "spec.md");
20605
- if (!existsSync18(path30.join(root2, plan)) || !existsSync18(path30.join(root2, spec)))
20843
+ if (!existsSync19(path30.join(root2, plan)) || !existsSync19(path30.join(root2, spec)))
20606
20844
  continue;
20607
- const score = Math.max(statSync8(path30.join(root2, spec)).mtimeMs, statSync8(path30.join(root2, plan)).mtimeMs);
20845
+ const score = Math.max(statSync9(path30.join(root2, spec)).mtimeMs, statSync9(path30.join(root2, plan)).mtimeMs);
20608
20846
  if (best === null || score > best.score || score === best.score && slug < best.spec.split("/")[1]) {
20609
20847
  best = { score, spec, plan, source: "active_pair" };
20610
20848
  }
@@ -20623,7 +20861,7 @@ var resolveWorkflowPaths = (root2, message) => {
20623
20861
  if (!("error" in active))
20624
20862
  return active;
20625
20863
  const docsDir = path30.join(root2, "docs");
20626
- if (!existsSync18(docsDir) || listMd(docsDir).length === 0) {
20864
+ if (!existsSync19(docsDir) || listMd(docsDir).length === 0) {
20627
20865
  return { error: "no docs/<slug>/ features found under docs/" };
20628
20866
  }
20629
20867
  return {
@@ -20793,7 +21031,7 @@ function createHandoffTools(client, state) {
20793
21031
  import path34 from "node:path";
20794
21032
 
20795
21033
  // packages/workit-core/src/core/youtrack-tools.ts
20796
- import { readFileSync as readFileSync21, statSync as statSync9 } from "node:fs";
21034
+ import { readFileSync as readFileSync21, statSync as statSync10 } from "node:fs";
20797
21035
  import os3 from "node:os";
20798
21036
  import path33 from "node:path";
20799
21037
  var ISSUE_RE2 = /^[A-Z]+-\d+$/;
@@ -20813,7 +21051,7 @@ function readCredentials(env = process.env, home = os3.homedir()) {
20813
21051
  const config2 = parsed;
20814
21052
  const tokenFile = config2.tokenFile ?? "youtrack.token";
20815
21053
  const tokenPath = path33.resolve(path33.dirname(resolvedConfig), tokenFile.replace(/^~(?=\/)/, home));
20816
- if (process.platform !== "win32" && (statSync9(tokenPath).mode & 511) !== 384)
21054
+ if (process.platform !== "win32" && (statSync10(tokenPath).mode & 511) !== 384)
20817
21055
  throw new Error("youtrack.token mode must be 0600");
20818
21056
  const token = readFileSync21(tokenPath, "utf8").trim();
20819
21057
  if (!token)
@@ -21271,7 +21509,7 @@ function createPresentTools() {
21271
21509
  }
21272
21510
 
21273
21511
  // packages/workit-core/src/core/docs-repo.ts
21274
- import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync12, readdirSync as readdirSync9 } from "node:fs";
21512
+ import { existsSync as existsSync20, mkdirSync as mkdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync12, readdirSync as readdirSync10 } from "node:fs";
21275
21513
  import { execFileSync as execFileSync5 } from "node:child_process";
21276
21514
  import path35 from "node:path";
21277
21515
  var configPath2 = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path35.join(configDir(), "docs-repo.json");
@@ -21291,7 +21529,7 @@ var writeDocsRepoConfig = (docsPath) => {
21291
21529
  };
21292
21530
  var docsRepoPath = () => readDocsRepoConfig()?.path ?? null;
21293
21531
  var validateDocsRepo = (docsPath) => {
21294
- if (!existsSync19(docsPath))
21532
+ if (!existsSync20(docsPath))
21295
21533
  return { ok: false, error: `docs repo path does not exist: ${docsPath}` };
21296
21534
  try {
21297
21535
  execFileSync5("git", ["-C", docsPath, "rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
@@ -21299,7 +21537,7 @@ var validateDocsRepo = (docsPath) => {
21299
21537
  return { ok: false, error: `docs repo is not a git repository: ${docsPath}` };
21300
21538
  }
21301
21539
  const featuresDir = path35.join(docsPath, "features");
21302
- if (!existsSync19(featuresDir))
21540
+ if (!existsSync20(featuresDir))
21303
21541
  mkdirSync10(featuresDir, { recursive: true });
21304
21542
  return { ok: true };
21305
21543
  };
@@ -21316,19 +21554,19 @@ var listSpecs = (workspaceRoot) => {
21316
21554
  const repoPath = docsRepoPath();
21317
21555
  const specs = [];
21318
21556
  const docsDir = path35.join(workspaceRoot, "docs");
21319
- if (existsSync19(docsDir)) {
21320
- for (const slug of readdirSync9(docsDir)) {
21557
+ if (existsSync20(docsDir)) {
21558
+ for (const slug of readdirSync10(docsDir)) {
21321
21559
  if (slug.startsWith("."))
21322
21560
  continue;
21323
21561
  const spec = path35.posix.join("docs", slug, "spec.md");
21324
- if (!existsSync19(path35.join(workspaceRoot, spec)))
21562
+ if (!existsSync20(path35.join(workspaceRoot, spec)))
21325
21563
  continue;
21326
21564
  let promoted = false;
21327
21565
  let target = null;
21328
21566
  if (repoPath) {
21329
21567
  const featuresDir = path35.join(repoPath, "features");
21330
- if (existsSync19(featuresDir)) {
21331
- const match = readdirSync9(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d));
21568
+ if (existsSync20(featuresDir)) {
21569
+ const match = readdirSync10(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d));
21332
21570
  if (match) {
21333
21571
  promoted = true;
21334
21572
  target = path35.join(repoPath, "features", match);
@@ -21402,7 +21640,7 @@ var promoteSpec = (workspaceRoot, slug, opts) => {
21402
21640
  }
21403
21641
  if (!opts.force) {
21404
21642
  const sddDir = path35.join(workspaceRootCanonical, "docs", slug, "sdd");
21405
- if (existsSync19(sddDir)) {
21643
+ if (existsSync20(sddDir)) {
21406
21644
  try {
21407
21645
  execFileSync5("git", [
21408
21646
  "-C",
@@ -21420,7 +21658,7 @@ var promoteSpec = (workspaceRoot, slug, opts) => {
21420
21658
  }
21421
21659
  const prefix = monthPrefix();
21422
21660
  const featuresDir = path35.join(repoPath, "features");
21423
- const existing = existsSync19(featuresDir) ? readdirSync9(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d)) : undefined;
21661
+ const existing = existsSync20(featuresDir) ? readdirSync10(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d)) : undefined;
21424
21662
  const targetDir = path35.join(featuresDir, existing ?? `${prefix}-${slug}`);
21425
21663
  mkdirSync10(targetDir, { recursive: true });
21426
21664
  const files = ["spec.md"];
@@ -21479,15 +21717,15 @@ ${row}
21479
21717
  // packages/workit-core/src/core/docs-migration.ts
21480
21718
  import { execFileSync as execFileSync6 } from "node:child_process";
21481
21719
  import {
21482
- existsSync as existsSync20,
21720
+ existsSync as existsSync21,
21483
21721
  lstatSync as lstatSync2,
21484
21722
  mkdirSync as mkdirSync11,
21485
- readdirSync as readdirSync10,
21723
+ readdirSync as readdirSync11,
21486
21724
  readFileSync as readFileSync23,
21487
21725
  realpathSync as realpathSync5,
21488
- renameSync as renameSync3,
21489
- rmSync as rmSync3,
21490
- statSync as statSync10,
21726
+ renameSync as renameSync4,
21727
+ rmSync as rmSync4,
21728
+ statSync as statSync11,
21491
21729
  writeFileSync as writeFileSync13
21492
21730
  } from "node:fs";
21493
21731
  import path36 from "node:path";
@@ -21536,14 +21774,14 @@ var explicitTargetSlug = (planText) => {
21536
21774
  var detectLegacyDocs = (workspace_root) => {
21537
21775
  const root2 = legacyRoot(workspace_root);
21538
21776
  const raw = [];
21539
- if (existsSync20(root2)) {
21540
- for (const entry of readdirSync10(root2, { withFileTypes: true })) {
21777
+ if (existsSync21(root2)) {
21778
+ for (const entry of readdirSync11(root2, { withFileTypes: true })) {
21541
21779
  const abs = path36.join(root2, entry.name);
21542
21780
  const rel = posix3(path36.relative(workspace_root, abs));
21543
21781
  if (entry.isDirectory()) {
21544
- const hasSpec = existsSync20(path36.join(abs, "spec.md"));
21545
- const hasPlan = existsSync20(path36.join(abs, "plan.md"));
21546
- if (!hasSpec && !hasPlan && !existsSync20(path36.join(abs, "sdd")))
21782
+ const hasSpec = existsSync21(path36.join(abs, "spec.md"));
21783
+ const hasPlan = existsSync21(path36.join(abs, "plan.md"));
21784
+ if (!hasSpec && !hasPlan && !existsSync21(path36.join(abs, "sdd")))
21547
21785
  continue;
21548
21786
  const explicit = explicitTargetSlug(hasPlan ? readFileSafe(path36.join(abs, "plan.md")) : null);
21549
21787
  raw.push({
@@ -21551,7 +21789,7 @@ var detectLegacyDocs = (workspace_root) => {
21551
21789
  legacy_dir: rel,
21552
21790
  spec: hasSpec ? posix3(path36.join(rel, "spec.md")) : null,
21553
21791
  plan: hasPlan ? posix3(path36.join(rel, "plan.md")) : null,
21554
- sdd: existsSync20(path36.join(abs, "sdd")),
21792
+ sdd: existsSync21(path36.join(abs, "sdd")),
21555
21793
  explicit: explicit !== null
21556
21794
  });
21557
21795
  } else if (entry.name === "spec.md" || entry.name === "plan.md") {
@@ -21679,7 +21917,7 @@ var planTree = (workspace, legacyAbs, legacyRel, destRelRoot, destAbsRoot, legac
21679
21917
  if (visits.has(real))
21680
21918
  return { ok: true };
21681
21919
  visits.add(real);
21682
- for (const entry of readdirSync10(real, { withFileTypes: true })) {
21920
+ for (const entry of readdirSync11(real, { withFileTypes: true })) {
21683
21921
  const fromAbs = path36.join(real, entry.name);
21684
21922
  const fromRel = posix3(path36.join(legacyRel, entry.name));
21685
21923
  const toRel = posix3(path36.join(destRelRoot, entry.name));
@@ -21699,7 +21937,7 @@ var planTree = (workspace, legacyAbs, legacyRel, destRelRoot, destAbsRoot, legac
21699
21937
  if (target !== workspaceReal && !target.startsWith(workspaceReal + path36.sep)) {
21700
21938
  return { ok: false, error: `symlink escape refused: ${fromRel}` };
21701
21939
  }
21702
- if (statSync10(target).isDirectory()) {
21940
+ if (statSync11(target).isDirectory()) {
21703
21941
  const sub = planTree(workspace, fromAbs, fromRel, toRel, path36.join(destAbsRoot, entry.name), legacyName, slug, plan, visits);
21704
21942
  if (!sub.ok)
21705
21943
  return sub;
@@ -21806,7 +22044,7 @@ var migrateLegacyDocs = (input) => {
21806
22044
  }
21807
22045
  const collisions = [];
21808
22046
  for (const item of plan) {
21809
- if (!existsSync20(item.destAbs))
22047
+ if (!existsSync21(item.destAbs))
21810
22048
  continue;
21811
22049
  let identical = false;
21812
22050
  try {
@@ -21847,10 +22085,10 @@ var migrateLegacyDocs = (input) => {
21847
22085
  try {
21848
22086
  mkdirSync11(path36.dirname(item.destAbs), { recursive: true });
21849
22087
  writeFileSync13(tmp, item.bytes);
21850
- renameSync3(tmp, item.destAbs);
22088
+ renameSync4(tmp, item.destAbs);
21851
22089
  } catch (error45) {
21852
22090
  try {
21853
- rmSync3(tmp, { force: true });
22091
+ rmSync4(tmp, { force: true });
21854
22092
  } catch {}
21855
22093
  return abort(`legacy migration retry required: failed to copy ${item.fromRel}: ${error45 instanceof Error ? error45.message : String(error45)}`);
21856
22094
  }
@@ -22050,7 +22288,7 @@ SDD: ${value.sdd}` : null;
22050
22288
  }
22051
22289
 
22052
22290
  // packages/workit-core/src/core/logger.ts
22053
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync12, readdirSync as readdirSync11, unlinkSync as unlinkSync3 } from "node:fs";
22291
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync12, readdirSync as readdirSync12, unlinkSync as unlinkSync3 } from "node:fs";
22054
22292
  import os4 from "node:os";
22055
22293
  import path37 from "node:path";
22056
22294
  var REDACTED = "[REDACTED]";
@@ -22185,7 +22423,7 @@ var dailyFileName = (date5) => {
22185
22423
  };
22186
22424
  var pruneOldFiles = (dir) => {
22187
22425
  try {
22188
- const files = readdirSync11(dir).filter((name) => DAY_FILE.test(name)).sort().reverse();
22426
+ const files = readdirSync12(dir).filter((name) => DAY_FILE.test(name)).sort().reverse();
22189
22427
  for (const file2 of files.slice(RETAINED_DAYS)) {
22190
22428
  try {
22191
22429
  unlinkSync3(path37.join(dir, file2));
@@ -22348,16 +22586,16 @@ var worktreeDenials = {
22348
22586
  };
22349
22587
  var hasMarkedDestination = (root3) => {
22350
22588
  const docsDir = path39.join(root3, "docs");
22351
- if (!existsSync21(docsDir))
22589
+ if (!existsSync22(docsDir))
22352
22590
  return false;
22353
22591
  let slugs;
22354
22592
  try {
22355
- slugs = readdirSync12(docsDir);
22593
+ slugs = readdirSync13(docsDir);
22356
22594
  } catch {
22357
22595
  return false;
22358
22596
  }
22359
22597
  for (const slug of slugs) {
22360
- if (!existsSync21(path39.join(docsDir, slug, "sdd", "flow.json")))
22598
+ if (!existsSync22(path39.join(docsDir, slug, "sdd", "flow.json")))
22361
22599
  continue;
22362
22600
  const effective = readEffectiveFlowState(root3, slug);
22363
22601
  if (effective.ok && effective.state.handoff_destination)
@@ -22482,7 +22720,7 @@ var plugin = async ({ client, directory }) => {
22482
22720
  const skillPath = path39.join(root2, "skills");
22483
22721
  const vendoredSkillsPath = path39.join(root2, "vendor", "superpowers", "skills");
22484
22722
  for (const p of [skillPath, vendoredSkillsPath]) {
22485
- if (existsSync21(p) && !mutable.skills.paths.includes(p)) {
22723
+ if (existsSync22(p) && !mutable.skills.paths.includes(p)) {
22486
22724
  mutable.skills.paths.push(p);
22487
22725
  }
22488
22726
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-opencode",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "private": false,
5
5
  "description": "Workit OpenCode plugin (thin wrapper over @brainervirus/workit-core)",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "typecheck": "tsc --noEmit"
35
35
  },
36
36
  "dependencies": {
37
- "@brainervirus/workit-core": "^0.9.0"
37
+ "@brainervirus/workit-core": "^0.10.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@opencode-ai/plugin": "1.17.7"