@useorgx/wizard 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1389,28 +1389,6 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1389
1389
  if (peopleFirstCapture !== void 0) state.peopleFirstCapture = peopleFirstCapture;
1390
1390
  return state;
1391
1391
  }
1392
- function hasPeopleFirstCaptureCompleted(workspaceId, statePath = ORGX_WIZARD_STATE_PATH) {
1393
- const state = readWizardState(statePath);
1394
- if (!state?.peopleFirstCapture) return false;
1395
- return state.peopleFirstCapture.entries.some(
1396
- (entry) => entry.workspaceId === workspaceId
1397
- );
1398
- }
1399
- function recordPeopleFirstCaptureCompletion(entry, statePath = ORGX_WIZARD_STATE_PATH) {
1400
- return updateWizardState((current) => {
1401
- const existingEntries = current.peopleFirstCapture?.entries ?? [];
1402
- const withoutExisting = existingEntries.filter(
1403
- (e) => e.workspaceId !== entry.workspaceId
1404
- );
1405
- return {
1406
- ...current,
1407
- peopleFirstCapture: {
1408
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1409
- entries: [...withoutExisting, entry]
1410
- }
1411
- };
1412
- }, statePath);
1413
- }
1414
1392
  function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
1415
1393
  const record = sanitizeWizardStateRecord(value);
1416
1394
  writeJsonFile(statePath, record, { mode: 384 });
@@ -4975,6 +4953,7 @@ function countPluginReportChanges(report) {
4975
4953
  // src/lib/setup-workspace.ts
4976
4954
  var CREATE_WORKSPACE_VALUE = "__create_workspace__";
4977
4955
  var SKIP_WORKSPACE_VALUE = "__skip_workspace__";
4956
+ var REAUTH_WORKSPACE_VALUE = "__reauth_workspace__";
4978
4957
  function trimDescription(value) {
4979
4958
  const trimmed = value.trim();
4980
4959
  return trimmed.length > 0 ? trimmed : void 0;
@@ -5084,24 +5063,35 @@ async function runWorkspaceSetup(client, prompts, options) {
5084
5063
  const currentWorkspace = workspaces.length > 0 ? await client.getCurrentWorkspace().catch(() => workspaces.find((workspace) => workspace.isDefault) ?? null) : null;
5085
5064
  if (workspaces.length === 0) {
5086
5065
  const action = await prompts.select({
5087
- message: "No OrgX workspaces were found. What should setup do next?",
5066
+ message: "OrgX authenticated, but returned 0 workspaces for this key. How should setup proceed?",
5088
5067
  options: [
5068
+ {
5069
+ value: REAUTH_WORKSPACE_VALUE,
5070
+ label: "Re-authenticate (recommended if you expected workspaces)",
5071
+ hint: "Run `wizard auth login` to re-link via OAuth if your API key is bound to a different user identity."
5072
+ },
5089
5073
  {
5090
5074
  value: CREATE_WORKSPACE_VALUE,
5091
5075
  label: "Create a new workspace",
5092
- hint: "Create one now and set it as the default for this machine."
5076
+ hint: "Use this only for a truly new account \u2014 this will fork data if your key is misbound."
5093
5077
  },
5094
5078
  {
5095
5079
  value: SKIP_WORKSPACE_VALUE,
5096
5080
  label: "Skip for now",
5097
- hint: "Finish surface setup without creating a workspace."
5081
+ hint: "Finish surface setup without touching workspaces."
5098
5082
  }
5099
5083
  ],
5100
- initialValue: CREATE_WORKSPACE_VALUE
5084
+ initialValue: REAUTH_WORKSPACE_VALUE
5101
5085
  });
5102
5086
  if (prompts.isCancel(action)) {
5103
5087
  return cancelResult(prompts);
5104
5088
  }
5089
+ if (action === REAUTH_WORKSPACE_VALUE) {
5090
+ return {
5091
+ message: "Re-authentication requested. Run `wizard auth login`, then rerun `wizard setup`.",
5092
+ status: "reauth_requested"
5093
+ };
5094
+ }
5105
5095
  if (action === SKIP_WORKSPACE_VALUE) {
5106
5096
  return {
5107
5097
  message: "Workspace bootstrap skipped.",
@@ -5391,7 +5381,357 @@ async function trackWizardTelemetry(event, properties = {}, options = {}) {
5391
5381
  return response?.ok === true;
5392
5382
  }
5393
5383
 
5384
+ // src/lib/intents.ts
5385
+ var AGENT_SLUGS = [
5386
+ "mark",
5387
+ "eli",
5388
+ "dana",
5389
+ "pace",
5390
+ "sage",
5391
+ "orion",
5392
+ "xandy"
5393
+ ];
5394
+ var INTENT_STATUSES = [
5395
+ "pending",
5396
+ "approved",
5397
+ "adjusted",
5398
+ "archived"
5399
+ ];
5400
+ var AGENT_ROLES = {
5401
+ mark: "Partnerships",
5402
+ eli: "Engineering",
5403
+ dana: "Brand",
5404
+ pace: "Product",
5405
+ sage: "Strategy",
5406
+ orion: "Routing",
5407
+ xandy: "Default"
5408
+ };
5409
+ var CONFIDENCE_DECIMAL = {
5410
+ low: 0.55,
5411
+ med: 0.78,
5412
+ high: 0.92
5413
+ };
5414
+ var AGENT_ANSI_256 = {
5415
+ pace: 34,
5416
+ // green
5417
+ eli: 44,
5418
+ // cyan
5419
+ mark: 208,
5420
+ // orange
5421
+ sage: 135,
5422
+ // purple
5423
+ orion: 214,
5424
+ // amber
5425
+ dana: 199,
5426
+ // pink
5427
+ xandy: 37
5428
+ // teal
5429
+ };
5430
+ function parseAgentSlug(value) {
5431
+ if (typeof value !== "string") return null;
5432
+ return AGENT_SLUGS.includes(value) ? value : null;
5433
+ }
5434
+ function parseStatus(value) {
5435
+ if (typeof value !== "string") return null;
5436
+ return INTENT_STATUSES.includes(value) ? value : null;
5437
+ }
5438
+ function parseConfidence(value) {
5439
+ if (value === "low" || value === "med" || value === "high") return value;
5440
+ return "med";
5441
+ }
5442
+ function parsePlanStep(value) {
5443
+ if (!isRecord(value)) return null;
5444
+ const title = typeof value.title === "string" ? value.title.trim() : "";
5445
+ if (!title) return null;
5446
+ const detail = typeof value.detail === "string" && value.detail.trim().length > 0 ? value.detail : void 0;
5447
+ const agentSlug = parseAgentSlug(value.agent_slug);
5448
+ const step = { title };
5449
+ if (detail !== void 0) step.detail = detail;
5450
+ if (agentSlug !== null) step.agent_slug = agentSlug;
5451
+ return step;
5452
+ }
5453
+ function parsePlanPreview(value) {
5454
+ if (!isRecord(value)) {
5455
+ return { steps: [], eta: "under a week", confidence: "med" };
5456
+ }
5457
+ const steps = Array.isArray(value.steps) ? value.steps.map(parsePlanStep).filter((step) => step !== null) : [];
5458
+ const eta = typeof value.eta === "string" && value.eta.trim().length > 0 ? value.eta : "under a week";
5459
+ return {
5460
+ steps,
5461
+ eta,
5462
+ confidence: parseConfidence(value.confidence)
5463
+ };
5464
+ }
5465
+ function parseIntent(value) {
5466
+ if (!isRecord(value)) return null;
5467
+ const id = typeof value.id === "string" ? value.id : null;
5468
+ const workspaceId = typeof value.workspace_id === "string" ? value.workspace_id : null;
5469
+ const slug = typeof value.slug === "string" ? value.slug : null;
5470
+ const text2 = typeof value.text === "string" ? value.text : null;
5471
+ const status = parseStatus(value.status);
5472
+ const createdAt = typeof value.created_at === "string" ? value.created_at : null;
5473
+ const updatedAt = typeof value.updated_at === "string" ? value.updated_at : null;
5474
+ if (!id || !workspaceId || !slug || !text2 || !status || !createdAt || !updatedAt) {
5475
+ return null;
5476
+ }
5477
+ return {
5478
+ id,
5479
+ workspace_id: workspaceId,
5480
+ slug,
5481
+ text: text2,
5482
+ status,
5483
+ suggested_agent_slug: parseAgentSlug(value.suggested_agent_slug),
5484
+ plan_preview: parsePlanPreview(value.plan_preview),
5485
+ approved_at: typeof value.approved_at === "string" ? value.approved_at : null,
5486
+ created_at: createdAt,
5487
+ updated_at: updatedAt
5488
+ };
5489
+ }
5490
+ async function parseResponseBody4(response) {
5491
+ const text2 = await response.text();
5492
+ if (!text2) return null;
5493
+ try {
5494
+ return JSON.parse(text2);
5495
+ } catch {
5496
+ return text2;
5497
+ }
5498
+ }
5499
+ function formatHttpError3(status, body) {
5500
+ if (typeof body === "string" && body.trim().length > 0) {
5501
+ return `HTTP ${status}: ${body}`;
5502
+ }
5503
+ if (isRecord(body)) {
5504
+ if (isRecord(body.error)) {
5505
+ const message = typeof body.error.message === "string" ? body.error.message : null;
5506
+ const code = typeof body.error.code === "string" ? body.error.code : null;
5507
+ if (message) return `HTTP ${status} (${code ?? "error"}): ${message}`;
5508
+ }
5509
+ if (typeof body.error === "string" && body.error.trim().length > 0) {
5510
+ return `HTTP ${status}: ${body.error}`;
5511
+ }
5512
+ }
5513
+ return `HTTP ${status}`;
5514
+ }
5515
+ async function requireOrgxAuth3(options = {}) {
5516
+ const auth = await resolveOrgxAuth(options);
5517
+ if (!auth) {
5518
+ throw new Error(
5519
+ "No OrgX API key configured. Run `orgx-wizard auth login` or `orgx-wizard auth set-key <oxk_...>` first."
5520
+ );
5521
+ }
5522
+ return auth;
5523
+ }
5524
+ async function createIntent(input, options = {}) {
5525
+ const text2 = input.text.trim();
5526
+ if (!text2) {
5527
+ throw new Error("Intent text is required.");
5528
+ }
5529
+ if (text2.length > 4e3) {
5530
+ throw new Error("Intent text exceeds 4,000 characters.");
5531
+ }
5532
+ const workspaceId = input.workspace_id.trim();
5533
+ if (!workspaceId) {
5534
+ throw new Error("Workspace id is required.");
5535
+ }
5536
+ const auth = await requireOrgxAuth3(options);
5537
+ const url = buildOrgxApiUrl("/v1/intents", auth.baseUrl);
5538
+ const response = await fetch(url, {
5539
+ method: "POST",
5540
+ headers: {
5541
+ Authorization: `Bearer ${auth.apiKey}`,
5542
+ "Content-Type": "application/json"
5543
+ },
5544
+ body: JSON.stringify({ workspace_id: workspaceId, text: text2 }),
5545
+ signal: AbortSignal.timeout(15e3)
5546
+ });
5547
+ const body = await parseResponseBody4(response);
5548
+ if (!response.ok) {
5549
+ throw new Error(
5550
+ `Failed to create intent. ${formatHttpError3(response.status, body)}`
5551
+ );
5552
+ }
5553
+ const intent = parseIntent(body);
5554
+ if (!intent) {
5555
+ throw new Error("OrgX returned an unexpected intent payload.");
5556
+ }
5557
+ return intent;
5558
+ }
5559
+ async function updateIntent(id, input, options = {}) {
5560
+ const trimmedId = id.trim();
5561
+ if (!trimmedId) {
5562
+ throw new Error("Intent id is required.");
5563
+ }
5564
+ const auth = await requireOrgxAuth3(options);
5565
+ const url = buildOrgxApiUrl(`/v1/intents/${encodeURIComponent(trimmedId)}`, auth.baseUrl);
5566
+ const response = await fetch(url, {
5567
+ method: "PATCH",
5568
+ headers: {
5569
+ Authorization: `Bearer ${auth.apiKey}`,
5570
+ "Content-Type": "application/json"
5571
+ },
5572
+ body: JSON.stringify(input),
5573
+ signal: AbortSignal.timeout(15e3)
5574
+ });
5575
+ const body = await parseResponseBody4(response);
5576
+ if (!response.ok) {
5577
+ throw new Error(
5578
+ `Failed to update intent. ${formatHttpError3(response.status, body)}`
5579
+ );
5580
+ }
5581
+ const intent = parseIntent(body);
5582
+ if (!intent) {
5583
+ throw new Error("OrgX returned an unexpected intent update payload.");
5584
+ }
5585
+ return intent;
5586
+ }
5587
+ function buildIntentHandoffUrl(slug, options = {}) {
5588
+ const base = options.baseUrl?.trim() || "https://useorgx.com";
5589
+ const normalized = base.replace(/\/+$/, "");
5590
+ return `${normalized}/command?intent=${encodeURIComponent(slug)}`;
5591
+ }
5592
+
5593
+ // src/lib/intent-render.ts
5594
+ function detectRenderCapabilities(env = process.env) {
5595
+ const noColor = Boolean(env.NO_COLOR && env.NO_COLOR.length > 0);
5596
+ const asciiOnly = (env.LC_ALL ?? "").toUpperCase() === "C" || (env.LANG ?? "").toUpperCase() === "C";
5597
+ return { noColor, asciiOnly };
5598
+ }
5599
+ function isInteractive(env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
5600
+ if (!isTTY) return false;
5601
+ if (env.CI === "1" || env.CI === "true") return false;
5602
+ if (env.GITHUB_ACTIONS === "true") return false;
5603
+ return true;
5604
+ }
5605
+ var CSI = "\x1B[";
5606
+ function wrap(code, text2, enabled) {
5607
+ if (!enabled) return text2;
5608
+ return `${CSI}${code}m${text2}${CSI}0m`;
5609
+ }
5610
+ function colorize(text2, ansi256, options = {}) {
5611
+ return wrap(`38;5;${ansi256}`, text2, !options.noColor);
5612
+ }
5613
+ function bold(text2, options = {}) {
5614
+ return wrap("1", text2, !options.noColor);
5615
+ }
5616
+ function dim(text2, options = {}) {
5617
+ return wrap("2", text2, !options.noColor);
5618
+ }
5619
+ function formatConfidence(value) {
5620
+ const bounded = Math.max(0, Math.min(1, value));
5621
+ return bounded.toFixed(2);
5622
+ }
5623
+ function renderRoutingLine(agent, confidence, options = {}) {
5624
+ const arrow = options.asciiOnly ? "->" : "\u2192";
5625
+ const separator = options.asciiOnly ? " - " : " \xB7 ";
5626
+ const role = AGENT_ROLES[agent];
5627
+ const name = agent.charAt(0).toUpperCase() + agent.slice(1);
5628
+ const coloredName = colorize(name, AGENT_ANSI_256[agent], options);
5629
+ const confidenceLabel = dim("confidence", options);
5630
+ const confidenceValue = formatConfidence(confidence);
5631
+ return ` ${arrow} ${bold(coloredName, options)}${separator}${role} ${confidenceLabel} ${confidenceValue}`;
5632
+ }
5633
+ function resolveConfidenceDecimal(plan) {
5634
+ return CONFIDENCE_DECIMAL[plan.confidence];
5635
+ }
5636
+ function renderPlanPreview(plan, options = {}) {
5637
+ const horizontal = options.asciiOnly ? "-" : "\u2500";
5638
+ const topLeft = options.asciiOnly ? "+" : "\u250C";
5639
+ const topRight = options.asciiOnly ? "+" : "\u2510";
5640
+ const bottomLeft = options.asciiOnly ? "+" : "\u2514";
5641
+ const bottomRight = options.asciiOnly ? "+" : "\u2518";
5642
+ const vertical = options.asciiOnly ? "|" : "\u2502";
5643
+ const steps = plan.steps.map((step, index) => {
5644
+ const number = `${index + 1}.`.padEnd(3, " ");
5645
+ return `${number} ${step.title}`;
5646
+ });
5647
+ const etaLine = `ETA ${plan.eta}`;
5648
+ const lines = [...steps, "", etaLine];
5649
+ const label = "Plan preview";
5650
+ const contentWidth = Math.max(
5651
+ // Keep enough room for the top-chrome label plus its "─ " prefix and
5652
+ // a minimum trailing dash so the border visually wraps the label.
5653
+ label.length + 4,
5654
+ ...lines.map((line) => line.length)
5655
+ );
5656
+ const innerWidth = contentWidth + 2;
5657
+ const leadingDashes = horizontal.repeat(1);
5658
+ const trailingDashes = horizontal.repeat(
5659
+ Math.max(1, innerWidth - label.length - 3)
5660
+ // leading dash + 2 spaces
5661
+ );
5662
+ const top = `${topLeft}${leadingDashes} ${label} ${trailingDashes}${topRight}`;
5663
+ const body = lines.map((line) => {
5664
+ const padded = line.padEnd(contentWidth, " ");
5665
+ return `${vertical} ${padded} ${vertical}`;
5666
+ }).join("\n");
5667
+ const bottom = `${bottomLeft}${horizontal.repeat(innerWidth)}${bottomRight}`;
5668
+ return [top, body, bottom].join("\n");
5669
+ }
5670
+ var TONE_ANSI = {
5671
+ primary: 190,
5672
+ // lime (--ox-primary)
5673
+ warning: 214,
5674
+ // amber (adjust)
5675
+ danger: 203,
5676
+ // rose (archive)
5677
+ neutral: 244
5678
+ // bright black (quit)
5679
+ };
5680
+ function renderHotkeyBar(entries, options = {}) {
5681
+ const prefix = options.asciiOnly ? ">>" : ">>";
5682
+ const segments = entries.map((entry) => {
5683
+ const tone = entry.tone ?? "neutral";
5684
+ const keyLabel = `[${entry.key.toUpperCase()}]`;
5685
+ const coloredKey = colorize(keyLabel, TONE_ANSI[tone], options);
5686
+ return `${coloredKey}${entry.label}`;
5687
+ });
5688
+ return `${prefix} ${segments.join(" ")}`;
5689
+ }
5690
+ var DEFAULT_HOTKEYS = [
5691
+ { key: "a", label: "pprove", tone: "primary" },
5692
+ { key: "e", label: "dit in browser", tone: "warning" },
5693
+ { key: "x", label: "archive", tone: "danger" },
5694
+ { key: "q", label: "uit", tone: "neutral" }
5695
+ ];
5696
+ function normalizeHotkey(input) {
5697
+ const trimmed = input.trim().toLowerCase();
5698
+ if (trimmed.length === 0) return null;
5699
+ const ch = trimmed.charAt(0);
5700
+ switch (ch) {
5701
+ case "a":
5702
+ return "approve";
5703
+ case "e":
5704
+ return "edit";
5705
+ case "x":
5706
+ return "archive";
5707
+ case "q":
5708
+ return "quit";
5709
+ default:
5710
+ return null;
5711
+ }
5712
+ }
5713
+
5394
5714
  // src/lib/daily-brief-onboarding.ts
5715
+ function extractErrorHint(body) {
5716
+ if (!body) return null;
5717
+ let parsed;
5718
+ try {
5719
+ parsed = JSON.parse(body);
5720
+ } catch {
5721
+ return body.slice(0, 160);
5722
+ }
5723
+ if (!parsed || typeof parsed !== "object") return null;
5724
+ const obj = parsed;
5725
+ const err = obj.error;
5726
+ if (typeof err === "string") return err;
5727
+ if (err && typeof err === "object") {
5728
+ const message = err.message;
5729
+ if (typeof message === "string") return message;
5730
+ const code = err.code;
5731
+ if (typeof code === "string") return code;
5732
+ }
5733
+ return null;
5734
+ }
5395
5735
  var BASELINE_PROMPTS = [
5396
5736
  { task_type: "code_review", label: "Code review", placeholder: "20" },
5397
5737
  { task_type: "prd_draft", label: "PRD draft", placeholder: "45" },
@@ -5551,9 +5891,10 @@ async function runDailyBriefOnboarding(options) {
5551
5891
  });
5552
5892
  if (!commitResponse.ok) {
5553
5893
  const text2 = await commitResponse.text().catch(() => "");
5894
+ const hint = extractErrorHint(text2) ?? `HTTP ${commitResponse.status}`;
5554
5895
  return {
5555
5896
  status: "failed",
5556
- message: "Could not commit onboarding capture.",
5897
+ message: `Could not commit onboarding capture \u2014 ${hint}`,
5557
5898
  error: `HTTP ${commitResponse.status}: ${text2.slice(0, 200)}`
5558
5899
  };
5559
5900
  }
@@ -5584,536 +5925,6 @@ async function fetchOnboardingState(auth) {
5584
5925
  }
5585
5926
  }
5586
5927
 
5587
- // src/lib/people-first-capture.ts
5588
- var RELATIONSHIP_STAGE_OPTIONS = [
5589
- { value: "stranger", label: "Stranger", hint: "no prior contact yet" },
5590
- { value: "prospect", label: "Prospect", hint: "outreach planned or in flight (default)" },
5591
- { value: "conversation", label: "Conversation", hint: "active 2-way dialogue" },
5592
- { value: "design_partner", label: "Design partner", hint: "paid / equity track underway" },
5593
- { value: "paused", label: "Paused", hint: "intentional pause, not wrong fit" },
5594
- { value: "churned", label: "Churned", hint: "ended; history preserved" },
5595
- { value: "alumni", label: "Alumni", hint: "closed engagement, may return" }
5596
- ];
5597
- var TRUST_TIER_OPTIONS = [
5598
- { value: "cold", label: "Cold / unknown", hint: "new or barely-met" },
5599
- { value: "warm", label: "Warm", hint: "know each other, some trust built" },
5600
- { value: "close", label: "Close", hint: "deep trust \u2014 inner-circle candidate" }
5601
- ];
5602
- async function fetchPeopleFirstOnboardingState(auth) {
5603
- try {
5604
- const res = await fetch(
5605
- buildOrgxApiUrl("/v1/people/onboarding", auth.baseUrl),
5606
- {
5607
- method: "GET",
5608
- headers: { Authorization: `Bearer ${auth.apiKey}` },
5609
- signal: AbortSignal.timeout(5e3)
5610
- }
5611
- );
5612
- if (!res.ok) return null;
5613
- const body = await res.json().catch(() => null);
5614
- if (!body || !Array.isArray(body.workspaces)) return null;
5615
- return body;
5616
- } catch {
5617
- return null;
5618
- }
5619
- }
5620
- function parseContactChannels(raw) {
5621
- const channels = [];
5622
- const parts = raw.split(/[,\n]+/).map((part) => part.trim()).filter(Boolean);
5623
- for (const part of parts) {
5624
- if (/^https?:\/\/(?:www\.)?linkedin\.com\//i.test(part) || part.toLowerCase().startsWith("linkedin.com/")) {
5625
- channels.push({ kind: "linkedin", value: part });
5626
- } else if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(part)) {
5627
- channels.push({ kind: "email", value: part });
5628
- } else if (/^\+?[\d][\d\s()\-.]{5,}$/.test(part)) {
5629
- channels.push({ kind: "phone", value: part.replace(/\s+/g, "") });
5630
- } else {
5631
- channels.push({ kind: "linkedin", value: part });
5632
- }
5633
- }
5634
- return channels;
5635
- }
5636
- async function postJson(auth, path, body) {
5637
- try {
5638
- const res = await fetch(buildOrgxApiUrl(path, auth.baseUrl), {
5639
- method: "POST",
5640
- headers: {
5641
- Authorization: `Bearer ${auth.apiKey}`,
5642
- "Content-Type": "application/json"
5643
- },
5644
- body: JSON.stringify(body),
5645
- signal: AbortSignal.timeout(1e4)
5646
- });
5647
- const text2 = await res.text().catch(() => "");
5648
- let parsed = null;
5649
- if (text2) {
5650
- try {
5651
- parsed = JSON.parse(text2);
5652
- } catch {
5653
- parsed = text2;
5654
- }
5655
- }
5656
- if (!res.ok) {
5657
- const detail = parsed && typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `HTTP ${res.status}`;
5658
- return { ok: false, error: detail };
5659
- }
5660
- return { ok: true, status: res.status, body: parsed };
5661
- } catch (err) {
5662
- const message = err instanceof Error ? err.message : String(err);
5663
- return { ok: false, error: message };
5664
- }
5665
- }
5666
- function extractId(body) {
5667
- if (body && typeof body === "object") {
5668
- const candidate = body.id ?? body.data;
5669
- if (typeof candidate === "string") return candidate;
5670
- if (candidate && typeof candidate === "object") {
5671
- const innerId = candidate.id;
5672
- if (typeof innerId === "string") return innerId;
5673
- }
5674
- }
5675
- return null;
5676
- }
5677
- var BACKEND_UNREACHABLE_HINT = "Could not sync with OrgX backend \u2014 check your network / run `orgx-wizard status`.";
5678
- async function runPeopleFirstCapture(options) {
5679
- if (!options.interactive) {
5680
- return {
5681
- status: "skipped_non_interactive",
5682
- message: "People-first capture skipped \u2014 not attached to a TTY."
5683
- };
5684
- }
5685
- if (!options.workspace) {
5686
- return {
5687
- status: "skipped_no_workspace",
5688
- message: "People-first capture skipped \u2014 no workspace resolved."
5689
- };
5690
- }
5691
- if (options.alreadyCompleted) {
5692
- return {
5693
- status: "skipped_already_completed",
5694
- message: "People-first capture already completed for this workspace."
5695
- };
5696
- }
5697
- const auth = await resolveOrgxAuth();
5698
- if (!auth) {
5699
- return {
5700
- status: "failed",
5701
- message: "People-first capture needs OrgX auth.",
5702
- error: "no_auth"
5703
- };
5704
- }
5705
- const state = await fetchPeopleFirstOnboardingState(auth);
5706
- if (state) {
5707
- const row = state.workspaces.find((w) => w.id === options.workspace.id);
5708
- if (row?.peopleFirstCaptureCompletedAt) {
5709
- return {
5710
- status: "skipped_already_completed",
5711
- message: "People-first capture already completed for this workspace."
5712
- };
5713
- }
5714
- }
5715
- const { prompts } = options;
5716
- const proceed = await prompts.confirm({
5717
- message: "Name the first person OrgX should know about? (takes ~30 seconds; OrgX will pre-draft a first-touch artifact for them)",
5718
- initialValue: true
5719
- });
5720
- if (prompts.isCancel(proceed)) {
5721
- return { status: "cancelled", message: "People-first capture cancelled." };
5722
- }
5723
- if (!proceed) {
5724
- return {
5725
- status: "skipped_declined",
5726
- message: "Skipped \u2014 run the wizard again any time to add your first person."
5727
- };
5728
- }
5729
- const headlineAnswer = await prompts.text({
5730
- message: 'Who is this person to you? (one line \u2014 e.g. "prospect at Acme", "design partner", "old teammate")',
5731
- placeholder: "design partner prospect for OrgX",
5732
- validate(value) {
5733
- if (!value || !value.trim()) return "Enter one line.";
5734
- if (value.trim().length > 160) return "Keep it under 160 chars.";
5735
- return void 0;
5736
- }
5737
- });
5738
- if (prompts.isCancel(headlineAnswer)) {
5739
- return { status: "cancelled", message: "People-first capture cancelled." };
5740
- }
5741
- const headline = typeof headlineAnswer === "string" ? headlineAnswer.trim() : "";
5742
- const contextAnswer = await prompts.select({
5743
- initialValue: "personal",
5744
- message: "Is this on behalf of a business, or a personal relationship?",
5745
- options: [
5746
- { value: "personal", label: "Personal", hint: "no business attached yet" },
5747
- { value: "business", label: "On behalf of a business", hint: "will also create a Business entity" }
5748
- ]
5749
- });
5750
- if (prompts.isCancel(contextAnswer)) {
5751
- return { status: "cancelled", message: "People-first capture cancelled." };
5752
- }
5753
- const hasBusiness = contextAnswer === "business";
5754
- let businessName;
5755
- if (hasBusiness) {
5756
- const businessAnswer = await prompts.text({
5757
- message: "Business name?",
5758
- placeholder: "Acme Treasury",
5759
- validate(value) {
5760
- if (!value || !value.trim()) return "Enter the business name.";
5761
- return void 0;
5762
- }
5763
- });
5764
- if (prompts.isCancel(businessAnswer)) {
5765
- return { status: "cancelled", message: "People-first capture cancelled." };
5766
- }
5767
- businessName = typeof businessAnswer === "string" ? businessAnswer.trim() : void 0;
5768
- }
5769
- const nameAnswer = await prompts.text({
5770
- message: "Their name?",
5771
- placeholder: "Laura Chen",
5772
- validate(value) {
5773
- if (!value || !value.trim()) return "Enter a display name.";
5774
- return void 0;
5775
- }
5776
- });
5777
- if (prompts.isCancel(nameAnswer)) {
5778
- return { status: "cancelled", message: "People-first capture cancelled." };
5779
- }
5780
- const displayName = typeof nameAnswer === "string" ? nameAnswer.trim() : "";
5781
- const contactAnswer = await prompts.text({
5782
- message: "How do you reach them? (email, LinkedIn URL, or phone \u2014 comma-separated, at least one)",
5783
- placeholder: "laura@acme.com, linkedin.com/in/laurachen",
5784
- validate(value) {
5785
- if (!value || !value.trim()) return "Enter at least one contact.";
5786
- const parsed = parseContactChannels(value);
5787
- if (parsed.length === 0) return "Could not parse any contact channels.";
5788
- return void 0;
5789
- }
5790
- });
5791
- if (prompts.isCancel(contactAnswer)) {
5792
- return { status: "cancelled", message: "People-first capture cancelled." };
5793
- }
5794
- const contactChannels = parseContactChannels(
5795
- typeof contactAnswer === "string" ? contactAnswer : ""
5796
- );
5797
- const stageAnswer = await prompts.select({
5798
- initialValue: "prospect",
5799
- message: "What stage is the relationship?",
5800
- options: RELATIONSHIP_STAGE_OPTIONS.map((opt) => ({
5801
- value: opt.value,
5802
- label: opt.label,
5803
- ...opt.hint ? { hint: opt.hint } : {}
5804
- }))
5805
- });
5806
- if (prompts.isCancel(stageAnswer)) {
5807
- return { status: "cancelled", message: "People-first capture cancelled." };
5808
- }
5809
- const relationshipStage = stageAnswer;
5810
- const trustAnswer = await prompts.select({
5811
- initialValue: "cold",
5812
- message: "How would you describe the trust level right now?",
5813
- options: TRUST_TIER_OPTIONS.map((opt) => ({
5814
- value: opt.value,
5815
- label: opt.label,
5816
- ...opt.hint ? { hint: opt.hint } : {}
5817
- }))
5818
- });
5819
- if (prompts.isCancel(trustAnswer)) {
5820
- return { status: "cancelled", message: "People-first capture cancelled." };
5821
- }
5822
- const trustTier = trustAnswer;
5823
- const innerCircleAnswer = await prompts.confirm({
5824
- message: "Mark this person as inner-circle? (affects tone of drafted artifacts)",
5825
- initialValue: false
5826
- });
5827
- if (prompts.isCancel(innerCircleAnswer)) {
5828
- return { status: "cancelled", message: "People-first capture cancelled." };
5829
- }
5830
- const innerCircle = Boolean(innerCircleAnswer);
5831
- const goalAnswer = await prompts.text({
5832
- message: "Which matters most right now? (one line \u2014 this becomes their Goal)",
5833
- placeholder: "agree on first pilot scope by May 3",
5834
- validate(value) {
5835
- if (!value || !value.trim()) return "Enter one line.";
5836
- return void 0;
5837
- }
5838
- });
5839
- if (prompts.isCancel(goalAnswer)) {
5840
- return { status: "cancelled", message: "People-first capture cancelled." };
5841
- }
5842
- const goalTitle = typeof goalAnswer === "string" ? goalAnswer.trim() : "";
5843
- let businessIntent;
5844
- if (hasBusiness && relationshipStage === "conversation") {
5845
- const intentAnswer = await prompts.select({
5846
- initialValue: "client",
5847
- message: "Is this person an investor in this business, or a client of it?",
5848
- options: [
5849
- { value: "client", label: "Client / prospect", hint: "default" },
5850
- { value: "investor", label: "Investor / advisor" },
5851
- { value: "unspecified", label: "Unsure / neither" }
5852
- ]
5853
- });
5854
- if (prompts.isCancel(intentAnswer)) {
5855
- return { status: "cancelled", message: "People-first capture cancelled." };
5856
- }
5857
- businessIntent = intentAnswer;
5858
- }
5859
- let businessId;
5860
- if (hasBusiness && businessName) {
5861
- const businessRes = await postJson(auth, "/v1/businesses", {
5862
- display_name: businessName,
5863
- relationship_stage: relationshipStage === "alumni" ? "alumni" : "engaged"
5864
- });
5865
- if (!businessRes.ok) {
5866
- return {
5867
- status: "failed",
5868
- message: `${BACKEND_UNREACHABLE_HINT} (businesses: ${businessRes.error})`,
5869
- error: businessRes.error
5870
- };
5871
- }
5872
- businessId = extractId(businessRes.body) ?? void 0;
5873
- }
5874
- const personPayload = {
5875
- display_name: displayName,
5876
- headline,
5877
- relationship_stage: relationshipStage,
5878
- contact_channels: contactChannels,
5879
- metadata: {
5880
- captured_via: "orgx-wizard",
5881
- inner_circle: innerCircle,
5882
- trust_tier: trustTier,
5883
- ...businessIntent ? { business_intent: businessIntent } : {}
5884
- },
5885
- ...businessId ? { business_id: businessId } : {}
5886
- };
5887
- const personRes = await postJson(auth, "/v1/people", personPayload);
5888
- if (!personRes.ok) {
5889
- return {
5890
- status: "failed",
5891
- message: `${BACKEND_UNREACHABLE_HINT} (people: ${personRes.error})`,
5892
- error: personRes.error
5893
- };
5894
- }
5895
- const personId = extractId(personRes.body) ?? void 0;
5896
- if (!personId) {
5897
- return {
5898
- status: "failed",
5899
- message: `${BACKEND_UNREACHABLE_HINT} (people: missing id in response)`,
5900
- error: "missing_person_id"
5901
- };
5902
- }
5903
- const goalRes = await postJson(auth, "/v1/goals", {
5904
- owner_type: "person",
5905
- owner_id: personId,
5906
- title: goalTitle
5907
- });
5908
- if (!goalRes.ok) {
5909
- return {
5910
- status: "failed",
5911
- message: `${BACKEND_UNREACHABLE_HINT} (goals: ${goalRes.error})`,
5912
- error: goalRes.error
5913
- };
5914
- }
5915
- const goalId = extractId(goalRes.body) ?? void 0;
5916
- if (!goalId) {
5917
- return {
5918
- status: "failed",
5919
- message: `${BACKEND_UNREACHABLE_HINT} (goals: missing id in response)`,
5920
- error: "missing_goal_id"
5921
- };
5922
- }
5923
- const person = {
5924
- id: personId,
5925
- display_name: displayName,
5926
- headline,
5927
- relationship_stage: relationshipStage,
5928
- contact_channels: contactChannels,
5929
- inner_circle: innerCircle,
5930
- trust_tier: trustTier,
5931
- ...businessId ? { business_id: businessId } : {},
5932
- ...businessIntent ? { business_intent: businessIntent } : {}
5933
- };
5934
- const goal = {
5935
- id: goalId,
5936
- owner_type: "person",
5937
- owner_id: personId,
5938
- title: goalTitle
5939
- };
5940
- return {
5941
- status: "completed",
5942
- message: `Captured ${displayName} in your workspace.`,
5943
- person,
5944
- goal
5945
- };
5946
- }
5947
-
5948
- // src/peopleFirst/templateSelect.ts
5949
- function selectPeopleFirstTemplate(input) {
5950
- const trustTier = input.trustTier ?? "cold";
5951
- if (input.innerCircle) {
5952
- return {
5953
- persona: "inner_circle",
5954
- reason: "inner-circle mark set by user",
5955
- needsBusinessIntentPrompt: false
5956
- };
5957
- }
5958
- switch (input.relationshipStage) {
5959
- case "stranger":
5960
- case "prospect":
5961
- return {
5962
- persona: "cold_outreach",
5963
- reason: `stage=${input.relationshipStage} \u2014 cold outreach draft`,
5964
- needsBusinessIntentPrompt: false
5965
- };
5966
- case "conversation": {
5967
- if (input.hasBusiness) {
5968
- if (input.businessIntent === "investor") {
5969
- return {
5970
- persona: "investor_prep",
5971
- reason: "conversation + business + investor intent",
5972
- needsBusinessIntentPrompt: false
5973
- };
5974
- }
5975
- if (input.businessIntent === "client") {
5976
- return {
5977
- persona: "client_trust",
5978
- reason: "conversation + business + client intent",
5979
- needsBusinessIntentPrompt: false
5980
- };
5981
- }
5982
- return {
5983
- persona: "client_trust",
5984
- reason: "conversation + business \u2014 defaulting to client_trust; ask to confirm",
5985
- needsBusinessIntentPrompt: true
5986
- };
5987
- }
5988
- if (trustTier === "warm" || trustTier === "close") {
5989
- return {
5990
- persona: "founder_ally",
5991
- reason: `conversation + trust=${trustTier} \u2014 founder-ally outreach`,
5992
- needsBusinessIntentPrompt: false
5993
- };
5994
- }
5995
- return {
5996
- persona: "cold_outreach",
5997
- reason: "conversation + cold trust \u2014 treating as cold_outreach",
5998
- needsBusinessIntentPrompt: false
5999
- };
6000
- }
6001
- case "design_partner":
6002
- case "active_client":
6003
- return {
6004
- persona: "client_trust",
6005
- reason: `stage=${input.relationshipStage} \u2014 client_trust cadence`,
6006
- needsBusinessIntentPrompt: false
6007
- };
6008
- case "alumni":
6009
- return {
6010
- persona: "alumni_touch",
6011
- reason: "stage=alumni \u2014 alumni_touch rekindle",
6012
- needsBusinessIntentPrompt: false
6013
- };
6014
- case "paused":
6015
- case "churned":
6016
- return {
6017
- persona: "alumni_touch",
6018
- reason: `stage=${input.relationshipStage} \u2014 treating as alumni_touch for rekindle tone`,
6019
- needsBusinessIntentPrompt: false
6020
- };
6021
- }
6022
- }
6023
-
6024
- // src/lib/people-first-artifact.ts
6025
- async function callDraftEndpoint(auth, body) {
6026
- try {
6027
- const res = await fetch(buildOrgxApiUrl("/v1/artifacts/draft", auth.baseUrl), {
6028
- method: "POST",
6029
- headers: {
6030
- Authorization: `Bearer ${auth.apiKey}`,
6031
- "Content-Type": "application/json"
6032
- },
6033
- body: JSON.stringify(body),
6034
- signal: AbortSignal.timeout(1e4)
6035
- });
6036
- if (!res.ok) {
6037
- return { ok: false, error: `HTTP ${res.status}` };
6038
- }
6039
- const data = await res.json().catch(() => null);
6040
- return { ok: true, data: data ?? {} };
6041
- } catch (err) {
6042
- const message = err instanceof Error ? err.message : String(err);
6043
- return { ok: false, error: message };
6044
- }
6045
- }
6046
- async function runPeopleFirstArtifactDraft(options) {
6047
- if (!options.interactive) {
6048
- return {
6049
- status: "skipped_non_interactive",
6050
- message: "Artifact draft skipped \u2014 not attached to a TTY."
6051
- };
6052
- }
6053
- const auth = await resolveOrgxAuth();
6054
- if (!auth) {
6055
- return {
6056
- status: "failed",
6057
- message: "Artifact draft needs OrgX auth.",
6058
- error: "no_auth"
6059
- };
6060
- }
6061
- let businessIntent = options.businessIntent;
6062
- const { prompts, person } = options;
6063
- const hasBusiness = Boolean(options.businessName || person.business_id);
6064
- const preselection = selectPeopleFirstTemplate({
6065
- relationshipStage: person.relationship_stage,
6066
- hasBusiness,
6067
- trustTier: person.trust_tier,
6068
- innerCircle: person.inner_circle,
6069
- ...businessIntent ? { businessIntent } : {}
6070
- });
6071
- let persona = preselection.persona;
6072
- if (preselection.needsBusinessIntentPrompt && !businessIntent) {
6073
- const answer = await prompts.select({
6074
- initialValue: "client",
6075
- message: "Is this more of a client-trust update, or investor-prep?",
6076
- options: [
6077
- { value: "client", label: "Client trust (default)" },
6078
- { value: "investor", label: "Investor prep" }
6079
- ]
6080
- });
6081
- if (prompts.isCancel(answer)) {
6082
- return { status: "cancelled", message: "Artifact draft cancelled." };
6083
- }
6084
- businessIntent = answer;
6085
- persona = selectPeopleFirstTemplate({
6086
- relationshipStage: person.relationship_stage,
6087
- hasBusiness,
6088
- trustTier: person.trust_tier,
6089
- innerCircle: person.inner_circle,
6090
- businessIntent
6091
- }).persona;
6092
- }
6093
- const serverResult = await callDraftEndpoint(auth, {
6094
- template_persona: persona,
6095
- person_id: person.id,
6096
- calibration_inputs: {
6097
- voice_examples: []
6098
- }
6099
- });
6100
- if (!serverResult.ok) {
6101
- return {
6102
- status: "failed",
6103
- message: `Could not draft artifact \u2014 ${serverResult.error}. Check your network / run \`orgx-wizard status\`.`,
6104
- persona,
6105
- error: serverResult.error
6106
- };
6107
- }
6108
- return {
6109
- status: "drafted",
6110
- message: `Drafted ${persona} artifact for ${person.display_name}.`,
6111
- persona,
6112
- ...serverResult.data.artifact_id ? { serverArtifactId: serverResult.data.artifact_id } : {},
6113
- ...serverResult.data.url ? { serverArtifactUrl: serverResult.data.url } : {}
6114
- };
6115
- }
6116
-
6117
5928
  // src/spinner.ts
6118
5929
  import ora from "ora";
6119
5930
  import pc2 from "picocolors";
@@ -6508,6 +6319,296 @@ function parseTimeoutSeconds(value) {
6508
6319
  }
6509
6320
  return parsed;
6510
6321
  }
6322
+ async function readSingleKey() {
6323
+ const stdin = process.stdin;
6324
+ if (!stdin.isTTY) return null;
6325
+ const previousRawMode = stdin.isRaw === true;
6326
+ return await new Promise((resolve) => {
6327
+ const cleanup = (result) => {
6328
+ stdin.off("data", onData);
6329
+ if (stdin.isTTY) {
6330
+ stdin.setRawMode(previousRawMode);
6331
+ }
6332
+ stdin.pause();
6333
+ resolve(result);
6334
+ };
6335
+ const onData = (chunk) => {
6336
+ const text2 = chunk.toString("utf8");
6337
+ const first = text2.charAt(0);
6338
+ if (first === "" || first === "") {
6339
+ cleanup(null);
6340
+ return;
6341
+ }
6342
+ cleanup(first.toLowerCase());
6343
+ };
6344
+ if (stdin.isTTY) {
6345
+ stdin.setRawMode(true);
6346
+ }
6347
+ stdin.resume();
6348
+ stdin.on("data", onData);
6349
+ });
6350
+ }
6351
+ function printIntentPreview(intent, baseUrl) {
6352
+ const render = detectRenderCapabilities();
6353
+ const agent = intent.suggested_agent_slug ?? "xandy";
6354
+ const confidence = resolveConfidenceDecimal(intent.plan_preview);
6355
+ console.log("");
6356
+ console.log(renderRoutingLine(agent, confidence, render));
6357
+ console.log("");
6358
+ console.log(renderPlanPreview(intent.plan_preview, render));
6359
+ console.log("");
6360
+ console.log(
6361
+ dim(
6362
+ ` slug ${intent.slug} handoff ${buildIntentHandoffUrl(intent.slug, { baseUrl })}`,
6363
+ render
6364
+ )
6365
+ );
6366
+ console.log("");
6367
+ console.log(renderHotkeyBar(DEFAULT_HOTKEYS, render));
6368
+ }
6369
+ async function maybeCaptureSetupIntent(input) {
6370
+ if (!input.interactive || !input.workspace) {
6371
+ return "skipped";
6372
+ }
6373
+ const prompt = await textPrompt({
6374
+ message: "In one line, what do you want OrgX to move first? (blank to skip \u2014 you can start from the dashboard)",
6375
+ placeholder: "e.g. open a warm-intro loop to 50 design-led SaaS founders",
6376
+ validate: (value) => {
6377
+ const trimmed = (value ?? "").trim();
6378
+ if (!trimmed) return void 0;
6379
+ if (trimmed.length > 4e3) return "Keep it under 4,000 characters.";
6380
+ return void 0;
6381
+ }
6382
+ });
6383
+ if (clack.isCancel(prompt)) {
6384
+ return "cancelled";
6385
+ }
6386
+ const intentText = typeof prompt === "string" ? prompt.trim() : "";
6387
+ if (!intentText) {
6388
+ return "skipped";
6389
+ }
6390
+ const spinner = createOrgxSpinner("Routing");
6391
+ spinner.start();
6392
+ let intent;
6393
+ try {
6394
+ intent = await createIntent({
6395
+ workspace_id: input.workspace.id,
6396
+ text: intentText
6397
+ });
6398
+ spinner.stop();
6399
+ } catch (error) {
6400
+ spinner.fail("Could not classify intent.");
6401
+ const message = error instanceof Error ? error.message : String(error);
6402
+ console.log(` ${ICON.warn} ${pc3.yellow("intent")} ${pc3.dim(message)}`);
6403
+ return "failed";
6404
+ }
6405
+ const auth = await resolveOrgxAuth().catch(() => null);
6406
+ const baseUrl = auth?.baseUrl ?? DEFAULT_ORGX_BASE_URL;
6407
+ printIntentPreview(intent, baseUrl);
6408
+ const approveChoice = await clack.confirm({
6409
+ message: "Approve this plan and hand off to OrgX?",
6410
+ initialValue: true
6411
+ });
6412
+ if (clack.isCancel(approveChoice)) {
6413
+ return "cancelled";
6414
+ }
6415
+ if (approveChoice) {
6416
+ const approveSpinner = createOrgxSpinner("Approving");
6417
+ approveSpinner.start();
6418
+ try {
6419
+ await updateIntent(intent.id, { status: "approved" });
6420
+ approveSpinner.stop();
6421
+ } catch (error) {
6422
+ approveSpinner.fail("Approve failed.");
6423
+ const message = error instanceof Error ? error.message : String(error);
6424
+ console.log(` ${ICON.warn} ${pc3.yellow("intent")} ${pc3.dim(message)}`);
6425
+ return "failed";
6426
+ }
6427
+ const handoff2 = buildIntentHandoffUrl(intent.slug, { baseUrl });
6428
+ console.log(` ${ICON.ok} ${pc3.green("intent")} ${pc3.dim(`approved \xB7 ${handoff2}`)}`);
6429
+ return "approved";
6430
+ }
6431
+ const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl });
6432
+ console.log(` ${ICON.skip} ${pc3.dim(`intent pending \xB7 ${handoff}`)}`);
6433
+ return "captured";
6434
+ }
6435
+ async function runIntentCommand(options) {
6436
+ const interactive = isInteractive();
6437
+ let intentText = options.initialText?.trim() ?? "";
6438
+ if (!intentText) {
6439
+ if (!interactive) {
6440
+ console.error(
6441
+ pc3.red("Intent text is required when running non-interactively.")
6442
+ );
6443
+ console.error(
6444
+ pc3.dim(' Example: orgx-wizard intent "launch partner outreach campaign"')
6445
+ );
6446
+ process.exitCode = 1;
6447
+ return;
6448
+ }
6449
+ const prompt = await textPrompt({
6450
+ message: "What do you want to move?",
6451
+ placeholder: "e.g. launch partner outreach campaign",
6452
+ validate: (value) => {
6453
+ const trimmed = (value ?? "").trim();
6454
+ if (!trimmed) return "Intent text cannot be empty.";
6455
+ if (trimmed.length > 4e3) return "Intent text exceeds 4,000 characters.";
6456
+ return void 0;
6457
+ }
6458
+ });
6459
+ if (clack.isCancel(prompt) || typeof prompt !== "string") {
6460
+ console.log(pc3.dim("Cancelled."));
6461
+ return;
6462
+ }
6463
+ intentText = prompt.trim();
6464
+ }
6465
+ let workspaceId = options.workspaceId ?? "";
6466
+ let workspaceName = null;
6467
+ let workspaceBaseUrl = null;
6468
+ if (!workspaceId) {
6469
+ const loadLabel = "Loading current OrgX workspace";
6470
+ const spinner = interactive ? createOrgxSpinner(loadLabel) : null;
6471
+ if (spinner) spinner.start();
6472
+ else console.log(pc3.dim(`${loadLabel}...`));
6473
+ try {
6474
+ const current = await getCurrentWorkspace();
6475
+ if (!current) {
6476
+ if (spinner) spinner.fail("No OrgX workspace is configured.");
6477
+ else console.error(pc3.red("No OrgX workspace is configured."));
6478
+ console.log(
6479
+ pc3.dim(" Run `orgx-wizard workspace create <name>` or pass --workspace <id>.")
6480
+ );
6481
+ process.exitCode = 1;
6482
+ return;
6483
+ }
6484
+ workspaceId = current.id;
6485
+ workspaceName = current.name;
6486
+ if (spinner) spinner.stop();
6487
+ } catch (error) {
6488
+ if (spinner) spinner.fail("Failed to load current workspace.");
6489
+ console.error(
6490
+ pc3.red(error instanceof Error ? error.message : String(error))
6491
+ );
6492
+ process.exitCode = 1;
6493
+ return;
6494
+ }
6495
+ }
6496
+ const classifyLabel = "Routing";
6497
+ const classifySpinner = interactive ? createOrgxSpinner(classifyLabel) : null;
6498
+ if (classifySpinner) classifySpinner.start();
6499
+ else console.log(pc3.dim(`${classifyLabel}...`));
6500
+ let intent;
6501
+ try {
6502
+ intent = await createIntent({ workspace_id: workspaceId, text: intentText });
6503
+ if (classifySpinner) classifySpinner.stop();
6504
+ } catch (error) {
6505
+ if (classifySpinner) classifySpinner.fail("Classification failed.");
6506
+ console.error(
6507
+ pc3.red(error instanceof Error ? error.message : String(error))
6508
+ );
6509
+ process.exitCode = 1;
6510
+ return;
6511
+ }
6512
+ const auth = await resolveOrgxAuth().catch(() => null);
6513
+ const baseUrl = auth?.baseUrl ?? DEFAULT_ORGX_BASE_URL;
6514
+ workspaceBaseUrl = baseUrl;
6515
+ if (options.jsonOutput) {
6516
+ const payload = {
6517
+ intent,
6518
+ handoff_url: buildIntentHandoffUrl(intent.slug, { baseUrl }),
6519
+ workspace: workspaceName ? { id: workspaceId, name: workspaceName } : { id: workspaceId }
6520
+ };
6521
+ console.log(JSON.stringify(payload, null, 2));
6522
+ return;
6523
+ }
6524
+ printIntentPreview(intent, baseUrl);
6525
+ console.log("");
6526
+ if (!interactive) {
6527
+ console.log(
6528
+ pc3.dim(
6529
+ `Run \`orgx-wizard intent --workspace ${workspaceId}\` interactively to approve, edit, or archive.`
6530
+ )
6531
+ );
6532
+ return;
6533
+ }
6534
+ let action = null;
6535
+ while (action === null) {
6536
+ const key = await readSingleKey();
6537
+ if (!key) {
6538
+ action = "quit";
6539
+ break;
6540
+ }
6541
+ action = normalizeHotkey(key);
6542
+ if (action === null) {
6543
+ console.log(
6544
+ pc3.dim(` Unrecognized key. Press a, e, x, or q.`)
6545
+ );
6546
+ }
6547
+ }
6548
+ switch (action) {
6549
+ case "approve": {
6550
+ const approveLabel = "Approving";
6551
+ const spinner = interactive ? createOrgxSpinner(approveLabel) : null;
6552
+ if (spinner) spinner.start();
6553
+ try {
6554
+ await updateIntent(intent.id, { status: "approved" });
6555
+ if (spinner) spinner.stop();
6556
+ } catch (error) {
6557
+ if (spinner) spinner.fail("Approve failed.");
6558
+ console.error(
6559
+ pc3.red(error instanceof Error ? error.message : String(error))
6560
+ );
6561
+ process.exitCode = 1;
6562
+ return;
6563
+ }
6564
+ const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl });
6565
+ console.log("");
6566
+ console.log(`${pc3.green("\u2713")} Approved \xB7 ${handoff}`);
6567
+ return;
6568
+ }
6569
+ case "edit": {
6570
+ const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl });
6571
+ console.log("");
6572
+ console.log(`${pc3.yellow("\u270E")} Opening ${handoff}`);
6573
+ const result = openBrowser(handoff);
6574
+ if (!result.ok) {
6575
+ console.log(pc3.dim(` Could not launch browser: ${result.error}`));
6576
+ console.log(pc3.dim(` Visit ${handoff} to finish editing.`));
6577
+ }
6578
+ return;
6579
+ }
6580
+ case "archive": {
6581
+ const archiveLabel = "Archiving";
6582
+ const spinner = interactive ? createOrgxSpinner(archiveLabel) : null;
6583
+ if (spinner) spinner.start();
6584
+ try {
6585
+ await updateIntent(intent.id, { status: "archived" });
6586
+ if (spinner) spinner.stop();
6587
+ } catch (error) {
6588
+ if (spinner) spinner.fail("Archive failed.");
6589
+ console.error(
6590
+ pc3.red(error instanceof Error ? error.message : String(error))
6591
+ );
6592
+ process.exitCode = 1;
6593
+ return;
6594
+ }
6595
+ console.log("");
6596
+ console.log(`${pc3.red("\u2715")} Archived \xB7 intent will not be executed.`);
6597
+ return;
6598
+ }
6599
+ case "quit":
6600
+ default: {
6601
+ console.log("");
6602
+ console.log(pc3.dim(" Exited without saving. Intent remains pending."));
6603
+ console.log(
6604
+ pc3.dim(
6605
+ ` Resume at ${buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl })}`
6606
+ )
6607
+ );
6608
+ return;
6609
+ }
6610
+ }
6611
+ }
6511
6612
  async function maybeConfigureOptionalWorkspaceAddOns(input) {
6512
6613
  if (!input.interactive || !input.workspace) {
6513
6614
  return "skipped";
@@ -6763,109 +6864,6 @@ async function maybeInstallOptionalCompanionPlugins(input) {
6763
6864
  ...input.telemetry ? { telemetry: input.telemetry } : {}
6764
6865
  });
6765
6866
  }
6766
- async function maybeRunPeopleFirstCapture(input) {
6767
- if (!input.interactive || !input.workspace) {
6768
- return "skipped";
6769
- }
6770
- const alreadyCompleted = hasPeopleFirstCaptureCompleted(input.workspace.id);
6771
- const captureResult = await runPeopleFirstCapture({
6772
- interactive: input.interactive,
6773
- workspace: input.workspace,
6774
- alreadyCompleted,
6775
- prompts: {
6776
- cancel: clack.cancel,
6777
- isCancel: clack.isCancel,
6778
- text: textPrompt,
6779
- select: selectPrompt,
6780
- confirm: clack.confirm
6781
- }
6782
- });
6783
- switch (captureResult.status) {
6784
- case "skipped_already_completed":
6785
- return "skipped";
6786
- case "skipped_non_interactive":
6787
- case "skipped_no_workspace":
6788
- return "skipped";
6789
- case "skipped_declined":
6790
- console.log(` ${ICON.skip} ${pc3.dim(captureResult.message)}`);
6791
- return "skipped";
6792
- case "cancelled":
6793
- return "cancelled";
6794
- case "failed":
6795
- console.log(` ${ICON.warn} ${pc3.yellow("people-first")} ${pc3.dim(captureResult.message)}`);
6796
- return "failed";
6797
- case "completed":
6798
- break;
6799
- }
6800
- if (!captureResult.person || !captureResult.goal) {
6801
- return "failed";
6802
- }
6803
- console.log(
6804
- ` ${ICON.ok} ${pc3.green("people-first")} ${pc3.dim(
6805
- `Captured ${captureResult.person.display_name} (${captureResult.person.relationship_stage}).`
6806
- )}`
6807
- );
6808
- const draftResult = await runPeopleFirstArtifactDraft({
6809
- interactive: input.interactive,
6810
- person: captureResult.person,
6811
- prompts: {
6812
- cancel: clack.cancel,
6813
- isCancel: clack.isCancel,
6814
- text: textPrompt,
6815
- select: selectPrompt,
6816
- confirm: clack.confirm
6817
- }
6818
- });
6819
- if (draftResult.status === "cancelled") {
6820
- } else if (draftResult.status === "failed") {
6821
- console.log(
6822
- ` ${ICON.warn} ${pc3.yellow("artifact draft")} ${pc3.dim(draftResult.message)}`
6823
- );
6824
- } else if (draftResult.status === "drafted") {
6825
- console.log(
6826
- ` ${ICON.ok} ${pc3.green("artifact draft")} ${pc3.dim(
6827
- `OrgX pre-drafted a ${draftResult.persona ?? "first-touch"} artifact.`
6828
- )}`
6829
- );
6830
- }
6831
- try {
6832
- recordPeopleFirstCaptureCompletion({
6833
- workspaceId: input.workspace.id,
6834
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
6835
- ...captureResult.person ? { personId: captureResult.person.id } : {},
6836
- ...draftResult.persona ? { templatePersona: draftResult.persona } : {}
6837
- });
6838
- } catch {
6839
- }
6840
- const baseUrl = process.env.ORGX_APP_URL?.trim() || DEFAULT_ORGX_BASE_URL;
6841
- const commandUrl = `${baseUrl.replace(/\/+$/, "")}/command`;
6842
- console.log("");
6843
- console.log(
6844
- ` ${ICON.ok} ${pc3.bold(
6845
- `You brought in ${captureResult.person.display_name}.`
6846
- )} ${pc3.dim(
6847
- `Head to ${commandUrl} to see them in your people list \u2014 OrgX already drafted a first-touch artifact.`
6848
- )}`
6849
- );
6850
- if (input.openInBrowser) {
6851
- const openResult = openBrowser(commandUrl);
6852
- if (!openResult.ok && openResult.error) {
6853
- console.log(` ${pc3.dim(`(Could not auto-open browser: ${openResult.error})`)}`);
6854
- }
6855
- } else {
6856
- const openAnswer = await clack.confirm({
6857
- message: `Open ${commandUrl} in your browser now?`,
6858
- initialValue: true
6859
- });
6860
- if (!clack.isCancel(openAnswer) && openAnswer === true) {
6861
- const openResult = openBrowser(commandUrl);
6862
- if (!openResult.ok && openResult.error) {
6863
- console.log(` ${pc3.dim(`(Could not auto-open browser: ${openResult.error})`)}`);
6864
- }
6865
- }
6866
- }
6867
- return "completed";
6868
- }
6869
6867
  function printAuthStatus(status) {
6870
6868
  if (!status.configured) {
6871
6869
  console.log(` ${ICON.warn} ${pc3.yellow("no account")} run ${pc3.cyan(`${getCmd()} auth login`)} to connect`);
@@ -6944,12 +6942,12 @@ function printDoctorReport(report, assessment) {
6944
6942
  async function main() {
6945
6943
  const program = new Command();
6946
6944
  program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
6947
- const pkgVersion = true ? "0.1.19" : void 0;
6945
+ const pkgVersion = true ? "0.1.21" : void 0;
6948
6946
  program.version(pkgVersion ?? "unknown", "-V, --version");
6949
6947
  program.hook("preAction", () => {
6950
6948
  console.log(renderBanner(pkgVersion));
6951
6949
  });
6952
- program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").option("--open", "After people-first capture, auto-open the OrgX dashboard in your browser.", false).action(async (options) => {
6950
+ program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").action(async (options) => {
6953
6951
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
6954
6952
  await safeTrackWizardTelemetry("wizard_started", {
6955
6953
  command: "setup",
@@ -7122,6 +7120,22 @@ async function main() {
7122
7120
  if (workspaceSetup.status === "cancelled") {
7123
7121
  return;
7124
7122
  }
7123
+ if (workspaceSetup.status === "reauth_requested") {
7124
+ console.log("");
7125
+ console.log(
7126
+ ` ${ICON.warn} ${pc3.yellow("workspace")} ${pc3.dim("API key authenticated but returned 0 workspaces \u2014 likely an identity mismatch.")}`
7127
+ );
7128
+ console.log(` ${pc3.cyan(`${getCmd()} auth login`)} ${pc3.dim("\u2192 re-link via OAuth, then rerun")} ${pc3.cyan(`${getCmd()} setup`)}`);
7129
+ await safeTrackWizardTelemetry(
7130
+ "workspace_bootstrapped",
7131
+ buildWorkspaceSetupTelemetryProperties(workspaceSetup, {
7132
+ command: "setup",
7133
+ interactive,
7134
+ preset: "standard"
7135
+ })
7136
+ );
7137
+ return;
7138
+ }
7125
7139
  await safeTrackWizardTelemetry(
7126
7140
  "workspace_bootstrapped",
7127
7141
  buildWorkspaceSetupTelemetryProperties(workspaceSetup, {
@@ -7155,12 +7169,11 @@ async function main() {
7155
7169
  } else if (briefResult.status === "failed") {
7156
7170
  console.log(` ${ICON.warn} ${pc3.yellow("daily brief")} ${pc3.dim(briefResult.message)}`);
7157
7171
  }
7158
- const peopleFirstResult = await maybeRunPeopleFirstCapture({
7172
+ const intentResult = await maybeCaptureSetupIntent({
7159
7173
  interactive,
7160
- openInBrowser: Boolean(options.open),
7161
7174
  workspace: resolvedWorkspace
7162
7175
  });
7163
- if (peopleFirstResult === "cancelled") {
7176
+ if (intentResult === "cancelled") {
7164
7177
  return;
7165
7178
  }
7166
7179
  const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
@@ -7580,6 +7593,17 @@ async function main() {
7580
7593
  persistContinuityDefaults({ workspace: result.workspace });
7581
7594
  printWorkspace(result.workspace);
7582
7595
  });
7596
+ program.command("intent").description(
7597
+ "Capture an intent, preview the classified agent + plan, and approve or hand off to the browser."
7598
+ ).argument("[text...]", "intent text (quotes optional)").option("--workspace <id>", "workspace id override; defaults to the current workspace").option("--json", "emit a JSON summary instead of the box-drawn preview").action(async (textParts, options) => {
7599
+ const initialText = textParts.join(" ").trim();
7600
+ const workspaceId = options.workspace?.trim() ?? "";
7601
+ await runIntentCommand({
7602
+ ...initialText ? { initialText } : {},
7603
+ ...workspaceId ? { workspaceId } : {},
7604
+ jsonOutput: Boolean(options.json)
7605
+ });
7606
+ });
7583
7607
  program.command("doctor").description("Verify local OrgX surface config and optional remote setup status.").action(async () => {
7584
7608
  const spinner = createOrgxSpinner("Running OrgX health check");
7585
7609
  spinner.start();