@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 +689 -665
- 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 });
|
|
@@ -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: "
|
|
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: "
|
|
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
|
|
5081
|
+
hint: "Finish surface setup without touching workspaces."
|
|
5098
5082
|
}
|
|
5099
5083
|
],
|
|
5100
|
-
initialValue:
|
|
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:
|
|
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.
|
|
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)").
|
|
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
|
|
7172
|
+
const intentResult = await maybeCaptureSetupIntent({
|
|
7159
7173
|
interactive,
|
|
7160
|
-
openInBrowser: Boolean(options.open),
|
|
7161
7174
|
workspace: resolvedWorkspace
|
|
7162
7175
|
});
|
|
7163
|
-
if (
|
|
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();
|