@useorgx/wizard 0.1.20 → 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 +657 -661
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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 });
|
|
@@ -5403,7 +5381,357 @@ async function trackWizardTelemetry(event, properties = {}, options = {}) {
|
|
|
5403
5381
|
return response?.ok === true;
|
|
5404
5382
|
}
|
|
5405
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
|
+
|
|
5406
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
|
+
}
|
|
5407
5735
|
var BASELINE_PROMPTS = [
|
|
5408
5736
|
{ task_type: "code_review", label: "Code review", placeholder: "20" },
|
|
5409
5737
|
{ task_type: "prd_draft", label: "PRD draft", placeholder: "45" },
|
|
@@ -5563,9 +5891,10 @@ async function runDailyBriefOnboarding(options) {
|
|
|
5563
5891
|
});
|
|
5564
5892
|
if (!commitResponse.ok) {
|
|
5565
5893
|
const text2 = await commitResponse.text().catch(() => "");
|
|
5894
|
+
const hint = extractErrorHint(text2) ?? `HTTP ${commitResponse.status}`;
|
|
5566
5895
|
return {
|
|
5567
5896
|
status: "failed",
|
|
5568
|
-
message:
|
|
5897
|
+
message: `Could not commit onboarding capture \u2014 ${hint}`,
|
|
5569
5898
|
error: `HTTP ${commitResponse.status}: ${text2.slice(0, 200)}`
|
|
5570
5899
|
};
|
|
5571
5900
|
}
|
|
@@ -5596,536 +5925,6 @@ async function fetchOnboardingState(auth) {
|
|
|
5596
5925
|
}
|
|
5597
5926
|
}
|
|
5598
5927
|
|
|
5599
|
-
// src/lib/people-first-capture.ts
|
|
5600
|
-
var RELATIONSHIP_STAGE_OPTIONS = [
|
|
5601
|
-
{ value: "stranger", label: "Stranger", hint: "no prior contact yet" },
|
|
5602
|
-
{ value: "prospect", label: "Prospect", hint: "outreach planned or in flight (default)" },
|
|
5603
|
-
{ value: "conversation", label: "Conversation", hint: "active 2-way dialogue" },
|
|
5604
|
-
{ value: "design_partner", label: "Design partner", hint: "paid / equity track underway" },
|
|
5605
|
-
{ value: "paused", label: "Paused", hint: "intentional pause, not wrong fit" },
|
|
5606
|
-
{ value: "churned", label: "Churned", hint: "ended; history preserved" },
|
|
5607
|
-
{ value: "alumni", label: "Alumni", hint: "closed engagement, may return" }
|
|
5608
|
-
];
|
|
5609
|
-
var TRUST_TIER_OPTIONS = [
|
|
5610
|
-
{ value: "cold", label: "Cold / unknown", hint: "new or barely-met" },
|
|
5611
|
-
{ value: "warm", label: "Warm", hint: "know each other, some trust built" },
|
|
5612
|
-
{ value: "close", label: "Close", hint: "deep trust \u2014 inner-circle candidate" }
|
|
5613
|
-
];
|
|
5614
|
-
async function fetchPeopleFirstOnboardingState(auth) {
|
|
5615
|
-
try {
|
|
5616
|
-
const res = await fetch(
|
|
5617
|
-
buildOrgxApiUrl("/v1/people/onboarding", auth.baseUrl),
|
|
5618
|
-
{
|
|
5619
|
-
method: "GET",
|
|
5620
|
-
headers: { Authorization: `Bearer ${auth.apiKey}` },
|
|
5621
|
-
signal: AbortSignal.timeout(5e3)
|
|
5622
|
-
}
|
|
5623
|
-
);
|
|
5624
|
-
if (!res.ok) return null;
|
|
5625
|
-
const body = await res.json().catch(() => null);
|
|
5626
|
-
if (!body || !Array.isArray(body.workspaces)) return null;
|
|
5627
|
-
return body;
|
|
5628
|
-
} catch {
|
|
5629
|
-
return null;
|
|
5630
|
-
}
|
|
5631
|
-
}
|
|
5632
|
-
function parseContactChannels(raw) {
|
|
5633
|
-
const channels = [];
|
|
5634
|
-
const parts = raw.split(/[,\n]+/).map((part) => part.trim()).filter(Boolean);
|
|
5635
|
-
for (const part of parts) {
|
|
5636
|
-
if (/^https?:\/\/(?:www\.)?linkedin\.com\//i.test(part) || part.toLowerCase().startsWith("linkedin.com/")) {
|
|
5637
|
-
channels.push({ kind: "linkedin", value: part });
|
|
5638
|
-
} else if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(part)) {
|
|
5639
|
-
channels.push({ kind: "email", value: part });
|
|
5640
|
-
} else if (/^\+?[\d][\d\s()\-.]{5,}$/.test(part)) {
|
|
5641
|
-
channels.push({ kind: "phone", value: part.replace(/\s+/g, "") });
|
|
5642
|
-
} else {
|
|
5643
|
-
channels.push({ kind: "linkedin", value: part });
|
|
5644
|
-
}
|
|
5645
|
-
}
|
|
5646
|
-
return channels;
|
|
5647
|
-
}
|
|
5648
|
-
async function postJson(auth, path, body) {
|
|
5649
|
-
try {
|
|
5650
|
-
const res = await fetch(buildOrgxApiUrl(path, auth.baseUrl), {
|
|
5651
|
-
method: "POST",
|
|
5652
|
-
headers: {
|
|
5653
|
-
Authorization: `Bearer ${auth.apiKey}`,
|
|
5654
|
-
"Content-Type": "application/json"
|
|
5655
|
-
},
|
|
5656
|
-
body: JSON.stringify(body),
|
|
5657
|
-
signal: AbortSignal.timeout(1e4)
|
|
5658
|
-
});
|
|
5659
|
-
const text2 = await res.text().catch(() => "");
|
|
5660
|
-
let parsed = null;
|
|
5661
|
-
if (text2) {
|
|
5662
|
-
try {
|
|
5663
|
-
parsed = JSON.parse(text2);
|
|
5664
|
-
} catch {
|
|
5665
|
-
parsed = text2;
|
|
5666
|
-
}
|
|
5667
|
-
}
|
|
5668
|
-
if (!res.ok) {
|
|
5669
|
-
const detail = parsed && typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `HTTP ${res.status}`;
|
|
5670
|
-
return { ok: false, error: detail };
|
|
5671
|
-
}
|
|
5672
|
-
return { ok: true, status: res.status, body: parsed };
|
|
5673
|
-
} catch (err) {
|
|
5674
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
5675
|
-
return { ok: false, error: message };
|
|
5676
|
-
}
|
|
5677
|
-
}
|
|
5678
|
-
function extractId(body) {
|
|
5679
|
-
if (body && typeof body === "object") {
|
|
5680
|
-
const candidate = body.id ?? body.data;
|
|
5681
|
-
if (typeof candidate === "string") return candidate;
|
|
5682
|
-
if (candidate && typeof candidate === "object") {
|
|
5683
|
-
const innerId = candidate.id;
|
|
5684
|
-
if (typeof innerId === "string") return innerId;
|
|
5685
|
-
}
|
|
5686
|
-
}
|
|
5687
|
-
return null;
|
|
5688
|
-
}
|
|
5689
|
-
var BACKEND_UNREACHABLE_HINT = "Could not sync with OrgX backend \u2014 check your network / run `orgx-wizard status`.";
|
|
5690
|
-
async function runPeopleFirstCapture(options) {
|
|
5691
|
-
if (!options.interactive) {
|
|
5692
|
-
return {
|
|
5693
|
-
status: "skipped_non_interactive",
|
|
5694
|
-
message: "People-first capture skipped \u2014 not attached to a TTY."
|
|
5695
|
-
};
|
|
5696
|
-
}
|
|
5697
|
-
if (!options.workspace) {
|
|
5698
|
-
return {
|
|
5699
|
-
status: "skipped_no_workspace",
|
|
5700
|
-
message: "People-first capture skipped \u2014 no workspace resolved."
|
|
5701
|
-
};
|
|
5702
|
-
}
|
|
5703
|
-
if (options.alreadyCompleted) {
|
|
5704
|
-
return {
|
|
5705
|
-
status: "skipped_already_completed",
|
|
5706
|
-
message: "People-first capture already completed for this workspace."
|
|
5707
|
-
};
|
|
5708
|
-
}
|
|
5709
|
-
const auth = await resolveOrgxAuth();
|
|
5710
|
-
if (!auth) {
|
|
5711
|
-
return {
|
|
5712
|
-
status: "failed",
|
|
5713
|
-
message: "People-first capture needs OrgX auth.",
|
|
5714
|
-
error: "no_auth"
|
|
5715
|
-
};
|
|
5716
|
-
}
|
|
5717
|
-
const state = await fetchPeopleFirstOnboardingState(auth);
|
|
5718
|
-
if (state) {
|
|
5719
|
-
const row = state.workspaces.find((w) => w.id === options.workspace.id);
|
|
5720
|
-
if (row?.peopleFirstCaptureCompletedAt) {
|
|
5721
|
-
return {
|
|
5722
|
-
status: "skipped_already_completed",
|
|
5723
|
-
message: "People-first capture already completed for this workspace."
|
|
5724
|
-
};
|
|
5725
|
-
}
|
|
5726
|
-
}
|
|
5727
|
-
const { prompts } = options;
|
|
5728
|
-
const proceed = await prompts.confirm({
|
|
5729
|
-
message: "Name the first person OrgX should know about? (takes ~30 seconds; OrgX will pre-draft a first-touch artifact for them)",
|
|
5730
|
-
initialValue: true
|
|
5731
|
-
});
|
|
5732
|
-
if (prompts.isCancel(proceed)) {
|
|
5733
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5734
|
-
}
|
|
5735
|
-
if (!proceed) {
|
|
5736
|
-
return {
|
|
5737
|
-
status: "skipped_declined",
|
|
5738
|
-
message: "Skipped \u2014 run the wizard again any time to add your first person."
|
|
5739
|
-
};
|
|
5740
|
-
}
|
|
5741
|
-
const headlineAnswer = await prompts.text({
|
|
5742
|
-
message: 'Who is this person to you? (one line \u2014 e.g. "prospect at Acme", "design partner", "old teammate")',
|
|
5743
|
-
placeholder: "design partner prospect for OrgX",
|
|
5744
|
-
validate(value) {
|
|
5745
|
-
if (!value || !value.trim()) return "Enter one line.";
|
|
5746
|
-
if (value.trim().length > 160) return "Keep it under 160 chars.";
|
|
5747
|
-
return void 0;
|
|
5748
|
-
}
|
|
5749
|
-
});
|
|
5750
|
-
if (prompts.isCancel(headlineAnswer)) {
|
|
5751
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5752
|
-
}
|
|
5753
|
-
const headline = typeof headlineAnswer === "string" ? headlineAnswer.trim() : "";
|
|
5754
|
-
const contextAnswer = await prompts.select({
|
|
5755
|
-
initialValue: "personal",
|
|
5756
|
-
message: "Is this on behalf of a business, or a personal relationship?",
|
|
5757
|
-
options: [
|
|
5758
|
-
{ value: "personal", label: "Personal", hint: "no business attached yet" },
|
|
5759
|
-
{ value: "business", label: "On behalf of a business", hint: "will also create a Business entity" }
|
|
5760
|
-
]
|
|
5761
|
-
});
|
|
5762
|
-
if (prompts.isCancel(contextAnswer)) {
|
|
5763
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5764
|
-
}
|
|
5765
|
-
const hasBusiness = contextAnswer === "business";
|
|
5766
|
-
let businessName;
|
|
5767
|
-
if (hasBusiness) {
|
|
5768
|
-
const businessAnswer = await prompts.text({
|
|
5769
|
-
message: "Business name?",
|
|
5770
|
-
placeholder: "Acme Treasury",
|
|
5771
|
-
validate(value) {
|
|
5772
|
-
if (!value || !value.trim()) return "Enter the business name.";
|
|
5773
|
-
return void 0;
|
|
5774
|
-
}
|
|
5775
|
-
});
|
|
5776
|
-
if (prompts.isCancel(businessAnswer)) {
|
|
5777
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5778
|
-
}
|
|
5779
|
-
businessName = typeof businessAnswer === "string" ? businessAnswer.trim() : void 0;
|
|
5780
|
-
}
|
|
5781
|
-
const nameAnswer = await prompts.text({
|
|
5782
|
-
message: "Their name?",
|
|
5783
|
-
placeholder: "Laura Chen",
|
|
5784
|
-
validate(value) {
|
|
5785
|
-
if (!value || !value.trim()) return "Enter a display name.";
|
|
5786
|
-
return void 0;
|
|
5787
|
-
}
|
|
5788
|
-
});
|
|
5789
|
-
if (prompts.isCancel(nameAnswer)) {
|
|
5790
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5791
|
-
}
|
|
5792
|
-
const displayName = typeof nameAnswer === "string" ? nameAnswer.trim() : "";
|
|
5793
|
-
const contactAnswer = await prompts.text({
|
|
5794
|
-
message: "How do you reach them? (email, LinkedIn URL, or phone \u2014 comma-separated, at least one)",
|
|
5795
|
-
placeholder: "laura@acme.com, linkedin.com/in/laurachen",
|
|
5796
|
-
validate(value) {
|
|
5797
|
-
if (!value || !value.trim()) return "Enter at least one contact.";
|
|
5798
|
-
const parsed = parseContactChannels(value);
|
|
5799
|
-
if (parsed.length === 0) return "Could not parse any contact channels.";
|
|
5800
|
-
return void 0;
|
|
5801
|
-
}
|
|
5802
|
-
});
|
|
5803
|
-
if (prompts.isCancel(contactAnswer)) {
|
|
5804
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5805
|
-
}
|
|
5806
|
-
const contactChannels = parseContactChannels(
|
|
5807
|
-
typeof contactAnswer === "string" ? contactAnswer : ""
|
|
5808
|
-
);
|
|
5809
|
-
const stageAnswer = await prompts.select({
|
|
5810
|
-
initialValue: "prospect",
|
|
5811
|
-
message: "What stage is the relationship?",
|
|
5812
|
-
options: RELATIONSHIP_STAGE_OPTIONS.map((opt) => ({
|
|
5813
|
-
value: opt.value,
|
|
5814
|
-
label: opt.label,
|
|
5815
|
-
...opt.hint ? { hint: opt.hint } : {}
|
|
5816
|
-
}))
|
|
5817
|
-
});
|
|
5818
|
-
if (prompts.isCancel(stageAnswer)) {
|
|
5819
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5820
|
-
}
|
|
5821
|
-
const relationshipStage = stageAnswer;
|
|
5822
|
-
const trustAnswer = await prompts.select({
|
|
5823
|
-
initialValue: "cold",
|
|
5824
|
-
message: "How would you describe the trust level right now?",
|
|
5825
|
-
options: TRUST_TIER_OPTIONS.map((opt) => ({
|
|
5826
|
-
value: opt.value,
|
|
5827
|
-
label: opt.label,
|
|
5828
|
-
...opt.hint ? { hint: opt.hint } : {}
|
|
5829
|
-
}))
|
|
5830
|
-
});
|
|
5831
|
-
if (prompts.isCancel(trustAnswer)) {
|
|
5832
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5833
|
-
}
|
|
5834
|
-
const trustTier = trustAnswer;
|
|
5835
|
-
const innerCircleAnswer = await prompts.confirm({
|
|
5836
|
-
message: "Mark this person as inner-circle? (affects tone of drafted artifacts)",
|
|
5837
|
-
initialValue: false
|
|
5838
|
-
});
|
|
5839
|
-
if (prompts.isCancel(innerCircleAnswer)) {
|
|
5840
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5841
|
-
}
|
|
5842
|
-
const innerCircle = Boolean(innerCircleAnswer);
|
|
5843
|
-
const goalAnswer = await prompts.text({
|
|
5844
|
-
message: "Which matters most right now? (one line \u2014 this becomes their Goal)",
|
|
5845
|
-
placeholder: "agree on first pilot scope by May 3",
|
|
5846
|
-
validate(value) {
|
|
5847
|
-
if (!value || !value.trim()) return "Enter one line.";
|
|
5848
|
-
return void 0;
|
|
5849
|
-
}
|
|
5850
|
-
});
|
|
5851
|
-
if (prompts.isCancel(goalAnswer)) {
|
|
5852
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5853
|
-
}
|
|
5854
|
-
const goalTitle = typeof goalAnswer === "string" ? goalAnswer.trim() : "";
|
|
5855
|
-
let businessIntent;
|
|
5856
|
-
if (hasBusiness && relationshipStage === "conversation") {
|
|
5857
|
-
const intentAnswer = await prompts.select({
|
|
5858
|
-
initialValue: "client",
|
|
5859
|
-
message: "Is this person an investor in this business, or a client of it?",
|
|
5860
|
-
options: [
|
|
5861
|
-
{ value: "client", label: "Client / prospect", hint: "default" },
|
|
5862
|
-
{ value: "investor", label: "Investor / advisor" },
|
|
5863
|
-
{ value: "unspecified", label: "Unsure / neither" }
|
|
5864
|
-
]
|
|
5865
|
-
});
|
|
5866
|
-
if (prompts.isCancel(intentAnswer)) {
|
|
5867
|
-
return { status: "cancelled", message: "People-first capture cancelled." };
|
|
5868
|
-
}
|
|
5869
|
-
businessIntent = intentAnswer;
|
|
5870
|
-
}
|
|
5871
|
-
let businessId;
|
|
5872
|
-
if (hasBusiness && businessName) {
|
|
5873
|
-
const businessRes = await postJson(auth, "/v1/businesses", {
|
|
5874
|
-
display_name: businessName,
|
|
5875
|
-
relationship_stage: relationshipStage === "alumni" ? "alumni" : "engaged"
|
|
5876
|
-
});
|
|
5877
|
-
if (!businessRes.ok) {
|
|
5878
|
-
return {
|
|
5879
|
-
status: "failed",
|
|
5880
|
-
message: `${BACKEND_UNREACHABLE_HINT} (businesses: ${businessRes.error})`,
|
|
5881
|
-
error: businessRes.error
|
|
5882
|
-
};
|
|
5883
|
-
}
|
|
5884
|
-
businessId = extractId(businessRes.body) ?? void 0;
|
|
5885
|
-
}
|
|
5886
|
-
const personPayload = {
|
|
5887
|
-
display_name: displayName,
|
|
5888
|
-
headline,
|
|
5889
|
-
relationship_stage: relationshipStage,
|
|
5890
|
-
contact_channels: contactChannels,
|
|
5891
|
-
metadata: {
|
|
5892
|
-
captured_via: "orgx-wizard",
|
|
5893
|
-
inner_circle: innerCircle,
|
|
5894
|
-
trust_tier: trustTier,
|
|
5895
|
-
...businessIntent ? { business_intent: businessIntent } : {}
|
|
5896
|
-
},
|
|
5897
|
-
...businessId ? { business_id: businessId } : {}
|
|
5898
|
-
};
|
|
5899
|
-
const personRes = await postJson(auth, "/v1/people", personPayload);
|
|
5900
|
-
if (!personRes.ok) {
|
|
5901
|
-
return {
|
|
5902
|
-
status: "failed",
|
|
5903
|
-
message: `${BACKEND_UNREACHABLE_HINT} (people: ${personRes.error})`,
|
|
5904
|
-
error: personRes.error
|
|
5905
|
-
};
|
|
5906
|
-
}
|
|
5907
|
-
const personId = extractId(personRes.body) ?? void 0;
|
|
5908
|
-
if (!personId) {
|
|
5909
|
-
return {
|
|
5910
|
-
status: "failed",
|
|
5911
|
-
message: `${BACKEND_UNREACHABLE_HINT} (people: missing id in response)`,
|
|
5912
|
-
error: "missing_person_id"
|
|
5913
|
-
};
|
|
5914
|
-
}
|
|
5915
|
-
const goalRes = await postJson(auth, "/v1/goals", {
|
|
5916
|
-
owner_type: "person",
|
|
5917
|
-
owner_id: personId,
|
|
5918
|
-
title: goalTitle
|
|
5919
|
-
});
|
|
5920
|
-
if (!goalRes.ok) {
|
|
5921
|
-
return {
|
|
5922
|
-
status: "failed",
|
|
5923
|
-
message: `${BACKEND_UNREACHABLE_HINT} (goals: ${goalRes.error})`,
|
|
5924
|
-
error: goalRes.error
|
|
5925
|
-
};
|
|
5926
|
-
}
|
|
5927
|
-
const goalId = extractId(goalRes.body) ?? void 0;
|
|
5928
|
-
if (!goalId) {
|
|
5929
|
-
return {
|
|
5930
|
-
status: "failed",
|
|
5931
|
-
message: `${BACKEND_UNREACHABLE_HINT} (goals: missing id in response)`,
|
|
5932
|
-
error: "missing_goal_id"
|
|
5933
|
-
};
|
|
5934
|
-
}
|
|
5935
|
-
const person = {
|
|
5936
|
-
id: personId,
|
|
5937
|
-
display_name: displayName,
|
|
5938
|
-
headline,
|
|
5939
|
-
relationship_stage: relationshipStage,
|
|
5940
|
-
contact_channels: contactChannels,
|
|
5941
|
-
inner_circle: innerCircle,
|
|
5942
|
-
trust_tier: trustTier,
|
|
5943
|
-
...businessId ? { business_id: businessId } : {},
|
|
5944
|
-
...businessIntent ? { business_intent: businessIntent } : {}
|
|
5945
|
-
};
|
|
5946
|
-
const goal = {
|
|
5947
|
-
id: goalId,
|
|
5948
|
-
owner_type: "person",
|
|
5949
|
-
owner_id: personId,
|
|
5950
|
-
title: goalTitle
|
|
5951
|
-
};
|
|
5952
|
-
return {
|
|
5953
|
-
status: "completed",
|
|
5954
|
-
message: `Captured ${displayName} in your workspace.`,
|
|
5955
|
-
person,
|
|
5956
|
-
goal
|
|
5957
|
-
};
|
|
5958
|
-
}
|
|
5959
|
-
|
|
5960
|
-
// src/peopleFirst/templateSelect.ts
|
|
5961
|
-
function selectPeopleFirstTemplate(input) {
|
|
5962
|
-
const trustTier = input.trustTier ?? "cold";
|
|
5963
|
-
if (input.innerCircle) {
|
|
5964
|
-
return {
|
|
5965
|
-
persona: "inner_circle",
|
|
5966
|
-
reason: "inner-circle mark set by user",
|
|
5967
|
-
needsBusinessIntentPrompt: false
|
|
5968
|
-
};
|
|
5969
|
-
}
|
|
5970
|
-
switch (input.relationshipStage) {
|
|
5971
|
-
case "stranger":
|
|
5972
|
-
case "prospect":
|
|
5973
|
-
return {
|
|
5974
|
-
persona: "cold_outreach",
|
|
5975
|
-
reason: `stage=${input.relationshipStage} \u2014 cold outreach draft`,
|
|
5976
|
-
needsBusinessIntentPrompt: false
|
|
5977
|
-
};
|
|
5978
|
-
case "conversation": {
|
|
5979
|
-
if (input.hasBusiness) {
|
|
5980
|
-
if (input.businessIntent === "investor") {
|
|
5981
|
-
return {
|
|
5982
|
-
persona: "investor_prep",
|
|
5983
|
-
reason: "conversation + business + investor intent",
|
|
5984
|
-
needsBusinessIntentPrompt: false
|
|
5985
|
-
};
|
|
5986
|
-
}
|
|
5987
|
-
if (input.businessIntent === "client") {
|
|
5988
|
-
return {
|
|
5989
|
-
persona: "client_trust",
|
|
5990
|
-
reason: "conversation + business + client intent",
|
|
5991
|
-
needsBusinessIntentPrompt: false
|
|
5992
|
-
};
|
|
5993
|
-
}
|
|
5994
|
-
return {
|
|
5995
|
-
persona: "client_trust",
|
|
5996
|
-
reason: "conversation + business \u2014 defaulting to client_trust; ask to confirm",
|
|
5997
|
-
needsBusinessIntentPrompt: true
|
|
5998
|
-
};
|
|
5999
|
-
}
|
|
6000
|
-
if (trustTier === "warm" || trustTier === "close") {
|
|
6001
|
-
return {
|
|
6002
|
-
persona: "founder_ally",
|
|
6003
|
-
reason: `conversation + trust=${trustTier} \u2014 founder-ally outreach`,
|
|
6004
|
-
needsBusinessIntentPrompt: false
|
|
6005
|
-
};
|
|
6006
|
-
}
|
|
6007
|
-
return {
|
|
6008
|
-
persona: "cold_outreach",
|
|
6009
|
-
reason: "conversation + cold trust \u2014 treating as cold_outreach",
|
|
6010
|
-
needsBusinessIntentPrompt: false
|
|
6011
|
-
};
|
|
6012
|
-
}
|
|
6013
|
-
case "design_partner":
|
|
6014
|
-
case "active_client":
|
|
6015
|
-
return {
|
|
6016
|
-
persona: "client_trust",
|
|
6017
|
-
reason: `stage=${input.relationshipStage} \u2014 client_trust cadence`,
|
|
6018
|
-
needsBusinessIntentPrompt: false
|
|
6019
|
-
};
|
|
6020
|
-
case "alumni":
|
|
6021
|
-
return {
|
|
6022
|
-
persona: "alumni_touch",
|
|
6023
|
-
reason: "stage=alumni \u2014 alumni_touch rekindle",
|
|
6024
|
-
needsBusinessIntentPrompt: false
|
|
6025
|
-
};
|
|
6026
|
-
case "paused":
|
|
6027
|
-
case "churned":
|
|
6028
|
-
return {
|
|
6029
|
-
persona: "alumni_touch",
|
|
6030
|
-
reason: `stage=${input.relationshipStage} \u2014 treating as alumni_touch for rekindle tone`,
|
|
6031
|
-
needsBusinessIntentPrompt: false
|
|
6032
|
-
};
|
|
6033
|
-
}
|
|
6034
|
-
}
|
|
6035
|
-
|
|
6036
|
-
// src/lib/people-first-artifact.ts
|
|
6037
|
-
async function callDraftEndpoint(auth, body) {
|
|
6038
|
-
try {
|
|
6039
|
-
const res = await fetch(buildOrgxApiUrl("/v1/artifacts/draft", auth.baseUrl), {
|
|
6040
|
-
method: "POST",
|
|
6041
|
-
headers: {
|
|
6042
|
-
Authorization: `Bearer ${auth.apiKey}`,
|
|
6043
|
-
"Content-Type": "application/json"
|
|
6044
|
-
},
|
|
6045
|
-
body: JSON.stringify(body),
|
|
6046
|
-
signal: AbortSignal.timeout(1e4)
|
|
6047
|
-
});
|
|
6048
|
-
if (!res.ok) {
|
|
6049
|
-
return { ok: false, error: `HTTP ${res.status}` };
|
|
6050
|
-
}
|
|
6051
|
-
const data = await res.json().catch(() => null);
|
|
6052
|
-
return { ok: true, data: data ?? {} };
|
|
6053
|
-
} catch (err) {
|
|
6054
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6055
|
-
return { ok: false, error: message };
|
|
6056
|
-
}
|
|
6057
|
-
}
|
|
6058
|
-
async function runPeopleFirstArtifactDraft(options) {
|
|
6059
|
-
if (!options.interactive) {
|
|
6060
|
-
return {
|
|
6061
|
-
status: "skipped_non_interactive",
|
|
6062
|
-
message: "Artifact draft skipped \u2014 not attached to a TTY."
|
|
6063
|
-
};
|
|
6064
|
-
}
|
|
6065
|
-
const auth = await resolveOrgxAuth();
|
|
6066
|
-
if (!auth) {
|
|
6067
|
-
return {
|
|
6068
|
-
status: "failed",
|
|
6069
|
-
message: "Artifact draft needs OrgX auth.",
|
|
6070
|
-
error: "no_auth"
|
|
6071
|
-
};
|
|
6072
|
-
}
|
|
6073
|
-
let businessIntent = options.businessIntent;
|
|
6074
|
-
const { prompts, person } = options;
|
|
6075
|
-
const hasBusiness = Boolean(options.businessName || person.business_id);
|
|
6076
|
-
const preselection = selectPeopleFirstTemplate({
|
|
6077
|
-
relationshipStage: person.relationship_stage,
|
|
6078
|
-
hasBusiness,
|
|
6079
|
-
trustTier: person.trust_tier,
|
|
6080
|
-
innerCircle: person.inner_circle,
|
|
6081
|
-
...businessIntent ? { businessIntent } : {}
|
|
6082
|
-
});
|
|
6083
|
-
let persona = preselection.persona;
|
|
6084
|
-
if (preselection.needsBusinessIntentPrompt && !businessIntent) {
|
|
6085
|
-
const answer = await prompts.select({
|
|
6086
|
-
initialValue: "client",
|
|
6087
|
-
message: "Is this more of a client-trust update, or investor-prep?",
|
|
6088
|
-
options: [
|
|
6089
|
-
{ value: "client", label: "Client trust (default)" },
|
|
6090
|
-
{ value: "investor", label: "Investor prep" }
|
|
6091
|
-
]
|
|
6092
|
-
});
|
|
6093
|
-
if (prompts.isCancel(answer)) {
|
|
6094
|
-
return { status: "cancelled", message: "Artifact draft cancelled." };
|
|
6095
|
-
}
|
|
6096
|
-
businessIntent = answer;
|
|
6097
|
-
persona = selectPeopleFirstTemplate({
|
|
6098
|
-
relationshipStage: person.relationship_stage,
|
|
6099
|
-
hasBusiness,
|
|
6100
|
-
trustTier: person.trust_tier,
|
|
6101
|
-
innerCircle: person.inner_circle,
|
|
6102
|
-
businessIntent
|
|
6103
|
-
}).persona;
|
|
6104
|
-
}
|
|
6105
|
-
const serverResult = await callDraftEndpoint(auth, {
|
|
6106
|
-
template_persona: persona,
|
|
6107
|
-
person_id: person.id,
|
|
6108
|
-
calibration_inputs: {
|
|
6109
|
-
voice_examples: []
|
|
6110
|
-
}
|
|
6111
|
-
});
|
|
6112
|
-
if (!serverResult.ok) {
|
|
6113
|
-
return {
|
|
6114
|
-
status: "failed",
|
|
6115
|
-
message: `Could not draft artifact \u2014 ${serverResult.error}. Check your network / run \`orgx-wizard status\`.`,
|
|
6116
|
-
persona,
|
|
6117
|
-
error: serverResult.error
|
|
6118
|
-
};
|
|
6119
|
-
}
|
|
6120
|
-
return {
|
|
6121
|
-
status: "drafted",
|
|
6122
|
-
message: `Drafted ${persona} artifact for ${person.display_name}.`,
|
|
6123
|
-
persona,
|
|
6124
|
-
...serverResult.data.artifact_id ? { serverArtifactId: serverResult.data.artifact_id } : {},
|
|
6125
|
-
...serverResult.data.url ? { serverArtifactUrl: serverResult.data.url } : {}
|
|
6126
|
-
};
|
|
6127
|
-
}
|
|
6128
|
-
|
|
6129
5928
|
// src/spinner.ts
|
|
6130
5929
|
import ora from "ora";
|
|
6131
5930
|
import pc2 from "picocolors";
|
|
@@ -6520,6 +6319,296 @@ function parseTimeoutSeconds(value) {
|
|
|
6520
6319
|
}
|
|
6521
6320
|
return parsed;
|
|
6522
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
|
+
}
|
|
6523
6612
|
async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
6524
6613
|
if (!input.interactive || !input.workspace) {
|
|
6525
6614
|
return "skipped";
|
|
@@ -6775,109 +6864,6 @@ async function maybeInstallOptionalCompanionPlugins(input) {
|
|
|
6775
6864
|
...input.telemetry ? { telemetry: input.telemetry } : {}
|
|
6776
6865
|
});
|
|
6777
6866
|
}
|
|
6778
|
-
async function maybeRunPeopleFirstCapture(input) {
|
|
6779
|
-
if (!input.interactive || !input.workspace) {
|
|
6780
|
-
return "skipped";
|
|
6781
|
-
}
|
|
6782
|
-
const alreadyCompleted = hasPeopleFirstCaptureCompleted(input.workspace.id);
|
|
6783
|
-
const captureResult = await runPeopleFirstCapture({
|
|
6784
|
-
interactive: input.interactive,
|
|
6785
|
-
workspace: input.workspace,
|
|
6786
|
-
alreadyCompleted,
|
|
6787
|
-
prompts: {
|
|
6788
|
-
cancel: clack.cancel,
|
|
6789
|
-
isCancel: clack.isCancel,
|
|
6790
|
-
text: textPrompt,
|
|
6791
|
-
select: selectPrompt,
|
|
6792
|
-
confirm: clack.confirm
|
|
6793
|
-
}
|
|
6794
|
-
});
|
|
6795
|
-
switch (captureResult.status) {
|
|
6796
|
-
case "skipped_already_completed":
|
|
6797
|
-
return "skipped";
|
|
6798
|
-
case "skipped_non_interactive":
|
|
6799
|
-
case "skipped_no_workspace":
|
|
6800
|
-
return "skipped";
|
|
6801
|
-
case "skipped_declined":
|
|
6802
|
-
console.log(` ${ICON.skip} ${pc3.dim(captureResult.message)}`);
|
|
6803
|
-
return "skipped";
|
|
6804
|
-
case "cancelled":
|
|
6805
|
-
return "cancelled";
|
|
6806
|
-
case "failed":
|
|
6807
|
-
console.log(` ${ICON.warn} ${pc3.yellow("people-first")} ${pc3.dim(captureResult.message)}`);
|
|
6808
|
-
return "failed";
|
|
6809
|
-
case "completed":
|
|
6810
|
-
break;
|
|
6811
|
-
}
|
|
6812
|
-
if (!captureResult.person || !captureResult.goal) {
|
|
6813
|
-
return "failed";
|
|
6814
|
-
}
|
|
6815
|
-
console.log(
|
|
6816
|
-
` ${ICON.ok} ${pc3.green("people-first")} ${pc3.dim(
|
|
6817
|
-
`Captured ${captureResult.person.display_name} (${captureResult.person.relationship_stage}).`
|
|
6818
|
-
)}`
|
|
6819
|
-
);
|
|
6820
|
-
const draftResult = await runPeopleFirstArtifactDraft({
|
|
6821
|
-
interactive: input.interactive,
|
|
6822
|
-
person: captureResult.person,
|
|
6823
|
-
prompts: {
|
|
6824
|
-
cancel: clack.cancel,
|
|
6825
|
-
isCancel: clack.isCancel,
|
|
6826
|
-
text: textPrompt,
|
|
6827
|
-
select: selectPrompt,
|
|
6828
|
-
confirm: clack.confirm
|
|
6829
|
-
}
|
|
6830
|
-
});
|
|
6831
|
-
if (draftResult.status === "cancelled") {
|
|
6832
|
-
} else if (draftResult.status === "failed") {
|
|
6833
|
-
console.log(
|
|
6834
|
-
` ${ICON.warn} ${pc3.yellow("artifact draft")} ${pc3.dim(draftResult.message)}`
|
|
6835
|
-
);
|
|
6836
|
-
} else if (draftResult.status === "drafted") {
|
|
6837
|
-
console.log(
|
|
6838
|
-
` ${ICON.ok} ${pc3.green("artifact draft")} ${pc3.dim(
|
|
6839
|
-
`OrgX pre-drafted a ${draftResult.persona ?? "first-touch"} artifact.`
|
|
6840
|
-
)}`
|
|
6841
|
-
);
|
|
6842
|
-
}
|
|
6843
|
-
try {
|
|
6844
|
-
recordPeopleFirstCaptureCompletion({
|
|
6845
|
-
workspaceId: input.workspace.id,
|
|
6846
|
-
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6847
|
-
...captureResult.person ? { personId: captureResult.person.id } : {},
|
|
6848
|
-
...draftResult.persona ? { templatePersona: draftResult.persona } : {}
|
|
6849
|
-
});
|
|
6850
|
-
} catch {
|
|
6851
|
-
}
|
|
6852
|
-
const baseUrl = process.env.ORGX_APP_URL?.trim() || DEFAULT_ORGX_BASE_URL;
|
|
6853
|
-
const commandUrl = `${baseUrl.replace(/\/+$/, "")}/command`;
|
|
6854
|
-
console.log("");
|
|
6855
|
-
console.log(
|
|
6856
|
-
` ${ICON.ok} ${pc3.bold(
|
|
6857
|
-
`You brought in ${captureResult.person.display_name}.`
|
|
6858
|
-
)} ${pc3.dim(
|
|
6859
|
-
`Head to ${commandUrl} to see them in your people list \u2014 OrgX already drafted a first-touch artifact.`
|
|
6860
|
-
)}`
|
|
6861
|
-
);
|
|
6862
|
-
if (input.openInBrowser) {
|
|
6863
|
-
const openResult = openBrowser(commandUrl);
|
|
6864
|
-
if (!openResult.ok && openResult.error) {
|
|
6865
|
-
console.log(` ${pc3.dim(`(Could not auto-open browser: ${openResult.error})`)}`);
|
|
6866
|
-
}
|
|
6867
|
-
} else {
|
|
6868
|
-
const openAnswer = await clack.confirm({
|
|
6869
|
-
message: `Open ${commandUrl} in your browser now?`,
|
|
6870
|
-
initialValue: true
|
|
6871
|
-
});
|
|
6872
|
-
if (!clack.isCancel(openAnswer) && openAnswer === true) {
|
|
6873
|
-
const openResult = openBrowser(commandUrl);
|
|
6874
|
-
if (!openResult.ok && openResult.error) {
|
|
6875
|
-
console.log(` ${pc3.dim(`(Could not auto-open browser: ${openResult.error})`)}`);
|
|
6876
|
-
}
|
|
6877
|
-
}
|
|
6878
|
-
}
|
|
6879
|
-
return "completed";
|
|
6880
|
-
}
|
|
6881
6867
|
function printAuthStatus(status) {
|
|
6882
6868
|
if (!status.configured) {
|
|
6883
6869
|
console.log(` ${ICON.warn} ${pc3.yellow("no account")} run ${pc3.cyan(`${getCmd()} auth login`)} to connect`);
|
|
@@ -6956,12 +6942,12 @@ function printDoctorReport(report, assessment) {
|
|
|
6956
6942
|
async function main() {
|
|
6957
6943
|
const program = new Command();
|
|
6958
6944
|
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
6959
|
-
const pkgVersion = true ? "0.1.
|
|
6945
|
+
const pkgVersion = true ? "0.1.21" : void 0;
|
|
6960
6946
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
6961
6947
|
program.hook("preAction", () => {
|
|
6962
6948
|
console.log(renderBanner(pkgVersion));
|
|
6963
6949
|
});
|
|
6964
|
-
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)").
|
|
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) => {
|
|
6965
6951
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
6966
6952
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
6967
6953
|
command: "setup",
|
|
@@ -7183,12 +7169,11 @@ async function main() {
|
|
|
7183
7169
|
} else if (briefResult.status === "failed") {
|
|
7184
7170
|
console.log(` ${ICON.warn} ${pc3.yellow("daily brief")} ${pc3.dim(briefResult.message)}`);
|
|
7185
7171
|
}
|
|
7186
|
-
const
|
|
7172
|
+
const intentResult = await maybeCaptureSetupIntent({
|
|
7187
7173
|
interactive,
|
|
7188
|
-
openInBrowser: Boolean(options.open),
|
|
7189
7174
|
workspace: resolvedWorkspace
|
|
7190
7175
|
});
|
|
7191
|
-
if (
|
|
7176
|
+
if (intentResult === "cancelled") {
|
|
7192
7177
|
return;
|
|
7193
7178
|
}
|
|
7194
7179
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
@@ -7608,6 +7593,17 @@ async function main() {
|
|
|
7608
7593
|
persistContinuityDefaults({ workspace: result.workspace });
|
|
7609
7594
|
printWorkspace(result.workspace);
|
|
7610
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
|
+
});
|
|
7611
7607
|
program.command("doctor").description("Verify local OrgX surface config and optional remote setup status.").action(async () => {
|
|
7612
7608
|
const spinner = createOrgxSpinner("Running OrgX health check");
|
|
7613
7609
|
spinner.start();
|