@brainervirus/workit-cli 0.9.2 → 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.
Files changed (2) hide show
  1. package/dist/index.js +1046 -392
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -42358,8 +42358,11 @@ var import_react62 = __toESM(require_react(), 1);
42358
42358
  // node_modules/@inkjs/ui/build/components/email-input/use-email-input.js
42359
42359
  var import_react63 = __toESM(require_react(), 1);
42360
42360
  var cursor3 = source_default.inverse(" ");
42361
+ // packages/workit-cli/src/index.tsx
42362
+ var import_react67 = __toESM(require_react(), 1);
42363
+
42361
42364
  // packages/workit-cli/src/steps.tsx
42362
- var import_react65 = __toESM(require_react(), 1);
42365
+ var import_react66 = __toESM(require_react(), 1);
42363
42366
 
42364
42367
  // packages/workit-core/src/core/config.ts
42365
42368
  import {
@@ -42463,7 +42466,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
42463
42466
  return dir;
42464
42467
  };
42465
42468
  var configDir = () => ensureConfigDir();
42466
- var LOCALE_RE = /^[a-z]{2,3}(-[A-Z]{2})?$/;
42469
+ var LOCALE_RE = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
42467
42470
  var DEFAULTS = {
42468
42471
  locale: "en",
42469
42472
  localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
@@ -44849,7 +44852,7 @@ function applyWizardBranchPolicy(branchPolicy, workspace_root, env3 = process.en
44849
44852
  }
44850
44853
 
44851
44854
  // packages/workit-cli/src/wizard-state.ts
44852
- import { existsSync as existsSync9 } from "node:fs";
44855
+ import { existsSync as existsSync9, statSync as statSync4 } from "node:fs";
44853
44856
  import path11 from "node:path";
44854
44857
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
44855
44858
  var NEXT = {
@@ -44860,9 +44863,11 @@ var NEXT = {
44860
44863
  timezoneOther: "branchPreset",
44861
44864
  branchPreset: "branchAllowed",
44862
44865
  branchAllowed: "branchProtected",
44863
- branchProtected: "youtrack",
44866
+ branchProtected: "issueTracker",
44867
+ issueTracker: "youtrack",
44864
44868
  youtrack: "vcs",
44865
- vcs: "workspaces",
44869
+ vcs: "basePath",
44870
+ basePath: "workspaces",
44866
44871
  workspaces: "branchPolicy",
44867
44872
  workspaceName: "workspaceGlob",
44868
44873
  workspaceGlob: "workspaceProvider",
@@ -44882,9 +44887,11 @@ var PREV = {
44882
44887
  branchPreset: "timezone",
44883
44888
  branchAllowed: "branchPreset",
44884
44889
  branchProtected: "branchAllowed",
44885
- youtrack: "branchProtected",
44890
+ issueTracker: "branchProtected",
44891
+ youtrack: "issueTracker",
44886
44892
  vcs: "youtrack",
44887
- workspaces: "vcs",
44893
+ basePath: "vcs",
44894
+ workspaces: "basePath",
44888
44895
  workspaceName: "workspaces",
44889
44896
  workspaceGlob: "workspaceName",
44890
44897
  workspaceProvider: "workspaceGlob",
@@ -44895,16 +44902,34 @@ var PREV = {
44895
44902
  exit: null
44896
44903
  };
44897
44904
  var skipsCustomBranch = (screen, preset) => (screen === "branchAllowed" || screen === "branchProtected") && preset !== "custom";
44898
- var skipsBranchPolicy = (screen) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync9(path11.join(process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), ".git"));
44899
- function nextScreen(screen, preset) {
44905
+ var skipsYoutrack = (screen, tracker) => screen === "youtrack" && tracker !== "youtrack";
44906
+ var skipsBasePath = (screen, basePath) => screen === "basePath" && basePath !== "";
44907
+ function resolveBasePath(values2, env3 = process.env) {
44908
+ return env3.WORKFLOW_WORKSPACE_ROOT?.trim() || values2.basePath.trim();
44909
+ }
44910
+ var isDirectory = (p) => {
44911
+ try {
44912
+ return statSync4(p).isDirectory();
44913
+ } catch {
44914
+ return false;
44915
+ }
44916
+ };
44917
+ var basePathMessage = (value) => {
44918
+ const p = value.trim();
44919
+ if (!p)
44920
+ return "workspace root path is required";
44921
+ return !path11.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
44922
+ };
44923
+ var skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync9(path11.join(basePath, ".git"));
44924
+ function nextScreen(screen, preset, tracker, basePath) {
44900
44925
  let next = NEXT[screen];
44901
- while (next && (skipsCustomBranch(next, preset) || skipsBranchPolicy(next)))
44926
+ while (next && (skipsCustomBranch(next, preset) || skipsBranchPolicy(next, basePath) || skipsYoutrack(next, tracker) || skipsBasePath(next, basePath)))
44902
44927
  next = NEXT[next];
44903
44928
  return next ?? screen;
44904
44929
  }
44905
- function prevScreen(screen, preset) {
44930
+ function prevScreen(screen, preset, tracker, basePath) {
44906
44931
  let prev = PREV[screen];
44907
- while (prev && (skipsCustomBranch(prev, preset) || skipsBranchPolicy(prev)))
44932
+ while (prev && (skipsCustomBranch(prev, preset) || skipsBranchPolicy(prev, basePath) || skipsYoutrack(prev, tracker) || skipsBasePath(prev, basePath)))
44908
44933
  prev = PREV[prev];
44909
44934
  return prev ?? screen;
44910
44935
  }
@@ -44935,6 +44960,10 @@ function validateScreen(draft) {
44935
44960
  const error = validateBaseUrl(values2.baseUrl);
44936
44961
  return error ? { field: "baseUrl", message: error } : null;
44937
44962
  }
44963
+ case "basePath": {
44964
+ const message = basePathMessage(values2.basePath);
44965
+ return message ? { field: "basePath", message } : null;
44966
+ }
44938
44967
  case "workspaceName":
44939
44968
  return (draft.workspaceDraft?.name ?? "").trim() ? null : { field: "workspaceName", message: "workspace name is required" };
44940
44969
  case "workspaceGlob": {
@@ -44950,8 +44979,9 @@ function validateScreen(draft) {
44950
44979
  }
44951
44980
  var decodeBranchPreset = (value, fallback) => value === "gitflow" || value === "github-flow" || value === "trunk-based" || value === "custom" ? value : fallback;
44952
44981
  var decodeVcsProvider = (value, fallback) => value === "gitlab" || value === "github" || value === "skip" ? value : fallback;
44982
+ var decodeIssueTracker = (value, fallback) => value === "youtrack" || value === "github" || value === "none" ? value : fallback;
44953
44983
  function setTextValue(draft, field, value) {
44954
- const message = field === "locale" ? validateLocale(value) : field === "timezone" ? validateTimezone(value) : field === "branchAllowed" ? parseList(value).length > 0 ? null : "at least one allowed branch pattern is required" : field === "branchProtected" ? parseList(value).length > 0 ? null : "at least one protected branch name is required" : value.trim() === "" ? null : validateBaseUrl(value);
44984
+ const message = field === "locale" ? validateLocale(value) : field === "timezone" ? validateTimezone(value) : field === "branchAllowed" ? parseList(value).length > 0 ? null : "at least one allowed branch pattern is required" : field === "branchProtected" ? parseList(value).length > 0 ? null : "at least one protected branch name is required" : field === "basePath" ? basePathMessage(value) : value.trim() === "" ? null : validateBaseUrl(value);
44955
44985
  if (draft.values[field] === value && (draft.errors[field] ?? undefined) === (message ?? undefined)) {
44956
44986
  return draft;
44957
44987
  }
@@ -44974,6 +45004,8 @@ function createInitialDraft(config = readConfig()) {
44974
45004
  branchAllowed: policy.allowed.join(", "),
44975
45005
  branchProtected: policy.protected.join(", "),
44976
45006
  baseUrl: "",
45007
+ basePath: process.env.WORKFLOW_WORKSPACE_ROOT ?? "",
45008
+ issueTracker: "youtrack",
44977
45009
  vcsProvider: "gitlab",
44978
45010
  workspaces: loadWorkspaces(),
44979
45011
  applyProject: false
@@ -45004,6 +45036,26 @@ function reducer3(draft, action) {
45004
45036
  return draft;
45005
45037
  return { ...draft, values: { ...draft.values, vcsProvider: next } };
45006
45038
  }
45039
+ case "issueTracker": {
45040
+ const next = decodeIssueTracker(action.value, draft.values.issueTracker);
45041
+ if (next === draft.values.issueTracker)
45042
+ return draft;
45043
+ const stripIssues = ({ issues: _, ...rest2 }) => rest2;
45044
+ const needsStrip = next !== "github" && (draft.values.workspaces.some((w) => w.issues !== undefined) || draft.workspaceDraft?.issues !== undefined);
45045
+ const errors = { ...draft.errors };
45046
+ delete errors.baseUrl;
45047
+ return {
45048
+ ...draft,
45049
+ errors,
45050
+ workspaceDraft: needsStrip && draft.workspaceDraft ? stripIssues(draft.workspaceDraft) : draft.workspaceDraft,
45051
+ values: {
45052
+ ...draft.values,
45053
+ issueTracker: next,
45054
+ baseUrl: next === "youtrack" ? draft.values.baseUrl : "",
45055
+ workspaces: needsStrip ? draft.values.workspaces.map(stripIssues) : draft.values.workspaces
45056
+ }
45057
+ };
45058
+ }
45007
45059
  case "applyProject":
45008
45060
  if (action.value === draft.values.applyProject)
45009
45061
  return draft;
@@ -45071,10 +45123,16 @@ function reducer3(draft, action) {
45071
45123
  const invalid = validateScreen(draft);
45072
45124
  if (invalid)
45073
45125
  return { ...draft, errors: { ...draft.errors, [invalid.field]: invalid.message } };
45074
- return { ...draft, screen: nextScreen(draft.screen, draft.values.branchPreset) };
45126
+ return {
45127
+ ...draft,
45128
+ screen: nextScreen(draft.screen, draft.values.branchPreset, draft.values.issueTracker, resolveBasePath(draft.values))
45129
+ };
45075
45130
  }
45076
45131
  case "back":
45077
- return { ...draft, screen: prevScreen(draft.screen, draft.values.branchPreset) };
45132
+ return {
45133
+ ...draft,
45134
+ screen: prevScreen(draft.screen, draft.values.branchPreset, draft.values.issueTracker, resolveBasePath(draft.values))
45135
+ };
45078
45136
  case "cancel":
45079
45137
  return { ...draft, screen: "exit", cancelled: true };
45080
45138
  case "apply":
@@ -45084,11 +45142,13 @@ function reducer3(draft, action) {
45084
45142
  ...draft,
45085
45143
  screen: "workspaceName",
45086
45144
  workspaceIndex: null,
45087
- workspaceDraft: {
45145
+ workspaceDraft: withGithubIssues({
45088
45146
  name: "",
45089
45147
  glob: "",
45090
- vcs: { provider: defaultWorkspaceProvider(draft.values.vcsProvider) }
45091
- },
45148
+ vcs: {
45149
+ provider: defaultWorkspaceProvider(draft.values.vcsProvider, draft.values.issueTracker)
45150
+ }
45151
+ }, draft.values.issueTracker),
45092
45152
  errors: {}
45093
45153
  };
45094
45154
  case "workspaceAddCurrent": {
@@ -45103,11 +45163,13 @@ function reducer3(draft, action) {
45103
45163
  ...draft.values,
45104
45164
  workspaces: [
45105
45165
  ...draft.values.workspaces,
45106
- {
45166
+ withGithubIssues({
45107
45167
  name,
45108
45168
  glob: `${p}/**`,
45109
- vcs: { provider: defaultWorkspaceProvider(draft.values.vcsProvider) }
45110
- }
45169
+ vcs: {
45170
+ provider: defaultWorkspaceProvider(draft.values.vcsProvider, draft.values.issueTracker)
45171
+ }
45172
+ }, draft.values.issueTracker)
45111
45173
  ]
45112
45174
  }
45113
45175
  };
@@ -45168,9 +45230,13 @@ function reducer3(draft, action) {
45168
45230
  }
45169
45231
  }
45170
45232
  }
45171
- function defaultWorkspaceProvider(vcs) {
45233
+ function defaultWorkspaceProvider(vcs, tracker) {
45234
+ if (tracker === "github")
45235
+ return "github";
45172
45236
  return vcs === "gitlab" || vcs === "github" ? vcs : "gitlab";
45173
45237
  }
45238
+ var GITHUB_ISSUES = { provider: "github", link_on_pr: true };
45239
+ var withGithubIssues = (draft, tracker) => tracker === "github" ? { ...draft, issues: { ...GITHUB_ISSUES } } : draft;
45174
45240
  function workspaceDraftText(draft, field, value) {
45175
45241
  const errorKey = field === "name" ? "workspaceName" : "workspaceGlob";
45176
45242
  const message = field === "name" ? value.trim() ? null : "workspace name is required" : value.trim() ? null : "workspace pattern is required";
@@ -45192,8 +45258,99 @@ function workspaceDraftText(draft, field, value) {
45192
45258
  };
45193
45259
  }
45194
45260
 
45195
- // packages/workit-cli/src/steps.tsx
45261
+ // packages/workit-cli/src/search-select.tsx
45262
+ var import_react65 = __toESM(require_react(), 1);
45196
45263
  var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
45264
+ var LOCALE_LANGUAGE_MAP = [
45265
+ { label: "Español (España)", locale: "es-ES" },
45266
+ { label: "Español (Latinoamérica)", locale: "es-419" },
45267
+ { label: "Español (Chile)", locale: "es-CL" },
45268
+ { label: "Español (México)", locale: "es-MX" },
45269
+ { label: "Español (Argentina)", locale: "es-AR" },
45270
+ { label: "English", locale: "en" },
45271
+ { label: "English (United States)", locale: "en-US" },
45272
+ { label: "English (United Kingdom)", locale: "en-GB" },
45273
+ { label: "Português (Brasil)", locale: "pt-BR" },
45274
+ { label: "Português (Portugal)", locale: "pt-PT" },
45275
+ { label: "Français (France)", locale: "fr-FR" },
45276
+ { label: "Français (Canada)", locale: "fr-CA" },
45277
+ { label: "Deutsch (Deutschland)", locale: "de-DE" },
45278
+ { label: "中文(简体)", locale: "zh-CN" },
45279
+ { label: "中文(繁體)", locale: "zh-TW" },
45280
+ { label: "日本語", locale: "ja-JP" },
45281
+ { label: "한국어", locale: "ko-KR" },
45282
+ { label: "Italiano", locale: "it-IT" },
45283
+ { label: "Русский", locale: "ru-RU" },
45284
+ { label: "العربية", locale: "ar-SA" },
45285
+ { label: "हिन्दी", locale: "hi-IN" },
45286
+ { label: "Nederlands (Nederland)", locale: "nl-NL" },
45287
+ { label: "Polski (Polska)", locale: "pl-PL" },
45288
+ { label: "Türkçe (Türkiye)", locale: "tr-TR" },
45289
+ { label: "Svenska (Sverige)", locale: "sv-SE" }
45290
+ ];
45291
+ var VISIBLE_ROWS = 5;
45292
+ var fold = (s) => s.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
45293
+ function filterOptions(options, query, limit = VISIBLE_ROWS) {
45294
+ const q = fold(query.trim().toLowerCase());
45295
+ if (!q)
45296
+ return options.slice(0, limit);
45297
+ return options.filter((option) => fold(option.label.toLowerCase()).includes(q) || fold(option.value.toLowerCase()).includes(q)).slice(0, limit);
45298
+ }
45299
+ function SearchSelect({
45300
+ options,
45301
+ value,
45302
+ placeholder,
45303
+ onSelect,
45304
+ onQueryChange
45305
+ }) {
45306
+ const [query, setQuery] = import_react65.useState("");
45307
+ const filtered = import_react65.useMemo(() => filterOptions(options, query), [options, query]);
45308
+ const [rawIndex, setRawIndex] = import_react65.useState(() => Math.max(0, options.findIndex((option) => option.value === value)));
45309
+ const index = Math.min(rawIndex, Math.max(0, filtered.length - 1));
45310
+ use_input_default((input, key) => {
45311
+ const type = (next) => {
45312
+ onQueryChange?.(next);
45313
+ setQuery(next);
45314
+ setRawIndex(0);
45315
+ };
45316
+ if (key.downArrow) {
45317
+ setRawIndex(Math.min(index + 1, filtered.length - 1));
45318
+ } else if (key.upArrow) {
45319
+ setRawIndex(Math.max(index - 1, 0));
45320
+ } else if (key.return) {
45321
+ if (filtered[index])
45322
+ onSelect(filtered[index].value);
45323
+ } else if (key.backspace || key.delete) {
45324
+ type(query.slice(0, -1));
45325
+ } else if (input && !key.ctrl && !key.meta && !key.escape && !key.tab) {
45326
+ type(query + input);
45327
+ }
45328
+ });
45329
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45330
+ flexDirection: "column",
45331
+ gap: 0,
45332
+ children: [
45333
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
45334
+ isDisabled: true,
45335
+ defaultValue: query,
45336
+ placeholder
45337
+ }, query, false, undefined, this),
45338
+ filtered.length === 0 ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45339
+ dimColor: true,
45340
+ children: "No matches"
45341
+ }, undefined, false, undefined, this) : filtered.map((option, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45342
+ color: i === index ? "cyan" : "dim",
45343
+ children: [
45344
+ i === index ? "❯ " : " ",
45345
+ option.label
45346
+ ]
45347
+ }, option.value, true, undefined, this))
45348
+ ]
45349
+ }, undefined, true, undefined, this);
45350
+ }
45351
+
45352
+ // packages/workit-cli/src/steps.tsx
45353
+ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
45197
45354
  var PLATFORMS = [
45198
45355
  { label: "OpenCode", value: "opencode" },
45199
45356
  { label: "Cursor", value: "cursor" }
@@ -45204,23 +45361,77 @@ var BRANCH_PRESETS = [
45204
45361
  { label: "Trunk-based", value: "trunk-based" },
45205
45362
  { label: "Custom", value: "custom" }
45206
45363
  ];
45364
+ var BRANCH_PRESET_DESCRIPTIONS = {
45365
+ gitflow: `${PRESETS.gitflow.allowed.join(", ")} allowed · ` + `${PRESETS.gitflow.protected.join(", ")} protected · work merges into develop via PRs or merge commits`,
45366
+ "github-flow": `Anything goes (${PRESETS["github-flow"].allowed[0]}) · only ${PRESETS["github-flow"].protected.join(", ")} is protected · branches off main, back to main`,
45367
+ "trunk-based": `Short-lived branches off trunk · ${PRESETS["trunk-based"].protected.join(", ")} is the only protected branch`,
45368
+ custom: "Define your own allowed and protected patterns in the next prompts"
45369
+ };
45370
+ var SCREEN_PLACEHOLDERS = {
45371
+ youtrack: "e.g. https://example.youtrack.cloud",
45372
+ localeOther: "e.g. en-US or es-CL",
45373
+ timezoneOther: "e.g. America/Santiago",
45374
+ branchAllowed: "e.g. feature/*, bugfix/*",
45375
+ branchProtected: "e.g. main, develop",
45376
+ workspaceName: "e.g. work",
45377
+ workspaceGlob: "e.g. /work/**",
45378
+ branchPolicyDevelop: "e.g. develop"
45379
+ };
45207
45380
  var VCS_PROVIDERS = [
45208
45381
  { label: "GitLab", value: "gitlab" },
45209
45382
  { label: "GitHub", value: "github" },
45210
45383
  { label: "Skip — configure later", value: "skip" }
45211
45384
  ];
45212
- var LOCALE_CHOICES = ["en", "es-CL"];
45213
- var TIMEZONE_CHOICES = ["UTC", "America/New_York", "Europe/London"];
45385
+ var LOCALE_PICKER_OPTIONS = [
45386
+ ...LOCALE_LANGUAGE_MAP.map((entry) => ({ label: entry.label, value: entry.locale })),
45387
+ { label: "Other…", value: "other" }
45388
+ ];
45389
+ var ISSUE_TRACKERS = [
45390
+ { label: "YouTrack", value: "youtrack" },
45391
+ { label: "GitHub Issues", value: "github" },
45392
+ { label: "None", value: "none" }
45393
+ ];
45394
+ var TIMEZONE_FALLBACK = [
45395
+ "UTC",
45396
+ "America/New_York",
45397
+ "America/Santiago",
45398
+ "America/Bogota",
45399
+ "America/Mexico_City",
45400
+ "America/Sao_Paulo",
45401
+ "America/Argentina/Buenos_Aires",
45402
+ "Europe/London",
45403
+ "Europe/Madrid",
45404
+ "Europe/Berlin",
45405
+ "Asia/Tokyo",
45406
+ "Asia/Shanghai",
45407
+ "Asia/Kolkata",
45408
+ "Australia/Sydney"
45409
+ ];
45410
+ var TIMEZONES = typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("timeZone") : TIMEZONE_FALLBACK;
45411
+ var DETECTED_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
45412
+ function timezonePickerOptions() {
45413
+ return TIMEZONE_PICKER_OPTIONS;
45414
+ }
45415
+ var TIMEZONE_PICKER_OPTIONS = [
45416
+ { label: DETECTED_TIMEZONE, value: DETECTED_TIMEZONE },
45417
+ ...TIMEZONES.filter((timezone) => timezone !== DETECTED_TIMEZONE).map((timezone) => ({
45418
+ label: timezone,
45419
+ value: timezone
45420
+ })),
45421
+ { label: "Other…", value: "other" }
45422
+ ];
45214
45423
  var TEXT_SCREENS = new Set([
45215
45424
  "localeOther",
45216
45425
  "timezoneOther",
45217
45426
  "branchAllowed",
45218
45427
  "branchProtected",
45219
45428
  "youtrack",
45429
+ "basePath",
45220
45430
  "workspaceName",
45221
45431
  "workspaceGlob",
45222
45432
  "branchPolicyDevelop"
45223
45433
  ]);
45434
+ var SEARCH_SCREENS = new Set(["locale", "timezone"]);
45224
45435
  function workspacePreviewTargets(cwd2) {
45225
45436
  const norm = cwd2.replace(/[\\/]+$/, "");
45226
45437
  const idx = norm.lastIndexOf("/");
@@ -45233,28 +45444,25 @@ function SelectList({
45233
45444
  onChange,
45234
45445
  onSelect
45235
45446
  }) {
45236
- const [index, setIndex] = import_react65.useState(() => Math.max(0, options.findIndex((option) => option.value === value)));
45447
+ const [index, setIndex] = import_react66.useState(() => Math.max(0, options.findIndex((option) => option.value === value)));
45448
+ const indexRef = import_react66.useRef(index);
45449
+ indexRef.current = index;
45237
45450
  use_input_default((_input, key) => {
45238
- if (key.downArrow) {
45239
- setIndex((i) => {
45240
- const next = Math.min(i + 1, options.length - 1);
45241
- onChange?.(options[next].value);
45242
- return next;
45243
- });
45244
- } else if (key.upArrow) {
45245
- setIndex((i) => {
45246
- const next = Math.max(i - 1, 0);
45247
- onChange?.(options[next].value);
45248
- return next;
45249
- });
45451
+ if (key.downArrow || key.upArrow) {
45452
+ const next = key.downArrow ? Math.min(indexRef.current + 1, options.length - 1) : Math.max(indexRef.current - 1, 0);
45453
+ if (next === indexRef.current)
45454
+ return;
45455
+ indexRef.current = next;
45456
+ setIndex(next);
45457
+ onChange?.(options[next].value);
45250
45458
  } else if (key.return) {
45251
- onSelect(options[index].value);
45459
+ onSelect(options[indexRef.current].value);
45252
45460
  }
45253
45461
  });
45254
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45462
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45255
45463
  flexDirection: "column",
45256
45464
  gap: 0,
45257
- children: options.map((option, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45465
+ children: options.map((option, i) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45258
45466
  color: i === index ? "cyan" : "dim",
45259
45467
  children: [
45260
45468
  i === index ? "❯ " : " ",
@@ -45263,16 +45471,6 @@ function SelectList({
45263
45471
  }, option.value, true, undefined, this))
45264
45472
  }, undefined, false, undefined, this);
45265
45473
  }
45266
- function localeOptions(current) {
45267
- const fixed = LOCALE_CHOICES.map((locale) => ({ label: locale, value: locale }));
45268
- const list = LOCALE_CHOICES.includes(current) ? fixed : [...fixed, { label: `Use current (${current})`, value: current }];
45269
- return [...list, { label: "Other…", value: "other" }];
45270
- }
45271
- function timezoneOptions(current) {
45272
- const fixed = TIMEZONE_CHOICES.map((timezone) => ({ label: timezone, value: timezone }));
45273
- const list = TIMEZONE_CHOICES.includes(current) ? fixed : [...fixed, { label: `Use current (${current})`, value: current }];
45274
- return [...list, { label: "Other…", value: "other" }];
45275
- }
45276
45474
  function effectivePolicy(values2) {
45277
45475
  return mergePreset(values2.branchPreset, {
45278
45476
  allowed: parseList(values2.branchAllowed),
@@ -45292,26 +45490,26 @@ var INTEGRATION_OPTIONS = [
45292
45490
  function BranchPolicyScreen({ draft, dispatch }) {
45293
45491
  const detected = draft.values.branchPolicyDetected;
45294
45492
  const policy = draft.values.branchPolicy ?? detected;
45295
- const [mode, setMode] = import_react65.useState("menu");
45296
- import_react65.useEffect(() => {
45493
+ const [mode, setMode] = import_react66.useState("menu");
45494
+ import_react66.useEffect(() => {
45297
45495
  if (detected)
45298
45496
  return;
45299
45497
  dispatch({
45300
45498
  type: "set",
45301
45499
  field: "branchPolicyDetected",
45302
- value: detectBranchPolicy(process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd())
45500
+ value: detectBranchPolicy(resolveBasePath(draft.values))
45303
45501
  });
45304
45502
  }, [detected, dispatch]);
45305
45503
  if (mode === "integration") {
45306
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45504
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45307
45505
  flexDirection: "column",
45308
45506
  gap: 1,
45309
45507
  children: [
45310
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45508
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45311
45509
  bold: true,
45312
45510
  children: "Step 5 — Branch policy · Integration"
45313
45511
  }, undefined, false, undefined, this),
45314
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
45512
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45315
45513
  options: INTEGRATION_OPTIONS,
45316
45514
  value: policy?.integration ?? "merge",
45317
45515
  onSelect: (value) => {
@@ -45319,77 +45517,77 @@ function BranchPolicyScreen({ draft, dispatch }) {
45319
45517
  setMode("menu");
45320
45518
  }
45321
45519
  }, undefined, false, undefined, this),
45322
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45520
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45323
45521
  dimColor: true,
45324
45522
  children: "Enter to select · b Back · Esc Cancel"
45325
45523
  }, undefined, false, undefined, this)
45326
45524
  ]
45327
45525
  }, undefined, true, undefined, this);
45328
45526
  }
45329
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45527
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45330
45528
  flexDirection: "column",
45331
45529
  gap: 1,
45332
45530
  children: [
45333
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45531
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45334
45532
  bold: true,
45335
45533
  children: "Step 5 — Branch policy"
45336
45534
  }, undefined, false, undefined, this),
45337
- policy ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45535
+ policy ? /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45338
45536
  flexDirection: "column",
45339
45537
  gap: 0,
45340
45538
  children: [
45341
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45539
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45342
45540
  children: [
45343
45541
  "Detected preset: ",
45344
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45542
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45345
45543
  color: "green",
45346
45544
  children: policy.preset
45347
45545
  }, undefined, false, undefined, this)
45348
45546
  ]
45349
45547
  }, undefined, true, undefined, this),
45350
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45548
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45351
45549
  children: [
45352
45550
  "Develop branch: ",
45353
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45551
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45354
45552
  color: "green",
45355
45553
  children: policy.developBranch ?? "—"
45356
45554
  }, undefined, false, undefined, this)
45357
45555
  ]
45358
45556
  }, undefined, true, undefined, this),
45359
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45557
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45360
45558
  children: [
45361
45559
  "Integration: ",
45362
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45560
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45363
45561
  color: "green",
45364
45562
  children: policy.integration
45365
45563
  }, undefined, false, undefined, this)
45366
45564
  ]
45367
45565
  }, undefined, true, undefined, this),
45368
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45566
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45369
45567
  children: [
45370
45568
  "Prefixes:",
45371
45569
  " ",
45372
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45570
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45373
45571
  color: "green",
45374
45572
  children: Object.values(policy.prefixes ?? {}).join(", ") || "—"
45375
45573
  }, undefined, false, undefined, this)
45376
45574
  ]
45377
45575
  }, undefined, true, undefined, this),
45378
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45576
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45379
45577
  children: [
45380
45578
  "Protected: ",
45381
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45579
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45382
45580
  color: "green",
45383
45581
  children: policy.protected?.join(", ") || "—"
45384
45582
  }, undefined, false, undefined, this)
45385
45583
  ]
45386
45584
  }, undefined, true, undefined, this)
45387
45585
  ]
45388
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45586
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45389
45587
  dimColor: true,
45390
45588
  children: "Detecting branch policy…"
45391
45589
  }, undefined, false, undefined, this),
45392
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
45590
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45393
45591
  options: BRANCH_POLICY_ACTIONS,
45394
45592
  value: "accept",
45395
45593
  onSelect: (value) => {
@@ -45405,7 +45603,7 @@ function BranchPolicyScreen({ draft, dispatch }) {
45405
45603
  dispatch({ type: "next" });
45406
45604
  }
45407
45605
  }, undefined, false, undefined, this),
45408
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45606
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45409
45607
  dimColor: true,
45410
45608
  children: "Enter to continue · b Back · Esc Cancel"
45411
45609
  }, undefined, false, undefined, this)
@@ -45415,8 +45613,12 @@ function BranchPolicyScreen({ draft, dispatch }) {
45415
45613
  function Wizard({
45416
45614
  onExit
45417
45615
  }) {
45418
- const [draft, dispatch] = import_react65.useReducer(reducer3, undefined, createInitialDraft);
45419
- const exitedRef = import_react65.useRef(false);
45616
+ const [draft, dispatch] = import_react66.useReducer(reducer3, undefined, createInitialDraft);
45617
+ const exitedRef = import_react66.useRef(false);
45618
+ const searchRef = import_react66.useRef({ q: "", typed: false });
45619
+ import_react66.useEffect(() => {
45620
+ searchRef.current = { q: "", typed: false };
45621
+ }, [draft.screen]);
45420
45622
  use_input_default((input, key) => {
45421
45623
  if (key.ctrl && input.toLowerCase() === "c") {
45422
45624
  dispatch({ type: "cancel" });
@@ -45426,27 +45628,36 @@ function Wizard({
45426
45628
  else
45427
45629
  dispatch({ type: "cancel" });
45428
45630
  } else if (input.toLowerCase() === "b" && !TEXT_SCREENS.has(draft.screen)) {
45429
- dispatch({ type: "back" });
45631
+ const search = searchRef.current;
45632
+ const searchOwnsB = SEARCH_SCREENS.has(draft.screen) && !(search.typed && search.q === "");
45633
+ if (!searchOwnsB)
45634
+ dispatch({ type: "back" });
45430
45635
  }
45431
45636
  });
45432
- import_react65.useEffect(() => {
45637
+ import_react66.useEffect(() => {
45433
45638
  if (draft.screen === "exit" && !exitedRef.current) {
45434
45639
  exitedRef.current = true;
45435
45640
  onExit(!draft.cancelled, draft.values);
45436
45641
  }
45437
45642
  }, [draft.screen, draft.cancelled, onExit]);
45438
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45643
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45439
45644
  flexDirection: "column",
45440
45645
  gap: 1,
45441
45646
  children: [
45442
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45647
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45443
45648
  bold: true,
45444
45649
  color: "cyan",
45445
45650
  children: "workit — workflow rails for agentic coding"
45446
45651
  }, undefined, false, undefined, this),
45447
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Screen, {
45652
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Screen, {
45448
45653
  draft,
45449
- dispatch
45654
+ dispatch,
45655
+ onSearchQueryChange: (query) => {
45656
+ const search = searchRef.current;
45657
+ search.q = query;
45658
+ if (query !== "")
45659
+ search.typed = true;
45660
+ }
45450
45661
  }, draft.screen, false, undefined, this)
45451
45662
  ]
45452
45663
  }, undefined, true, undefined, this);
@@ -45469,22 +45680,56 @@ function describeMutation(m) {
45469
45680
  return `+ change ${m.key} in ${m.path} → ${m.value}`;
45470
45681
  }
45471
45682
  }
45472
- function Screen({ draft, dispatch }) {
45683
+ function BasePathScreen({ draft, dispatch }) {
45684
+ const onChange = import_react66.useCallback((value) => dispatch({ type: "set", field: "basePath", value }), [dispatch]);
45685
+ const onSubmit = import_react66.useCallback((value) => {
45686
+ dispatch({ type: "set", field: "basePath", value });
45687
+ dispatch({ type: "next" });
45688
+ }, [dispatch]);
45689
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45690
+ flexDirection: "column",
45691
+ gap: 1,
45692
+ children: [
45693
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45694
+ bold: true,
45695
+ children: "Step 5 — Workspace root"
45696
+ }, undefined, false, undefined, this),
45697
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45698
+ dimColor: true,
45699
+ children: "Absolute path where your projects live (e.g. /work):"
45700
+ }, undefined, false, undefined, this),
45701
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
45702
+ defaultValue: draft.values.basePath,
45703
+ onChange,
45704
+ onSubmit
45705
+ }, undefined, false, undefined, this),
45706
+ draft.errors.basePath && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45707
+ color: "red",
45708
+ children: draft.errors.basePath
45709
+ }, undefined, false, undefined, this),
45710
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45711
+ dimColor: true,
45712
+ children: "Enter to continue · Esc Back"
45713
+ }, undefined, false, undefined, this)
45714
+ ]
45715
+ }, undefined, true, undefined, this);
45716
+ }
45717
+ function Screen({ draft, dispatch, onSearchQueryChange }) {
45473
45718
  switch (draft.screen) {
45474
45719
  case "platforms":
45475
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45720
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45476
45721
  flexDirection: "column",
45477
45722
  gap: 1,
45478
45723
  children: [
45479
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45724
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45480
45725
  bold: true,
45481
45726
  children: "Step 1 — Platforms"
45482
45727
  }, undefined, false, undefined, this),
45483
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45728
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45484
45729
  dimColor: true,
45485
45730
  children: "Select the tools to configure (space to toggle):"
45486
45731
  }, undefined, false, undefined, this),
45487
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(MultiSelect, {
45732
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(MultiSelect, {
45488
45733
  options: PLATFORMS,
45489
45734
  defaultValue: draft.values.platforms,
45490
45735
  onChange: (values2) => dispatch({ type: "set", field: "platforms", value: values2 }),
@@ -45493,36 +45738,43 @@ function Screen({ draft, dispatch }) {
45493
45738
  dispatch({ type: "next" });
45494
45739
  }
45495
45740
  }, undefined, false, undefined, this),
45496
- draft.errors.platforms && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45741
+ draft.errors.platforms && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45497
45742
  color: "red",
45498
45743
  children: draft.errors.platforms
45499
45744
  }, undefined, false, undefined, this),
45500
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45745
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45501
45746
  dimColor: true,
45502
45747
  children: "Enter to continue · Esc Cancel"
45503
45748
  }, undefined, false, undefined, this)
45504
45749
  ]
45505
45750
  }, undefined, true, undefined, this);
45506
45751
  case "locale":
45507
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45752
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45508
45753
  flexDirection: "column",
45509
45754
  gap: 1,
45510
45755
  children: [
45511
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45756
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45512
45757
  bold: true,
45513
45758
  children: "Step 2 — Global config · Locale"
45514
45759
  }, undefined, false, undefined, this),
45515
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45760
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45516
45761
  dimColor: true,
45517
45762
  children: "Locale (BCP-47):"
45518
45763
  }, undefined, false, undefined, this),
45519
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
45520
- options: localeOptions(draft.values.locale),
45764
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45765
+ children: [
45766
+ "Current: ",
45767
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45768
+ color: "green",
45769
+ children: draft.values.locale
45770
+ }, undefined, false, undefined, this)
45771
+ ]
45772
+ }, undefined, true, undefined, this),
45773
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SearchSelect, {
45774
+ options: LOCALE_PICKER_OPTIONS,
45521
45775
  value: draft.values.locale,
45522
- onChange: (value) => {
45523
- if (value !== "other")
45524
- dispatch({ type: "set", field: "locale", value });
45525
- },
45776
+ placeholder: "Type to search languages…",
45777
+ onQueryChange: onSearchQueryChange,
45526
45778
  onSelect: (value) => {
45527
45779
  if (value === "other")
45528
45780
  dispatch({ type: "pickOther" });
@@ -45532,63 +45784,71 @@ function Screen({ draft, dispatch }) {
45532
45784
  }
45533
45785
  }
45534
45786
  }, undefined, false, undefined, this),
45535
- draft.errors.locale && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45787
+ draft.errors.locale && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45536
45788
  color: "red",
45537
45789
  children: draft.errors.locale
45538
45790
  }, undefined, false, undefined, this),
45539
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45791
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45540
45792
  dimColor: true,
45541
- children: "Enter to continue · b Back · Esc Cancel"
45793
+ children: "Type to filter · Enter to continue · b Back · Esc Cancel"
45542
45794
  }, undefined, false, undefined, this)
45543
45795
  ]
45544
45796
  }, undefined, true, undefined, this);
45545
45797
  case "localeOther":
45546
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45798
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45547
45799
  flexDirection: "column",
45548
45800
  gap: 1,
45549
45801
  children: [
45550
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45802
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45551
45803
  bold: true,
45552
45804
  children: "Step 2 — Global config · Locale (custom)"
45553
45805
  }, undefined, false, undefined, this),
45554
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45806
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45555
45807
  dimColor: true,
45556
45808
  children: "Type a BCP-47 locale (e.g. en or es-CL):"
45557
45809
  }, undefined, false, undefined, this),
45558
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
45810
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
45811
+ placeholder: SCREEN_PLACEHOLDERS.localeOther,
45559
45812
  onChange: (value) => dispatch({ type: "set", field: "locale", value }),
45560
45813
  onSubmit: () => dispatch({ type: "next" })
45561
45814
  }, undefined, false, undefined, this),
45562
- draft.errors.locale && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45815
+ draft.errors.locale && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45563
45816
  color: "red",
45564
45817
  children: draft.errors.locale
45565
45818
  }, undefined, false, undefined, this),
45566
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45819
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45567
45820
  dimColor: true,
45568
45821
  children: "Enter to continue · Esc Back"
45569
45822
  }, undefined, false, undefined, this)
45570
45823
  ]
45571
45824
  }, undefined, true, undefined, this);
45572
45825
  case "timezone":
45573
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45826
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45574
45827
  flexDirection: "column",
45575
45828
  gap: 1,
45576
45829
  children: [
45577
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45830
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45578
45831
  bold: true,
45579
45832
  children: "Step 2 — Global config · Timezone"
45580
45833
  }, undefined, false, undefined, this),
45581
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45834
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45582
45835
  dimColor: true,
45583
45836
  children: "Timezone (IANA name):"
45584
45837
  }, undefined, false, undefined, this),
45585
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
45586
- options: timezoneOptions(draft.values.timezone),
45587
- value: draft.values.timezone,
45588
- onChange: (value) => {
45589
- if (value !== "other")
45590
- dispatch({ type: "set", field: "timezone", value });
45591
- },
45838
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45839
+ children: [
45840
+ "Current: ",
45841
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45842
+ color: "green",
45843
+ children: draft.values.timezone
45844
+ }, undefined, false, undefined, this)
45845
+ ]
45846
+ }, undefined, true, undefined, this),
45847
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SearchSelect, {
45848
+ options: timezonePickerOptions(),
45849
+ value: draft.values.timezone || DETECTED_TIMEZONE,
45850
+ placeholder: "Type to search timezones…",
45851
+ onQueryChange: onSearchQueryChange,
45592
45852
  onSelect: (value) => {
45593
45853
  if (value === "other")
45594
45854
  dispatch({ type: "pickOther" });
@@ -45598,38 +45858,39 @@ function Screen({ draft, dispatch }) {
45598
45858
  }
45599
45859
  }
45600
45860
  }, undefined, false, undefined, this),
45601
- draft.errors.timezone && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45861
+ draft.errors.timezone && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45602
45862
  color: "red",
45603
45863
  children: draft.errors.timezone
45604
45864
  }, undefined, false, undefined, this),
45605
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45865
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45606
45866
  dimColor: true,
45607
- children: "Enter to continue · b Back · Esc Cancel"
45867
+ children: "Type to filter · Enter to continue · b Back · Esc Cancel"
45608
45868
  }, undefined, false, undefined, this)
45609
45869
  ]
45610
45870
  }, undefined, true, undefined, this);
45611
45871
  case "timezoneOther":
45612
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45872
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45613
45873
  flexDirection: "column",
45614
45874
  gap: 1,
45615
45875
  children: [
45616
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45876
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45617
45877
  bold: true,
45618
45878
  children: "Step 2 — Global config · Timezone (custom)"
45619
45879
  }, undefined, false, undefined, this),
45620
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45880
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45621
45881
  dimColor: true,
45622
45882
  children: "Type an IANA timezone (e.g. America/Santiago):"
45623
45883
  }, undefined, false, undefined, this),
45624
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
45884
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
45885
+ placeholder: SCREEN_PLACEHOLDERS.timezoneOther,
45625
45886
  onChange: (value) => dispatch({ type: "set", field: "timezone", value }),
45626
45887
  onSubmit: () => dispatch({ type: "next" })
45627
45888
  }, undefined, false, undefined, this),
45628
- draft.errors.timezone && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45889
+ draft.errors.timezone && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45629
45890
  color: "red",
45630
45891
  children: draft.errors.timezone
45631
45892
  }, undefined, false, undefined, this),
45632
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45893
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45633
45894
  dimColor: true,
45634
45895
  children: "Enter to continue · Esc Back"
45635
45896
  }, undefined, false, undefined, this)
@@ -45637,41 +45898,45 @@ function Screen({ draft, dispatch }) {
45637
45898
  }, undefined, true, undefined, this);
45638
45899
  case "branchPreset": {
45639
45900
  const policy = effectivePolicy(draft.values);
45640
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45901
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45641
45902
  flexDirection: "column",
45642
45903
  gap: 1,
45643
45904
  children: [
45644
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45905
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45645
45906
  bold: true,
45646
45907
  children: "Step 2 — Global config · Branch policy"
45647
45908
  }, undefined, false, undefined, this),
45648
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45909
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45649
45910
  dimColor: true,
45650
45911
  children: "Branch policy preset:"
45651
45912
  }, undefined, false, undefined, this),
45652
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
45913
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45653
45914
  options: BRANCH_PRESETS,
45654
45915
  value: draft.values.branchPreset,
45655
45916
  onChange: (value) => dispatch({ type: "set", field: "branchPreset", value }),
45656
45917
  onSelect: () => dispatch({ type: "next" })
45657
45918
  }, undefined, false, undefined, this),
45658
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45919
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45920
+ dimColor: true,
45921
+ children: BRANCH_PRESET_DESCRIPTIONS[draft.values.branchPreset]
45922
+ }, undefined, false, undefined, this),
45923
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45659
45924
  flexDirection: "column",
45660
45925
  gap: 0,
45661
45926
  children: [
45662
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45927
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45663
45928
  children: [
45664
45929
  "Allowed: ",
45665
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45930
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45666
45931
  color: "green",
45667
45932
  children: policy.allowed.join(", ") || "—"
45668
45933
  }, undefined, false, undefined, this)
45669
45934
  ]
45670
45935
  }, undefined, true, undefined, this),
45671
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45936
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45672
45937
  children: [
45673
45938
  "Protected: ",
45674
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45939
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45675
45940
  color: "green",
45676
45941
  children: policy.protected.join(", ") || "—"
45677
45942
  }, undefined, false, undefined, this)
@@ -45679,7 +45944,7 @@ function Screen({ draft, dispatch }) {
45679
45944
  }, undefined, true, undefined, this)
45680
45945
  ]
45681
45946
  }, undefined, true, undefined, this),
45682
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45947
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45683
45948
  dimColor: true,
45684
45949
  children: policy.preset === "custom" ? "Enter to continue — define the patterns next · b Back · Esc Cancel" : "Enter to continue · b Back · Esc Cancel"
45685
45950
  }, undefined, false, undefined, this)
@@ -45687,116 +45952,149 @@ function Screen({ draft, dispatch }) {
45687
45952
  }, undefined, true, undefined, this);
45688
45953
  }
45689
45954
  case "branchAllowed":
45690
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45955
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45691
45956
  flexDirection: "column",
45692
45957
  gap: 1,
45693
45958
  children: [
45694
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45959
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45695
45960
  bold: true,
45696
45961
  children: "Step 2 — Global config · Allowed branch patterns"
45697
45962
  }, undefined, false, undefined, this),
45698
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45963
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45699
45964
  dimColor: true,
45700
45965
  children: "Allowed branch patterns (comma-separated):"
45701
45966
  }, undefined, false, undefined, this),
45702
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
45967
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
45968
+ placeholder: SCREEN_PLACEHOLDERS.branchAllowed,
45703
45969
  defaultValue: draft.values.branchAllowed,
45704
45970
  onChange: (value) => dispatch({ type: "set", field: "branchAllowed", value }),
45705
45971
  onSubmit: () => dispatch({ type: "next" })
45706
45972
  }, undefined, false, undefined, this),
45707
- draft.errors.branchAllowed && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45973
+ draft.errors.branchAllowed && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45708
45974
  color: "red",
45709
45975
  children: draft.errors.branchAllowed
45710
45976
  }, undefined, false, undefined, this),
45711
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45977
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45712
45978
  dimColor: true,
45713
45979
  children: "Enter to continue · Esc Back"
45714
45980
  }, undefined, false, undefined, this)
45715
45981
  ]
45716
45982
  }, undefined, true, undefined, this);
45717
45983
  case "branchProtected":
45718
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
45984
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45719
45985
  flexDirection: "column",
45720
45986
  gap: 1,
45721
45987
  children: [
45722
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45988
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45723
45989
  bold: true,
45724
45990
  children: "Step 2 — Global config · Protected branch names"
45725
45991
  }, undefined, false, undefined, this),
45726
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
45992
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45727
45993
  dimColor: true,
45728
45994
  children: "Protected branch names (comma-separated):"
45729
45995
  }, undefined, false, undefined, this),
45730
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
45996
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
45997
+ placeholder: SCREEN_PLACEHOLDERS.branchProtected,
45731
45998
  defaultValue: draft.values.branchProtected,
45732
45999
  onChange: (value) => dispatch({ type: "set", field: "branchProtected", value }),
45733
46000
  onSubmit: () => dispatch({ type: "next" })
45734
46001
  }, undefined, false, undefined, this),
45735
- draft.errors.branchProtected && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46002
+ draft.errors.branchProtected && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45736
46003
  color: "red",
45737
46004
  children: draft.errors.branchProtected
45738
46005
  }, undefined, false, undefined, this),
45739
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46006
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45740
46007
  dimColor: true,
45741
46008
  children: "Enter to continue · Esc Back"
45742
46009
  }, undefined, false, undefined, this)
45743
46010
  ]
45744
46011
  }, undefined, true, undefined, this);
46012
+ case "issueTracker":
46013
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46014
+ flexDirection: "column",
46015
+ gap: 1,
46016
+ children: [
46017
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46018
+ bold: true,
46019
+ children: "Step 3 — Issue tracker"
46020
+ }, undefined, false, undefined, this),
46021
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46022
+ dimColor: true,
46023
+ children: "Where do issues live?"
46024
+ }, undefined, false, undefined, this),
46025
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
46026
+ options: ISSUE_TRACKERS,
46027
+ value: draft.values.issueTracker,
46028
+ onChange: (value) => dispatch({ type: "set", field: "issueTracker", value }),
46029
+ onSelect: () => dispatch({ type: "next" })
46030
+ }, undefined, false, undefined, this),
46031
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46032
+ dimColor: true,
46033
+ children: "Enter to continue · b Back · Esc Cancel"
46034
+ }, undefined, false, undefined, this)
46035
+ ]
46036
+ }, undefined, true, undefined, this);
45745
46037
  case "youtrack":
45746
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46038
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45747
46039
  flexDirection: "column",
45748
46040
  gap: 1,
45749
46041
  children: [
45750
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46042
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45751
46043
  bold: true,
45752
46044
  children: "Step 3 — YouTrack"
45753
46045
  }, undefined, false, undefined, this),
45754
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46046
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45755
46047
  dimColor: true,
45756
46048
  children: "Base URL (https):"
45757
46049
  }, undefined, false, undefined, this),
45758
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
46050
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
46051
+ placeholder: SCREEN_PLACEHOLDERS.youtrack,
45759
46052
  defaultValue: draft.values.baseUrl,
45760
46053
  onChange: (value) => dispatch({ type: "set", field: "baseUrl", value }),
45761
46054
  onSubmit: () => dispatch({ type: "next" })
45762
46055
  }, undefined, false, undefined, this),
45763
- draft.errors.baseUrl && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46056
+ draft.errors.baseUrl && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45764
46057
  color: "red",
45765
46058
  children: draft.errors.baseUrl
45766
46059
  }, undefined, false, undefined, this),
45767
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46060
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45768
46061
  dimColor: true,
45769
46062
  children: "Enter to continue · Esc Back"
45770
46063
  }, undefined, false, undefined, this)
45771
46064
  ]
45772
46065
  }, undefined, true, undefined, this);
45773
46066
  case "vcs":
45774
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46067
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45775
46068
  flexDirection: "column",
45776
46069
  gap: 1,
45777
46070
  children: [
45778
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46071
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45779
46072
  bold: true,
45780
46073
  children: "Step 4 — Version control"
45781
46074
  }, undefined, false, undefined, this),
45782
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46075
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45783
46076
  dimColor: true,
45784
46077
  children: "Provider:"
45785
46078
  }, undefined, false, undefined, this),
45786
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
46079
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45787
46080
  options: VCS_PROVIDERS,
45788
46081
  value: draft.values.vcsProvider,
45789
46082
  onChange: (value) => dispatch({ type: "set", field: "vcsProvider", value }),
45790
46083
  onSelect: () => dispatch({ type: "next" })
45791
46084
  }, undefined, false, undefined, this),
45792
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46085
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45793
46086
  dimColor: true,
45794
46087
  children: "Enter to continue · b Back · Esc Cancel"
45795
46088
  }, undefined, false, undefined, this)
45796
46089
  ]
45797
46090
  }, undefined, true, undefined, this);
46091
+ case "basePath":
46092
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(BasePathScreen, {
46093
+ draft,
46094
+ dispatch
46095
+ }, undefined, false, undefined, this);
45798
46096
  case "workspaces": {
45799
- const cwd2 = process.cwd();
46097
+ const base2 = resolveBasePath(draft.values);
45800
46098
  const options = [
45801
46099
  ...draft.values.workspaces.map((w, i) => ({
45802
46100
  label: `Edit ${w.name} (${w.glob})`,
@@ -45807,26 +46105,26 @@ function Screen({ draft, dispatch }) {
45807
46105
  value: `remove:${i}`
45808
46106
  })),
45809
46107
  { label: "Add workspace", value: "add" },
45810
- { label: `Use current project (${cwd2})`, value: "current" },
46108
+ { label: `Use current project (${base2})`, value: "current" },
45811
46109
  { label: "Done", value: "done" }
45812
46110
  ];
45813
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46111
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45814
46112
  flexDirection: "column",
45815
46113
  gap: 1,
45816
46114
  children: [
45817
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46115
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45818
46116
  bold: true,
45819
46117
  children: "Step 5 — Workspaces"
45820
46118
  }, undefined, false, undefined, this),
45821
- draft.values.workspaces.length === 0 ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46119
+ draft.values.workspaces.length === 0 ? /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45822
46120
  dimColor: true,
45823
46121
  children: "No workspaces configured yet."
45824
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46122
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45825
46123
  flexDirection: "column",
45826
46124
  gap: 0,
45827
46125
  children: draft.values.workspaces.map((w) => {
45828
- const matches2 = matchWorkspace(w.glob, cwd2);
45829
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46126
+ const matches2 = matchWorkspace(w.glob, base2);
46127
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45830
46128
  children: [
45831
46129
  matches2 ? "✓ matches" : "✗ no match",
45832
46130
  " ",
@@ -45840,7 +46138,7 @@ function Screen({ draft, dispatch }) {
45840
46138
  }, `${w.name}|${w.glob}|${w.vcs?.provider ?? ""}`, true, undefined, this);
45841
46139
  })
45842
46140
  }, undefined, false, undefined, this),
45843
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
46141
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45844
46142
  options,
45845
46143
  value: "done",
45846
46144
  onSelect: (value) => {
@@ -45851,12 +46149,12 @@ function Screen({ draft, dispatch }) {
45851
46149
  else if (value === "add")
45852
46150
  dispatch({ type: "workspaceAdd" });
45853
46151
  else if (value === "current")
45854
- dispatch({ type: "workspaceAddCurrent", path: cwd2 });
46152
+ dispatch({ type: "workspaceAddCurrent", path: base2 });
45855
46153
  else
45856
46154
  dispatch({ type: "next" });
45857
46155
  }
45858
46156
  }, draft.values.workspaces.map((w) => `${w.name}:${w.glob}`).join("|"), false, undefined, this),
45859
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46157
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45860
46158
  dimColor: true,
45861
46159
  children: "Enter to continue · b Back · Esc Cancel"
45862
46160
  }, undefined, false, undefined, this)
@@ -45864,28 +46162,29 @@ function Screen({ draft, dispatch }) {
45864
46162
  }, undefined, true, undefined, this);
45865
46163
  }
45866
46164
  case "workspaceName":
45867
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46165
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45868
46166
  flexDirection: "column",
45869
46167
  gap: 1,
45870
46168
  children: [
45871
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46169
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45872
46170
  bold: true,
45873
46171
  children: "Step 5 — Workspaces · Name"
45874
46172
  }, undefined, false, undefined, this),
45875
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46173
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45876
46174
  dimColor: true,
45877
46175
  children: draft.workspaceIndex === null ? "New workspace name:" : `Edit workspace name (${draft.values.workspaces[draft.workspaceIndex]?.name ?? ""}):`
45878
46176
  }, undefined, false, undefined, this),
45879
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
46177
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
46178
+ placeholder: SCREEN_PLACEHOLDERS.workspaceName,
45880
46179
  defaultValue: draft.workspaceDraft?.name ?? "",
45881
46180
  onChange: (value) => dispatch({ type: "workspaceDraftName", value }),
45882
46181
  onSubmit: () => dispatch({ type: "next" })
45883
46182
  }, undefined, false, undefined, this),
45884
- draft.errors.workspaceName && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46183
+ draft.errors.workspaceName && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45885
46184
  color: "red",
45886
46185
  children: draft.errors.workspaceName
45887
46186
  }, undefined, false, undefined, this),
45888
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46187
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45889
46188
  dimColor: true,
45890
46189
  children: "Enter to continue · Esc Back"
45891
46190
  }, undefined, false, undefined, this)
@@ -45893,34 +46192,35 @@ function Screen({ draft, dispatch }) {
45893
46192
  }, undefined, true, undefined, this);
45894
46193
  case "workspaceGlob": {
45895
46194
  const glob = draft.workspaceDraft?.glob ?? "";
45896
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46195
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45897
46196
  flexDirection: "column",
45898
46197
  gap: 1,
45899
46198
  children: [
45900
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46199
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45901
46200
  bold: true,
45902
46201
  children: "Step 5 — Workspaces · Pattern"
45903
46202
  }, undefined, false, undefined, this),
45904
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46203
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45905
46204
  dimColor: true,
45906
46205
  children: "Workspace pattern (glob, e.g. /work/**):"
45907
46206
  }, undefined, false, undefined, this),
45908
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
46207
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
46208
+ placeholder: SCREEN_PLACEHOLDERS.workspaceGlob,
45909
46209
  defaultValue: glob,
45910
46210
  onChange: (value) => dispatch({ type: "workspaceDraftGlob", value }),
45911
46211
  onSubmit: () => dispatch({ type: "next" })
45912
46212
  }, undefined, false, undefined, this),
45913
- glob.trim() !== "" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46213
+ glob.trim() !== "" && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45914
46214
  flexDirection: "column",
45915
46215
  gap: 0,
45916
46216
  children: [
45917
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46217
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45918
46218
  bold: true,
45919
46219
  children: "Match preview (shared matcher):"
45920
46220
  }, undefined, false, undefined, this),
45921
- workspacePreviewTargets(process.cwd()).map((target) => {
46221
+ workspacePreviewTargets(resolveBasePath(draft.values)).map((target) => {
45922
46222
  const matches2 = matchWorkspace(glob, target);
45923
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46223
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45924
46224
  color: matches2 ? "green" : "red",
45925
46225
  children: [
45926
46226
  matches2 ? "✓ matches" : "✗ no match",
@@ -45931,11 +46231,11 @@ function Screen({ draft, dispatch }) {
45931
46231
  })
45932
46232
  ]
45933
46233
  }, undefined, true, undefined, this),
45934
- draft.errors.workspaceGlob && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46234
+ draft.errors.workspaceGlob && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45935
46235
  color: "red",
45936
46236
  children: draft.errors.workspaceGlob
45937
46237
  }, undefined, false, undefined, this),
45938
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46238
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45939
46239
  dimColor: true,
45940
46240
  children: "Enter to continue · Esc Back"
45941
46241
  }, undefined, false, undefined, this)
@@ -45943,19 +46243,19 @@ function Screen({ draft, dispatch }) {
45943
46243
  }, undefined, true, undefined, this);
45944
46244
  }
45945
46245
  case "workspaceProvider":
45946
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46246
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45947
46247
  flexDirection: "column",
45948
46248
  gap: 1,
45949
46249
  children: [
45950
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46250
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45951
46251
  bold: true,
45952
46252
  children: "Step 5 — Workspaces · Provider"
45953
46253
  }, undefined, false, undefined, this),
45954
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46254
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45955
46255
  dimColor: true,
45956
46256
  children: "Version control provider for this workspace:"
45957
46257
  }, undefined, false, undefined, this),
45958
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(SelectList, {
46258
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(SelectList, {
45959
46259
  options: VCS_PROVIDERS.filter((option) => option.value !== "skip"),
45960
46260
  value: draft.workspaceDraft?.vcs?.provider ?? "gitlab",
45961
46261
  onChange: (value) => dispatch({ type: "workspaceDraftProvider", value }),
@@ -45964,61 +46264,62 @@ function Screen({ draft, dispatch }) {
45964
46264
  dispatch({ type: "workspaceSave" });
45965
46265
  }
45966
46266
  }, undefined, false, undefined, this),
45967
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46267
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45968
46268
  dimColor: true,
45969
46269
  children: "Enter to save · b Back · Esc Cancel"
45970
46270
  }, undefined, false, undefined, this)
45971
46271
  ]
45972
46272
  }, undefined, true, undefined, this);
45973
46273
  case "branchPolicy":
45974
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(BranchPolicyScreen, {
46274
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(BranchPolicyScreen, {
45975
46275
  draft,
45976
46276
  dispatch
45977
46277
  }, undefined, false, undefined, this);
45978
46278
  case "branchPolicyDevelop":
45979
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46279
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
45980
46280
  flexDirection: "column",
45981
46281
  gap: 1,
45982
46282
  children: [
45983
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46283
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45984
46284
  bold: true,
45985
46285
  children: "Step 5 — Branch policy · Develop branch"
45986
46286
  }, undefined, false, undefined, this),
45987
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46287
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45988
46288
  dimColor: true,
45989
46289
  children: "Integration/develop branch name (leave empty to unset):"
45990
46290
  }, undefined, false, undefined, this),
45991
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(TextInput, {
46291
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(TextInput, {
46292
+ placeholder: SCREEN_PLACEHOLDERS.branchPolicyDevelop,
45992
46293
  defaultValue: draft.values.branchPolicy?.developBranch ?? draft.values.branchPolicyDetected?.developBranch ?? "",
45993
46294
  onSubmit: (value) => {
45994
46295
  dispatch({ type: "set", field: "branchPolicyDevelop", value });
45995
46296
  dispatch({ type: "next" });
45996
46297
  }
45997
46298
  }, undefined, false, undefined, this),
45998
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46299
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
45999
46300
  dimColor: true,
46000
46301
  children: "Enter to save · Esc Back"
46001
46302
  }, undefined, false, undefined, this)
46002
46303
  ]
46003
46304
  }, undefined, true, undefined, this);
46004
46305
  case "project":
46005
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46306
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46006
46307
  flexDirection: "column",
46007
46308
  gap: 1,
46008
46309
  children: [
46009
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46310
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46010
46311
  bold: true,
46011
46312
  children: "Step 6 — Project setup"
46012
46313
  }, undefined, false, undefined, this),
46013
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46314
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46014
46315
  dimColor: true,
46015
46316
  children: [
46016
46317
  "Will apply gitignore + hygiene in ",
46017
- process.cwd(),
46318
+ resolveBasePath(draft.values),
46018
46319
  " (existing files are never overwritten):"
46019
46320
  ]
46020
46321
  }, undefined, true, undefined, this),
46021
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(ConfirmInput, {
46322
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(ConfirmInput, {
46022
46323
  defaultChoice: "confirm",
46023
46324
  submitOnEnter: false,
46024
46325
  onConfirm: () => {
@@ -46027,7 +46328,7 @@ function Screen({ draft, dispatch }) {
46027
46328
  },
46028
46329
  onCancel: () => {}
46029
46330
  }, undefined, false, undefined, this),
46030
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46331
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46031
46332
  dimColor: true,
46032
46333
  children: "y to continue · n to stay · b Back · Esc Cancel"
46033
46334
  }, undefined, false, undefined, this)
@@ -46035,47 +46336,47 @@ function Screen({ draft, dispatch }) {
46035
46336
  }, undefined, true, undefined, this);
46036
46337
  case "summary": {
46037
46338
  const policy = effectivePolicy(draft.values);
46038
- const preview = buildSetupPreview(draft.values);
46039
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46339
+ const preview = buildSetupPreview(draft.values, { cwd: resolveBasePath(draft.values) });
46340
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46040
46341
  flexDirection: "column",
46041
46342
  gap: 1,
46042
46343
  children: [
46043
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46344
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46044
46345
  bold: true,
46045
46346
  color: "cyan",
46046
46347
  children: "Review"
46047
46348
  }, undefined, false, undefined, this),
46048
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46349
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46049
46350
  children: [
46050
46351
  "Platforms: ",
46051
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46352
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46052
46353
  color: "green",
46053
46354
  children: draft.values.platforms.join(", ") || "—"
46054
46355
  }, undefined, false, undefined, this)
46055
46356
  ]
46056
46357
  }, undefined, true, undefined, this),
46057
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46358
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46058
46359
  children: [
46059
46360
  "Locale: ",
46060
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46361
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46061
46362
  color: "green",
46062
46363
  children: draft.values.locale
46063
46364
  }, undefined, false, undefined, this)
46064
46365
  ]
46065
46366
  }, undefined, true, undefined, this),
46066
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46367
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46067
46368
  children: [
46068
46369
  "Timezone: ",
46069
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46370
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46070
46371
  color: "green",
46071
46372
  children: draft.values.timezone
46072
46373
  }, undefined, false, undefined, this)
46073
46374
  ]
46074
46375
  }, undefined, true, undefined, this),
46075
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46376
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46076
46377
  children: [
46077
46378
  "Branch policy: ",
46078
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46379
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46079
46380
  color: "green",
46080
46381
  children: policy.preset
46081
46382
  }, undefined, false, undefined, this),
@@ -46086,43 +46387,43 @@ function Screen({ draft, dispatch }) {
46086
46387
  policy.protected.join(", ")
46087
46388
  ]
46088
46389
  }, undefined, true, undefined, this),
46089
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46390
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46090
46391
  children: [
46091
46392
  "YouTrack base URL:",
46092
46393
  " ",
46093
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46394
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46094
46395
  color: "green",
46095
- children: draft.values.baseUrl.trim() ? draft.values.baseUrl : "— (skip)"
46396
+ children: draft.values.issueTracker === "youtrack" ? draft.values.baseUrl.trim() ? draft.values.baseUrl : "— (skip)" : "—"
46096
46397
  }, undefined, false, undefined, this)
46097
46398
  ]
46098
46399
  }, undefined, true, undefined, this),
46099
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46400
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46100
46401
  children: [
46101
46402
  "VCS provider: ",
46102
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46403
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46103
46404
  color: "green",
46104
46405
  children: draft.values.vcsProvider
46105
46406
  }, undefined, false, undefined, this)
46106
46407
  ]
46107
46408
  }, undefined, true, undefined, this),
46108
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46409
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46109
46410
  children: [
46110
46411
  "Project hygiene: ",
46111
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46412
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46112
46413
  color: "green",
46113
46414
  children: draft.values.applyProject ? "yes" : "no"
46114
46415
  }, undefined, false, undefined, this)
46115
46416
  ]
46116
46417
  }, undefined, true, undefined, this),
46117
- preview.overrides.length > 0 && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46418
+ preview.overrides.length > 0 && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46118
46419
  flexDirection: "column",
46119
46420
  gap: 0,
46120
46421
  children: [
46121
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46422
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46122
46423
  bold: true,
46123
46424
  children: "Environment overrides (not applied by the wizard):"
46124
46425
  }, undefined, false, undefined, this),
46125
- preview.overrides.map((o) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46426
+ preview.overrides.map((o) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46126
46427
  color: "yellow",
46127
46428
  children: [
46128
46429
  o.envKey,
@@ -46134,18 +46435,18 @@ function Screen({ draft, dispatch }) {
46134
46435
  }, o.envKey, true, undefined, this))
46135
46436
  ]
46136
46437
  }, undefined, true, undefined, this),
46137
- preview.ok ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46438
+ preview.ok ? /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46138
46439
  flexDirection: "column",
46139
46440
  gap: 0,
46140
46441
  children: [
46141
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46442
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46142
46443
  bold: true,
46143
46444
  children: "Will apply:"
46144
46445
  }, undefined, false, undefined, this),
46145
- preview.mutations.map((m) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46446
+ preview.mutations.map((m) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46146
46447
  children: describeMutation(m)
46147
46448
  }, `${m.type}:${m.path}`, false, undefined, this)),
46148
- preview.preserved.map((p) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46449
+ preview.preserved.map((p) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46149
46450
  color: "green",
46150
46451
  children: [
46151
46452
  "preserve ",
@@ -46154,32 +46455,32 @@ function Screen({ draft, dispatch }) {
46154
46455
  ]
46155
46456
  }, p, true, undefined, this))
46156
46457
  ]
46157
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46458
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46158
46459
  flexDirection: "column",
46159
46460
  gap: 0,
46160
46461
  children: [
46161
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46462
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46162
46463
  bold: true,
46163
46464
  color: "red",
46164
46465
  children: "Apply blocked — malformed configuration:"
46165
46466
  }, undefined, false, undefined, this),
46166
- preview.blocked.map((b) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46467
+ preview.blocked.map((b) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46167
46468
  color: "red",
46168
46469
  children: b
46169
46470
  }, b, false, undefined, this)),
46170
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46471
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46171
46472
  dimColor: true,
46172
46473
  children: "Fix or remove the blocked file above, then return here. Esc Cancel."
46173
46474
  }, undefined, false, undefined, this)
46174
46475
  ]
46175
46476
  }, undefined, true, undefined, this),
46176
- preview.ok && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(ConfirmInput, {
46477
+ preview.ok && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(ConfirmInput, {
46177
46478
  defaultChoice: "confirm",
46178
46479
  submitOnEnter: false,
46179
46480
  onConfirm: () => dispatch({ type: "apply" }),
46180
46481
  onCancel: () => {}
46181
46482
  }, undefined, false, undefined, this),
46182
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46483
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46183
46484
  dimColor: true,
46184
46485
  children: preview.ok ? "y to apply · b Back · Esc Cancel" : "b Back · Esc Cancel"
46185
46486
  }, undefined, false, undefined, this)
@@ -46187,10 +46488,10 @@ function Screen({ draft, dispatch }) {
46187
46488
  }, undefined, true, undefined, this);
46188
46489
  }
46189
46490
  case "exit":
46190
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
46491
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
46191
46492
  flexDirection: "column",
46192
46493
  gap: 1,
46193
- children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
46494
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
46194
46495
  dimColor: true,
46195
46496
  children: "Exiting…"
46196
46497
  }, undefined, false, undefined, this)
@@ -46424,71 +46725,305 @@ var createLogger = (options = {}) => {
46424
46725
  };
46425
46726
  };
46426
46727
 
46728
+ // packages/workit-core/src/core/uninstall.ts
46729
+ import { existsSync as existsSync10, readFileSync as readFileSync9, realpathSync as realpathSync2, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
46730
+ import os7 from "node:os";
46731
+ import path13 from "node:path";
46732
+ var resolveUninstallPaths = (options = {}) => {
46733
+ const home = options.home ?? options.env?.HOME ?? os7.homedir();
46734
+ return {
46735
+ opencodeConfig: options.opencodeConfig ?? path13.join(home, ".config", "opencode", "opencode.json"),
46736
+ cursorSettings: options.cursorSettings ?? path13.join(home, ".cursor", "settings.json"),
46737
+ cursorMcp: options.cursorMcp ?? path13.join(home, ".cursor", "mcp.json"),
46738
+ cursorPluginDir: options.cursorPluginDir ?? path13.join(home, ".cursor", "plugins", "local", "workit")
46739
+ };
46740
+ };
46741
+ var isRecord3 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
46742
+ var readJsonRecord = (file) => {
46743
+ let raw;
46744
+ try {
46745
+ raw = readFileSync9(file, "utf8");
46746
+ } catch {
46747
+ if (existsSync10(file))
46748
+ return { kind: "malformed", error: `${file} is not readable` };
46749
+ return { kind: "missing" };
46750
+ }
46751
+ try {
46752
+ const value = JSON.parse(raw);
46753
+ return isRecord3(value) ? { kind: "record", value } : { kind: "malformed", error: `${file} is not a JSON object` };
46754
+ } catch {
46755
+ return { kind: "malformed", error: `${file} is not valid JSON` };
46756
+ }
46757
+ };
46758
+ var stripTrailingSep = (p) => {
46759
+ const j = path13.join(p);
46760
+ return path13.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
46761
+ };
46762
+ var CURSOR_LEGACY_IDENTITIES = ["workflow-toolkit", "local/workflow-toolkit"];
46763
+ function cleanCursorSettings(settings, pluginDir) {
46764
+ const next = { ...settings };
46765
+ let changed = false;
46766
+ if (isRecord3(next.enabled_plugins)) {
46767
+ const enabled = { ...next.enabled_plugins };
46768
+ for (const identity2 of ["workit", ...CURSOR_LEGACY_IDENTITIES]) {
46769
+ if (identity2 in enabled) {
46770
+ delete enabled[identity2];
46771
+ changed = true;
46772
+ }
46773
+ }
46774
+ next.enabled_plugins = enabled;
46775
+ }
46776
+ if (Array.isArray(next.plugin_dirs)) {
46777
+ const canonical = stripTrailingSep(pluginDir);
46778
+ const kept = next.plugin_dirs.map(String).filter((d) => stripTrailingSep(d) !== canonical);
46779
+ if (kept.length !== next.plugin_dirs.length) {
46780
+ next.plugin_dirs = kept;
46781
+ changed = true;
46782
+ }
46783
+ }
46784
+ return { next, changed };
46785
+ }
46786
+ function cleanOpenCodeConfig(config) {
46787
+ const next = { ...config };
46788
+ let changed = false;
46789
+ if (Array.isArray(next.plugin)) {
46790
+ const plugins = next.plugin.map(String);
46791
+ const kept = plugins.filter((p) => !isWorkitPlugin(p));
46792
+ if (kept.length !== plugins.length) {
46793
+ next.plugin = kept;
46794
+ changed = true;
46795
+ }
46796
+ } else if (typeof next.plugin === "string" && isWorkitPlugin(next.plugin)) {
46797
+ delete next.plugin;
46798
+ changed = true;
46799
+ }
46800
+ return { next, changed };
46801
+ }
46802
+ function cleanCursorMcp(mcp) {
46803
+ const next = { ...mcp };
46804
+ let changed = false;
46805
+ if (isRecord3(next.mcpServers)) {
46806
+ const servers = { ...next.mcpServers };
46807
+ for (const name of ["workit", "workflow-toolkit"]) {
46808
+ if (name in servers) {
46809
+ delete servers[name];
46810
+ changed = true;
46811
+ }
46812
+ }
46813
+ next.mcpServers = servers;
46814
+ }
46815
+ return { next, changed };
46816
+ }
46817
+ var jsonCleanerFor = (target, res) => {
46818
+ if (target === res.opencodeConfig)
46819
+ return cleanOpenCodeConfig;
46820
+ if (target === res.cursorSettings)
46821
+ return (r) => cleanCursorSettings(r, res.cursorPluginDir);
46822
+ if (target === res.cursorMcp)
46823
+ return cleanCursorMcp;
46824
+ return null;
46825
+ };
46826
+ function planUninstall(paths = {}) {
46827
+ const res = resolveUninstallPaths(paths);
46828
+ const ocExisting = readJsonRecord(res.opencodeConfig);
46829
+ const ocDirty = ocExisting.kind === "malformed" || ocExisting.kind === "record" && cleanOpenCodeConfig(ocExisting.value).changed;
46830
+ const opencode = {
46831
+ host: "opencode",
46832
+ installed: ocDirty,
46833
+ actions: ocDirty ? [
46834
+ {
46835
+ kind: "edit-json-remove",
46836
+ path: res.opencodeConfig,
46837
+ detail: "remove workit plugin entries from opencode.json"
46838
+ }
46839
+ ] : []
46840
+ };
46841
+ const settingsExisting = readJsonRecord(res.cursorSettings);
46842
+ const mcpExisting = readJsonRecord(res.cursorMcp);
46843
+ const settingsDirty = settingsExisting.kind === "malformed" || settingsExisting.kind === "record" && cleanCursorSettings(settingsExisting.value, res.cursorPluginDir).changed;
46844
+ const mcpDirty = mcpExisting.kind === "malformed" || mcpExisting.kind === "record" && cleanCursorMcp(mcpExisting.value).changed;
46845
+ const dirExists = existsSync10(res.cursorPluginDir);
46846
+ const actions = [];
46847
+ if (settingsDirty) {
46848
+ actions.push({
46849
+ kind: "edit-json-remove",
46850
+ path: res.cursorSettings,
46851
+ detail: "remove workit enabled_plugins/plugin_dirs entries from settings.json"
46852
+ });
46853
+ }
46854
+ if (mcpDirty) {
46855
+ actions.push({
46856
+ kind: "edit-json-remove",
46857
+ path: res.cursorMcp,
46858
+ detail: "remove the workit MCP server registration from mcp.json"
46859
+ });
46860
+ }
46861
+ if (dirExists) {
46862
+ actions.push({
46863
+ kind: "remove-dir",
46864
+ path: res.cursorPluginDir,
46865
+ detail: "delete the local workit plugin directory"
46866
+ });
46867
+ }
46868
+ const cursor4 = {
46869
+ host: "cursor",
46870
+ installed: settingsDirty || mcpDirty || dirExists,
46871
+ actions
46872
+ };
46873
+ return { hosts: [opencode, cursor4] };
46874
+ }
46875
+ var canonicalRemoveDirAllowed = (actionPath, res) => {
46876
+ const expected = path13.resolve(res.cursorPluginDir);
46877
+ if (!(actionPath === expected && path13.basename(expected) === "workit" && path13.basename(path13.dirname(expected)) === "local" && path13.basename(path13.dirname(path13.dirname(expected))) === "plugins")) {
46878
+ return false;
46879
+ }
46880
+ try {
46881
+ return realpathSync2(actionPath) === realpathSync2(expected);
46882
+ } catch {
46883
+ return true;
46884
+ }
46885
+ };
46886
+ var applyEditJsonRemove = (target, cleaner) => {
46887
+ const existing = readJsonRecord(target);
46888
+ if (existing.kind === "malformed") {
46889
+ return { status: "failed", detail: `${existing.error} — file untouched` };
46890
+ }
46891
+ if (existing.kind === "missing") {
46892
+ return { status: "skipped", detail: "file already absent" };
46893
+ }
46894
+ const { next, changed } = cleaner(existing.value);
46895
+ if (!changed)
46896
+ return { status: "skipped", detail: "no workit entries present" };
46897
+ const serialized = JSON.stringify(next, null, 2) + `
46898
+ `;
46899
+ let current;
46900
+ try {
46901
+ current = readFileSync9(target, "utf8");
46902
+ } catch (error) {
46903
+ return {
46904
+ status: "failed",
46905
+ detail: `read failed before write: ${error instanceof Error ? error.message : String(error)}`
46906
+ };
46907
+ }
46908
+ if (current === serialized) {
46909
+ return { status: "skipped", detail: "already clean" };
46910
+ }
46911
+ try {
46912
+ writeFileSync6(target, serialized, "utf8");
46913
+ } catch (error) {
46914
+ return {
46915
+ status: "failed",
46916
+ detail: `write failed: ${error instanceof Error ? error.message : String(error)}`
46917
+ };
46918
+ }
46919
+ return { status: "removed" };
46920
+ };
46921
+ function applyUninstall(plan, paths = {}) {
46922
+ const res = resolveUninstallPaths(paths);
46923
+ const entries = [];
46924
+ for (const hostPlan of plan.hosts) {
46925
+ for (const action of hostPlan.actions) {
46926
+ let status;
46927
+ let detail;
46928
+ if (action.kind === "remove-dir") {
46929
+ const resolved = path13.resolve(action.path);
46930
+ if (!canonicalRemoveDirAllowed(resolved, res)) {
46931
+ status = "failed";
46932
+ detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
46933
+ } else if (!existsSync10(resolved)) {
46934
+ status = "skipped";
46935
+ detail = "directory already absent";
46936
+ } else {
46937
+ try {
46938
+ rmSync2(resolved, { recursive: true, force: true });
46939
+ status = "removed";
46940
+ } catch (error) {
46941
+ status = "failed";
46942
+ detail = error instanceof Error ? error.message : String(error);
46943
+ }
46944
+ }
46945
+ } else {
46946
+ const cleaner = jsonCleanerFor(action.path, res);
46947
+ if (cleaner === null) {
46948
+ status = "failed";
46949
+ detail = `${action.path} is not a recognized uninstall target for this host`;
46950
+ } else {
46951
+ const outcome = applyEditJsonRemove(action.path, cleaner);
46952
+ status = outcome.status;
46953
+ detail = outcome.detail;
46954
+ }
46955
+ }
46956
+ entries.push({ host: hostPlan.host, path: action.path, status, detail });
46957
+ }
46958
+ }
46959
+ return { ok: entries.every((e) => e.status !== "failed"), entries };
46960
+ }
46961
+
46427
46962
  // packages/workit-cli/src/flow.ts
46428
46963
  import { createInterface } from "node:readline/promises";
46429
- import path21 from "node:path";
46964
+ import path22 from "node:path";
46430
46965
 
46431
46966
  // packages/workit-core/src/core/flow-state.ts
46432
46967
  import {
46433
46968
  closeSync,
46434
- existsSync as existsSync15,
46969
+ existsSync as existsSync16,
46435
46970
  fstatSync,
46436
46971
  fsyncSync,
46437
46972
  mkdirSync as mkdirSync8,
46438
46973
  openSync,
46439
46974
  readdirSync as readdirSync6,
46440
- readFileSync as readFileSync13,
46975
+ readFileSync as readFileSync14,
46441
46976
  renameSync as renameSync3,
46442
- rmSync as rmSync3,
46443
- statSync as statSync8,
46977
+ rmSync as rmSync4,
46978
+ statSync as statSync9,
46444
46979
  unlinkSync as unlinkSync3,
46445
- writeFileSync as writeFileSync8
46980
+ writeFileSync as writeFileSync9
46446
46981
  } from "node:fs";
46447
46982
  import { createHash } from "node:crypto";
46448
- import path18 from "node:path";
46983
+ import path19 from "node:path";
46449
46984
 
46450
46985
  // packages/workit-core/src/core/docs-validate.ts
46451
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
46986
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
46452
46987
  import { execFileSync as execFileSync2 } from "node:child_process";
46453
- import path14 from "node:path";
46988
+ import path15 from "node:path";
46454
46989
 
46455
46990
  // packages/workit-core/src/core/docs-layout.ts
46456
- import { existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync5, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
46457
- import path13 from "node:path";
46991
+ import { existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync5, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
46992
+ import path14 from "node:path";
46458
46993
  var SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
46459
46994
  var LEGACY_SLUG = "superpowers";
46460
- var posix = (p) => p.split(path13.sep).join("/");
46995
+ var posix = (p) => p.split(path14.sep).join("/");
46461
46996
  var canonicalize = (base2, candidate) => {
46462
- const abs = path13.resolve(base2, candidate);
46997
+ const abs = path14.resolve(base2, candidate);
46463
46998
  let ancestor = abs;
46464
- while (!existsSync10(ancestor))
46465
- ancestor = path13.dirname(ancestor);
46999
+ while (!existsSync11(ancestor))
47000
+ ancestor = path14.dirname(ancestor);
46466
47001
  let real;
46467
47002
  try {
46468
- real = realpathSync2(ancestor);
47003
+ real = realpathSync3(ancestor);
46469
47004
  } catch (error) {
46470
47005
  if (error.code === "EACCES" && !lstatSync(ancestor).isSymbolicLink()) {
46471
- real = path13.join(realpathSync2(path13.dirname(ancestor)), path13.basename(ancestor));
47006
+ real = path14.join(realpathSync3(path14.dirname(ancestor)), path14.basename(ancestor));
46472
47007
  } else {
46473
47008
  throw error;
46474
47009
  }
46475
47010
  }
46476
- if (real !== base2 && !real.startsWith(base2 + path13.sep)) {
47011
+ if (real !== base2 && !real.startsWith(base2 + path14.sep)) {
46477
47012
  throw new Error(`path must stay inside repository root: ${candidate}`);
46478
47013
  }
46479
- return path13.join(real, path13.relative(ancestor, abs));
47014
+ return path14.join(real, path14.relative(ancestor, abs));
46480
47015
  };
46481
47016
  var buildLayout = (workspace, slug) => {
46482
47017
  const docs = canonicalize(workspace, "docs");
46483
- const dir = canonicalize(workspace, path13.join(docs, slug));
47018
+ const dir = canonicalize(workspace, path14.join(docs, slug));
46484
47019
  return {
46485
47020
  workspace,
46486
47021
  slug,
46487
47022
  docs,
46488
47023
  dir,
46489
- spec: path13.join(dir, "spec.md"),
46490
- plan: path13.join(dir, "plan.md"),
46491
- sdd: path13.join(dir, "sdd")
47024
+ spec: path14.join(dir, "spec.md"),
47025
+ plan: path14.join(dir, "plan.md"),
47026
+ sdd: path14.join(dir, "sdd")
46492
47027
  };
46493
47028
  };
46494
47029
  var resolveCanonicalLayout = (input) => {
@@ -46497,7 +47032,7 @@ var resolveCanonicalLayout = (input) => {
46497
47032
  return { ok: false, error: "workspace_root required" };
46498
47033
  let workspace;
46499
47034
  try {
46500
- workspace = realpathSync2(path13.resolve(workspace_root));
47035
+ workspace = realpathSync3(path14.resolve(workspace_root));
46501
47036
  } catch {
46502
47037
  return { ok: false, error: `workspace root not found: ${workspace_root}` };
46503
47038
  }
@@ -46508,7 +47043,7 @@ var resolveCanonicalLayout = (input) => {
46508
47043
  ]) {
46509
47044
  if (!candidate)
46510
47045
  continue;
46511
- if (path13.isAbsolute(candidate)) {
47046
+ if (path14.isAbsolute(candidate)) {
46512
47047
  return { ok: false, error: `absolute path not allowed: ${candidate}` };
46513
47048
  }
46514
47049
  const spelling = posix(candidate);
@@ -46529,7 +47064,7 @@ var resolveCanonicalLayout = (input) => {
46529
47064
  if (match[2] !== kind) {
46530
47065
  return {
46531
47066
  ok: false,
46532
- error: `wrong basename for ${kind}: expected ${kind}.md, got ${path13.basename(candidate)}`
47067
+ error: `wrong basename for ${kind}: expected ${kind}.md, got ${path14.basename(candidate)}`
46533
47068
  };
46534
47069
  }
46535
47070
  if (derived && derived !== pathSlug) {
@@ -46545,7 +47080,7 @@ var resolveCanonicalLayout = (input) => {
46545
47080
  } catch (error) {
46546
47081
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
46547
47082
  }
46548
- if (posix(path13.relative(workspace, abs)) !== spelling) {
47083
+ if (posix(path14.relative(workspace, abs)) !== spelling) {
46549
47084
  return {
46550
47085
  ok: false,
46551
47086
  error: `path must resolve to ${JSON.stringify(spelling)}: ${candidate}`
@@ -46578,18 +47113,18 @@ var resolveCanonicalLayout = (input) => {
46578
47113
  }
46579
47114
  };
46580
47115
  var resolveDocsPath = (input) => {
46581
- if (path13.isAbsolute(input.path)) {
47116
+ if (path14.isAbsolute(input.path)) {
46582
47117
  return { ok: false, error: `absolute path not allowed: ${input.path}` };
46583
47118
  }
46584
47119
  let workspace;
46585
47120
  try {
46586
- workspace = realpathSync2(path13.resolve(input.workspace_root));
47121
+ workspace = realpathSync3(path14.resolve(input.workspace_root));
46587
47122
  } catch {
46588
47123
  return { ok: false, error: `workspace root not found: ${input.workspace_root}` };
46589
47124
  }
46590
47125
  try {
46591
47126
  const abs = canonicalize(workspace, input.path);
46592
- const relative = posix(path13.relative(workspace, abs));
47127
+ const relative = posix(path14.relative(workspace, abs));
46593
47128
  if (!relative.startsWith("docs/") || relative === `docs/${LEGACY_SLUG}` || relative.startsWith(`docs/${LEGACY_SLUG}/`)) {
46594
47129
  return {
46595
47130
  ok: false,
@@ -46606,10 +47141,10 @@ var resolveDocsPath = (input) => {
46606
47141
  var BRANCH_RE = /^\s*\*+Branch:\*+\s*`?([^`\s|]+)`?\s*$/im;
46607
47142
  var SPEC_LINK_RE = /^\s*\*+Spec:\*+\s*(?:`([^`]+)`|(\S+))\s*$/im;
46608
47143
  var TASK_RE = /^###\s+Task\s+(\d+):\s*(.*)$/i;
46609
- var err = (code, message, path15) => {
47144
+ var err = (code, message, path16) => {
46610
47145
  const item = { code, message };
46611
- if (path15)
46612
- item.path = path15;
47146
+ if (path16)
47147
+ item.path = path16;
46613
47148
  return item;
46614
47149
  };
46615
47150
  var failValidate = (errors) => ({
@@ -46696,7 +47231,7 @@ var docsValidate = ({
46696
47231
  const errors = [];
46697
47232
  const read = (p) => {
46698
47233
  try {
46699
- return readFileSync9(p, "utf8");
47234
+ return readFileSync10(p, "utf8");
46700
47235
  } catch {
46701
47236
  return null;
46702
47237
  }
@@ -46749,8 +47284,8 @@ var docsValidate = ({
46749
47284
  return failValidate([err("task_order", `task mismatch at position ${i + 1}`, plan_path)]);
46750
47285
  }
46751
47286
  }
46752
- const relSpec = path14.isAbsolute(spec_path) ? path14.relative(cwd2, specAbs) : spec_path;
46753
- const relPlan = path14.isAbsolute(plan_path) ? path14.relative(cwd2, planAbs) : plan_path;
47287
+ const relSpec = path15.isAbsolute(spec_path) ? path15.relative(cwd2, specAbs) : spec_path;
47288
+ const relPlan = path15.isAbsolute(plan_path) ? path15.relative(cwd2, planAbs) : plan_path;
46754
47289
  const quality = qualitySpec(specText);
46755
47290
  if (!sddIgnored(cwd2, slug)) {
46756
47291
  quality.push({
@@ -46881,8 +47416,8 @@ var qualitySpec = (text) => {
46881
47416
  return findings;
46882
47417
  };
46883
47418
  var sddIgnored = (cwd2, slug) => {
46884
- const sddDir = path14.join(cwd2, "docs", slug, "sdd");
46885
- if (!existsSync11(sddDir))
47419
+ const sddDir = path15.join(cwd2, "docs", slug, "sdd");
47420
+ if (!existsSync12(sddDir))
46886
47421
  return true;
46887
47422
  try {
46888
47423
  execFileSync2("git", ["-C", cwd2, "rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
@@ -46890,7 +47425,7 @@ var sddIgnored = (cwd2, slug) => {
46890
47425
  return true;
46891
47426
  }
46892
47427
  try {
46893
- execFileSync2("git", ["-C", cwd2, "check-ignore", path14.posix.join("docs", slug, "sdd", "progress.md")], { stdio: "pipe" });
47428
+ execFileSync2("git", ["-C", cwd2, "check-ignore", path15.posix.join("docs", slug, "sdd", "progress.md")], { stdio: "pipe" });
46894
47429
  return true;
46895
47430
  } catch {
46896
47431
  return false;
@@ -46900,22 +47435,22 @@ var sddIgnored = (cwd2, slug) => {
46900
47435
  // packages/workit-core/src/core/sdd.ts
46901
47436
  import {
46902
47437
  appendFileSync as appendFileSync2,
46903
- existsSync as existsSync12,
47438
+ existsSync as existsSync13,
46904
47439
  mkdirSync as mkdirSync6,
46905
- readFileSync as readFileSync10,
46906
- statSync as statSync5,
46907
- writeFileSync as writeFileSync6
47440
+ readFileSync as readFileSync11,
47441
+ statSync as statSync6,
47442
+ writeFileSync as writeFileSync7
46908
47443
  } from "node:fs";
46909
47444
  import { execFileSync as execFileSync3 } from "node:child_process";
46910
- import path15 from "node:path";
46911
- var posix2 = (p) => p.split(path15.sep).join("/");
47445
+ import path16 from "node:path";
47446
+ var posix2 = (p) => p.split(path16.sep).join("/");
46912
47447
  function ledgerCompletion(root, slug) {
46913
47448
  let started = false;
46914
47449
  const completed = [];
46915
- const absProgress = path15.join(root, "docs", slug, "sdd", "progress.md");
46916
- if (existsSync12(absProgress)) {
47450
+ const absProgress = path16.join(root, "docs", slug, "sdd", "progress.md");
47451
+ if (existsSync13(absProgress)) {
46917
47452
  try {
46918
- for (const line of readFileSync10(absProgress, "utf8").split(`
47453
+ for (const line of readFileSync11(absProgress, "utf8").split(`
46919
47454
  `)) {
46920
47455
  const match = /^Task\s+(\d+):/i.exec(line);
46921
47456
  if (match) {
@@ -46928,9 +47463,9 @@ function ledgerCompletion(root, slug) {
46928
47463
  }
46929
47464
  const required = [];
46930
47465
  try {
46931
- const absPlan = path15.join(root, "docs", slug, "plan.md");
46932
- if (existsSync12(absPlan)) {
46933
- for (const task of parseTasksFromPlan(readFileSync10(absPlan, "utf8")))
47466
+ const absPlan = path16.join(root, "docs", slug, "plan.md");
47467
+ if (existsSync13(absPlan)) {
47468
+ for (const task of parseTasksFromPlan(readFileSync11(absPlan, "utf8")))
46934
47469
  required.push(task.id);
46935
47470
  }
46936
47471
  } catch {}
@@ -46962,7 +47497,7 @@ function sddReviewPackage({
46962
47497
  const dir = contained.path;
46963
47498
  const base7 = base_sha.slice(0, 7);
46964
47499
  const head7 = head_sha.slice(0, 7);
46965
- const diffPath = path15.join(dir, `review-${base7}..${head7}.diff`);
47500
+ const diffPath = path16.join(dir, `review-${base7}..${head7}.diff`);
46966
47501
  try {
46967
47502
  const diff2 = execFileSync3("git", ["diff", base_sha, head_sha], {
46968
47503
  cwd: contained.base,
@@ -46976,8 +47511,8 @@ function sddReviewPackage({
46976
47511
  };
46977
47512
  }
46978
47513
  mkdirSync6(dir, { recursive: true });
46979
- writeFileSync6(diffPath, diff2, "utf8");
46980
- const rel = posix2(path15.relative(contained.base, diffPath));
47514
+ writeFileSync7(diffPath, diff2, "utf8");
47515
+ const rel = posix2(path16.relative(contained.base, diffPath));
46981
47516
  return { diff_path: rel, base_sha, head_sha, base7, head7 };
46982
47517
  } catch (error) {
46983
47518
  return { error: error instanceof Error ? error.message : "git diff failed" };
@@ -47022,24 +47557,24 @@ function sddAppendAdvisory({
47022
47557
  if (!contained.ok)
47023
47558
  return { error: contained.error, code: "advisory_path_invalid" };
47024
47559
  const abs = contained.path;
47025
- if (existsSync12(abs) && statSync5(abs).isDirectory()) {
47560
+ if (existsSync13(abs) && statSync6(abs).isDirectory()) {
47026
47561
  return {
47027
47562
  error: `advisory target is a directory: ${advisories_path}`,
47028
47563
  code: "advisory_target_invalid"
47029
47564
  };
47030
47565
  }
47031
- mkdirSync6(path15.dirname(abs), { recursive: true });
47566
+ mkdirSync6(path16.dirname(abs), { recursive: true });
47032
47567
  const line = `- Task ${task_id}: ${collapsed}
47033
47568
  `;
47034
47569
  appendFileSync2(abs, line, "utf8");
47035
- const rel = posix2(path15.relative(contained.base, abs));
47570
+ const rel = posix2(path16.relative(contained.base, abs));
47036
47571
  return { ok: true, advisory: collapsed, advisories_path: rel };
47037
47572
  }
47038
47573
 
47039
47574
  // packages/workit-core/src/core/verify-project.ts
47040
47575
  import { spawnSync as spawnSync4 } from "node:child_process";
47041
- import { existsSync as existsSync14, readFileSync as readFileSync12, statSync as statSync7 } from "node:fs";
47042
- import path17 from "node:path";
47576
+ import { existsSync as existsSync15, readFileSync as readFileSync13, statSync as statSync8 } from "node:fs";
47577
+ import path18 from "node:path";
47043
47578
 
47044
47579
  // packages/workit-core/src/core/repo-context.ts
47045
47580
  import { spawnSync as spawnSync3 } from "node:child_process";
@@ -47048,16 +47583,16 @@ import { spawnSync as spawnSync3 } from "node:child_process";
47048
47583
  import {
47049
47584
  copyFileSync as copyFileSync3,
47050
47585
  cpSync as cpSync3,
47051
- existsSync as existsSync13,
47586
+ existsSync as existsSync14,
47052
47587
  mkdirSync as mkdirSync7,
47053
- readFileSync as readFileSync11,
47588
+ readFileSync as readFileSync12,
47054
47589
  readdirSync as readdirSync5,
47055
47590
  renameSync as renameSync2,
47056
- rmSync as rmSync2,
47057
- statSync as statSync6,
47058
- writeFileSync as writeFileSync7
47591
+ rmSync as rmSync3,
47592
+ statSync as statSync7,
47593
+ writeFileSync as writeFileSync8
47059
47594
  } from "node:fs";
47060
- import path16 from "node:path";
47595
+ import path17 from "node:path";
47061
47596
 
47062
47597
  // packages/workit-core/src/core/git.ts
47063
47598
  import { execFileSync as execFileSync4 } from "node:child_process";
@@ -47136,7 +47671,7 @@ var DECLARE_RE = /^\s*\*+Branch:\*+\s*`?([^`\s|]+)`?\s*$/gim;
47136
47671
  var USE_CURRENT_RE = /^\s*\*+Branch:\*+\s*use-current\s*$/im;
47137
47672
  var readSafe2 = (p) => {
47138
47673
  try {
47139
- return readFileSync11(p, "utf8");
47674
+ return readFileSync12(p, "utf8");
47140
47675
  } catch {
47141
47676
  return null;
47142
47677
  }
@@ -47153,7 +47688,7 @@ var normalizeBranch = (root, name) => {
47153
47688
  return parts.join("/");
47154
47689
  };
47155
47690
  var deriveSlug = (planPath) => {
47156
- const dirName = path16.basename(path16.dirname(planPath));
47691
+ const dirName = path17.basename(path17.dirname(planPath));
47157
47692
  return dirName === "." || dirName === "/" || dirName === "" ? "" : dirName;
47158
47693
  };
47159
47694
  var deriveKind = (planPath, fallback = "feature") => {
@@ -47176,8 +47711,8 @@ var resolveBranch = ({
47176
47711
  plan_path,
47177
47712
  workspace_root
47178
47713
  }) => {
47179
- const cwd2 = path16.resolve(workspace_root);
47180
- const abs = (p) => path16.isAbsolute(p) ? p : path16.join(cwd2, p);
47714
+ const cwd2 = path17.resolve(workspace_root);
47715
+ const abs = (p) => path17.isAbsolute(p) ? p : path17.join(cwd2, p);
47181
47716
  const spec = abs(spec_path);
47182
47717
  const plan = abs(plan_path);
47183
47718
  const git = gitContext(cwd2);
@@ -47242,17 +47777,17 @@ var repoRoot2 = (cwd2) => {
47242
47777
 
47243
47778
  // packages/workit-core/src/core/verify-project.ts
47244
47779
  var commandOnPath2 = (name) => {
47245
- const dirs = (process.env.PATH ?? "").split(path17.delimiter);
47780
+ const dirs = (process.env.PATH ?? "").split(path18.delimiter);
47246
47781
  const names = process.platform === "win32" ? [name, `${name}.exe`] : [name];
47247
47782
  for (const dir of dirs) {
47248
47783
  if (!dir)
47249
47784
  continue;
47250
47785
  for (const candidateName of names) {
47251
- const candidate = path17.join(dir, candidateName);
47786
+ const candidate = path18.join(dir, candidateName);
47252
47787
  try {
47253
- statSync7(candidate);
47788
+ statSync8(candidate);
47254
47789
  if (process.platform !== "win32") {
47255
- const mode = statSync7(candidate).mode & 73;
47790
+ const mode = statSync8(candidate).mode & 73;
47256
47791
  if (mode === 0)
47257
47792
  continue;
47258
47793
  }
@@ -47263,29 +47798,29 @@ var commandOnPath2 = (name) => {
47263
47798
  return false;
47264
47799
  };
47265
47800
  var hasScript = (cwd2, name) => {
47266
- const pkgPath = path17.join(cwd2, "package.json");
47267
- if (!existsSync14(pkgPath))
47801
+ const pkgPath = path18.join(cwd2, "package.json");
47802
+ if (!existsSync15(pkgPath))
47268
47803
  return false;
47269
47804
  try {
47270
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
47805
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
47271
47806
  return Boolean(pkg.scripts && typeof pkg.scripts[name] === "string");
47272
47807
  } catch {
47273
47808
  return false;
47274
47809
  }
47275
47810
  };
47276
47811
  var packageRunner = (cwd2) => {
47277
- if (existsSync14(path17.join(cwd2, "pnpm-lock.yaml")))
47812
+ if (existsSync15(path18.join(cwd2, "pnpm-lock.yaml")))
47278
47813
  return "pnpm";
47279
- const pkgPath = path17.join(cwd2, "package.json");
47280
- if (existsSync14(pkgPath)) {
47814
+ const pkgPath = path18.join(cwd2, "package.json");
47815
+ if (existsSync15(pkgPath)) {
47281
47816
  try {
47282
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
47817
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
47283
47818
  if (typeof pkg.packageManager === "string" && pkg.packageManager.startsWith("pnpm")) {
47284
47819
  return "pnpm";
47285
47820
  }
47286
47821
  } catch {}
47287
47822
  }
47288
- if (existsSync14(path17.join(cwd2, "yarn.lock")))
47823
+ if (existsSync15(path18.join(cwd2, "yarn.lock")))
47289
47824
  return "yarn";
47290
47825
  return "npm";
47291
47826
  };
@@ -47345,8 +47880,8 @@ root: ${cwd2}
47345
47880
  `);
47346
47881
  lines.push(`dry_run: ${String(dryRun)}
47347
47882
  `);
47348
- const pkgPath = path17.join(cwd2, "package.json");
47349
- if (existsSync14(pkgPath)) {
47883
+ const pkgPath = path18.join(cwd2, "package.json");
47884
+ if (existsSync15(pkgPath)) {
47350
47885
  const runner = packageRunner(cwd2);
47351
47886
  for (const script of ["lint", "format:check", "test", "build"]) {
47352
47887
  if (hasScript(cwd2, script)) {
@@ -47361,7 +47896,7 @@ root: ${cwd2}
47361
47896
  } else {
47362
47897
  skipCheck("javascript", "package.json not found");
47363
47898
  }
47364
- const cargoManifest = existsSync14(path17.join(cwd2, "Cargo.toml")) ? "Cargo.toml" : existsSync14(path17.join(cwd2, "src-tauri/Cargo.toml")) ? "src-tauri/Cargo.toml" : "";
47899
+ const cargoManifest = existsSync15(path18.join(cwd2, "Cargo.toml")) ? "Cargo.toml" : existsSync15(path18.join(cwd2, "src-tauri/Cargo.toml")) ? "src-tauri/Cargo.toml" : "";
47365
47900
  if (cargoManifest) {
47366
47901
  runCheck("cargo fmt", "cargo", ["fmt", "--manifest-path", cargoManifest, "--", "--check"]);
47367
47902
  runCheck("cargo clippy", "cargo", [
@@ -47377,7 +47912,7 @@ root: ${cwd2}
47377
47912
  } else {
47378
47913
  skipCheck("rust", "Cargo.toml not found");
47379
47914
  }
47380
- if (existsSync14(path17.join(cwd2, "pyproject.toml")) || existsSync14(path17.join(cwd2, "pytest.ini")) || existsSync14(path17.join(cwd2, "tests"))) {
47915
+ if (existsSync15(path18.join(cwd2, "pyproject.toml")) || existsSync15(path18.join(cwd2, "pytest.ini")) || existsSync15(path18.join(cwd2, "tests"))) {
47381
47916
  if (commandOnPath2("pytest"))
47382
47917
  runCheck("pytest", "pytest", []);
47383
47918
  else
@@ -47394,13 +47929,13 @@ root: ${cwd2}
47394
47929
  lines.push(`command: grep -qi "## [Unreleased]" CHANGELOG.md
47395
47930
 
47396
47931
  `);
47397
- const changelogPath = path17.join(cwd2, "CHANGELOG.md");
47932
+ const changelogPath = path18.join(cwd2, "CHANGELOG.md");
47398
47933
  if (dryRun) {
47399
47934
  lines.push(`status: skipped (dry run)
47400
47935
  `);
47401
47936
  skipped += 1;
47402
- } else if (existsSync14(changelogPath)) {
47403
- if (/## \[Unreleased\]/i.test(readFileSync12(changelogPath, "utf8"))) {
47937
+ } else if (existsSync15(changelogPath)) {
47938
+ if (/## \[Unreleased\]/i.test(readFileSync13(changelogPath, "utf8"))) {
47404
47939
  lines.push(`status: pass
47405
47940
  `);
47406
47941
  passed += 1;
@@ -47453,7 +47988,7 @@ var SLUG_RE2 = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
47453
47988
  var flowPath = (root, slug) => {
47454
47989
  if (!SLUG_RE2.test(slug))
47455
47990
  throw new Error(`invalid slug: ${JSON.stringify(slug)}`);
47456
- return path18.join(root, "docs", slug, "sdd", "flow.json");
47991
+ return path19.join(root, "docs", slug, "sdd", "flow.json");
47457
47992
  };
47458
47993
  var resolveDoc = (root, slug, docPath, kind) => {
47459
47994
  const resolved = resolveCanonicalLayout({
@@ -47468,11 +48003,11 @@ var resolveDoc = (root, slug, docPath, kind) => {
47468
48003
  var HEX64_RE = /^[0-9a-f]{64}$/;
47469
48004
  var FLOW_STATUSES = ["draft", "self_reviewed", "approved"];
47470
48005
  var EXECUTION_STATUSES = ["pending", "active", "paused", "completed"];
47471
- var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
48006
+ var isRecord4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
47472
48007
  var validateEvidenceValue = (v, allowCli) => {
47473
48008
  if (v === null)
47474
48009
  return true;
47475
- if (!isRecord3(v))
48010
+ if (!isRecord4(v))
47476
48011
  return false;
47477
48012
  if (v.host === "opencode") {
47478
48013
  return v.attested === true && typeof v.callID === "string" && typeof v.selectedLabel === "string" && typeof v.recordedAt === "number";
@@ -47485,7 +48020,7 @@ var validateEvidenceValue = (v, allowCli) => {
47485
48020
  return false;
47486
48021
  };
47487
48022
  var validateState = (parsed, slug) => {
47488
- if (!isRecord3(parsed))
48023
+ if (!isRecord4(parsed))
47489
48024
  return { ok: false, error: "flow state must be a JSON object" };
47490
48025
  if (parsed.slug !== undefined && (typeof parsed.slug !== "string" || parsed.slug !== slug)) {
47491
48026
  return { ok: false, error: `flow state slug must be ${JSON.stringify(slug)}` };
@@ -47500,8 +48035,8 @@ var validateState = (parsed, slug) => {
47500
48035
  return { ok: false, error: "flow state updated_at must be a finite number" };
47501
48036
  }
47502
48037
  const doc = (value, name) => {
47503
- const p = isRecord3(value) ? value : {};
47504
- if (!isRecord3(value) && value !== undefined) {
48038
+ const p = isRecord4(value) ? value : {};
48039
+ if (!isRecord4(value) && value !== undefined) {
47505
48040
  return `flow state ${name} must be an object`;
47506
48041
  }
47507
48042
  if (p.status !== undefined && !FLOW_STATUSES.includes(p.status)) {
@@ -47529,8 +48064,8 @@ var validateState = (parsed, slug) => {
47529
48064
  const plan = doc(parsed.plan, "plan");
47530
48065
  if (typeof plan === "string")
47531
48066
  return { ok: false, error: plan };
47532
- const menuRaw = isRecord3(parsed.menu) ? parsed.menu : undefined;
47533
- if (parsed.menu !== undefined && !isRecord3(parsed.menu)) {
48067
+ const menuRaw = isRecord4(parsed.menu) ? parsed.menu : undefined;
48068
+ if (parsed.menu !== undefined && !isRecord4(parsed.menu)) {
47534
48069
  return { ok: false, error: "flow state menu must be an object" };
47535
48070
  }
47536
48071
  if (menuRaw?.presented !== undefined && typeof menuRaw.presented !== "boolean") {
@@ -47548,8 +48083,8 @@ var validateState = (parsed, slug) => {
47548
48083
  if (menuRaw?.evidence !== undefined && !validateEvidenceValue(menuRaw.evidence, false)) {
47549
48084
  return { ok: false, error: "flow state menu.evidence has an unsupported shape" };
47550
48085
  }
47551
- const execRaw = isRecord3(parsed.execution) ? parsed.execution : undefined;
47552
- if (parsed.execution !== undefined && !isRecord3(parsed.execution)) {
48086
+ const execRaw = isRecord4(parsed.execution) ? parsed.execution : undefined;
48087
+ if (parsed.execution !== undefined && !isRecord4(parsed.execution)) {
47553
48088
  return { ok: false, error: "flow state execution must be an object" };
47554
48089
  }
47555
48090
  if (execRaw?.status !== undefined && !EXECUTION_STATUSES.includes(execRaw.status)) {
@@ -47598,13 +48133,13 @@ var validateState = (parsed, slug) => {
47598
48133
  };
47599
48134
  var readFlowStrict = (root, slug) => {
47600
48135
  const file = flowPath(root, slug);
47601
- const rel = path18.posix.join("docs", slug, "sdd", "flow.json");
47602
- if (!existsSync15(file)) {
48136
+ const rel = path19.posix.join("docs", slug, "sdd", "flow.json");
48137
+ if (!existsSync16(file)) {
47603
48138
  return err2("flow_not_activated", `flow not activated for ${slug} — run workit_flow_status first`);
47604
48139
  }
47605
48140
  let text;
47606
48141
  try {
47607
- text = readFileSync13(file, "utf8");
48142
+ text = readFileSync14(file, "utf8");
47608
48143
  } catch (error) {
47609
48144
  return err2("flow_io_error", `cannot read flow state at ${file}: ${error instanceof Error ? error.message : String(error)}`);
47610
48145
  }
@@ -47628,11 +48163,11 @@ var writeFlowFileAtomic = (file, state) => {
47628
48163
  const text = JSON.stringify(state, null, 2) + `
47629
48164
  `;
47630
48165
  const tmp = uniqueTempPath(file);
47631
- mkdirSync8(path18.dirname(file), { recursive: true });
48166
+ mkdirSync8(path19.dirname(file), { recursive: true });
47632
48167
  let fd = null;
47633
48168
  try {
47634
48169
  fd = openSync(tmp, "w");
47635
- writeFileSync8(fd, text, "utf8");
48170
+ writeFileSync9(fd, text, "utf8");
47636
48171
  fsyncSync(fd);
47637
48172
  closeSync(fd);
47638
48173
  fd = null;
@@ -47643,8 +48178,8 @@ var writeFlowFileAtomic = (file, state) => {
47643
48178
  closeSync(fd);
47644
48179
  } catch {}
47645
48180
  try {
47646
- if (existsSync15(tmp))
47647
- rmSync3(tmp, { force: true });
48181
+ if (existsSync16(tmp))
48182
+ rmSync4(tmp, { force: true });
47648
48183
  } catch {}
47649
48184
  }
47650
48185
  };
@@ -47652,14 +48187,14 @@ var MAX_WRITE_ATTEMPTS = 5;
47652
48187
  var STALE_LOCK_MS = 1000;
47653
48188
  var lockMtimeMs = (lock) => {
47654
48189
  try {
47655
- return statSync8(lock).mtimeMs;
48190
+ return statSync9(lock).mtimeMs;
47656
48191
  } catch {
47657
48192
  return null;
47658
48193
  }
47659
48194
  };
47660
48195
  var lockOwnedBy = (fd, lock) => {
47661
48196
  try {
47662
- return fstatSync(fd).ino === statSync8(lock).ino;
48197
+ return fstatSync(fd).ino === statSync9(lock).ino;
47663
48198
  } catch {
47664
48199
  return false;
47665
48200
  }
@@ -47675,16 +48210,16 @@ var writeFlowStateIfCurrent = (root, expected, next) => {
47675
48210
  const tmp = uniqueTempPath(file);
47676
48211
  let fd = null;
47677
48212
  try {
47678
- const currentText = existsSync15(file) ? readFileSync13(file, "utf8") : null;
48213
+ const currentText = existsSync16(file) ? readFileSync14(file, "utf8") : null;
47679
48214
  if (currentText !== expectedText)
47680
48215
  return { ok: false, conflict: true };
47681
- mkdirSync8(path18.dirname(file), { recursive: true });
48216
+ mkdirSync8(path19.dirname(file), { recursive: true });
47682
48217
  fd = openSync(tmp, "w");
47683
- writeFileSync8(fd, nextText, "utf8");
48218
+ writeFileSync9(fd, nextText, "utf8");
47684
48219
  fsyncSync(fd);
47685
48220
  closeSync(fd);
47686
48221
  fd = null;
47687
- const reRead = existsSync15(file) ? readFileSync13(file, "utf8") : null;
48222
+ const reRead = existsSync16(file) ? readFileSync14(file, "utf8") : null;
47688
48223
  if (reRead !== expectedText)
47689
48224
  return { ok: false, conflict: true };
47690
48225
  renameSync3(tmp, file);
@@ -47697,16 +48232,16 @@ var writeFlowStateIfCurrent = (root, expected, next) => {
47697
48232
  closeSync(fd);
47698
48233
  } catch {}
47699
48234
  try {
47700
- if (existsSync15(tmp))
47701
- rmSync3(tmp, { force: true });
48235
+ if (existsSync16(tmp))
48236
+ rmSync4(tmp, { force: true });
47702
48237
  } catch {}
47703
48238
  }
47704
48239
  };
47705
48240
  var readCanonicalDigest = (root, rel) => {
47706
- const abs = path18.join(root, ...rel.split("/"));
48241
+ const abs = path19.join(root, ...rel.split("/"));
47707
48242
  let bytes;
47708
48243
  try {
47709
- bytes = readFileSync13(abs);
48244
+ bytes = readFileSync14(abs);
47710
48245
  } catch (error) {
47711
48246
  if (error.code === "ENOENT") {
47712
48247
  return { ok: false, code: "document_missing" };
@@ -47744,8 +48279,8 @@ var driftCodeFor = (root, relPath, storedDigest) => {
47744
48279
  return current.digest !== storedDigest ? "digest_mismatch" : null;
47745
48280
  };
47746
48281
  var reconcileState = (root, slug, state) => {
47747
- const specPath = path18.posix.join("docs", slug, "spec.md");
47748
- const planPath = path18.posix.join("docs", slug, "plan.md");
48282
+ const specPath = path19.posix.join("docs", slug, "spec.md");
48283
+ const planPath = path19.posix.join("docs", slug, "plan.md");
47749
48284
  if (state.spec.status === "approved") {
47750
48285
  const code = driftCodeFor(root, specPath, state.spec.approved_digest);
47751
48286
  if (code) {
@@ -47779,7 +48314,7 @@ var deriveLegacyExecution = (root, slug, state) => {
47779
48314
  return { status: "pending", mode: null, evidence: null, coordinator_session_id: null };
47780
48315
  };
47781
48316
  var normalizeCompatibility = (root, slug, parsed, state) => {
47782
- if (!isRecord3(parsed) || !("execution" in parsed)) {
48317
+ if (!isRecord4(parsed) || !("execution" in parsed)) {
47783
48318
  const derived = deriveLegacyExecution(root, slug, state);
47784
48319
  const current = state.execution;
47785
48320
  if (derived.status !== current.status || derived.mode !== current.mode) {
@@ -47787,7 +48322,7 @@ var normalizeCompatibility = (root, slug, parsed, state) => {
47787
48322
  }
47788
48323
  return { state, changed: false };
47789
48324
  }
47790
- const execRaw = isRecord3(parsed.execution) ? parsed.execution : undefined;
48325
+ const execRaw = isRecord4(parsed.execution) ? parsed.execution : undefined;
47791
48326
  if (execRaw && !("coordinator_session_id" in execRaw)) {
47792
48327
  return { state: { ...state, updated_at: Date.now() }, changed: true };
47793
48328
  }
@@ -47795,11 +48330,11 @@ var normalizeCompatibility = (root, slug, parsed, state) => {
47795
48330
  };
47796
48331
  var withFlowLock = (file, fn) => {
47797
48332
  const lock = `${file}.lock`;
47798
- if (!existsSync15(path18.dirname(file)))
48333
+ if (!existsSync16(path19.dirname(file)))
47799
48334
  return { locked: true, value: fn() };
47800
48335
  try {
47801
- if (existsSync15(`${lock}.stale`))
47802
- rmSync3(`${lock}.stale`, { force: true });
48336
+ if (existsSync16(`${lock}.stale`))
48337
+ rmSync4(`${lock}.stale`, { force: true });
47803
48338
  } catch {}
47804
48339
  const wait = new Int32Array(new SharedArrayBuffer(4));
47805
48340
  let fd = null;
@@ -47837,7 +48372,7 @@ var withFlowLock = (file, fn) => {
47837
48372
  if (attempt2 === MAX_WRITE_ATTEMPTS - 1) {
47838
48373
  return {
47839
48374
  locked: false,
47840
- error: err2("flow_concurrent_conflict", `concurrent flow update detected for ${path18.dirname(file)}: re-read the flow state and retry the transition`)
48375
+ error: err2("flow_concurrent_conflict", `concurrent flow update detected for ${path19.dirname(file)}: re-read the flow state and retry the transition`)
47841
48376
  };
47842
48377
  }
47843
48378
  Atomics.wait(wait, 0, 0, 10);
@@ -47846,7 +48381,7 @@ var withFlowLock = (file, fn) => {
47846
48381
  if (fd === null) {
47847
48382
  return {
47848
48383
  locked: false,
47849
- error: err2("flow_concurrent_conflict", `concurrent flow update detected for ${path18.dirname(file)}: re-read the flow state and retry the transition`)
48384
+ error: err2("flow_concurrent_conflict", `concurrent flow update detected for ${path19.dirname(file)}: re-read the flow state and retry the transition`)
47850
48385
  };
47851
48386
  }
47852
48387
  try {
@@ -47854,7 +48389,7 @@ var withFlowLock = (file, fn) => {
47854
48389
  } finally {
47855
48390
  try {
47856
48391
  if (fd !== null && lockOwnedBy(fd, lock))
47857
- rmSync3(lock, { force: true });
48392
+ rmSync4(lock, { force: true });
47858
48393
  } catch {}
47859
48394
  try {
47860
48395
  if (fd !== null)
@@ -47864,7 +48399,7 @@ var withFlowLock = (file, fn) => {
47864
48399
  };
47865
48400
  var readEffectiveFlowState = (root, slug) => {
47866
48401
  const file = flowPath(root, slug);
47867
- const rel = path18.posix.join("docs", slug, "sdd", "flow.json");
48402
+ const rel = path19.posix.join("docs", slug, "sdd", "flow.json");
47868
48403
  const locked = withFlowLock(file, () => {
47869
48404
  const strict = readFlowStrict(root, slug);
47870
48405
  if (!strict.ok)
@@ -48293,7 +48828,7 @@ var transitionExecution = (root, slug, planPath, action, evidence, ctx, deps) =>
48293
48828
  });
48294
48829
  };
48295
48830
  var slugFromPath = (p) => {
48296
- const dirName = path18.basename(path18.dirname(p));
48831
+ const dirName = path19.basename(path19.dirname(p));
48297
48832
  return dirName === "." || dirName === "/" || dirName === "" ? "" : dirName;
48298
48833
  };
48299
48834
  var assertSddControlGates = (root, slug, opts = {}, ctx) => {
@@ -48315,8 +48850,8 @@ var assertSddControlGates = (root, slug, opts = {}, ctx) => {
48315
48850
  }
48316
48851
  if (opts.requireDocs) {
48317
48852
  const validated = docsValidate({
48318
- spec_path: path18.posix.join("docs", slug, "spec.md"),
48319
- plan_path: path18.posix.join("docs", slug, "plan.md"),
48853
+ spec_path: path19.posix.join("docs", slug, "spec.md"),
48854
+ plan_path: path19.posix.join("docs", slug, "plan.md"),
48320
48855
  workspace_root: root
48321
48856
  });
48322
48857
  if (validated.ok === false)
@@ -48452,11 +48987,11 @@ var BASH_GIT_VALUE_FLAGS = new Set([
48452
48987
  var COORDINATOR_SHELL_DENIED_TEXT = "Coordinator shell commands are restricted while a subagent-driven plan is " + "active: only bounded read/test/review commands are allowed (the exact " + "allowlist is in flow-state.ts, isCoordinatorBashAllowed). " + COORDINATOR_RECOVERY_TEXT;
48453
48988
 
48454
48989
  // packages/workit-core/src/core/handoff-tools.ts
48455
- import path20 from "node:path";
48990
+ import path21 from "node:path";
48456
48991
 
48457
48992
  // packages/workit-core/src/core/handoff-context.ts
48458
- import { existsSync as existsSync16, readFileSync as readFileSync14, readdirSync as readdirSync7, statSync as statSync9 } from "node:fs";
48459
- import path19 from "node:path";
48993
+ import { existsSync as existsSync17, readFileSync as readFileSync15, readdirSync as readdirSync7, statSync as statSync10 } from "node:fs";
48994
+ import path20 from "node:path";
48460
48995
  var DOC_RE = /docs\/([A-Za-z0-9][A-Za-z0-9._-]*)\/(spec|plan)\.md/g;
48461
48996
  var listMd = (dir) => {
48462
48997
  try {
@@ -48476,13 +49011,13 @@ var resolveFromMessagePaths = (root, message) => {
48476
49011
  const slug = slugs[0];
48477
49012
  const plan = `docs/${slug}/plan.md`;
48478
49013
  const spec = `docs/${slug}/spec.md`;
48479
- if (!existsSync16(path19.join(root, plan)) || !existsSync16(path19.join(root, spec))) {
49014
+ if (!existsSync17(path20.join(root, plan)) || !existsSync17(path20.join(root, spec))) {
48480
49015
  return { error: `docs/${slug}/ must contain both plan.md and spec.md` };
48481
49016
  }
48482
49017
  return { spec, plan, source: "message_paths" };
48483
49018
  };
48484
49019
  var resolveActivePair = (root) => {
48485
- const docsDir = path19.join(root, "docs");
49020
+ const docsDir = path20.join(root, "docs");
48486
49021
  let best = null;
48487
49022
  let entries = [];
48488
49023
  try {
@@ -48493,11 +49028,11 @@ var resolveActivePair = (root) => {
48493
49028
  for (const slug of entries) {
48494
49029
  if (slug.startsWith("."))
48495
49030
  continue;
48496
- const plan = path19.join("docs", slug, "plan.md");
48497
- const spec = path19.join("docs", slug, "spec.md");
48498
- if (!existsSync16(path19.join(root, plan)) || !existsSync16(path19.join(root, spec)))
49031
+ const plan = path20.join("docs", slug, "plan.md");
49032
+ const spec = path20.join("docs", slug, "spec.md");
49033
+ if (!existsSync17(path20.join(root, plan)) || !existsSync17(path20.join(root, spec)))
48499
49034
  continue;
48500
- const score = Math.max(statSync9(path19.join(root, spec)).mtimeMs, statSync9(path19.join(root, plan)).mtimeMs);
49035
+ const score = Math.max(statSync10(path20.join(root, spec)).mtimeMs, statSync10(path20.join(root, plan)).mtimeMs);
48501
49036
  if (best === null || score > best.score || score === best.score && slug < best.spec.split("/")[1]) {
48502
49037
  best = { score, spec, plan, source: "active_pair" };
48503
49038
  }
@@ -48515,8 +49050,8 @@ var resolveWorkflowPaths = (root, message) => {
48515
49050
  const active = resolveActivePair(root);
48516
49051
  if (!("error" in active))
48517
49052
  return active;
48518
- const docsDir = path19.join(root, "docs");
48519
- if (!existsSync16(docsDir) || listMd(docsDir).length === 0) {
49053
+ const docsDir = path20.join(root, "docs");
49054
+ if (!existsSync17(docsDir) || listMd(docsDir).length === 0) {
48520
49055
  return { error: "no docs/<slug>/ features found under docs/" };
48521
49056
  }
48522
49057
  return {
@@ -48540,15 +49075,15 @@ ${JSON.stringify({ ok: false, errors: validated.errors })}`
48540
49075
  if ("error" in branchResolved)
48541
49076
  return { error: branchResolved.error };
48542
49077
  const branch = branchResolved.branch;
48543
- const slug = path19.basename(path19.dirname(plan));
49078
+ const slug = path20.basename(path20.dirname(plan));
48544
49079
  const sddDir = `docs/${slug}/sdd`;
48545
- const planText = readFileSync14(path19.join(root, plan), "utf8");
49080
+ const planText = readFileSync15(path20.join(root, plan), "utf8");
48546
49081
  const tasks = parseTasksFromPlan(planText);
48547
49082
  const taskList = tasks.map((t) => `- Task ${t.id}: ${t.title}`).join(`
48548
49083
  `);
48549
49084
  let contract;
48550
49085
  try {
48551
- contract = readFileSync14(templatePath, "utf8");
49086
+ contract = readFileSync15(templatePath, "utf8");
48552
49087
  } catch {
48553
49088
  return { error: "missing template templates/execution-contract.md" };
48554
49089
  }
@@ -48564,7 +49099,7 @@ var buildHandoffPrompt = (root, message) => {
48564
49099
  const resolved = resolveWorkflowPaths(root, message);
48565
49100
  if ("error" in resolved)
48566
49101
  return { error: resolved.error };
48567
- const templatePath = path20.join(assetRoot(), "templates", "execution-contract.md");
49102
+ const templatePath = path21.join(assetRoot(), "templates", "execution-contract.md");
48568
49103
  const contract = buildHandoffContract({
48569
49104
  root,
48570
49105
  spec: resolved.spec,
@@ -48573,7 +49108,7 @@ var buildHandoffPrompt = (root, message) => {
48573
49108
  });
48574
49109
  if ("error" in contract)
48575
49110
  return { error: contract.error };
48576
- const sdd = `docs/${path20.basename(path20.dirname(resolved.plan))}/sdd`;
49111
+ const sdd = `docs/${path21.basename(path21.dirname(resolved.plan))}/sdd`;
48577
49112
  return { prompt: contract.prompt, spec: resolved.spec, plan: resolved.plan, sdd };
48578
49113
  };
48579
49114
 
@@ -48761,7 +49296,7 @@ function statusCommand(root, plan, out, err3) {
48761
49296
  execution: state.execution,
48762
49297
  handoff_destination: state.handoff_destination,
48763
49298
  drift,
48764
- flow_path: path21.posix.join("docs", state.slug, "sdd", "flow.json")
49299
+ flow_path: path22.posix.join("docs", state.slug, "sdd", "flow.json")
48765
49300
  });
48766
49301
  return 0;
48767
49302
  }
@@ -48788,7 +49323,7 @@ function reviewPackageCommand(root, parsed, out, err3) {
48788
49323
  if (!resolved.ok)
48789
49324
  return domainFail(err3, "path_invalid", resolved.error);
48790
49325
  const result2 = sddReviewPackage({
48791
- sdd_dir: path21.posix.join("docs", resolved.layout.slug, "sdd"),
49326
+ sdd_dir: path22.posix.join("docs", resolved.layout.slug, "sdd"),
48792
49327
  base_sha: parsed.base,
48793
49328
  head_sha: parsed.head,
48794
49329
  workspace_root: root
@@ -48815,7 +49350,7 @@ function appendAdvisoryCommand(root, parsed, out, err3) {
48815
49350
  const trimmed = parsed.task.trim();
48816
49351
  const taskId = /^-?\d+(\.\d+)?$/.test(trimmed) ? Number(trimmed) : trimmed;
48817
49352
  const result2 = sddAppendAdvisory({
48818
- advisories_path: path21.posix.join("docs", slug, "sdd", "advisories.md"),
49353
+ advisories_path: path22.posix.join("docs", slug, "sdd", "advisories.md"),
48819
49354
  task_id: taskId,
48820
49355
  text: parsed.text,
48821
49356
  workspace_root: root
@@ -48873,7 +49408,7 @@ async function runHandoffCommand(argv, deps = {}) {
48873
49408
  }
48874
49409
 
48875
49410
  // packages/workit-cli/src/index.tsx
48876
- var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
49411
+ var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
48877
49412
  var logger = createLogger({
48878
49413
  stderr: (event) => {
48879
49414
  if (event.level === "debug" || event.level === "info")
@@ -48897,6 +49432,7 @@ var HELP = `workit — workflow rails for agentic coding
48897
49432
  Usage:
48898
49433
  workit init Run the interactive setup wizard
48899
49434
  workit doctor Verify the offline installation health (add --json for a machine-readable report)
49435
+ workit uninstall Remove workit host registrations interactively (~/.config/workit is kept)
48900
49436
  ${COMMAND_DESCRIPTIONS.map(([cmd, desc]) => ` ${cmd.padEnd(helpColumn)}${desc}`).join(`
48901
49437
  `)}
48902
49438
  workit Show this help
@@ -48924,10 +49460,12 @@ function printMalformedBlocked(state) {
48924
49460
  async function runInit() {
48925
49461
  const state = readSetupState();
48926
49462
  if (state.config.status === "malformed") {
49463
+ process.stdout.write("\x1B[2J\x1B[H");
48927
49464
  printMalformedBlocked(state);
48928
49465
  process.exit(1);
48929
49466
  }
48930
49467
  if (process.stdin.isTTY !== true) {
49468
+ process.stdout.write("\x1B[2J\x1B[H");
48931
49469
  console.log("workit init requires an interactive terminal (TTY).");
48932
49470
  for (const line of setupCompletionGuidance())
48933
49471
  console.log(line);
@@ -48936,25 +49474,32 @@ async function runInit() {
48936
49474
  logger.info(EVENT.installSteps, { step: "wizard_start" });
48937
49475
  const exits = [];
48938
49476
  let done = () => {};
48939
- const { waitUntilExit, unmount } = render_default(/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Wizard, {
49477
+ process.stdout.write("\x1B[2J\x1B[H");
49478
+ const instance = render_default(/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Wizard, {
48940
49479
  onExit: (complete, values2) => {
48941
49480
  exits.push({ complete, values: values2 });
48942
49481
  done();
48943
49482
  }
48944
- }, undefined, false, undefined, this));
48945
- done = unmount;
48946
- await waitUntilExit();
49483
+ }, undefined, false, undefined, this), { interactive: true });
49484
+ done = instance.unmount;
49485
+ try {
49486
+ await instance.waitUntilExit();
49487
+ } finally {
49488
+ instance.unmount();
49489
+ }
49490
+ process.stdout.write("\x1B[2J\x1B[H");
48947
49491
  const exit = exits[0];
48948
49492
  if (exit && exit.complete && exit.values) {
48949
- const preview = buildSetupPreview(exit.values, { cwd: process.cwd(), env: process.env });
49493
+ const base2 = resolveBasePath(exit.values);
49494
+ const preview = buildSetupPreview(exit.values, { cwd: base2, env: process.env });
48950
49495
  if (!preview.ok) {
48951
49496
  printMalformedBlocked(preview.state);
48952
49497
  process.exit(1);
48953
49498
  }
48954
- const result2 = applySetupPreview(preview, { cwd: process.cwd(), env: process.env });
49499
+ const result2 = applySetupPreview(preview, { cwd: base2, env: process.env });
48955
49500
  let exitCode = result2.exitCode;
48956
49501
  if (exit.values.branchPolicy) {
48957
- const bp = applyWizardBranchPolicy(exit.values.branchPolicy, process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), process.env);
49502
+ const bp = applyWizardBranchPolicy(exit.values.branchPolicy, base2, process.env);
48958
49503
  if (bp.ok) {
48959
49504
  console.log(`${String(bp.status).padEnd(11)} ${bp.config_path} — branch policy`);
48960
49505
  } else {
@@ -48972,6 +49517,111 @@ async function runInit() {
48972
49517
  });
48973
49518
  process.exit(exit !== undefined && exit.complete ? 0 : 1);
48974
49519
  }
49520
+ var UNINSTALL_HOST_OPTIONS = [
49521
+ { label: "OpenCode", value: "opencode" },
49522
+ { label: "Cursor", value: "cursor" }
49523
+ ];
49524
+ function UninstallWizard({ onExit }) {
49525
+ const [hosts, setHosts] = import_react67.useState([]);
49526
+ const [plan, setPlan] = import_react67.useState(null);
49527
+ if (!plan) {
49528
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
49529
+ flexDirection: "column",
49530
+ gap: 1,
49531
+ children: [
49532
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49533
+ bold: true,
49534
+ children: "Uninstall workit"
49535
+ }, undefined, false, undefined, this),
49536
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49537
+ dimColor: true,
49538
+ children: "Select the hosts to remove workit from (space to toggle):"
49539
+ }, undefined, false, undefined, this),
49540
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(MultiSelect, {
49541
+ options: UNINSTALL_HOST_OPTIONS,
49542
+ defaultValue: [],
49543
+ onChange: (values2) => setHosts(values2),
49544
+ onSubmit: (values2) => {
49545
+ setHosts(values2);
49546
+ setPlan(planUninstall({ env: process.env }));
49547
+ }
49548
+ }, undefined, false, undefined, this),
49549
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49550
+ dimColor: true,
49551
+ children: "Enter to continue"
49552
+ }, undefined, false, undefined, this)
49553
+ ]
49554
+ }, undefined, true, undefined, this);
49555
+ }
49556
+ const selected = plan.hosts.filter((h) => hosts.includes(h.host));
49557
+ const reviewed = { hosts: selected };
49558
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
49559
+ flexDirection: "column",
49560
+ gap: 1,
49561
+ children: [
49562
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49563
+ bold: true,
49564
+ children: "Uninstall workit — review"
49565
+ }, undefined, false, undefined, this),
49566
+ selected.every((h) => h.actions.length === 0) ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49567
+ children: "No workit registrations found for the selected hosts."
49568
+ }, undefined, false, undefined, this) : selected.flatMap((h) => h.actions.map((a) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49569
+ children: [
49570
+ "• [",
49571
+ h.host,
49572
+ "] ",
49573
+ a.detail,
49574
+ ": ",
49575
+ a.path
49576
+ ]
49577
+ }, `${h.host}:${a.path}`, true, undefined, this))),
49578
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
49579
+ children: "Apply uninstall? (y/N)"
49580
+ }, undefined, false, undefined, this),
49581
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ConfirmInput, {
49582
+ onConfirm: () => onExit({ confirmed: true, hosts, plan: reviewed }),
49583
+ onCancel: () => onExit({ confirmed: false, hosts, plan: reviewed })
49584
+ }, undefined, false, undefined, this)
49585
+ ]
49586
+ }, undefined, true, undefined, this);
49587
+ }
49588
+ async function runUninstall() {
49589
+ if (process.stdin.isTTY !== true) {
49590
+ console.log("workit uninstall requires an interactive terminal (TTY).");
49591
+ console.log("It removes workit registrations from OpenCode and/or Cursor; your ~/.config/workit configuration is always kept.");
49592
+ process.exit(2);
49593
+ }
49594
+ const outcomes = [];
49595
+ let done = () => {};
49596
+ const instance = render_default(/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(UninstallWizard, {
49597
+ onExit: (outcome2) => {
49598
+ outcomes.push(outcome2);
49599
+ done();
49600
+ }
49601
+ }, undefined, false, undefined, this), { interactive: true });
49602
+ done = instance.unmount;
49603
+ try {
49604
+ await instance.waitUntilExit();
49605
+ } finally {
49606
+ instance.unmount();
49607
+ }
49608
+ const outcome = outcomes[0];
49609
+ if (!outcome || !outcome.confirmed || !outcome.plan) {
49610
+ console.log("Uninstall cancelled — nothing was changed.");
49611
+ process.exit(0);
49612
+ }
49613
+ const actions = outcome.plan.hosts.flatMap((h) => h.actions);
49614
+ if (actions.length === 0) {
49615
+ console.log("Nothing to remove for the selected hosts.");
49616
+ process.exit(0);
49617
+ }
49618
+ const result2 = applyUninstall(outcome.plan, { env: process.env });
49619
+ for (const entry of result2.entries) {
49620
+ console.log(`${entry.status.padEnd(8)} ${entry.path}${entry.detail ? ` — ${entry.detail}` : ""}`);
49621
+ }
49622
+ console.log(result2.ok ? "Uninstall complete." : "Uninstall finished with problems.");
49623
+ process.exit(result2.ok ? 0 : 1);
49624
+ }
48975
49625
  function runDoctorCommand(args) {
48976
49626
  const report = runDoctor({ host: "cli", cwd: process.cwd() });
48977
49627
  if (args.includes("--json")) {
@@ -49006,11 +49656,15 @@ if (__require.main == __require.module) {
49006
49656
  process.exit(await runFlowCommand(args.slice(1)));
49007
49657
  } else if (subcommand === "handoff") {
49008
49658
  process.exit(await runHandoffCommand(args.slice(1)));
49659
+ } else if (subcommand === "uninstall") {
49660
+ await runUninstall();
49009
49661
  } else {
49010
49662
  console.log(HELP);
49011
49663
  process.exit(0);
49012
49664
  }
49013
49665
  }
49014
49666
  export {
49667
+ runUninstall,
49668
+ runInit,
49015
49669
  logger
49016
49670
  };