@logic-joe/fleek 0.2.15 → 0.2.17

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/fleek.mjs +651 -259
  2. package/package.json +1 -1
package/dist/fleek.mjs CHANGED
@@ -2395,6 +2395,7 @@ var require_tools = __commonJS({
2395
2395
  fleek_get_whiteboard: "whiteboards.get",
2396
2396
  whiteboard_scene: "whiteboards.get",
2397
2397
  fleek_list_attachments: "attachments.list",
2398
+ fleek_get_attachment: "attachments.get",
2398
2399
  // DOCFMT stage 1 (DOC-P2) reads, registered in INTEG-4 (coordinator 12.10.2026, IP10 option a)
2399
2400
  fleek_read_document_fmd: "documents.readFmd",
2400
2401
  fleek_list_space_documents: "documents.listInSpace",
@@ -4652,7 +4653,7 @@ var require_setup_session = __commonJS({
4652
4653
  exports.SETUP_SESSION_TTL_MINUTES = 30;
4653
4654
  exports.SETUP_SESSION_OPEN_MAX = 10;
4654
4655
  exports.SETUP_SESSION_CLAIM_LIMIT = 10;
4655
- exports.FLEEK_CLI_SETUP_VERSION_DEFAULT = "0.2.15";
4656
+ exports.FLEEK_CLI_SETUP_VERSION_DEFAULT = "0.2.17";
4656
4657
  exports.FLEEK_CLI_PACKAGE = "@logic-joe/fleek";
4657
4658
  exports.FLEEK_CANONICAL_SERVER = "https://api.onfleek.app";
4658
4659
  exports.SETUP_CLIENT_APPS = ["claude-code", "codex", "orca", "cursor", "other"];
@@ -5594,7 +5595,7 @@ var require_util = __commonJS({
5594
5595
  else
5595
5596
  target[key] = value;
5596
5597
  }
5597
- function mirrorShape(target, source, keys, wrap) {
5598
+ function mirrorShape(target, source, keys, wrap2) {
5598
5599
  const raw = sourceShape(source);
5599
5600
  for (const key of keys) {
5600
5601
  const desc = Object.getOwnPropertyDescriptor(raw, key);
@@ -5603,10 +5604,10 @@ var require_util = __commonJS({
5603
5604
  if (desc.get) {
5604
5605
  deferProp(target, key, () => {
5605
5606
  const value = source._zod.def.shape[key];
5606
- return wrap ? wrap(value, key) : value;
5607
+ return wrap2 ? wrap2(value, key) : value;
5607
5608
  });
5608
5609
  } else
5609
- putProp(target, key, wrap ? wrap(desc.value, key) : desc.value);
5610
+ putProp(target, key, wrap2 ? wrap2(desc.value, key) : desc.value);
5610
5611
  }
5611
5612
  }
5612
5613
  function mirrorProps(target, source) {
@@ -31680,7 +31681,7 @@ var require_secret_shape = __commonJS({
31680
31681
  Object.defineProperty(exports, "__esModule", { value: true });
31681
31682
  exports.SECRET_SHAPE_LIMITS = void 0;
31682
31683
  exports.validUrlHost = validUrlHost;
31683
- exports.detectSecretShape = detectSecretShape;
31684
+ exports.detectSecretShape = detectSecretShape2;
31684
31685
  exports.SECRET_SHAPE_LIMITS = { highEntropyMinRun: 32, highEntropyMinBits: 4.2, highEntropyMinSwitchRate: 0.35 };
31685
31686
  var TOKEN_PREFIXES = [
31686
31687
  ["ghp_", 30],
@@ -31982,7 +31983,7 @@ var require_secret_shape = __commonJS({
31982
31983
  }
31983
31984
  return -1;
31984
31985
  }
31985
- function detectSecretShape(text6) {
31986
+ function detectSecretShape2(text6) {
31986
31987
  if (text6.length === 0)
31987
31988
  return null;
31988
31989
  if (text6.includes("-----BEGIN "))
@@ -32669,7 +32670,7 @@ var require_knowledge_skeleton = __commonJS({
32669
32670
  "../validation/dist/agent-platform/knowledge-skeleton.js"(exports) {
32670
32671
  "use strict";
32671
32672
  Object.defineProperty(exports, "__esModule", { value: true });
32672
- exports.PROJECT_CORE_PAGES = exports.DEVELOPMENT_PROFILE_KEYS = void 0;
32673
+ exports.PROJECT_CORE_PAGES = exports.DEVELOPMENT_PROFILE_KEYS = exports.AGENT_GIT_KEYS = exports.AGENT_GIT_DEFAULTS = void 0;
32673
32674
  exports.exampleProfileSchema = exampleProfileSchema;
32674
32675
  exports.withMissingExampleFields = withMissingExampleFields;
32675
32676
  exports.skeletonLabels = skeletonLabels;
@@ -32693,7 +32694,8 @@ var require_knowledge_skeleton = __commonJS({
32693
32694
  // `fleek_get_project_brief` (never guessed; forms written as examples, without angle brackets: the agent reads them through
32694
32695
  // the text owner). Env files only by name, never credentials.
32695
32696
  ...DEVELOPMENT_FIELDS.map(([key, de, en, type]) => developmentField(key, t(L(de, en)), type)),
32696
- // "Agenten dürfen (Git)": true = without asking; empty / false = ask first (strict default - never pre-set to true)
32697
+ // "Agenten dürfen (Git)": true = without asking; false = ask first. Empty = the code default `AGENT_GIT_DEFAULTS` (bundle R A8;
32698
+ // the brief returns the effective value with its source) - the profile field is never pre-set
32697
32699
  ...AGENT_GIT_FIELDS.map(([key, de, en]) => ({ key, label: t(L(de, en)), type: "bool" }))
32698
32700
  ]
32699
32701
  };
@@ -32730,6 +32732,17 @@ var require_knowledge_skeleton = __commonJS({
32730
32732
  ["agent_git_delete_remote", "Agenten dürfen Remote-Branch löschen", "Agents may delete the remote branch"],
32731
32733
  ["agent_git_stop_servers", "Agenten dürfen fremde Server stoppen", "Agents may stop other servers"]
32732
32734
  ];
32735
+ exports.AGENT_GIT_DEFAULTS = Object.freeze({
32736
+ agent_git_commit: true,
32737
+ agent_git_push: true,
32738
+ // own feature branch only
32739
+ agent_git_open_mr: true,
32740
+ agent_git_merge: false,
32741
+ agent_git_delete_local: false,
32742
+ agent_git_delete_remote: false,
32743
+ agent_git_stop_servers: false
32744
+ });
32745
+ exports.AGENT_GIT_KEYS = AGENT_GIT_FIELDS.map(([key]) => key);
32733
32746
  exports.DEVELOPMENT_PROFILE_KEYS = [...DEVELOPMENT_FIELDS.map(([key]) => key), ...AGENT_GIT_FIELDS.map(([key]) => key)];
32734
32747
  function developmentField(key, label, type) {
32735
32748
  switch (type) {
@@ -36152,7 +36165,7 @@ var require_agent_error_details = __commonJS({
36152
36165
  CLAIMED_BY_OTHER: { holderLabel: string4, expiresAt: string4, holderRef: personRef },
36153
36166
  CLAIM_REQUIRED: { issueIds: list2, requiredPurpose: oneOf3(["work"]), providedPurpose: oneOf3(["review"]) },
36154
36167
  RENEW_LIMIT: { hardExpiresAt: string4 },
36155
- NOT_READY: { readySelector: string4 },
36168
+ NOT_READY: { readySelector: string4, reason: oneOf3(["restricted_person", "not_own_agent"]) },
36156
36169
  REVISION_CONFLICT: { currentRevision: integer },
36157
36170
  STATE_CONFLICT: { currentStateVersion: integer },
36158
36171
  TYPED_COMMENT_IMMUTABLE: { kind: string4 },
@@ -36471,7 +36484,7 @@ var require_dist2 = __commonJS({
36471
36484
  var import_types11 = __toESM(require_dist(), 1);
36472
36485
  import { spawn as spawn9 } from "node:child_process";
36473
36486
  import { createHash as createHash9, randomBytes as randomBytes12 } from "node:crypto";
36474
- import { rm as rm13 } from "node:fs/promises";
36487
+ import { rm as rm13, stat as stat16 } from "node:fs/promises";
36475
36488
  import { hostname as osHostname2 } from "node:os";
36476
36489
  import { join as join33 } from "node:path";
36477
36490
  import { parseArgs } from "node:util";
@@ -36944,6 +36957,11 @@ var Output = class {
36944
36957
  if (this.activities.size) this.progress(null);
36945
36958
  this.stderr.write(`${this.render(text6, "err")}
36946
36959
  `);
36960
+ }
36961
+ /** The keyboard list (tui.ts): CLI-owned cursor control plus rendered lines in one write, so a redraw never flickers. */
36962
+ screen(control, lines) {
36963
+ this.stdout.write(control + lines.map((line) => `${this.render(line, "out")}
36964
+ `).join(""));
36947
36965
  }
36948
36966
  /** CLI-owned OSC-8 link. The label/URI are neutralized; JSON, pipes and dumb terminals get a plain URL. */
36949
36967
  link(label, uri, stream = "out") {
@@ -37270,20 +37288,32 @@ var EN = {
37270
37288
  "menu.setupServer": "Server: {server}",
37271
37289
  "menu.resume": "Continue {key}",
37272
37290
  "menu.ticketDefault": "Ticket key (Enter = {key}):",
37273
- "menu.fix": "Setup needs attention: {command} (option 3).",
37274
- "menu.recommend": "Recommended: {action}",
37291
+ "menu.fix": "Setup needs attention: {command}. Open status and repair.",
37292
+ "menu.recommended": "Recommended",
37293
+ "menu.quit": "Quit",
37294
+ "menu.loading": "Loading …",
37295
+ "menu.yes": "Yes",
37296
+ "menu.no": "No",
37297
+ "menu.yesNo": "(y/N)",
37298
+ "menu.setupComputer": "Set up this computer",
37299
+ "menu.switchCheckout": "Switch checkout",
37300
+ "menu.checkoutTitle": "Which checkout do you want to work in?",
37301
+ "menu.key.move": "↑↓ move",
37302
+ "menu.key.open": "Enter open",
37303
+ "menu.key.confirm": "Enter confirm",
37304
+ "menu.key.back": "Esc back",
37305
+ "menu.key.cancel": "Esc cancel",
37306
+ "menu.key.quit": "q quit",
37275
37307
  "menu.connect": "Connect this computer",
37276
- "menu.bind": "Choose a checkout or set up this computer",
37277
37308
  "menu.pick": "My next ticket",
37278
37309
  "menu.continue": "Continue a ticket",
37279
37310
  "menu.doctor": "Status and repair",
37280
37311
  "menu.connections": "Connect ChatGPT / Claude · Settings › Connections",
37281
37312
  "menu.help": "All commands",
37282
- "menu.choose": "Number (Enter cancels):",
37283
- "menu.checkout": "Checkout number (0 = setup, Enter cancels):",
37313
+ "menu.choose": "Number (Enter quits):",
37284
37314
  "menu.code": "Paste fleek setup <code> from Settings › Connections (Enter cancels):",
37285
37315
  "menu.ticket": "Ticket key (Enter cancels):",
37286
- "menu.repair": "Run {command} to review repair offers? (y/N)",
37316
+ "menu.repair": "Run {command} to review repair offers?",
37287
37317
  "read.more": "More details: add --json.",
37288
37318
  "read.empty": "No entries.",
37289
37319
  "read.items": "Entries",
@@ -37660,6 +37690,7 @@ var EN = {
37660
37690
  "orca.rateWait": "Rate limit: waiting {seconds} s, then continuing at the same page.",
37661
37691
  "orca.partial": "Partial list after {pages} pages. Narrow it with --project or --mine.",
37662
37692
  "orca.listCount": "{count} open tickets · mine first, priority, recently updated",
37693
+ "orca.pickTitle": "{count} tickets · mine first, priority, recently updated",
37663
37694
  "orca.pickPage": "Tickets {first}–{last} of {count} · mine first, priority, recently updated",
37664
37695
  "orca.pickPages": "n: next page · p: previous page · enter any ticket number",
37665
37696
  "errors.proxyProfileAmbiguous": "Several sign-ins are bound to this checkout. Pin one with --profile <key> or FLEEK_PROFILE.",
@@ -37935,6 +37966,7 @@ var EN = {
37935
37966
  "init.manualBoundary": "You start the agent yourself: the file selection is only a recommendation, the agent may read more on your machine.",
37936
37967
  "init.outputTimeout": "{app}: no output file in time.",
37937
37968
  "init.outputInvalid": "{app}: the output file is not valid ({field}).",
37969
+ "init.outputInvalidValue": '{app}: the output file is not valid ({field}: "{value}" is not allowed).',
37938
37970
  "init.unusable": "{app}: the analysis contains something that looks like a credential in a required field - nothing sent.",
37939
37971
  "init.removed": "{count} value(s) removed: looks like a credential or a forbidden path ({paths}).",
37940
37972
  "init.preview": "{app}: {sections} section(s), {components} component(s), {hints} review hint(s), {environments} environment(s), {warnings} hint(s) for the reviewer.",
@@ -38045,20 +38077,32 @@ var DE = {
38045
38077
  "menu.setupServer": "Server: {server}",
38046
38078
  "menu.resume": "{key} weiterarbeiten",
38047
38079
  "menu.ticketDefault": "Ticket-Schlüssel (Enter = {key}):",
38048
- "menu.fix": "Einrichtung prüfen: {command} (Option 3).",
38049
- "menu.recommend": "Empfohlen: {action}",
38080
+ "menu.fix": "Einrichtung prüfen: {command}. Öffne Status und Reparatur.",
38081
+ "menu.recommended": "Empfohlen",
38082
+ "menu.quit": "Beenden",
38083
+ "menu.loading": "Lädt …",
38084
+ "menu.yes": "Ja",
38085
+ "menu.no": "Nein",
38086
+ "menu.yesNo": "(j/N)",
38087
+ "menu.setupComputer": "Rechner einrichten",
38088
+ "menu.switchCheckout": "Checkout wechseln",
38089
+ "menu.checkoutTitle": "In welchem Checkout möchtest du arbeiten?",
38090
+ "menu.key.move": "↑↓ wählen",
38091
+ "menu.key.open": "Enter öffnen",
38092
+ "menu.key.confirm": "Enter bestätigen",
38093
+ "menu.key.back": "Esc zurück",
38094
+ "menu.key.cancel": "Esc abbrechen",
38095
+ "menu.key.quit": "q beenden",
38050
38096
  "menu.connect": "Rechner verbinden",
38051
- "menu.bind": "Checkout wählen oder Rechner einrichten",
38052
38097
  "menu.pick": "Mein nächstes Ticket",
38053
38098
  "menu.continue": "Ticket fortsetzen",
38054
38099
  "menu.doctor": "Status und Reparatur",
38055
38100
  "menu.connections": "ChatGPT / Claude verbinden · Einstellungen › Verbindungen",
38056
38101
  "menu.help": "Alle Befehle",
38057
- "menu.choose": "Nummer (Enter bricht ab):",
38058
- "menu.checkout": "Checkout-Nummer (0 = Einrichtung, Enter bricht ab):",
38102
+ "menu.choose": "Nummer (Enter beendet):",
38059
38103
  "menu.code": "fleek setup <code> aus Einstellungen › Verbindungen einfügen (Enter bricht ab):",
38060
38104
  "menu.ticket": "Ticket-Schlüssel (Enter bricht ab):",
38061
- "menu.repair": "Mit {command} Reparaturangebote prüfen? (j/N)",
38105
+ "menu.repair": "Mit {command} Reparaturangebote prüfen?",
38062
38106
  "read.more": "Weitere Details: --json ergänzen.",
38063
38107
  "read.empty": "Keine Einträge.",
38064
38108
  "read.items": "Einträge",
@@ -38308,7 +38352,7 @@ var DE = {
38308
38352
  " fleek work complete <claim> --outcome done|partial|handed_off --summary <text>",
38309
38353
  " fleek work progress <claim> --summary <text>",
38310
38354
  "Fragen: fleek ask <ticket> --text <frage> | fleek answer <frage> --text <antwort>",
38311
- "Abwicklung: fleek route <ticket> <schlüssel> [--claim <id>] | fleek route <ticket> --default",
38355
+ "Auftragsart: fleek route <ticket> <schlüssel> [--claim <id>] | fleek route <ticket> --default",
38312
38356
  "Kontext: fleek context <ticket> | fleek inbox | fleek wait [--cursor <c>] [--seconds <n>]",
38313
38357
  "Ereignisse: fleek listen --exec <programm> [args...] [--name <n>] [--timeout <1..3600>] [--concurrency <1|2>] [--quiet-children] [--from-now]",
38314
38358
  "MCP: fleek mcp proxy [--profile <schlüssel|workspace>] [--app claude-code|codex|orca] [--label <text>] (stdio-MCP über diese Anmeldung)",
@@ -38435,6 +38479,7 @@ var DE = {
38435
38479
  "orca.rateWait": "Anfragelimit: {seconds} s warten, dann auf derselben Seite fortsetzen.",
38436
38480
  "orca.partial": "Teilliste nach {pages} Seiten. Mit --project oder --mine eingrenzen.",
38437
38481
  "orca.listCount": "{count} offene Tickets · eigene zuerst, Priorität, zuletzt aktualisiert",
38482
+ "orca.pickTitle": "{count} Tickets · eigene zuerst, Priorität, zuletzt aktualisiert",
38438
38483
  "orca.pickPage": "Tickets {first}–{last} von {count} · eigene zuerst, Priorität, zuletzt aktualisiert",
38439
38484
  "orca.pickPages": "n: nächste Seite · p: vorherige Seite · beliebige Ticket-Nummer eingeben",
38440
38485
  "errors.proxyProfileAmbiguous": "Mehrere Anmeldungen sind an dieses Repo gebunden. Leg eine fest mit --profile <schlüssel> oder FLEEK_PROFILE.",
@@ -38710,6 +38755,7 @@ var DE = {
38710
38755
  "init.manualBoundary": "Du startest den Agenten selbst: Die Dateiauswahl ist nur eine Empfehlung, der Agent kann auf deinem Rechner mehr lesen.",
38711
38756
  "init.outputTimeout": "{app}: keine Ausgabedatei innerhalb der Frist.",
38712
38757
  "init.outputInvalid": "{app}: Die Ausgabedatei ist ungültig ({field}).",
38758
+ "init.outputInvalidValue": "{app}: Die Ausgabedatei ist ungültig ({field}: „{value}“ ist nicht erlaubt).",
38713
38759
  "init.unusable": "{app}: Die Analyse enthält in einem Pflichtfeld etwas, das wie ein Zugangsschlüssel aussieht - nichts gesendet.",
38714
38760
  "init.removed": "{count} Angabe(n) entfernt: sieht aus wie ein Zugangsschlüssel oder ein verbotener Pfad ({paths}).",
38715
38761
  "init.preview": "{app}: {sections} Abschnitt(e), {components} Komponente(n), {hints} Prüfhinweis(e), {environments} Umgebung(en), {warnings} Hinweis(e) für die Prüfung.",
@@ -38807,8 +38853,8 @@ async function processStart(pid) {
38807
38853
  if (process.platform === "win32") return null;
38808
38854
  if (process.platform === "linux") {
38809
38855
  try {
38810
- const stat16 = await readFile2(`/proc/${pid}/stat`, "utf8");
38811
- const fields = stat16.slice(stat16.lastIndexOf(")") + 2).split(" ");
38856
+ const stat17 = await readFile2(`/proc/${pid}/stat`, "utf8");
38857
+ const fields = stat17.slice(stat17.lastIndexOf(")") + 2).split(" ");
38812
38858
  const ticks = Number(fields[19]);
38813
38859
  return Number.isSafeInteger(ticks) ? ticks : null;
38814
38860
  } catch {
@@ -49716,7 +49762,7 @@ async function reloadProxyProfile(store, started) {
49716
49762
  // src/orca.ts
49717
49763
  import { execFile as nodeExecFile } from "node:child_process";
49718
49764
  import { realpath as realpath4 } from "node:fs/promises";
49719
- import { posix, win32 } from "node:path";
49765
+ import { posix as posix2, win32 as win322 } from "node:path";
49720
49766
  import { setTimeout as sleep4 } from "node:timers/promises";
49721
49767
 
49722
49768
  // src/tools.ts
@@ -49773,12 +49819,277 @@ var WIRE = {
49773
49819
  reportServiceHost: "fleek_report_service_host"
49774
49820
  };
49775
49821
 
49822
+ // src/header.ts
49823
+ import { win32, posix } from "node:path";
49824
+
49825
+ // src/uuid.ts
49826
+ var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
49827
+ function isUuid(value) {
49828
+ return UUID2.test(value);
49829
+ }
49830
+ function canonicalId(value) {
49831
+ if (!UUID2.test(value)) throw new Error("INVALID_UUID");
49832
+ return value.toLowerCase();
49833
+ }
49834
+
49835
+ // src/header.ts
49836
+ var LOGO2 = [" ▄██████▀", " ▄█████▀ ", " ██▀ "];
49837
+ var ASCII_LOGO = [" ######/", " #####/ ", " ##/ "];
49838
+ var BRAND = "\x1B[38;2;69;94;255m";
49839
+ function shouldShowHeader(positionals, options, terminal) {
49840
+ if (options.json || options.version || terminal.stream.isTTY !== true) return false;
49841
+ const active = (value) => value !== void 0 && value !== "" && value !== "0" && value !== "false";
49842
+ if (["CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS", "BUILD_NUMBER", "TF_BUILD"].some((key) => active(terminal.env[key]))) return false;
49843
+ const [command, sub] = positionals;
49844
+ return !command || command === "help" || !!options.help || command === "setup" || command === "doctor" || command === "init" || command === "kit" && ["setup", "doctor", "pull"].includes(sub ?? "") || command === "service" && sub === "setup";
49845
+ }
49846
+ function cells(value) {
49847
+ let width = 0;
49848
+ for (const char of value) {
49849
+ const code = char.codePointAt(0);
49850
+ if (new RegExp("\\p{Mark}", "u").test(char)) continue;
49851
+ width += code >= 4352 && (code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744) ? 2 : 1;
49852
+ }
49853
+ return width;
49854
+ }
49855
+ function fit(value, width, ascii) {
49856
+ if (cells(value) <= width) return value;
49857
+ const suffix = ascii ? "..." : "…";
49858
+ if (width <= suffix.length) return suffix.slice(0, Math.max(0, width));
49859
+ let out = "";
49860
+ for (const char of value) {
49861
+ if (cells(out + char) > width - suffix.length) break;
49862
+ out += char;
49863
+ }
49864
+ return out + suffix;
49865
+ }
49866
+ var safe = (value) => neutralizeLine(redact(value));
49867
+ function directory(context, windows, env) {
49868
+ const path = windows ? win32 : posix;
49869
+ const home = context.home ?? userHome(env, windows ? "win32" : process.platform);
49870
+ const relative3 = path.relative(home, context.cwd);
49871
+ const inside = relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${path.sep}`) && !path.isAbsolute(relative3);
49872
+ return safe(inside ? relative3 ? `~${path.sep}${relative3}` : "~" : context.cwd);
49873
+ }
49874
+ function displayPath(cwd, home, env) {
49875
+ return directory({ version: "", cwd, home }, process.platform === "win32", env);
49876
+ }
49877
+ function headerServer(value) {
49878
+ if (!value) return void 0;
49879
+ try {
49880
+ const url = new URL(value);
49881
+ return ["http:", "https:"].includes(url.protocol) ? url.host : void 0;
49882
+ } catch {
49883
+ return void 0;
49884
+ }
49885
+ }
49886
+ function renderHeader(context, terminal, t) {
49887
+ const windows = (terminal.platform ?? process.platform) === "win32";
49888
+ const ascii = windows || terminal.env.TERM === "dumb";
49889
+ const separator = ascii ? " - " : " · ";
49890
+ const requested = terminal.stream.columns ?? Number(terminal.env.COLUMNS);
49891
+ const columns = Number.isFinite(requested) && requested > 0 ? Math.floor(requested) : 80;
49892
+ const title = t("header.title", { version: safe(context.version) });
49893
+ const cwd = directory(context, windows, terminal.env);
49894
+ const parts = [context.workspace, context.project && !isUuid(context.project) ? context.project : void 0, headerServer(context.server), context.displayName].filter((value) => !!value);
49895
+ const details = parts.length ? parts.map(safe).join(separator) : t("header.noContext");
49896
+ if (columns < 60) return ["", fit([title, cwd].join(separator), columns, ascii)];
49897
+ const logo = ascii ? ASCII_LOGO : LOGO2;
49898
+ const width = Math.max(...logo.map(cells));
49899
+ const color = colorEnabled(terminal.env, terminal.stream);
49900
+ const available2 = columns - width - 6;
49901
+ const tagline = separator + t("header.tagline");
49902
+ const attribution = separator + t("header.attribution");
49903
+ const secondary = cells(title + tagline) <= available2 ? tagline + (cells(title + tagline + attribution) <= available2 ? attribution : "") : "";
49904
+ const text6 = [title, details, cwd];
49905
+ const rows = logo.map((row, index) => {
49906
+ const mark = row.padEnd(width);
49907
+ const label = fit(text6[index], available2, ascii);
49908
+ if (index === 0) {
49909
+ const heading = color ? `\x1B[1m${label}\x1B[22m` : label;
49910
+ const branding = color && secondary ? `\x1B[2m${secondary}\x1B[22m` : secondary;
49911
+ return `${color ? `${BRAND}${mark}\x1B[39m` : mark} ${heading}${branding}`;
49912
+ }
49913
+ const styled = color ? `\x1B[2m${label}\x1B[22m` : label;
49914
+ return `${color ? `${BRAND}${mark}\x1B[39m` : mark} ${styled}`;
49915
+ });
49916
+ const inner = Math.max(...rows.map((row) => cells(stripAnsi(row))));
49917
+ const edge = (value) => color ? `${BRAND}${value}\x1B[39m` : value;
49918
+ const vertical = ascii ? "|" : "│";
49919
+ return [
49920
+ "",
49921
+ edge(`${ascii ? "+" : "╭"}${(ascii ? "-" : "─").repeat(inner + 2)}${ascii ? "+" : "╮"}`),
49922
+ ...rows.map((row) => `${edge(vertical)} ${row}${" ".repeat(inner - cells(stripAnsi(row)))} ${edge(vertical)}`),
49923
+ edge(`${ascii ? "+" : "╰"}${(ascii ? "-" : "─").repeat(inner + 2)}${ascii ? "+" : "╯"}`)
49924
+ ];
49925
+ }
49926
+ function printHeader(out, context, terminal, t) {
49927
+ for (const line of renderHeader(context, terminal, t)) out.line(line);
49928
+ out.line();
49929
+ out.indentHumanOutput();
49930
+ }
49931
+
49932
+ // src/tui.ts
49933
+ var yesNoList = (question, t) => ({
49934
+ title: [question],
49935
+ items: [{ id: "no", label: t("menu.no") }, { id: "yes", label: t("menu.yes") }],
49936
+ initial: "no",
49937
+ back: true,
49938
+ confirm: true,
49939
+ echo: (item2) => `${question} ${item2.label}`
49940
+ });
49941
+ var isYes = (result) => result.kind === "select" && result.id === "yes";
49942
+ function isKeyInput(stream) {
49943
+ const input = stream;
49944
+ return !!input && input.isTTY === true && typeof input.setRawMode === "function";
49945
+ }
49946
+ var SEQUENCE = /\u001b\[[0-9;]*[A-Za-z~]|\u001bO[A-Za-z]|[\s\S]/g;
49947
+ var NAMED = {
49948
+ "\x1B[A": "up",
49949
+ "\x1BOA": "up",
49950
+ k: "up",
49951
+ "\x1B[B": "down",
49952
+ "\x1BOB": "down",
49953
+ j: "down",
49954
+ "\x1B[H": "home",
49955
+ "\x1BOH": "home",
49956
+ "\x1B[1~": "home",
49957
+ "\x1B[F": "end",
49958
+ "\x1BOF": "end",
49959
+ "\x1B[4~": "end",
49960
+ "\x1B[5~": "pageUp",
49961
+ "\x1B[6~": "pageDown",
49962
+ "\r": "enter",
49963
+ "\n": "enter",
49964
+ "\x1B[C": "enter",
49965
+ "\x1BOC": "enter",
49966
+ "\x1B": "back",
49967
+ "\x1B[D": "back",
49968
+ "\x1BOD": "back",
49969
+ q: "quit",
49970
+ "": "abort",
49971
+ "": "abort"
49972
+ };
49973
+ function parseKeys(chunk) {
49974
+ return (chunk.match(SEQUENCE) ?? []).flatMap((part) => {
49975
+ const named = NAMED[part];
49976
+ if (named) return [named];
49977
+ return /^[1-9]$/.test(part) ? [`digit${Number(part)}`] : [];
49978
+ });
49979
+ }
49980
+ function wrap(text6, width) {
49981
+ const lines = [];
49982
+ let line = "";
49983
+ for (const word of text6.split(" ")) {
49984
+ if (line && cells(`${line} ${word}`) > width) {
49985
+ lines.push(line);
49986
+ line = "";
49987
+ }
49988
+ line = line ? `${line} ${word}` : word;
49989
+ }
49990
+ return [...lines, line].map((entry) => fit(entry, width, false));
49991
+ }
49992
+ function selectList(terminal, options) {
49993
+ const { stdin, stdout, out, t } = terminal;
49994
+ const s = out.style, items = options.items;
49995
+ const pointer = s.unicode ? "›" : ">";
49996
+ let cursor = Math.max(0, items.findIndex((item2) => item2.id === options.initial));
49997
+ let top = 0, drawn = 0;
49998
+ const footer = () => [
49999
+ t("menu.key.move"),
50000
+ t(options.confirm ? "menu.key.confirm" : "menu.key.open"),
50001
+ ...options.back ? [t(options.confirm ? "menu.key.cancel" : "menu.key.back")] : [],
50002
+ ...options.quit ? [t("menu.key.quit")] : []
50003
+ ].join(` ${s.glyph.bullet} `);
50004
+ const view = () => {
50005
+ const width = Math.max(20, (stdout.columns ?? 80) - 3);
50006
+ const title = [
50007
+ ...options.context ? [s.dim(fit(neutralizeLine(options.context), width, !s.unicode))] : [],
50008
+ ...(options.title ?? []).flatMap((line) => wrap(neutralizeLine(line), width)).map((line) => s.bold(line))
50009
+ ];
50010
+ const room = Math.max(3, (stdout.rows ?? 24) - title.length - 5);
50011
+ const size = Math.min(items.length, room);
50012
+ if (cursor < top) top = cursor;
50013
+ if (cursor >= top + size) top = cursor - size + 1;
50014
+ top = Math.min(top, items.length - size);
50015
+ const shown3 = items.slice(top, top + size).map((item2) => ({ item: item2, label: neutralizeLine(item2.label), hint: item2.hint ? neutralizeLine(item2.hint) : "" }));
50016
+ const column = Math.max(...shown3.map(({ label, hint }) => hint ? cells(label) : 0));
50017
+ const rows = shown3.map(({ item: item2, label, hint }) => {
50018
+ const room2 = hint ? width - 2 - cells(hint) - 2 : width - 2;
50019
+ const text6 = fit(label, room2, !s.unicode);
50020
+ const pad = hint ? " ".repeat(Math.max(2, column - cells(text6) + 2)) : "";
50021
+ const chosen = items[cursor] === item2;
50022
+ return `${chosen ? s.cmd(`${pointer} `) : " "}${chosen ? s.bold(s.cmd(text6)) : text6}${pad}${hint ? s.dim(hint) : ""}`;
50023
+ });
50024
+ const position = items.length > size ? `${cursor + 1}/${items.length} ${s.glyph.bullet} ` : "";
50025
+ return [...title, ...title.length ? [""] : [], ...rows, "", s.dim(`${position}${footer()}`)];
50026
+ };
50027
+ const draw = () => {
50028
+ const lines = view();
50029
+ out.screen(`${drawn ? `\x1B[${drawn}A` : ""}\r\x1B[J`, lines);
50030
+ drawn = lines.length;
50031
+ };
50032
+ return new Promise((resolve9) => {
50033
+ const showCursor = () => out.screen("\x1B[?25h", []);
50034
+ const finish2 = (result) => {
50035
+ stdin.off("data", onData);
50036
+ stdin.off("end", onEnd);
50037
+ stdout.off?.("resize", draw);
50038
+ process.off("exit", showCursor);
50039
+ stdin.setRawMode(false);
50040
+ stdin.pause();
50041
+ out.screen(`\x1B[${drawn}A\r\x1B[J\x1B[?25h`, []);
50042
+ if (result.kind === "select") {
50043
+ const item2 = items[cursor];
50044
+ out.line(s.dim(`${pointer} ${neutralizeLine(options.echo ? options.echo(item2) : item2.label)}`));
50045
+ }
50046
+ resolve9(result);
50047
+ };
50048
+ const onEnd = () => finish2({ kind: "abort" });
50049
+ const onData = (chunk) => {
50050
+ for (const key of parseKeys(String(chunk))) {
50051
+ if (key === "abort") return finish2({ kind: "abort" });
50052
+ if (key === "quit" && options.quit) return finish2({ kind: "quit" });
50053
+ if (key === "quit" && options.back) return finish2({ kind: "back" });
50054
+ if (key === "back" && options.back) return finish2({ kind: "back" });
50055
+ if (key === "enter") return finish2({ kind: "select", id: items[cursor].id });
50056
+ if (key === "up") cursor = (cursor - 1 + items.length) % items.length;
50057
+ else if (key === "down") cursor = (cursor + 1) % items.length;
50058
+ else if (key === "home") cursor = 0;
50059
+ else if (key === "end") cursor = items.length - 1;
50060
+ else if (key === "pageUp") cursor = Math.max(0, cursor - 10);
50061
+ else if (key === "pageDown") cursor = Math.min(items.length - 1, cursor + 10);
50062
+ else if (key.startsWith("digit") && !options.confirm) {
50063
+ const index = Number(key.slice(5)) - 1;
50064
+ if (items[index]) {
50065
+ cursor = index;
50066
+ return finish2({ kind: "select", id: items[index].id });
50067
+ }
50068
+ }
50069
+ }
50070
+ draw();
50071
+ };
50072
+ process.once("exit", showCursor);
50073
+ stdin.setRawMode(true);
50074
+ stdin.resume();
50075
+ stdin.on("data", onData);
50076
+ stdin.once("end", onEnd);
50077
+ stdout.on?.("resize", draw);
50078
+ out.screen("\x1B[?25l", []);
50079
+ draw();
50080
+ });
50081
+ }
50082
+
49776
50083
  // src/orca.ts
49777
50084
  var ORCA_LIMITS = { items: 200, projects: 200, title: 1e3, status: 120, id: 200 };
49778
50085
  var KEY = /^[A-Z0-9]{2,10}-[1-9][0-9]*$/;
49779
- var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
50086
+ var UUID3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
49780
50087
  var CLOSED = /* @__PURE__ */ new Set(["completed", "cancelled", "canceled"]);
49781
- var terminalConfirm = (deps) => async (question) => deps.isTTY && deps.ask ? /^(y|yes|j|ja)$/i.test((await deps.ask(`${question} (y/N)`)).trim()) : null;
50088
+ var terminalConfirm = (deps) => async (question) => {
50089
+ if (!deps.isTTY || !deps.ask) return null;
50090
+ if (deps.select) return isYes(await deps.select(yesNoList(question, deps.t)));
50091
+ return /^(y|yes|j|ja)$/i.test((await deps.ask(`${question} (y/N)`)).trim());
50092
+ };
49782
50093
  var notBound = () => new CliError("errors.orcaNotBound", EXIT.failed, {}, "NOT_BOUND");
49783
50094
  var usage = () => new CliError("errors.usage", EXIT.usage, {}, "USAGE");
49784
50095
  var bounded = (value, max) => String(value ?? "").slice(0, max);
@@ -49845,7 +50156,7 @@ async function readTool(client, tool, args, read2) {
49845
50156
  }
49846
50157
  async function claimableIds(client, teamId, read2) {
49847
50158
  const candidates = await pages(client, WIRE.findWork, { ...teamId ? { teamId } : {} }, void 0, read2);
49848
- return new Set(candidates.filter((row) => Array.isArray(row.claims) && !row.claims.some((claim) => object3(claim) && claim.purpose === "work") && (!object3(row.eligibility) || row.eligibility.allowAgents === true && !row.eligibility.blockedBy) && (!object3(row.request) || row.request.canTake !== false)).map((row) => String(row.issueId ?? "").toLowerCase()).filter((id) => UUID2.test(id)));
50159
+ return new Set(candidates.filter((row) => Array.isArray(row.claims) && !row.claims.some((claim) => object3(claim) && claim.purpose === "work") && (!object3(row.eligibility) || row.eligibility.allowAgents === true && !row.eligibility.blockedBy) && (!object3(row.request) || row.request.canTake !== false)).map((row) => String(row.issueId ?? "").toLowerCase()).filter((id) => UUID3.test(id)));
49849
50160
  }
49850
50161
  async function pages(client, tool, args, max = Number.POSITIVE_INFINITY, read2) {
49851
50162
  await available(client, tool);
@@ -49886,7 +50197,7 @@ function sortIssues(issues, mine) {
49886
50197
  return [...issues].sort((a, b) => Number(mine.has(b.id)) - Number(mine.has(a.id)) || priority(a) - priority(b) || updated(b) - updated(a) || String(a.identifier ?? "").localeCompare(String(b.identifier ?? ""), "en", { numeric: true }));
49887
50198
  }
49888
50199
  async function teams(client, read2) {
49889
- return (await pages(client, "fleek_list_teams", {}, ORCA_LIMITS.projects, read2)).filter((team) => typeof team.id === "string" && UUID2.test(team.id)).map((team) => ({ id: team.id.toLowerCase(), key: bounded(team.key, 32), name: bounded(team.name, 512) }));
50200
+ return (await pages(client, "fleek_list_teams", {}, ORCA_LIMITS.projects, read2)).filter((team) => typeof team.id === "string" && UUID3.test(team.id)).map((team) => ({ id: team.id.toLowerCase(), key: bounded(team.key, 32), name: bounded(team.name, 512) }));
49890
50201
  }
49891
50202
  async function statesOf(client, teamIds, read2) {
49892
50203
  const states = /* @__PURE__ */ new Map();
@@ -49898,9 +50209,9 @@ async function statesOf(client, teamIds, read2) {
49898
50209
  return states;
49899
50210
  }
49900
50211
  function item(profile, issue, teamsById, states) {
49901
- const id = typeof issue.id === "string" && UUID2.test(issue.id) ? issue.id.toLowerCase() : null;
50212
+ const id = typeof issue.id === "string" && UUID3.test(issue.id) ? issue.id.toLowerCase() : null;
49902
50213
  const key = typeof issue.identifier === "string" && KEY.test(issue.identifier) ? issue.identifier : null;
49903
- const teamId = typeof issue.teamId === "string" && UUID2.test(issue.teamId) ? issue.teamId.toLowerCase() : null;
50214
+ const teamId = typeof issue.teamId === "string" && UUID3.test(issue.teamId) ? issue.teamId.toLowerCase() : null;
49904
50215
  if (!id || !key || !teamId) return null;
49905
50216
  const status = typeof issue.stateId === "string" ? states.get(issue.stateId.toLowerCase())?.name ?? "" : "";
49906
50217
  return { id, key, title: bounded(issue.title, ORCA_LIMITS.title), status, url: ticketUrl(profile, teamsById.get(teamId)?.key ?? null, key), projectId: teamId };
@@ -49908,14 +50219,14 @@ function item(profile, issue, teamsById, states) {
49908
50219
  function projectOf(values, found, list2) {
49909
50220
  if (values.project === void 0) return found.projectId;
49910
50221
  const value = values.project.trim();
49911
- const match = UUID2.test(value) ? list2.find((team) => team.id === value.toLowerCase()) : list2.find((team) => team.key.toUpperCase() === value.toUpperCase());
50222
+ const match = UUID3.test(value) ? list2.find((team) => team.id === value.toLowerCase()) : list2.find((team) => team.key.toUpperCase() === value.toUpperCase());
49912
50223
  if (!match) throw new CliError("errors.orcaProjectUnknown", EXIT.usage, {}, "NOT_FOUND");
49913
50224
  return match.id;
49914
50225
  }
49915
50226
  async function myUserId(client, read2) {
49916
50227
  const who = (await readTool(client, WIRE.whoami, {}, read2)).structured;
49917
50228
  const id = who.principal?.userId;
49918
- if (typeof id !== "string" || !UUID2.test(id)) throw new CliError("errors.metadata", EXIT.failed, { reason: "context" }, "METADATA_INVALID");
50229
+ if (typeof id !== "string" || !UUID3.test(id)) throw new CliError("errors.metadata", EXIT.failed, { reason: "context" }, "METADATA_INVALID");
49919
50230
  return id.toLowerCase();
49920
50231
  }
49921
50232
  async function orcaContext(deps, values = {}) {
@@ -50013,7 +50324,7 @@ var defaultExec = (program, args, options) => new Promise((resolve9) => nodeExec
50013
50324
  (error, stdout, stderr) => resolve9({ code: error ? typeof error.code === "number" ? error.code : 1 : 0, stdout: String(stdout), stderr: String(stderr) })
50014
50325
  ));
50015
50326
  async function orcaProgram(deps, runtime = { platform: process.platform }) {
50016
- const paths = runtime.platform === "win32" ? win32 : posix;
50327
+ const paths = runtime.platform === "win32" ? win322 : posix2;
50017
50328
  const custom = deps.env.ORCA_CLI_COMMAND || void 0;
50018
50329
  const found = custom ?? (runtime.platform === "linux" ? await deps.which("orca-ide") : null) ?? await deps.which("orca");
50019
50330
  if (!found || !paths.isAbsolute(found) || paths.resolve(found) === "/usr/bin/orca" || await (runtime.realpath ?? realpath4)(found).catch(() => found) === "/usr/bin/orca") {
@@ -50053,6 +50364,11 @@ async function orcaPick(deps, values, start2) {
50053
50364
  deps.out.line(deps.out.style.note(deps.t("orca.none")));
50054
50365
  return EXIT.ok;
50055
50366
  }
50367
+ if (deps.select) {
50368
+ const rows = deps.out.style.columns(items.map((entry) => [entry.key, mineIds.has(entry.id) ? deps.t("orca.mine") : "", neutralizeLine(entry.status), neutralizeLine(entry.title).slice(0, 100)]), "");
50369
+ const choice = await deps.select({ title: [deps.t("orca.pickTitle", { count: items.length })], items: items.map((entry, index) => ({ id: entry.key, label: rows[index] })), back: true });
50370
+ return choice.kind === "select" ? start2(choice.id) : EXIT.ok;
50371
+ }
50056
50372
  let offset = 0;
50057
50373
  while (true) {
50058
50374
  const end = Math.min(offset + 50, items.length);
@@ -50158,7 +50474,7 @@ async function liveFacts(client, task) {
50158
50474
  const claims = (Array.isArray(work2.claims) ? work2.claims : []).filter(object3).map((claim) => ({
50159
50475
  purpose: string3(claim.purpose),
50160
50476
  isMine: claim.isMine === true,
50161
- claimId: typeof claim.claimId === "string" && UUID2.test(claim.claimId) ? claim.claimId.toLowerCase() : null,
50477
+ claimId: typeof claim.claimId === "string" && UUID3.test(claim.claimId) ? claim.claimId.toLowerCase() : null,
50162
50478
  holder: object3(claim.holder) ? string3(claim.holder.text) : "",
50163
50479
  expiresAt: string3(claim.expiresAt)
50164
50480
  }));
@@ -50264,7 +50580,7 @@ var foreignClaim = (key, holder, expiresAt) => new CliError(
50264
50580
  async function takeClaim(deps, client, task, purpose, runLabel) {
50265
50581
  try {
50266
50582
  const claim = (await mutate(client, WIRE.claim, { issueId: task.id, purpose, runLabel: runLabel.slice(0, 120) }, { backoffMs: deps.backoffMs })).result;
50267
- return typeof claim.claimId === "string" && UUID2.test(claim.claimId) ? claim.claimId.toLowerCase() : null;
50583
+ return typeof claim.claimId === "string" && UUID3.test(claim.claimId) ? claim.claimId.toLowerCase() : null;
50268
50584
  } catch (error) {
50269
50585
  if (error instanceof ToolError && error.code === "ALREADY_CLAIMED") {
50270
50586
  const details = object3(error.details) ? error.details : {};
@@ -51751,7 +52067,7 @@ var USER_SKILL_MARKER = "<!-- Generated by scripts/agent-guidance/generate.mjs f
51751
52067
  var USER_SKILLS = [
51752
52068
  {
51753
52069
  "name": "fleek-orca-coordinator",
51754
- "content": "---\nname: fleek-orca-coordinator\ndescription: \"Coordinate Fleek tickets in Orca: find claimable work, claim it for this machine, start a builder in its own worktree with the project kit, review with the other model, leave gates to people and deliver to review. Use when you coordinate Orca agents for a Fleek project.\"\nmetadata:\n protocol: fleek-work-protocol/1.13\n---\n\n<!-- Generated by scripts/agent-guidance/generate.mjs from scripts/agent-guidance/protocol.json - do not edit by hand. -->\n\n# Fleek in Orca: coordinator recipe\n\nFleek holds the tickets and every human decision; Orca runs worktrees and agents. Follow the fleek-work skill for every Fleek call. Never change Orca's code or settings.\n\n## 1. Ready check\n- `fleek doctor` in the repo: Fleek MCP current for Claude Code, Codex and every Orca account, repo bound to its Fleek project. Otherwise ask the person to run the setup command from Fleek once per machine (Settings › Connections › Set up this computer: `fleek setup <code>`). Never sign in for them.\n\n## 2. Find work\n- fleek_find_work and fleek_my_work_inbox (claimable: agent-ready or assigned to your person; addressed work first); `fleek orca tasks` lists the project's open tickets. Take only status roles where agents work: intake_review, ready, analysis, design, implementation, review. Skip tickets another holder claims.\n- Read stage in fleek_get_work_context before starting a worker, then use this role table. Do not infer a role from the displayed status name or from the ticket title.\n\n| Status role | Work and delivery |\n| --- | --- |\n| intake_review | One triage agent: duplicates, criteria and readiness; no product code or PR. |\n| ready | Claim, then re-read the live stage and use its row. A claim is not permission to skip analysis or design. |\n| analysis / design | One agent: concept or design proposal with evidence; no product code or PR. |\n| implementation | Builder, other-model review, then deliver the work claim (sections 3-5). |\n| review | One reviewer with a review claim (`fleek orca start KEY --yes --agent OTHER-MODEL` takes it on the delivered branch in its own worktree): checklist, acceptance and evidence; record the verdict, then release that review claim. No builder, implementation, PR or complete_work outcome done loop. Findings go back to the existing implementation work or to the person. |\n| collecting / clarification / acceptance / customer gate | Start no builder; prepare a draft only if requested and wait for the responsible person or customer. Never decide their gate. |\n| done / cancelled | Start nothing. |\n\n- Only implementation uses sections 3-5. `fleek orca tasks` is an overview; `fleek orca pick` works only in a person's terminal and offers only server candidates without an existing work claim. Re-read the live context after claiming: availability is not a status-role decision.\n\n## 3. Claim, worktree, builder\n- `fleek orca start KEY --yes` (the core of `fleek start` for coordinators: Orca required; a new or restarted agent stays in the background, one already running comes to the front) takes or reuses the claim for this machine, creates the Orca worktree named after the key from the project's base branch with the Fleek ticket as reference and starts the agent with a first prompt naming key and claim. You run without a terminal: only `--yes` replaces the person's confirmation, without it the command refuses with CONFIRMATION_REQUIRED. Use it only for tickets your person lets you start; the web link and a person's own terminal keep asking. With the Fleek start command as Orca's agent command (`fleek setup` names it), the agent loads the project's kit. Your own claim is reused, no error. Another holder's claim or NOT_READY: pick another ticket.\n- By hand: fleek_claim_issue (purpose work, runLabel \"orca\" plus the worktree name), then `orca worktree create --name eng-123-slug --reference TICKET-URL --agent claude` from the base branch of fleek_get_project_brief.\n- The builder's task is a pointer: key, claimId, worktree, branch, role builder. Never paste ticket text, criteria or sign-in data; the agent reads them live from Fleek.\n- Models only from providers conventions.aiProviders allows (fleek_get_work_context); a customer's code never goes to another provider.\n- Card: `orca worktree set --worktree id:WORKTREE-ID --workspace-status in-progress`.\n\n## 4. Review by the other model\n- After the builder's worker_done verify its report in two reads before starting a reviewer: the fetched feature branch head equals the reported SHA and the worktree has no uncommitted changes; the test note is on the ticket when the project kit asks for one. A mismatch goes back to the builder, not to the reviewer.\n- Then start a reviewer with the other model (Claude and Codex swap; only one provider allowed: a fresh session of it) in the same worktree, role reviewer. It claims purpose review, checks criteria and checklist and records its verdict at the ticket.\n- Check the review's shape (fleek-work, In Orca, reviewer): verdict on the first line, blockers each with a reproduction, anchors only inside the reviewed range, each finding read or measured, questions for a person at the ticket. A review that misses it goes back to the reviewer once with the exact points.\n- Verdict not ready or a criterion not_met: builder round 2 in the same worktree, then review again. After two rounds ask the person.\n\n## 5. Deliver\n- Clean review: load the guidance (fleek_get_work_context), then fleek_complete_work on the work claim, outcome done, with SHA, branch, PR, checks and result, acceptance per criterion and nextStep. The ticket moves to the project's review state, never Done; check moved and toStateId.\n- A coordination or review claim that only records a status writes fleek_post_progress, not a result. One completion = one fleek_complete_work; no extra summary or analysis comment. Put the recommendation in nextStep; do not add a note about your own draft or publication request.\n- Parts open: outcome partial. Blocked: fleek_release_issue outcome not_doable. Interrupted: outcome paused. A failed dispatch is never done.\n- Card in-review with the existing result; no extra ticket comment.\n\n## 6. People decide\n- Questions only a person can answer go to the ticket (fleek_ask_question); the worker waits, the card gets `--unread`. Gates, acceptance, customer text and Done are decided by a person in Fleek, by an agent only where the project rule allows it and the person approved or gave a standing mandate. Never orca gate-resolve or a terminal yes on their behalf.\n- Answer an orca ask only when a rule or a decision recorded at the ticket settles it, and cite it. Anything else a person decides goes back as \"ask at the ticket\": the asking agent calls fleek_ask_question with the deciding person as addressee and waits. Your own person's answer in chat or terminal is recorded verbatim as an internal ticket comment (\"Answer NAME in chat, DATE: ...\"); pass it on only together with that comment, never a chat answer alone. The comment only records the factual answer of your own person; it decides no gate, customer acceptance or publication and grants or widens no mandate or agent_git_* right - those stay decisions in Fleek.\n\n## 7. Keep claims alive\n- Renew by expiresAt (about every 20 minutes) while a worker runs or waits; an Orca heartbeat is no renewal. The claim belongs to the machine, so a switched account or a usage-limit pause keeps it: renew and resume. Nobody can continue before expiry: release paused.\n- After a crash read your live claims (fleek_my_work_inbox) and `orca worktree list`, then continue on the same claim (`fleek orca start KEY --yes` restarts an ended agent) or release it. Never claim or complete twice.\n\n## 8. Limits\n- One builder per ticket, one ticket per worktree. Parallel tickets: as many as the person allows, default 2, each with its reviewer; queue the rest. QUOTA_EXCEEDED: the machine's claims are used up - finish or release one first.\n- No Orca code changes, forks or pull requests on Orca. Git effects only as far as the project brief allows.\n"
52070
+ "content": "---\nname: fleek-orca-coordinator\ndescription: \"Coordinate Fleek tickets in Orca: find claimable work, claim it for this machine, start a builder in its own worktree with the project kit, review with the other model, leave gates to people and deliver to review. Use when you coordinate Orca agents for a Fleek project.\"\nmetadata:\n protocol: fleek-work-protocol/1.13\n---\n\n<!-- Generated by scripts/agent-guidance/generate.mjs from scripts/agent-guidance/protocol.json - do not edit by hand. -->\n\n# Fleek in Orca: coordinator recipe\n\nFleek holds the tickets and every human decision; Orca runs worktrees and agents. Follow the fleek-work skill for every Fleek call. Never change Orca's code or settings.\n\n## 1. Ready check\n- `fleek doctor` in the repo: Fleek MCP current for Claude Code, Codex and every Orca account, repo bound to its Fleek project. Otherwise ask the person to run the setup command from Fleek once per machine (Settings › Connections › Set up this computer: `fleek setup <code>`). Never sign in for them.\n\n## 2. Find work\n- fleek_find_work and fleek_my_work_inbox (claimable: agent-ready or assigned to your person; addressed work first); `fleek orca tasks` lists the project's open tickets. Take only status roles where agents work: intake_review, ready, analysis, design, implementation, review. Skip tickets another holder claims.\n- Read stage in fleek_get_work_context before starting a worker, then use this role table. Do not infer a role from the displayed status name or from the ticket title.\n\n| Status role | Work and delivery |\n| --- | --- |\n| intake_review | One triage agent: duplicates, criteria and readiness; no product code or PR. |\n| ready | Claim, then re-read the live stage and use its row. A claim is not permission to skip analysis or design. |\n| analysis / design | One agent: concept or design proposal with evidence; no product code or PR. |\n| implementation | Builder, other-model review, then deliver the work claim (sections 3-5). |\n| review | One reviewer with a review claim (`fleek orca start KEY --yes --agent OTHER-MODEL` takes it on the delivered branch in its own worktree): checklist, acceptance and evidence; record the verdict, then release that review claim. No builder, implementation, PR or complete_work outcome done loop. Findings go back to the existing implementation work or to the person. |\n| collecting / clarification / acceptance / customer gate | Start no builder; prepare a draft only if requested and wait for the responsible person or customer. Never decide their gate. |\n| done / cancelled | Start nothing. |\n\n- Only implementation uses sections 3-5. `fleek orca tasks` is an overview; `fleek orca pick` works only in a person's terminal and offers only server candidates without an existing work claim. Re-read the live context after claiming: availability is not a status-role decision.\n\n## 3. Claim, worktree, builder\n- `fleek orca start KEY --yes` (the core of `fleek start` for coordinators: Orca required; a new or restarted agent stays in the background, one already running comes to the front) takes or reuses the claim for this machine, creates the Orca worktree named after the key from the project's base branch with the Fleek ticket as reference and starts the agent with a first prompt naming key and claim. You run without a terminal: only `--yes` replaces the person's confirmation, without it the command refuses with CONFIRMATION_REQUIRED. Use it only for tickets your person lets you start; the web link and a person's own terminal keep asking. With the Fleek start command as Orca's agent command (`fleek setup` names it), the agent loads the project's kit. Your own claim is reused, no error. Another holder's claim or NOT_READY: pick another ticket.\n- By hand: fleek_claim_issue (purpose work, runLabel \"orca\" plus the worktree name), then `orca worktree create --name eng-123-slug --reference TICKET-URL --agent claude` from the base branch of fleek_get_project_brief.\n- The builder's task is a pointer: key, claimId, worktree, branch, role builder. Never paste ticket text, criteria or sign-in data; the agent reads them live from Fleek.\n- Models only from providers conventions.aiProviders allows (fleek_get_work_context); a customer's code never goes to another provider.\n- Card: `orca worktree set --worktree id:WORKTREE-ID --workspace-status in-progress`.\n\n## 4. Review by the other model\n- After the builder's worker_done verify its report in two reads before starting a reviewer: the fetched feature branch head equals the reported SHA and the worktree has no uncommitted changes; the test note is on the ticket when the project kit asks for one. A mismatch goes back to the builder, not to the reviewer.\n- Then start a reviewer with the other model (Claude and Codex swap; only one provider allowed: a fresh session of it) in the same worktree, role reviewer. It claims purpose review, checks criteria and checklist and records its verdict at the ticket.\n- Check the review's shape (fleek-work, In Orca, reviewer): verdict on the first line, blockers each with a reproduction, anchors only inside the reviewed range, each finding read or measured, questions for a person at the ticket. A review that misses it goes back to the reviewer once with the exact points.\n- Verdict not ready or a criterion not_met: builder round 2 in the same worktree, then review again. After two rounds ask the person.\n\n## 5. Deliver\n- Clean review: load the guidance (fleek_get_work_context), then fleek_complete_work on the work claim, outcome done, with SHA, branch, PR, checks and result, acceptance per criterion and nextStep. The ticket moves to the project's review state, never Done; check moved and toStateId.\n- A coordination or review claim that only records a status writes fleek_post_progress, not a result. One completion = one fleek_complete_work; no extra summary or analysis comment. Put the recommendation in nextStep; do not add a note about your own draft or publication request.\n- Parts open: outcome partial. Blocked: fleek_release_issue outcome not_doable. Interrupted: outcome paused. A failed dispatch is never done.\n- Card in-review with the existing result; no extra ticket comment.\n\n## 6. People decide\n- Questions only a person can answer go to the ticket (fleek_ask_question); the worker waits, the card gets `--unread`. Gates, acceptance, customer text and Done are decided by a person in Fleek, by an agent only where the project rule allows it and the person approved or gave a standing mandate. Never orca gate-resolve or a terminal yes on their behalf.\n- Answer an orca ask only when a rule or a decision recorded at the ticket settles it, and cite it. Anything else a person decides goes back as \"ask at the ticket\": the asking agent calls fleek_ask_question with the deciding person as addressee and waits. Your own person's answer in chat or terminal is recorded verbatim as an internal ticket comment (\"Answer NAME in chat, DATE: ...\"); pass it on only together with that comment, never a chat answer alone. The comment only records the factual answer of your own person; it decides no gate, customer acceptance or publication and grants or widens no mandate or agent_git_* right - those stay decisions in Fleek.\n\n## 7. Keep claims alive\n- Renew by expiresAt (about every 20 minutes) while a worker runs or waits; an Orca heartbeat is no renewal. The claim belongs to the machine, so a switched account or a usage-limit pause keeps it: renew and resume. Nobody can continue before expiry: release paused. A ticket you paused stays claimable for your agent under your person's work mandate until someone else changes its status or assignee.\n- After a crash read your live claims (fleek_my_work_inbox) and `orca worktree list`, then continue on the same claim (`fleek orca start KEY --yes` restarts an ended agent) or release it. Never claim or complete twice.\n\n## 8. Limits\n- One builder per ticket, one ticket per worktree. Parallel tickets: as many as the person allows, default 2, each with its reviewer; queue the rest. QUOTA_EXCEEDED: the machine's claims are used up - finish or release one first.\n- No Orca code changes, forks or pull requests on Orca. Git effects only as far as the project brief allows.\n"
51755
52071
  }
51756
52072
  ];
51757
52073
 
@@ -51981,8 +52297,9 @@ function initAgentArgs(prompt) {
51981
52297
  JSON.stringify({ disableAllHooks: true })
51982
52298
  ];
51983
52299
  }
51984
- function initAgentEnv(env) {
51985
- const result = { PATH: dirname9(process.execPath) };
52300
+ function initAgentEnv(env, platform = process.platform) {
52301
+ const path = platform === "darwin" ? [dirname9(process.execPath), "/usr/bin"] : [dirname9(process.execPath)];
52302
+ const result = { PATH: path.join(delimiter2) };
51986
52303
  for (const key of [
51987
52304
  "HOME",
51988
52305
  "USER",
@@ -54265,113 +54582,6 @@ var Session = class {
54265
54582
  }
54266
54583
  };
54267
54584
 
54268
- // src/header.ts
54269
- import { win32 as win322, posix as posix2 } from "node:path";
54270
-
54271
- // src/uuid.ts
54272
- var UUID3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
54273
- function isUuid(value) {
54274
- return UUID3.test(value);
54275
- }
54276
- function canonicalId(value) {
54277
- if (!UUID3.test(value)) throw new Error("INVALID_UUID");
54278
- return value.toLowerCase();
54279
- }
54280
-
54281
- // src/header.ts
54282
- var LOGO2 = [" ▄██████▀", " ▄█████▀ ", " ██▀ "];
54283
- var ASCII_LOGO = [" ######/", " #####/ ", " ##/ "];
54284
- var BRAND = "\x1B[38;2;69;94;255m";
54285
- function shouldShowHeader(positionals, options, terminal) {
54286
- if (options.json || options.version || terminal.stream.isTTY !== true) return false;
54287
- const active = (value) => value !== void 0 && value !== "" && value !== "0" && value !== "false";
54288
- if (["CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS", "BUILD_NUMBER", "TF_BUILD"].some((key) => active(terminal.env[key]))) return false;
54289
- const [command, sub] = positionals;
54290
- return !command || command === "help" || !!options.help || command === "setup" || command === "doctor" || command === "init" || command === "kit" && ["setup", "doctor", "pull"].includes(sub ?? "") || command === "service" && sub === "setup";
54291
- }
54292
- function cells(value) {
54293
- let width = 0;
54294
- for (const char of value) {
54295
- const code = char.codePointAt(0);
54296
- if (new RegExp("\\p{Mark}", "u").test(char)) continue;
54297
- width += code >= 4352 && (code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744) ? 2 : 1;
54298
- }
54299
- return width;
54300
- }
54301
- function fit(value, width, ascii) {
54302
- if (cells(value) <= width) return value;
54303
- const suffix = ascii ? "..." : "…";
54304
- if (width <= suffix.length) return suffix.slice(0, Math.max(0, width));
54305
- let out = "";
54306
- for (const char of value) {
54307
- if (cells(out + char) > width - suffix.length) break;
54308
- out += char;
54309
- }
54310
- return out + suffix;
54311
- }
54312
- var safe = (value) => neutralizeLine(redact(value));
54313
- function directory(context, windows, env) {
54314
- const path = windows ? win322 : posix2;
54315
- const home = context.home ?? userHome(env, windows ? "win32" : process.platform);
54316
- const relative3 = path.relative(home, context.cwd);
54317
- const inside = relative3 === "" || relative3 !== ".." && !relative3.startsWith(`..${path.sep}`) && !path.isAbsolute(relative3);
54318
- return safe(inside ? relative3 ? `~${path.sep}${relative3}` : "~" : context.cwd);
54319
- }
54320
- function headerServer(value) {
54321
- if (!value) return void 0;
54322
- try {
54323
- const url = new URL(value);
54324
- return ["http:", "https:"].includes(url.protocol) ? url.host : void 0;
54325
- } catch {
54326
- return void 0;
54327
- }
54328
- }
54329
- function renderHeader(context, terminal, t) {
54330
- const windows = (terminal.platform ?? process.platform) === "win32";
54331
- const ascii = windows || terminal.env.TERM === "dumb";
54332
- const separator = ascii ? " - " : " · ";
54333
- const requested = terminal.stream.columns ?? Number(terminal.env.COLUMNS);
54334
- const columns = Number.isFinite(requested) && requested > 0 ? Math.floor(requested) : 80;
54335
- const title = t("header.title", { version: safe(context.version) });
54336
- const cwd = directory(context, windows, terminal.env);
54337
- const parts = [context.workspace, context.project && !isUuid(context.project) ? context.project : void 0, headerServer(context.server), context.displayName].filter((value) => !!value);
54338
- const details = parts.length ? parts.map(safe).join(separator) : t("header.noContext");
54339
- if (columns < 60) return ["", fit([title, cwd].join(separator), columns, ascii)];
54340
- const logo = ascii ? ASCII_LOGO : LOGO2;
54341
- const width = Math.max(...logo.map(cells));
54342
- const color = colorEnabled(terminal.env, terminal.stream);
54343
- const available2 = columns - width - 6;
54344
- const tagline = separator + t("header.tagline");
54345
- const attribution = separator + t("header.attribution");
54346
- const secondary = cells(title + tagline) <= available2 ? tagline + (cells(title + tagline + attribution) <= available2 ? attribution : "") : "";
54347
- const text6 = [title, details, cwd];
54348
- const rows = logo.map((row, index) => {
54349
- const mark = row.padEnd(width);
54350
- const label = fit(text6[index], available2, ascii);
54351
- if (index === 0) {
54352
- const heading = color ? `\x1B[1m${label}\x1B[22m` : label;
54353
- const branding = color && secondary ? `\x1B[2m${secondary}\x1B[22m` : secondary;
54354
- return `${color ? `${BRAND}${mark}\x1B[39m` : mark} ${heading}${branding}`;
54355
- }
54356
- const styled = color ? `\x1B[2m${label}\x1B[22m` : label;
54357
- return `${color ? `${BRAND}${mark}\x1B[39m` : mark} ${styled}`;
54358
- });
54359
- const inner = Math.max(...rows.map((row) => cells(stripAnsi(row))));
54360
- const edge = (value) => color ? `${BRAND}${value}\x1B[39m` : value;
54361
- const vertical = ascii ? "|" : "│";
54362
- return [
54363
- "",
54364
- edge(`${ascii ? "+" : "╭"}${(ascii ? "-" : "─").repeat(inner + 2)}${ascii ? "+" : "╮"}`),
54365
- ...rows.map((row) => `${edge(vertical)} ${row}${" ".repeat(inner - cells(stripAnsi(row)))} ${edge(vertical)}`),
54366
- edge(`${ascii ? "+" : "╰"}${(ascii ? "-" : "─").repeat(inner + 2)}${ascii ? "+" : "╯"}`)
54367
- ];
54368
- }
54369
- function printHeader(out, context, terminal, t) {
54370
- for (const line of renderHeader(context, terminal, t)) out.line(line);
54371
- out.line();
54372
- out.indentHumanOutput();
54373
- }
54374
-
54375
54585
  // src/project-reference.ts
54376
54586
  async function visibleProject(client, ref) {
54377
54587
  let cursor;
@@ -57296,9 +57506,43 @@ function instructions2(ctx, app, facts) {
57296
57506
  }, null, 2),
57297
57507
  "```",
57298
57508
  "",
57509
+ ...allowedValueLines(de),
57299
57510
  de ? `Grenzen: Abschnitte ≤ ${import_validation3.PROJECT_INIT_LIMITS.section} Zeichen, Hinweise ≤ ${import_validation3.PROJECT_INIT_LIMITS.reviewHints}, Datei ≤ 64 KiB. Einfacher Text mit Absätzen und Spiegelstrichen.` : `Bounds: sections <= ${import_validation3.PROJECT_INIT_LIMITS.section} characters, hints <= ${import_validation3.PROJECT_INIT_LIMITS.reviewHints}, file <= 64 KiB. Plain text with paragraphs and bullets.`
57300
57511
  ].join("\n");
57301
57512
  }
57513
+ var INIT_AGENT_ENUM_FIELDS = [
57514
+ ["cms.items[].kind", import_validation3.PROJECT_INIT_CMS_ITEM_KINDS],
57515
+ ["integrations[].kind", import_validation3.PROJECT_INIT_INTEGRATION_KINDS],
57516
+ ["integrations[].direction", import_validation3.PROJECT_INIT_DIRECTIONS],
57517
+ ["environments[].label", import_validation3.PROJECT_INIT_ENVIRONMENTS],
57518
+ ["reviewHints[].topic", import_validation3.PROJECT_INIT_HINT_TOPICS],
57519
+ ["statementChecks[].result", import_validation3.PROJECT_INIT_STATEMENT_RESULTS]
57520
+ ];
57521
+ function allowedValueLines(de) {
57522
+ return [
57523
+ de ? "## Erlaubte Werte" : "## Allowed values",
57524
+ de ? "- Diese Felder nehmen genau einen der genannten Werte; jeder andere Wert macht die ganze Ausgabe ungültig. Passt keiner, nimm `other`, wo es ihn gibt." : "- These fields take exactly one of the listed values; any other value invalidates the whole output. If none fits, use `other` where it exists.",
57525
+ ...INIT_AGENT_ENUM_FIELDS.map(([field, values]) => `- \`${field}\`: ${values.map((value) => `\`${value}\``).join(", ")}`),
57526
+ ""
57527
+ ];
57528
+ }
57529
+ function rejectedEnumValue(root, issue) {
57530
+ if (!issue || issue.reason !== "invalid_enum_value") return null;
57531
+ let current2 = root;
57532
+ for (const [, index, key] of issue.path.matchAll(/\[(\d+)\]|([^.[\]]+)/g)) {
57533
+ if (current2 === null || typeof current2 !== "object") return null;
57534
+ const step = index !== void 0 ? Number(index) : key;
57535
+ if (!Object.prototype.hasOwnProperty.call(current2, step)) return null;
57536
+ current2 = current2[step];
57537
+ }
57538
+ if (typeof current2 !== "string" || current2.length === 0 || current2.length > 40 || !/^[\p{L}\p{N} _.\-/]+$/u.test(current2)) return null;
57539
+ return (0, import_validation3.detectSecretShape)(current2) ? null : current2;
57540
+ }
57541
+ function outputInvalidLine(ctx, app, root, issue) {
57542
+ const field = issue?.path || "-";
57543
+ const value = rejectedEnumValue(root, issue);
57544
+ return value === null ? ctx.t("init.outputInvalid", { app, field }) : ctx.t("init.outputInvalidValue", { app, field, value });
57545
+ }
57302
57546
  function projectFactLines(de, facts) {
57303
57547
  const matched = projectFactsForStack(facts.stack.map((item2) => item2.product));
57304
57548
  if (!matched.length) return [];
@@ -57779,7 +58023,7 @@ async function runApplication(ctx, client, values, checkout, context, app, appli
57779
58023
  const agentOutput = raw === void 0 ? null : (0, import_validation3.parseProjectInitAgentOutput)(raw);
57780
58024
  if (!agentOutput?.ok) {
57781
58025
  emit(ctx, { event: "error", app: app.key, code: "output_invalid" });
57782
- if (!ctx.json) ctx.out.error(ctx.out.style.fail(ctx.t("init.outputInvalid", { app: app.key, field: agentOutput && !agentOutput.ok ? agentOutput.issues[0]?.path || "-" : "-" })));
58026
+ if (!ctx.json) ctx.out.error(ctx.out.style.fail(outputInvalidLine(ctx, app.key, raw, agentOutput && !agentOutput.ok ? agentOutput.issues[0] : void 0)));
57783
58027
  return "failed";
57784
58028
  }
57785
58029
  const composed = (0, import_validation3.composeProjectInitSummary)({
@@ -57791,7 +58035,7 @@ async function runApplication(ctx, client, values, checkout, context, app, appli
57791
58035
  const parsed = (0, import_validation3.parseProjectInitSummary)(composed);
57792
58036
  if (!parsed.ok) {
57793
58037
  emit(ctx, { event: "error", app: app.key, code: "output_invalid" });
57794
- if (!ctx.json) ctx.out.error(ctx.out.style.fail(ctx.t("init.outputInvalid", { app: app.key, field: parsed.issues[0]?.path || "-" })));
58038
+ if (!ctx.json) ctx.out.error(ctx.out.style.fail(outputInvalidLine(ctx, app.key, composed, parsed.issues[0])));
57795
58039
  return "failed";
57796
58040
  }
57797
58041
  const findings = (0, import_validation3.scanProjectInit)(parsed.value);
@@ -59288,6 +59532,20 @@ async function guidedMenu(d) {
59288
59532
  out.line(`$ fleek ${args[0] === "setup" && args[1] && !args[1].startsWith("--") ? "setup <code>" : args.map(neutralizeLine).join(" ")}`);
59289
59533
  return d.run(args, cwd2);
59290
59534
  };
59535
+ const choose = async (options) => {
59536
+ if (d.select) return d.select(options);
59537
+ for (const line of [...options.context ? [options.context] : [], ...options.title ?? []]) out.line(line);
59538
+ for (const [i, item2] of options.items.entries()) out.line(`${i + 1} ${item2.label}${item2.hint ? ` · ${item2.hint}` : ""}`);
59539
+ const answer2 = (await d.ask(t("menu.choose"))).trim();
59540
+ if (!answer2) return { kind: "back" };
59541
+ const chosen = /^[1-9][0-9]*$/.test(answer2) ? options.items[Number(answer2) - 1] : void 0;
59542
+ if (!chosen) throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59543
+ return { kind: "select", id: chosen.id };
59544
+ };
59545
+ const confirm2 = async (question) => {
59546
+ if (!d.select) return /^(y|yes|j|ja)$/i.test((await d.ask(`${question} ${t("menu.yesNo")}`)).trim());
59547
+ return isYes(await d.select(yesNoList(question, t)));
59548
+ };
59291
59549
  const connect = async (setup) => {
59292
59550
  await d.connect();
59293
59551
  if (!setup) return EXIT.ok;
@@ -59311,53 +59569,121 @@ async function guidedMenu(d) {
59311
59569
  }
59312
59570
  return run2(["setup", code, ...language ? ["--language", language] : []]);
59313
59571
  };
59314
- out.line(t("menu.recommend", { action: d.resume ? t("menu.resume", { key: d.resume }) : t(!d.signedIn ? "menu.connect" : d.stateError ? "menu.doctor" : !d.bound ? "menu.bind" : "menu.pick") }));
59315
- if (d.stateError) out.line(t("menu.stateUnreadable"));
59316
- if (!d.signedIn) {
59317
- out.line(`1 ${t("menu.connect")}`);
59318
- out.line(`2 ${t("menu.help")}`);
59319
- const choice2 = (await d.ask(t("menu.choose"))).trim();
59320
- if (!choice2) return EXIT.ok;
59321
- if (choice2 === "1") return connect(true);
59322
- if (choice2 === "2") return run2(["help"]);
59323
- throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59324
- }
59325
59572
  let cwd;
59326
- if (!d.bound && !d.stateError) {
59327
- for (const [i, path] of d.checkouts.entries()) out.line(`${i + 1} ${neutralizeLine(path)}`);
59328
- out.line(`0 ${t("menu.connect")}`);
59329
- const choice2 = (await d.ask(t("menu.checkout"))).trim();
59330
- if (!choice2) return EXIT.ok;
59331
- if (choice2 === "0") return connect(true);
59332
- const index = Number(choice2) - 1;
59333
- if (!/^\d+$/.test(choice2) || !d.checkouts[index]) throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59334
- cwd = d.checkouts[index];
59335
- }
59336
- if (d.repair) out.line(t("menu.fix", { command: `fleek ${repair.join(" ")}` }));
59337
- for (const [i, key] of ["pick", "continue", "doctor", "connections", "help"].entries()) out.line(`${i + 1} ${t(`menu.${key}`)}`);
59338
- const choice = (await d.ask(t("menu.choose"))).trim();
59339
- switch (choice) {
59340
- case "":
59573
+ let state;
59574
+ let cursor;
59575
+ while (true) {
59576
+ if (!state) {
59577
+ out.progress(t("menu.loading"));
59578
+ try {
59579
+ state = await d.state(cwd);
59580
+ } catch {
59581
+ state = { signedIn: false, bound: false, stateError: true, checkouts: [] };
59582
+ }
59583
+ out.progress(null);
59584
+ if (cwd && !state.bound && !state.stateError) {
59585
+ cwd = void 0;
59586
+ continue;
59587
+ }
59588
+ }
59589
+ const current2 = state;
59590
+ const recommended = (id2, wanted2) => id2 === wanted2 ? { hint: t("menu.recommended") } : {};
59591
+ const chooser2 = current2.signedIn && !current2.bound && !current2.stateError;
59592
+ const canSwitch = !chooser2 && !!cwd;
59593
+ const wanted = !current2.signedIn ? "connect" : current2.resume ? "resume" : current2.stateError ? "doctor" : "pick";
59594
+ const items = !current2.signedIn ? [{ id: "connect", label: t("menu.connect"), ...recommended("connect", wanted) }, { id: "help", label: t("menu.help") }, { id: "quit", label: t("menu.quit") }] : chooser2 ? [
59595
+ ...current2.checkouts.map((checkout, i) => ({ id: `checkout:${i}`, label: checkout.label ?? checkout.path, ...checkout.project ? { hint: checkout.project } : {} })),
59596
+ { id: "connect", label: t("menu.setupComputer") },
59597
+ { id: "help", label: t("menu.help") },
59598
+ { id: "quit", label: t("menu.quit") }
59599
+ ] : [
59600
+ ...current2.resume ? [{ id: "resume", label: t("menu.resume", { key: current2.resume }), ...recommended("resume", wanted) }] : [],
59601
+ { id: "pick", label: t("menu.pick"), ...recommended("pick", wanted) },
59602
+ { id: "continue", label: t("menu.continue") },
59603
+ { id: "doctor", label: t("menu.doctor"), ...recommended("doctor", wanted) },
59604
+ { id: "connections", label: t("menu.connections") },
59605
+ ...canSwitch ? [{ id: "switch", label: t("menu.switchCheckout") }] : [],
59606
+ { id: "help", label: t("menu.help") },
59607
+ { id: "quit", label: t("menu.quit") }
59608
+ ];
59609
+ const title = [
59610
+ ...chooser2 ? [t("menu.checkoutTitle")] : [],
59611
+ ...current2.stateError && current2.signedIn ? [t("menu.stateUnreadable")] : [],
59612
+ ...current2.repair && current2.signedIn && !chooser2 ? [t("menu.fix", { command: `fleek ${repair.join(" ")}` })] : []
59613
+ ];
59614
+ let choice;
59615
+ try {
59616
+ choice = await choose({ ...current2.context ? { context: current2.context } : {}, title, items, initial: cursor && items.some((item2) => item2.id === cursor) ? cursor : wanted, quit: true, back: canSwitch });
59617
+ } catch (error) {
59618
+ d.report(error);
59619
+ out.line();
59620
+ continue;
59621
+ }
59622
+ if (choice.kind !== "select") {
59623
+ if (choice.kind === "back" && canSwitch) {
59624
+ cwd = void 0;
59625
+ state = void 0;
59626
+ cursor = void 0;
59627
+ continue;
59628
+ }
59341
59629
  return EXIT.ok;
59342
- case "1":
59343
- return run2(["start", "--mine"], cwd);
59344
- case "2": {
59345
- const key = (await d.ask(d.resume ? t("menu.ticketDefault", { key: d.resume }) : t("menu.ticket"))).trim().toUpperCase() || d.resume;
59346
- if (!key) return EXIT.ok;
59347
- if (!/^[A-Z0-9]{2,10}-[1-9][0-9]*$/.test(key)) throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59348
- return run2(["start", key], cwd);
59349
- }
59350
- case "3": {
59351
- const code = await run2(["doctor"], cwd);
59352
- if ((code !== EXIT.ok || d.repair || d.stateError) && /^(y|yes|j|ja)$/i.test((await d.ask(t("menu.repair", { command: `fleek ${repair.join(" ")}` }))).trim())) return run2(repair, cwd);
59353
- return code;
59354
59630
  }
59355
- case "4":
59356
- return connect(false);
59357
- case "5":
59358
- return run2(["help"]);
59359
- default:
59360
- throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59631
+ const id = choice.id;
59632
+ if (id === "quit") return EXIT.ok;
59633
+ cursor = id;
59634
+ if (id === "switch") {
59635
+ cwd = void 0;
59636
+ state = void 0;
59637
+ cursor = void 0;
59638
+ continue;
59639
+ }
59640
+ if (id.startsWith("checkout:")) {
59641
+ cwd = current2.checkouts[Number(id.slice(9))]?.path;
59642
+ state = void 0;
59643
+ cursor = void 0;
59644
+ continue;
59645
+ }
59646
+ let refresh = true, code = EXIT.ok;
59647
+ try {
59648
+ switch (id) {
59649
+ case "connect":
59650
+ code = await connect(true);
59651
+ break;
59652
+ case "resume":
59653
+ code = await run2(["start", current2.resume], cwd);
59654
+ break;
59655
+ case "pick":
59656
+ code = await run2(["start", "--mine"], cwd);
59657
+ break;
59658
+ case "continue": {
59659
+ const key = (await d.ask(current2.resume ? t("menu.ticketDefault", { key: current2.resume }) : t("menu.ticket"))).trim().toUpperCase() || current2.resume;
59660
+ if (!key) {
59661
+ refresh = false;
59662
+ break;
59663
+ }
59664
+ if (!/^[A-Z0-9]{2,10}-[1-9][0-9]*$/.test(key)) throw new CliError("errors.usage", EXIT.usage, {}, "USAGE");
59665
+ code = await run2(["start", key], cwd);
59666
+ break;
59667
+ }
59668
+ case "doctor":
59669
+ code = await run2(["doctor"], cwd);
59670
+ if (!d.leaving?.() && (code !== EXIT.ok || current2.repair || current2.stateError) && await confirm2(t("menu.repair", { command: `fleek ${repair.join(" ")}` }))) code = await run2(repair, cwd);
59671
+ break;
59672
+ case "connections":
59673
+ refresh = false;
59674
+ code = await connect(false);
59675
+ break;
59676
+ case "help":
59677
+ refresh = false;
59678
+ code = await run2(["help"]);
59679
+ break;
59680
+ }
59681
+ } catch (error) {
59682
+ d.report(error);
59683
+ }
59684
+ if (d.leaving?.()) return code;
59685
+ out.line();
59686
+ if (refresh) state = void 0;
59361
59687
  }
59362
59688
  }
59363
59689
 
@@ -59731,6 +60057,10 @@ var Context = class {
59731
60057
  fetch;
59732
60058
  now;
59733
60059
  headerShown = false;
60060
+ /** Bare `fleek` is an application: an update hint once, and these two end it after the current action. */
60061
+ updateChecked = false;
60062
+ agentRan = false;
60063
+ appQuit = false;
59734
60064
  store;
59735
60065
  boundProfile;
59736
60066
  /** The look of human lines (colours only for a TTY, never with --json). */
@@ -60034,7 +60364,7 @@ async function confirmLocal(ctx, lines) {
60034
60364
  const rl = createInterface2({ input: process.stdin, output: process.stderr });
60035
60365
  try {
60036
60366
  for (const line of lines.slice(0, -1)) ctx.out.error(line);
60037
- const answer2 = await rl.question(`${ctx.out.render(ctx.s.question(lines.at(-1) ?? ""), "err")} `);
60367
+ const answer2 = await askLine(rl, `${ctx.out.render(ctx.s.question(lines.at(-1) ?? ""), "err")} `);
60038
60368
  return /^(?:j|ja|y|yes)$/i.test(answer2.trim());
60039
60369
  } finally {
60040
60370
  rl.close();
@@ -60394,7 +60724,8 @@ async function dispatch(ctx, positionals, values, exec, passthrough) {
60394
60724
  displayName: profile?.needsLogin ? void 0 : profile?.displayName
60395
60725
  }, terminal, ctx.t);
60396
60726
  }
60397
- if (!["update", "uninstall", "mcp", "listen", "help", "login", "setup"].includes(command ?? "") && !(command === "kit" && sub === "run") && !values.help) {
60727
+ if (!ctx.updateChecked && !["update", "uninstall", "mcp", "listen", "help", "login", "setup"].includes(command ?? "") && !(command === "kit" && sub === "run") && !values.help) {
60728
+ ctx.updateChecked = true;
60398
60729
  await updateHint({
60399
60730
  configDir: ctx.configDir,
60400
60731
  env: ctx.env,
@@ -60408,47 +60739,19 @@ async function dispatch(ctx, positionals, values, exec, passthrough) {
60408
60739
  }, ctx.deps.isTTY ?? (process.stderr.isTTY === true && process.stdin.isTTY === true));
60409
60740
  }
60410
60741
  if (!command && !values.help && !ctx.json && (ctx.deps.isTTY ?? (process.stdin.isTTY === true && (ctx.deps.stdout ?? process.stdout).isTTY === true))) {
60411
- let stateError = false;
60412
- const found = await resolveBinding(ctx.profiles, ctx.configDir, { flag: ctx.profileFlag, env: ctx.env, cwd: ctx.deps.cwd ?? process.cwd(), allowCurrent: true }).catch(() => {
60413
- stateError = true;
60414
- return null;
60415
- });
60416
- const profile = found?.profile ?? await ctx.profiles.current().catch(() => null);
60417
- const checkouts = profile ? await new CheckoutIndex(ctx.configDir, profile.key).entries().catch(() => {
60418
- stateError = true;
60419
- return [];
60420
- }) : [];
60421
- const domain = profile && found?.projectId ? new KitDomain(ctx.configDir, profile.key, found.projectId) : null;
60422
- let kitNeedsRepair = false;
60423
- if (domain) {
60424
- try {
60425
- kitNeedsRepair = !await domain.current() && await domain.pulledAt() === null;
60426
- } catch {
60427
- stateError = true;
60428
- kitNeedsRepair = true;
60429
- }
60430
- }
60431
- const handler = await inspectSetupHandler(kitContext(ctx, values)).catch(() => {
60432
- stateError = true;
60433
- return null;
60434
- });
60435
- const repair = handler?.state === "missing" || kitNeedsRepair ? ["kit", "setup"] : void 0;
60436
- const resume = profile && !profile.needsLogin && found?.projectId ? await ctx.session().then(async ({ client }) => {
60437
- const inbox = (await client.callTool(WIRE.inbox, { limit: 25, kinds: ["claim"], teamId: found.projectId })).structured;
60438
- const rows = Array.isArray(inbox.items) ? inbox.items : [];
60439
- return rows.find((row) => row.kind === "claim" && typeof row.identifier === "string" && /^[A-Z0-9]{2,10}-[1-9][0-9]*$/.test(row.identifier))?.identifier;
60440
- }).catch(() => void 0) : void 0;
60742
+ let leaving = false;
60441
60743
  return guidedMenu({
60442
- resume,
60443
- stateError,
60444
60744
  out: ctx.out,
60445
- t: ctx.t,
60745
+ t: (key, params) => ctx.t(key, params),
60446
60746
  ask: orcaDeps(ctx).ask,
60447
- signedIn: !!profile && !profile.needsLogin,
60448
- repair,
60449
- bound: !!found?.projectId,
60450
- checkouts: checkouts.map(([path]) => path),
60747
+ ...selectFor(ctx),
60748
+ state: (cwd) => menuState(ctx, values, cwd),
60749
+ leaving: () => leaving,
60750
+ report: (error) => {
60751
+ reportFailure(ctx.out, ctx.t, error, false);
60752
+ },
60451
60753
  connect: async () => {
60754
+ const profile = await ctx.profiles.current().catch(() => null);
60452
60755
  const origin = profile ? webOrigin(profile) : "https://app.onfleek.app";
60453
60756
  if (!origin) {
60454
60757
  ctx.out.line(ctx.t("menu.setupExternal"));
@@ -60462,7 +60765,13 @@ async function dispatch(ctx, positionals, values, exec, passthrough) {
60462
60765
  const target = cwd ? new Context({ ...ctx.deps, cwd }, false, ctx.profileFlag, ctx.languageFlag) : ctx;
60463
60766
  const parsed = parseArgs({ args, options: OPTIONS, allowPositionals: true });
60464
60767
  target.headerShown = ctx.headerShown;
60465
- return dispatch(target, parsed.positionals, { profile: values.profile, language: values.language, ...parsed.values, yes: false }, null, null);
60768
+ target.updateChecked = true;
60769
+ if (target !== ctx && ctx.headerShown) target.out.indentHumanOutput();
60770
+ try {
60771
+ return await dispatch(target, parsed.positionals, { profile: values.profile, language: values.language, ...parsed.values, yes: false }, null, null);
60772
+ } finally {
60773
+ leaving = target.agentRan || target.appQuit;
60774
+ }
60466
60775
  }
60467
60776
  });
60468
60777
  }
@@ -60750,6 +61059,82 @@ async function mcpProxy(ctx, args, values) {
60750
61059
  ...ctx.deps.proxyRetryDelaysMs ? { retryDelaysMs: ctx.deps.proxyRetryDelaysMs } : {}
60751
61060
  });
60752
61061
  }
61062
+ function selectFor(ctx) {
61063
+ const stdin = ctx.deps.stdin ?? process.stdin, stdout = ctx.deps.stdout ?? process.stdout;
61064
+ if (ctx.json || !isKeyInput(stdin) || stdout.isTTY !== true || ctx.env.TERM === "dumb") return {};
61065
+ return { select: async (options) => {
61066
+ const result = await selectList({ stdin, stdout, out: ctx.out, t: ctx.t }, options);
61067
+ if (result.kind === "abort") ctx.appQuit = true;
61068
+ return result;
61069
+ } };
61070
+ }
61071
+ function askLine(rl, question) {
61072
+ return new Promise((resolve9, reject) => {
61073
+ rl.once("close", () => resolve9(""));
61074
+ rl.question(question).then(resolve9, reject);
61075
+ });
61076
+ }
61077
+ var RESUME_READ_MS = 3e3;
61078
+ async function menuState(ctx, values, cwd) {
61079
+ let stateError = false;
61080
+ const folder = cwd ?? ctx.deps.cwd ?? process.cwd();
61081
+ const found = await resolveBinding(ctx.profiles, ctx.configDir, { flag: ctx.profileFlag, env: ctx.env, cwd: folder, allowCurrent: true }).catch(() => {
61082
+ stateError = true;
61083
+ return null;
61084
+ });
61085
+ const profile = found?.profile ?? await ctx.profiles.current().catch(() => null);
61086
+ if (profile?.language && !ctx.languageFlag) ctx.t = translator(profile.language);
61087
+ const keys = profile ? new ProjectKeyIndex(ctx.configDir, profile.key) : null;
61088
+ const keyOf = async (project2) => await keys?.keyFor(project2).catch(() => null) ?? void 0;
61089
+ const entries = profile ? await new CheckoutIndex(ctx.configDir, profile.key).entries().catch(() => {
61090
+ stateError = true;
61091
+ return [];
61092
+ }) : [];
61093
+ const checkouts = (await Promise.all(entries.map(async ([path, project2]) => {
61094
+ if (!await stat16(path).then((info) => info.isDirectory(), () => false)) return null;
61095
+ const key = await keyOf(project2);
61096
+ return { path, label: displayPath(path, ctx.home, ctx.env), ...key ? { project: key } : {} };
61097
+ }))).filter((entry) => entry !== null);
61098
+ const domain = profile && found?.projectId ? new KitDomain(ctx.configDir, profile.key, found.projectId) : null;
61099
+ let kitNeedsRepair = false;
61100
+ if (domain) {
61101
+ try {
61102
+ kitNeedsRepair = !await domain.current() && await domain.pulledAt() === null;
61103
+ } catch {
61104
+ stateError = true;
61105
+ kitNeedsRepair = true;
61106
+ }
61107
+ }
61108
+ const handler = await inspectSetupHandler(kitContext(ctx, values)).catch(() => {
61109
+ stateError = true;
61110
+ return null;
61111
+ });
61112
+ const signedIn = !!profile && !profile.needsLogin;
61113
+ let resume;
61114
+ if (signedIn && found?.projectId) {
61115
+ const read2 = ctx.sessionFor(profile).then(async ({ client }) => {
61116
+ const inbox = (await client.callTool(WIRE.inbox, { limit: 25, kinds: ["claim"], teamId: found.projectId })).structured;
61117
+ const rows = Array.isArray(inbox.items) ? inbox.items : [];
61118
+ return rows.find((row) => row.kind === "claim" && typeof row.identifier === "string" && /^[A-Z0-9]{2,10}-[1-9][0-9]*$/.test(row.identifier))?.identifier;
61119
+ }).catch(() => void 0);
61120
+ let timer;
61121
+ resume = await Promise.race([read2, new Promise((resolve9) => {
61122
+ timer = setTimeout(() => resolve9(void 0), RESUME_READ_MS);
61123
+ })]);
61124
+ clearTimeout(timer);
61125
+ }
61126
+ const project = found?.projectId ? await keyOf(found.projectId) : void 0;
61127
+ const context = signedIn ? [profile.workspace.name, project, displayPath(folder, ctx.home, ctx.env)].filter(Boolean).map((part) => neutralizeLine(part)).join(" · ") : void 0;
61128
+ return {
61129
+ signedIn,
61130
+ bound: !!found?.projectId,
61131
+ stateError,
61132
+ checkouts,
61133
+ ...resume ? { resume } : {},
61134
+ ...context ? { context } : {},
61135
+ ...handler?.state === "missing" || kitNeedsRepair ? { repair: true } : {}
61136
+ };
61137
+ }
60753
61138
  function orcaDeps(ctx) {
60754
61139
  return {
60755
61140
  out: ctx.out,
@@ -60768,11 +61153,12 @@ function orcaDeps(ctx) {
60768
61153
  const { createInterface: createInterface2 } = await import("node:readline/promises");
60769
61154
  const rl = createInterface2({ input: process.stdin, output: ctx.json ? process.stderr : process.stdout });
60770
61155
  try {
60771
- return await rl.question(`${ctx.out.style.question(question)} `);
61156
+ return await askLine(rl, `${ctx.out.render(ctx.out.style.question(question), ctx.json ? "err" : "out")} `);
60772
61157
  } finally {
60773
61158
  rl.close();
60774
61159
  }
60775
61160
  }),
61161
+ ...selectFor(ctx),
60776
61162
  ...ctx.deps.mutationBackoffMs !== void 0 ? { backoffMs: ctx.deps.mutationBackoffMs } : {}
60777
61163
  };
60778
61164
  }
@@ -60789,7 +61175,11 @@ async function start(ctx, key, values) {
60789
61175
  ...orcaDeps(ctx),
60790
61176
  ...ctx.deps.linkDialog ? { dialog: ctx.deps.linkDialog } : {},
60791
61177
  kitReady: async (agent, found) => !!(await new KitDomain(ctx.configDir, found.profile.key, found.projectId).current())?.state.targets[agent],
60792
- runAgent: (agent, args, found) => kitRun(kitContext(ctx, values, { profile: found.profile, projectId: found.projectId, source: "repo", root: found.root }), agent, { project: found.projectId }, args)
61178
+ runAgent: async (agent, args, found) => {
61179
+ const code = await kitRun(kitContext(ctx, values, { profile: found.profile, projectId: found.projectId, source: "repo", root: found.root }), agent, { project: found.projectId }, args);
61180
+ ctx.agentRan = code !== 127;
61181
+ return code;
61182
+ }
60793
61183
  };
60794
61184
  return key ? fleekStart(deps, key, own4) : orcaPick(deps, own4, (chosen) => fleekStart(deps, chosen, own4));
60795
61185
  }
@@ -61080,6 +61470,31 @@ async function setupDeveloper(ctx, code, values) {
61080
61470
  }
61081
61471
  }, code, values);
61082
61472
  }
61473
+ function reportFailure(out, t, error, json2) {
61474
+ const errno = error?.code;
61475
+ const failure2 = error instanceof CliError ? error : typeof errno === "string" && /^E[A-Z]{2,16}$/.test(errno) ? new CliError("errors.internalCode", EXIT.failed, { code: errno }, "INTERNAL") : new CliError("errors.internal", EXIT.failed, {}, "INTERNAL");
61476
+ if (json2) out.json({ error: failure2.code ?? failure2.key, ...Object.keys(failure2.params).length ? { details: failure2.params } : {} });
61477
+ else {
61478
+ const params = Object.fromEntries(Object.entries(failure2.params).map(([key, value]) => [key, typeof value === "string" ? neutralizeLine(value) : value]));
61479
+ let friendlyKey = failure2 instanceof ToolError && ["RATE_LIMITED", "ACCESS_DENIED", "CONFLICT", "TRANSITION_DENIED"].includes(failure2.code ?? "") ? `errors.server.${failure2.code}` : failure2.key;
61480
+ if (failure2.code === "KIT_INVALID" || failure2.code === "KIT_UNSIGNED") {
61481
+ const reason = String(failure2.params.reason ?? "");
61482
+ const kind = kitRefusalCategory(failure2.code, reason);
61483
+ friendlyKey = `errors.kitRefused.${kind}`;
61484
+ }
61485
+ out.error(out.style.fail(redact(t(friendlyKey, params))));
61486
+ if (failure2 instanceof ToolError && failure2.code === "TRANSITION_DENIED") {
61487
+ const details = failure2.details;
61488
+ const key = typeof details?.reason === "string" ? `errors.transition.${details.reason}` : "";
61489
+ if (Object.hasOwn(EN, key)) out.error(t(key));
61490
+ }
61491
+ const suggestion = failure2.suggestion;
61492
+ if (suggestion) out.error(t("errors.didYouMean", { command: out.style.cmd(suggestion) }));
61493
+ if (failure2.code === "KIT_INVALID" || failure2.code === "KIT_UNSIGNED") out.error(out.style.dim(redact(t("errors.kitReason", { ...params, reason: params.reason ?? failure2.code }))));
61494
+ if (`${friendlyKey}.next` in EN) out.error(` ${t("next.step", { command: out.style.cmd(redact(t(`${friendlyKey}.next`, params))) })}`);
61495
+ }
61496
+ return failure2;
61497
+ }
61083
61498
  async function main(argv, deps = {}) {
61084
61499
  const env = deps.env ?? process.env;
61085
61500
  let t = translator(locale(env));
@@ -61110,30 +61525,7 @@ async function main(argv, deps = {}) {
61110
61525
  context = new Context(deps, json2, parsed.values.profile, parsed.values.language === "en" || parsed.values.language === "de" ? parsed.values.language : void 0);
61111
61526
  return await dispatch(context, parsed.positionals, parsed.values, exec, passthrough);
61112
61527
  } catch (error) {
61113
- t = context?.t ?? t;
61114
- const errorOut = context?.out ?? out;
61115
- const errno = error?.code;
61116
- const failure2 = error instanceof CliError ? error : typeof errno === "string" && /^E[A-Z]{2,16}$/.test(errno) ? new CliError("errors.internalCode", EXIT.failed, { code: errno }, "INTERNAL") : new CliError("errors.internal", EXIT.failed, {}, "INTERNAL");
61117
- if (json2) errorOut.json({ error: failure2.code ?? failure2.key, ...Object.keys(failure2.params).length ? { details: failure2.params } : {} });
61118
- else {
61119
- const params = Object.fromEntries(Object.entries(failure2.params).map(([key, value]) => [key, typeof value === "string" ? neutralizeLine(value) : value]));
61120
- let friendlyKey = failure2 instanceof ToolError && ["RATE_LIMITED", "ACCESS_DENIED", "CONFLICT", "TRANSITION_DENIED"].includes(failure2.code ?? "") ? `errors.server.${failure2.code}` : failure2.key;
61121
- if (failure2.code === "KIT_INVALID" || failure2.code === "KIT_UNSIGNED") {
61122
- const reason = String(failure2.params.reason ?? "");
61123
- const kind = kitRefusalCategory(failure2.code, reason);
61124
- friendlyKey = `errors.kitRefused.${kind}`;
61125
- }
61126
- errorOut.error(errorOut.style.fail(redact(t(friendlyKey, params))));
61127
- if (failure2 instanceof ToolError && failure2.code === "TRANSITION_DENIED") {
61128
- const details = failure2.details;
61129
- const key = typeof details?.reason === "string" ? `errors.transition.${details.reason}` : "";
61130
- if (Object.hasOwn(EN, key)) errorOut.error(t(key));
61131
- }
61132
- const suggestion = failure2.suggestion;
61133
- if (suggestion) errorOut.error(t("errors.didYouMean", { command: errorOut.style.cmd(suggestion) }));
61134
- if (failure2.code === "KIT_INVALID" || failure2.code === "KIT_UNSIGNED") errorOut.error(errorOut.style.dim(redact(t("errors.kitReason", { ...params, reason: params.reason ?? failure2.code }))));
61135
- if (`${friendlyKey}.next` in EN) errorOut.error(` ${t("next.step", { command: errorOut.style.cmd(redact(t(`${friendlyKey}.next`, params))) })}`);
61136
- }
61528
+ const failure2 = reportFailure(context?.out ?? out, context?.t ?? t, error, json2);
61137
61529
  if (["listen", "mcp"].includes(commandName ?? "") && failure2.code === "ACCESS_DENIED") return EXIT.accessDenied;
61138
61530
  return failure2.exitCode;
61139
61531
  }