@useorgx/wizard 0.1.20 → 0.1.22
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 +1286 -642
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import * as clack from "@clack/prompts";
|
|
5
5
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
6
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6
7
|
import { hostname } from "os";
|
|
8
|
+
import { resolve } from "path";
|
|
7
9
|
import { Command } from "commander";
|
|
8
10
|
import pc3 from "picocolors";
|
|
9
11
|
|
|
@@ -791,7 +793,7 @@ function parsePairingPollResult(value) {
|
|
|
791
793
|
};
|
|
792
794
|
}
|
|
793
795
|
function sleep(ms) {
|
|
794
|
-
return new Promise((
|
|
796
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
795
797
|
}
|
|
796
798
|
async function startBrowserPairing(options, fetchImpl) {
|
|
797
799
|
const data = await fetchJson({
|
|
@@ -904,12 +906,12 @@ h1{font-size:1.5rem;color:#b91c1c}p{color:#555;margin-top:.5rem}</style>
|
|
|
904
906
|
<p>Return to your terminal and try again.</p>
|
|
905
907
|
</div></body></html>`;
|
|
906
908
|
function tryListen(port, hostname2) {
|
|
907
|
-
return new Promise((
|
|
909
|
+
return new Promise((resolve2, reject) => {
|
|
908
910
|
const server = createServer();
|
|
909
911
|
server.once("error", reject);
|
|
910
912
|
server.listen(port, hostname2, () => {
|
|
911
913
|
server.removeListener("error", reject);
|
|
912
|
-
|
|
914
|
+
resolve2(server);
|
|
913
915
|
});
|
|
914
916
|
});
|
|
915
917
|
}
|
|
@@ -938,7 +940,7 @@ async function startLocalAuthServer(options) {
|
|
|
938
940
|
const successHtml = options.successHtml ?? DEFAULT_SUCCESS_HTML;
|
|
939
941
|
const errorHtml = options.errorHtml ?? DEFAULT_ERROR_HTML;
|
|
940
942
|
const { server, port } = await bindServer(options.preferredPort, hostname2);
|
|
941
|
-
const result = new Promise((
|
|
943
|
+
const result = new Promise((resolve2, reject) => {
|
|
942
944
|
const timer = setTimeout(() => {
|
|
943
945
|
server.close();
|
|
944
946
|
reject(new Error("Timed out waiting for browser authorization."));
|
|
@@ -981,7 +983,7 @@ async function startLocalAuthServer(options) {
|
|
|
981
983
|
res.writeHead(200, { "Content-Type": "text/html" }).end(successHtml);
|
|
982
984
|
clearTimeout(timer);
|
|
983
985
|
server.close();
|
|
984
|
-
|
|
986
|
+
resolve2({ code, state });
|
|
985
987
|
});
|
|
986
988
|
});
|
|
987
989
|
return { port, result };
|
|
@@ -1389,28 +1391,6 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
|
1389
1391
|
if (peopleFirstCapture !== void 0) state.peopleFirstCapture = peopleFirstCapture;
|
|
1390
1392
|
return state;
|
|
1391
1393
|
}
|
|
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
1394
|
function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
|
|
1415
1395
|
const record = sanitizeWizardStateRecord(value);
|
|
1416
1396
|
writeJsonFile(statePath, record, { mode: 384 });
|
|
@@ -4457,7 +4437,7 @@ function formatCommandFailure(command, args, result) {
|
|
|
4457
4437
|
return `${command} ${args.join(" ")} failed${result.exitCode >= 0 ? ` with exit code ${result.exitCode}` : ""}${detail ? `: ${detail}` : "."}`;
|
|
4458
4438
|
}
|
|
4459
4439
|
async function defaultCommandRunner(command, args) {
|
|
4460
|
-
return await new Promise((
|
|
4440
|
+
return await new Promise((resolve2) => {
|
|
4461
4441
|
const child = spawn(command, [...args], {
|
|
4462
4442
|
env: process.env,
|
|
4463
4443
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4472,7 +4452,7 @@ async function defaultCommandRunner(command, args) {
|
|
|
4472
4452
|
});
|
|
4473
4453
|
child.on("error", (error) => {
|
|
4474
4454
|
const errorCode = typeof error === "object" && error && "code" in error ? String(error.code) : void 0;
|
|
4475
|
-
|
|
4455
|
+
resolve2({
|
|
4476
4456
|
exitCode: -1,
|
|
4477
4457
|
stdout,
|
|
4478
4458
|
stderr,
|
|
@@ -4480,7 +4460,7 @@ async function defaultCommandRunner(command, args) {
|
|
|
4480
4460
|
});
|
|
4481
4461
|
});
|
|
4482
4462
|
child.on("close", (code) => {
|
|
4483
|
-
|
|
4463
|
+
resolve2({
|
|
4484
4464
|
exitCode: code ?? -1,
|
|
4485
4465
|
stdout,
|
|
4486
4466
|
stderr
|
|
@@ -5403,7 +5383,357 @@ async function trackWizardTelemetry(event, properties = {}, options = {}) {
|
|
|
5403
5383
|
return response?.ok === true;
|
|
5404
5384
|
}
|
|
5405
5385
|
|
|
5386
|
+
// src/lib/intents.ts
|
|
5387
|
+
var AGENT_SLUGS = [
|
|
5388
|
+
"mark",
|
|
5389
|
+
"eli",
|
|
5390
|
+
"dana",
|
|
5391
|
+
"pace",
|
|
5392
|
+
"sage",
|
|
5393
|
+
"orion",
|
|
5394
|
+
"xandy"
|
|
5395
|
+
];
|
|
5396
|
+
var INTENT_STATUSES = [
|
|
5397
|
+
"pending",
|
|
5398
|
+
"approved",
|
|
5399
|
+
"adjusted",
|
|
5400
|
+
"archived"
|
|
5401
|
+
];
|
|
5402
|
+
var AGENT_ROLES = {
|
|
5403
|
+
mark: "Partnerships",
|
|
5404
|
+
eli: "Engineering",
|
|
5405
|
+
dana: "Brand",
|
|
5406
|
+
pace: "Product",
|
|
5407
|
+
sage: "Strategy",
|
|
5408
|
+
orion: "Routing",
|
|
5409
|
+
xandy: "Default"
|
|
5410
|
+
};
|
|
5411
|
+
var CONFIDENCE_DECIMAL = {
|
|
5412
|
+
low: 0.55,
|
|
5413
|
+
med: 0.78,
|
|
5414
|
+
high: 0.92
|
|
5415
|
+
};
|
|
5416
|
+
var AGENT_ANSI_256 = {
|
|
5417
|
+
pace: 34,
|
|
5418
|
+
// green
|
|
5419
|
+
eli: 44,
|
|
5420
|
+
// cyan
|
|
5421
|
+
mark: 208,
|
|
5422
|
+
// orange
|
|
5423
|
+
sage: 135,
|
|
5424
|
+
// purple
|
|
5425
|
+
orion: 214,
|
|
5426
|
+
// amber
|
|
5427
|
+
dana: 199,
|
|
5428
|
+
// pink
|
|
5429
|
+
xandy: 37
|
|
5430
|
+
// teal
|
|
5431
|
+
};
|
|
5432
|
+
function parseAgentSlug(value) {
|
|
5433
|
+
if (typeof value !== "string") return null;
|
|
5434
|
+
return AGENT_SLUGS.includes(value) ? value : null;
|
|
5435
|
+
}
|
|
5436
|
+
function parseStatus(value) {
|
|
5437
|
+
if (typeof value !== "string") return null;
|
|
5438
|
+
return INTENT_STATUSES.includes(value) ? value : null;
|
|
5439
|
+
}
|
|
5440
|
+
function parseConfidence(value) {
|
|
5441
|
+
if (value === "low" || value === "med" || value === "high") return value;
|
|
5442
|
+
return "med";
|
|
5443
|
+
}
|
|
5444
|
+
function parsePlanStep(value) {
|
|
5445
|
+
if (!isRecord(value)) return null;
|
|
5446
|
+
const title = typeof value.title === "string" ? value.title.trim() : "";
|
|
5447
|
+
if (!title) return null;
|
|
5448
|
+
const detail = typeof value.detail === "string" && value.detail.trim().length > 0 ? value.detail : void 0;
|
|
5449
|
+
const agentSlug = parseAgentSlug(value.agent_slug);
|
|
5450
|
+
const step = { title };
|
|
5451
|
+
if (detail !== void 0) step.detail = detail;
|
|
5452
|
+
if (agentSlug !== null) step.agent_slug = agentSlug;
|
|
5453
|
+
return step;
|
|
5454
|
+
}
|
|
5455
|
+
function parsePlanPreview(value) {
|
|
5456
|
+
if (!isRecord(value)) {
|
|
5457
|
+
return { steps: [], eta: "under a week", confidence: "med" };
|
|
5458
|
+
}
|
|
5459
|
+
const steps = Array.isArray(value.steps) ? value.steps.map(parsePlanStep).filter((step) => step !== null) : [];
|
|
5460
|
+
const eta = typeof value.eta === "string" && value.eta.trim().length > 0 ? value.eta : "under a week";
|
|
5461
|
+
return {
|
|
5462
|
+
steps,
|
|
5463
|
+
eta,
|
|
5464
|
+
confidence: parseConfidence(value.confidence)
|
|
5465
|
+
};
|
|
5466
|
+
}
|
|
5467
|
+
function parseIntent(value) {
|
|
5468
|
+
if (!isRecord(value)) return null;
|
|
5469
|
+
const id = typeof value.id === "string" ? value.id : null;
|
|
5470
|
+
const workspaceId = typeof value.workspace_id === "string" ? value.workspace_id : null;
|
|
5471
|
+
const slug = typeof value.slug === "string" ? value.slug : null;
|
|
5472
|
+
const text2 = typeof value.text === "string" ? value.text : null;
|
|
5473
|
+
const status = parseStatus(value.status);
|
|
5474
|
+
const createdAt = typeof value.created_at === "string" ? value.created_at : null;
|
|
5475
|
+
const updatedAt = typeof value.updated_at === "string" ? value.updated_at : null;
|
|
5476
|
+
if (!id || !workspaceId || !slug || !text2 || !status || !createdAt || !updatedAt) {
|
|
5477
|
+
return null;
|
|
5478
|
+
}
|
|
5479
|
+
return {
|
|
5480
|
+
id,
|
|
5481
|
+
workspace_id: workspaceId,
|
|
5482
|
+
slug,
|
|
5483
|
+
text: text2,
|
|
5484
|
+
status,
|
|
5485
|
+
suggested_agent_slug: parseAgentSlug(value.suggested_agent_slug),
|
|
5486
|
+
plan_preview: parsePlanPreview(value.plan_preview),
|
|
5487
|
+
approved_at: typeof value.approved_at === "string" ? value.approved_at : null,
|
|
5488
|
+
created_at: createdAt,
|
|
5489
|
+
updated_at: updatedAt
|
|
5490
|
+
};
|
|
5491
|
+
}
|
|
5492
|
+
async function parseResponseBody4(response) {
|
|
5493
|
+
const text2 = await response.text();
|
|
5494
|
+
if (!text2) return null;
|
|
5495
|
+
try {
|
|
5496
|
+
return JSON.parse(text2);
|
|
5497
|
+
} catch {
|
|
5498
|
+
return text2;
|
|
5499
|
+
}
|
|
5500
|
+
}
|
|
5501
|
+
function formatHttpError3(status, body) {
|
|
5502
|
+
if (typeof body === "string" && body.trim().length > 0) {
|
|
5503
|
+
return `HTTP ${status}: ${body}`;
|
|
5504
|
+
}
|
|
5505
|
+
if (isRecord(body)) {
|
|
5506
|
+
if (isRecord(body.error)) {
|
|
5507
|
+
const message = typeof body.error.message === "string" ? body.error.message : null;
|
|
5508
|
+
const code = typeof body.error.code === "string" ? body.error.code : null;
|
|
5509
|
+
if (message) return `HTTP ${status} (${code ?? "error"}): ${message}`;
|
|
5510
|
+
}
|
|
5511
|
+
if (typeof body.error === "string" && body.error.trim().length > 0) {
|
|
5512
|
+
return `HTTP ${status}: ${body.error}`;
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
return `HTTP ${status}`;
|
|
5516
|
+
}
|
|
5517
|
+
async function requireOrgxAuth3(options = {}) {
|
|
5518
|
+
const auth = await resolveOrgxAuth(options);
|
|
5519
|
+
if (!auth) {
|
|
5520
|
+
throw new Error(
|
|
5521
|
+
"No OrgX API key configured. Run `orgx-wizard auth login` or `orgx-wizard auth set-key <oxk_...>` first."
|
|
5522
|
+
);
|
|
5523
|
+
}
|
|
5524
|
+
return auth;
|
|
5525
|
+
}
|
|
5526
|
+
async function createIntent(input, options = {}) {
|
|
5527
|
+
const text2 = input.text.trim();
|
|
5528
|
+
if (!text2) {
|
|
5529
|
+
throw new Error("Intent text is required.");
|
|
5530
|
+
}
|
|
5531
|
+
if (text2.length > 4e3) {
|
|
5532
|
+
throw new Error("Intent text exceeds 4,000 characters.");
|
|
5533
|
+
}
|
|
5534
|
+
const workspaceId = input.workspace_id.trim();
|
|
5535
|
+
if (!workspaceId) {
|
|
5536
|
+
throw new Error("Workspace id is required.");
|
|
5537
|
+
}
|
|
5538
|
+
const auth = await requireOrgxAuth3(options);
|
|
5539
|
+
const url = buildOrgxApiUrl("/v1/intents", auth.baseUrl);
|
|
5540
|
+
const response = await fetch(url, {
|
|
5541
|
+
method: "POST",
|
|
5542
|
+
headers: {
|
|
5543
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
5544
|
+
"Content-Type": "application/json"
|
|
5545
|
+
},
|
|
5546
|
+
body: JSON.stringify({ workspace_id: workspaceId, text: text2 }),
|
|
5547
|
+
signal: AbortSignal.timeout(15e3)
|
|
5548
|
+
});
|
|
5549
|
+
const body = await parseResponseBody4(response);
|
|
5550
|
+
if (!response.ok) {
|
|
5551
|
+
throw new Error(
|
|
5552
|
+
`Failed to create intent. ${formatHttpError3(response.status, body)}`
|
|
5553
|
+
);
|
|
5554
|
+
}
|
|
5555
|
+
const intent = parseIntent(body);
|
|
5556
|
+
if (!intent) {
|
|
5557
|
+
throw new Error("OrgX returned an unexpected intent payload.");
|
|
5558
|
+
}
|
|
5559
|
+
return intent;
|
|
5560
|
+
}
|
|
5561
|
+
async function updateIntent(id, input, options = {}) {
|
|
5562
|
+
const trimmedId = id.trim();
|
|
5563
|
+
if (!trimmedId) {
|
|
5564
|
+
throw new Error("Intent id is required.");
|
|
5565
|
+
}
|
|
5566
|
+
const auth = await requireOrgxAuth3(options);
|
|
5567
|
+
const url = buildOrgxApiUrl(`/v1/intents/${encodeURIComponent(trimmedId)}`, auth.baseUrl);
|
|
5568
|
+
const response = await fetch(url, {
|
|
5569
|
+
method: "PATCH",
|
|
5570
|
+
headers: {
|
|
5571
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
5572
|
+
"Content-Type": "application/json"
|
|
5573
|
+
},
|
|
5574
|
+
body: JSON.stringify(input),
|
|
5575
|
+
signal: AbortSignal.timeout(15e3)
|
|
5576
|
+
});
|
|
5577
|
+
const body = await parseResponseBody4(response);
|
|
5578
|
+
if (!response.ok) {
|
|
5579
|
+
throw new Error(
|
|
5580
|
+
`Failed to update intent. ${formatHttpError3(response.status, body)}`
|
|
5581
|
+
);
|
|
5582
|
+
}
|
|
5583
|
+
const intent = parseIntent(body);
|
|
5584
|
+
if (!intent) {
|
|
5585
|
+
throw new Error("OrgX returned an unexpected intent update payload.");
|
|
5586
|
+
}
|
|
5587
|
+
return intent;
|
|
5588
|
+
}
|
|
5589
|
+
function buildIntentHandoffUrl(slug, options = {}) {
|
|
5590
|
+
const base = options.baseUrl?.trim() || "https://useorgx.com";
|
|
5591
|
+
const normalized = base.replace(/\/+$/, "");
|
|
5592
|
+
return `${normalized}/command?intent=${encodeURIComponent(slug)}`;
|
|
5593
|
+
}
|
|
5594
|
+
|
|
5595
|
+
// src/lib/intent-render.ts
|
|
5596
|
+
function detectRenderCapabilities(env = process.env) {
|
|
5597
|
+
const noColor = Boolean(env.NO_COLOR && env.NO_COLOR.length > 0);
|
|
5598
|
+
const asciiOnly = (env.LC_ALL ?? "").toUpperCase() === "C" || (env.LANG ?? "").toUpperCase() === "C";
|
|
5599
|
+
return { noColor, asciiOnly };
|
|
5600
|
+
}
|
|
5601
|
+
function isInteractive(env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
|
|
5602
|
+
if (!isTTY) return false;
|
|
5603
|
+
if (env.CI === "1" || env.CI === "true") return false;
|
|
5604
|
+
if (env.GITHUB_ACTIONS === "true") return false;
|
|
5605
|
+
return true;
|
|
5606
|
+
}
|
|
5607
|
+
var CSI = "\x1B[";
|
|
5608
|
+
function wrap(code, text2, enabled) {
|
|
5609
|
+
if (!enabled) return text2;
|
|
5610
|
+
return `${CSI}${code}m${text2}${CSI}0m`;
|
|
5611
|
+
}
|
|
5612
|
+
function colorize(text2, ansi256, options = {}) {
|
|
5613
|
+
return wrap(`38;5;${ansi256}`, text2, !options.noColor);
|
|
5614
|
+
}
|
|
5615
|
+
function bold(text2, options = {}) {
|
|
5616
|
+
return wrap("1", text2, !options.noColor);
|
|
5617
|
+
}
|
|
5618
|
+
function dim(text2, options = {}) {
|
|
5619
|
+
return wrap("2", text2, !options.noColor);
|
|
5620
|
+
}
|
|
5621
|
+
function formatConfidence(value) {
|
|
5622
|
+
const bounded = Math.max(0, Math.min(1, value));
|
|
5623
|
+
return bounded.toFixed(2);
|
|
5624
|
+
}
|
|
5625
|
+
function renderRoutingLine(agent, confidence, options = {}) {
|
|
5626
|
+
const arrow = options.asciiOnly ? "->" : "\u2192";
|
|
5627
|
+
const separator = options.asciiOnly ? " - " : " \xB7 ";
|
|
5628
|
+
const role = AGENT_ROLES[agent];
|
|
5629
|
+
const name = agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
5630
|
+
const coloredName = colorize(name, AGENT_ANSI_256[agent], options);
|
|
5631
|
+
const confidenceLabel = dim("confidence", options);
|
|
5632
|
+
const confidenceValue = formatConfidence(confidence);
|
|
5633
|
+
return ` ${arrow} ${bold(coloredName, options)}${separator}${role} ${confidenceLabel} ${confidenceValue}`;
|
|
5634
|
+
}
|
|
5635
|
+
function resolveConfidenceDecimal(plan) {
|
|
5636
|
+
return CONFIDENCE_DECIMAL[plan.confidence];
|
|
5637
|
+
}
|
|
5638
|
+
function renderPlanPreview(plan, options = {}) {
|
|
5639
|
+
const horizontal = options.asciiOnly ? "-" : "\u2500";
|
|
5640
|
+
const topLeft = options.asciiOnly ? "+" : "\u250C";
|
|
5641
|
+
const topRight = options.asciiOnly ? "+" : "\u2510";
|
|
5642
|
+
const bottomLeft = options.asciiOnly ? "+" : "\u2514";
|
|
5643
|
+
const bottomRight = options.asciiOnly ? "+" : "\u2518";
|
|
5644
|
+
const vertical = options.asciiOnly ? "|" : "\u2502";
|
|
5645
|
+
const steps = plan.steps.map((step, index) => {
|
|
5646
|
+
const number = `${index + 1}.`.padEnd(3, " ");
|
|
5647
|
+
return `${number} ${step.title}`;
|
|
5648
|
+
});
|
|
5649
|
+
const etaLine = `ETA ${plan.eta}`;
|
|
5650
|
+
const lines = [...steps, "", etaLine];
|
|
5651
|
+
const label = "Plan preview";
|
|
5652
|
+
const contentWidth = Math.max(
|
|
5653
|
+
// Keep enough room for the top-chrome label plus its "─ " prefix and
|
|
5654
|
+
// a minimum trailing dash so the border visually wraps the label.
|
|
5655
|
+
label.length + 4,
|
|
5656
|
+
...lines.map((line) => line.length)
|
|
5657
|
+
);
|
|
5658
|
+
const innerWidth = contentWidth + 2;
|
|
5659
|
+
const leadingDashes = horizontal.repeat(1);
|
|
5660
|
+
const trailingDashes = horizontal.repeat(
|
|
5661
|
+
Math.max(1, innerWidth - label.length - 3)
|
|
5662
|
+
// leading dash + 2 spaces
|
|
5663
|
+
);
|
|
5664
|
+
const top = `${topLeft}${leadingDashes} ${label} ${trailingDashes}${topRight}`;
|
|
5665
|
+
const body = lines.map((line) => {
|
|
5666
|
+
const padded = line.padEnd(contentWidth, " ");
|
|
5667
|
+
return `${vertical} ${padded} ${vertical}`;
|
|
5668
|
+
}).join("\n");
|
|
5669
|
+
const bottom = `${bottomLeft}${horizontal.repeat(innerWidth)}${bottomRight}`;
|
|
5670
|
+
return [top, body, bottom].join("\n");
|
|
5671
|
+
}
|
|
5672
|
+
var TONE_ANSI = {
|
|
5673
|
+
primary: 190,
|
|
5674
|
+
// lime (--ox-primary)
|
|
5675
|
+
warning: 214,
|
|
5676
|
+
// amber (adjust)
|
|
5677
|
+
danger: 203,
|
|
5678
|
+
// rose (archive)
|
|
5679
|
+
neutral: 244
|
|
5680
|
+
// bright black (quit)
|
|
5681
|
+
};
|
|
5682
|
+
function renderHotkeyBar(entries, options = {}) {
|
|
5683
|
+
const prefix = options.asciiOnly ? ">>" : ">>";
|
|
5684
|
+
const segments = entries.map((entry) => {
|
|
5685
|
+
const tone = entry.tone ?? "neutral";
|
|
5686
|
+
const keyLabel = `[${entry.key.toUpperCase()}]`;
|
|
5687
|
+
const coloredKey = colorize(keyLabel, TONE_ANSI[tone], options);
|
|
5688
|
+
return `${coloredKey}${entry.label}`;
|
|
5689
|
+
});
|
|
5690
|
+
return `${prefix} ${segments.join(" ")}`;
|
|
5691
|
+
}
|
|
5692
|
+
var DEFAULT_HOTKEYS = [
|
|
5693
|
+
{ key: "a", label: "pprove", tone: "primary" },
|
|
5694
|
+
{ key: "e", label: "dit in browser", tone: "warning" },
|
|
5695
|
+
{ key: "x", label: "archive", tone: "danger" },
|
|
5696
|
+
{ key: "q", label: "uit", tone: "neutral" }
|
|
5697
|
+
];
|
|
5698
|
+
function normalizeHotkey(input) {
|
|
5699
|
+
const trimmed = input.trim().toLowerCase();
|
|
5700
|
+
if (trimmed.length === 0) return null;
|
|
5701
|
+
const ch = trimmed.charAt(0);
|
|
5702
|
+
switch (ch) {
|
|
5703
|
+
case "a":
|
|
5704
|
+
return "approve";
|
|
5705
|
+
case "e":
|
|
5706
|
+
return "edit";
|
|
5707
|
+
case "x":
|
|
5708
|
+
return "archive";
|
|
5709
|
+
case "q":
|
|
5710
|
+
return "quit";
|
|
5711
|
+
default:
|
|
5712
|
+
return null;
|
|
5713
|
+
}
|
|
5714
|
+
}
|
|
5715
|
+
|
|
5406
5716
|
// src/lib/daily-brief-onboarding.ts
|
|
5717
|
+
function extractErrorHint(body) {
|
|
5718
|
+
if (!body) return null;
|
|
5719
|
+
let parsed;
|
|
5720
|
+
try {
|
|
5721
|
+
parsed = JSON.parse(body);
|
|
5722
|
+
} catch {
|
|
5723
|
+
return body.slice(0, 160);
|
|
5724
|
+
}
|
|
5725
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
5726
|
+
const obj = parsed;
|
|
5727
|
+
const err = obj.error;
|
|
5728
|
+
if (typeof err === "string") return err;
|
|
5729
|
+
if (err && typeof err === "object") {
|
|
5730
|
+
const message = err.message;
|
|
5731
|
+
if (typeof message === "string") return message;
|
|
5732
|
+
const code = err.code;
|
|
5733
|
+
if (typeof code === "string") return code;
|
|
5734
|
+
}
|
|
5735
|
+
return null;
|
|
5736
|
+
}
|
|
5407
5737
|
var BASELINE_PROMPTS = [
|
|
5408
5738
|
{ task_type: "code_review", label: "Code review", placeholder: "20" },
|
|
5409
5739
|
{ task_type: "prd_draft", label: "PRD draft", placeholder: "45" },
|
|
@@ -5563,9 +5893,10 @@ async function runDailyBriefOnboarding(options) {
|
|
|
5563
5893
|
});
|
|
5564
5894
|
if (!commitResponse.ok) {
|
|
5565
5895
|
const text2 = await commitResponse.text().catch(() => "");
|
|
5896
|
+
const hint = extractErrorHint(text2) ?? `HTTP ${commitResponse.status}`;
|
|
5566
5897
|
return {
|
|
5567
5898
|
status: "failed",
|
|
5568
|
-
message:
|
|
5899
|
+
message: `Could not commit onboarding capture \u2014 ${hint}`,
|
|
5569
5900
|
error: `HTTP ${commitResponse.status}: ${text2.slice(0, 200)}`
|
|
5570
5901
|
};
|
|
5571
5902
|
}
|
|
@@ -5596,534 +5927,501 @@ async function fetchOnboardingState(auth) {
|
|
|
5596
5927
|
}
|
|
5597
5928
|
}
|
|
5598
5929
|
|
|
5599
|
-
// src/lib/
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5930
|
+
// src/lib/self-audit.ts
|
|
5931
|
+
import { createHash as createHash3 } from "crypto";
|
|
5932
|
+
var SELF_AUDIT_SCHEMA_VERSION = "2026-04-27";
|
|
5933
|
+
var AUDIT_DIMENSIONS = [
|
|
5934
|
+
"queryability",
|
|
5935
|
+
"proof_density",
|
|
5936
|
+
"loop_closure",
|
|
5937
|
+
"context_debt",
|
|
5938
|
+
"autonomy_readiness",
|
|
5939
|
+
"roi_visibility"
|
|
5608
5940
|
];
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5941
|
+
function clampScore(value) {
|
|
5942
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
5943
|
+
}
|
|
5944
|
+
function ratio(numerator, denominator, fallback = 0) {
|
|
5945
|
+
if (denominator <= 0) return fallback;
|
|
5946
|
+
return numerator / denominator;
|
|
5947
|
+
}
|
|
5948
|
+
function includesAny(value, patterns) {
|
|
5949
|
+
return patterns.some((pattern) => pattern.test(value));
|
|
5950
|
+
}
|
|
5951
|
+
function classifyLine(line) {
|
|
5952
|
+
const normalized = line.trim();
|
|
5953
|
+
if (!normalized) return null;
|
|
5954
|
+
if (/^(decision|decided|we decided|d:)\b/i.test(normalized)) return "decision";
|
|
5955
|
+
if (/^(commitment|committed|promise|promised|todo:|we will)\b/i.test(normalized)) return "commitment";
|
|
5956
|
+
if (/^(artifact|receipt|proof|shipped|implemented|commit|pr:)\b/i.test(normalized)) return "artifact";
|
|
5957
|
+
if (/^(open loop|gap|blocker|risk|missing|needs|unresolved)\b/i.test(normalized)) return "open_loop";
|
|
5958
|
+
if (/^(next action|follow[- ]?up|next step|action:)\b/i.test(normalized)) return "next_action";
|
|
5959
|
+
if (/^(outcome|result|impact|metric|adoption)\b/i.test(normalized)) return "outcome";
|
|
5960
|
+
if (/^(roi|economics|token|tokens|cost|saved|time saved|api bill)\b/i.test(normalized)) return "economics";
|
|
5961
|
+
return null;
|
|
5962
|
+
}
|
|
5963
|
+
function extractFounderLoopItems(imports) {
|
|
5964
|
+
const items = [];
|
|
5965
|
+
for (const source of imports) {
|
|
5966
|
+
const lines = source.text.split(/\r?\n/);
|
|
5967
|
+
lines.forEach((line, index) => {
|
|
5968
|
+
const type = classifyLine(line);
|
|
5969
|
+
if (!type) return;
|
|
5970
|
+
const lineNumber = index + 1;
|
|
5971
|
+
items.push({
|
|
5972
|
+
evidenceRef: `${source.sourceId}:L${lineNumber}`,
|
|
5973
|
+
lineNumber,
|
|
5974
|
+
sourceId: source.sourceId,
|
|
5975
|
+
sourceLabel: source.sourceLabel,
|
|
5976
|
+
text: line.trim(),
|
|
5977
|
+
type
|
|
5978
|
+
});
|
|
5979
|
+
});
|
|
5630
5980
|
}
|
|
5981
|
+
return items;
|
|
5982
|
+
}
|
|
5983
|
+
function buildSelfAuditSignals(imports, items, options = {}) {
|
|
5984
|
+
const allText = imports.map((source) => source.text).join("\n");
|
|
5985
|
+
const lower = allText.toLowerCase();
|
|
5986
|
+
const decisions = items.filter((item) => item.type === "decision");
|
|
5987
|
+
const artifacts = items.filter((item) => item.type === "artifact");
|
|
5988
|
+
const commitments = items.filter((item) => item.type === "commitment");
|
|
5989
|
+
const nextActions = items.filter((item) => item.type === "next_action");
|
|
5990
|
+
const outcomes = items.filter((item) => item.type === "outcome");
|
|
5991
|
+
const economics = items.filter((item) => item.type === "economics");
|
|
5992
|
+
const proofMentions = (lower.match(/\b(proof|verified|verification|receipt|quality score|artifact)\b/g) ?? []).length;
|
|
5993
|
+
const ownerMentions = (lower.match(/\b(owner|dri|responsible|agent:|founder)\b/g) ?? []).length;
|
|
5994
|
+
const artifactNextActionMentions = artifacts.filter(
|
|
5995
|
+
(item) => includesAny(item.text.toLowerCase(), [/\bnext action\b/, /\bfollow[- ]?up\b/, /\brollback\b/])
|
|
5996
|
+
).length;
|
|
5997
|
+
const writebackMentions = (lower.match(/\b(approve|approved|writeback|rollback|create task|follow-up task)\b/g) ?? []).length;
|
|
5998
|
+
const repeatedContextPrompts = (lower.match(/\b(recap|catch you up|context again|restate|reread|remind me)\b/g) ?? []).length;
|
|
5999
|
+
return {
|
|
6000
|
+
approvedWritebackTargets: Math.min(3, writebackMentions),
|
|
6001
|
+
artifactsWithNextActions: Math.min(artifacts.length, nextActions.length + artifactNextActionMentions),
|
|
6002
|
+
artifactsWithOwners: Math.min(artifacts.length, ownerMentions),
|
|
6003
|
+
completedWorkItems: artifacts.length,
|
|
6004
|
+
completedWorkWithProof: Math.min(artifacts.length, proofMentions),
|
|
6005
|
+
connectedSources: Math.max(options.connectedSources?.length ?? 0, imports.length),
|
|
6006
|
+
decisionsWithEvidence: decisions.length,
|
|
6007
|
+
economicSignals: economics.length + (lower.includes("token") || lower.includes("cost") || lower.includes("saved") ? 1 : 0),
|
|
6008
|
+
missingSources: options.missingSources?.length ?? 0,
|
|
6009
|
+
openLoops: items.filter((item) => item.type === "open_loop").length,
|
|
6010
|
+
outcomeLinkedItems: outcomes.length,
|
|
6011
|
+
repeatedContextPrompts,
|
|
6012
|
+
totalArtifacts: artifacts.length,
|
|
6013
|
+
totalContextItems: Math.max(items.length, allText.split(/\s+/).filter(Boolean).length),
|
|
6014
|
+
totalDecisions: decisions.length,
|
|
6015
|
+
unresolvedCommitments: Math.max(0, commitments.length - nextActions.length - outcomes.length)
|
|
6016
|
+
};
|
|
5631
6017
|
}
|
|
5632
|
-
function
|
|
5633
|
-
const
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
6018
|
+
function scoreSelfAudit(signals) {
|
|
6019
|
+
const queryability = clampScore(
|
|
6020
|
+
30 + ratio(signals.decisionsWithEvidence, Math.max(1, signals.totalDecisions), 0) * 25 + Math.min(20, signals.connectedSources * 5) + Math.min(30, (signals.totalArtifacts + signals.outcomeLinkedItems + signals.approvedWritebackTargets) * 5)
|
|
6021
|
+
);
|
|
6022
|
+
const proofDensity = clampScore(
|
|
6023
|
+
30 + ratio(signals.completedWorkWithProof, Math.max(1, signals.completedWorkItems), 0) * 35 + ratio(signals.artifactsWithOwners, Math.max(1, signals.totalArtifacts), 0) * 20 + ratio(signals.artifactsWithNextActions, Math.max(1, signals.totalArtifacts), 0) * 15
|
|
6024
|
+
);
|
|
6025
|
+
const loopClosure = clampScore(
|
|
6026
|
+
40 + Math.min(25, signals.outcomeLinkedItems * 25) + Math.min(35, signals.approvedWritebackTargets * 20) + (signals.openLoops === 0 ? 15 : Math.max(0, 15 - signals.openLoops * 3))
|
|
6027
|
+
);
|
|
6028
|
+
const contextDebt = clampScore(
|
|
6029
|
+
100 - Math.min(35, signals.repeatedContextPrompts * 10) - Math.min(35, signals.openLoops * 6) - Math.min(20, signals.missingSources * 4) - Math.min(10, signals.unresolvedCommitments * 3)
|
|
6030
|
+
);
|
|
6031
|
+
const autonomyReadiness = clampScore(
|
|
6032
|
+
35 + Math.min(30, signals.approvedWritebackTargets * 15) + Math.min(20, signals.completedWorkWithProof * 5) + (signals.openLoops <= 1 ? 15 : 5)
|
|
6033
|
+
);
|
|
6034
|
+
const roiVisibility = clampScore(
|
|
6035
|
+
30 + Math.min(40, signals.economicSignals * 18) + Math.min(25, signals.outcomeLinkedItems * 25) + Math.min(10, signals.completedWorkWithProof * 3)
|
|
6036
|
+
);
|
|
6037
|
+
return {
|
|
6038
|
+
autonomy_readiness: autonomyReadiness,
|
|
6039
|
+
context_debt: contextDebt,
|
|
6040
|
+
loop_closure: loopClosure,
|
|
6041
|
+
proof_density: proofDensity,
|
|
6042
|
+
queryability,
|
|
6043
|
+
roi_visibility: roiVisibility
|
|
6044
|
+
};
|
|
6045
|
+
}
|
|
6046
|
+
function buildFindings(scores, signals) {
|
|
6047
|
+
const findings = [];
|
|
6048
|
+
for (const dimension of AUDIT_DIMENSIONS) {
|
|
6049
|
+
const score = scores[dimension];
|
|
6050
|
+
if (score >= 95) {
|
|
6051
|
+
findings.push({
|
|
6052
|
+
dimension,
|
|
6053
|
+
evidence: `Score ${score}/100 meets the Phase 2 target.`,
|
|
6054
|
+
recommendation: "Keep this dimension gated by evidence so the score stays earned.",
|
|
6055
|
+
severity: "info",
|
|
6056
|
+
title: `${dimension.replace(/_/g, " ")} is at the 95+ target`
|
|
6057
|
+
});
|
|
6058
|
+
continue;
|
|
5644
6059
|
}
|
|
6060
|
+
const recommendationByDimension = {
|
|
6061
|
+
autonomy_readiness: "Keep writeback approval-gated and add rollback references to every generated action.",
|
|
6062
|
+
context_debt: "Reduce repeated context prompts and close unresolved open loops with task or decision artifacts.",
|
|
6063
|
+
loop_closure: "Add outcome references and approved follow-up writebacks so planning changes after execution.",
|
|
6064
|
+
proof_density: "Attach owners, next actions, and verification proof to every completed work artifact.",
|
|
6065
|
+
queryability: "Add cited decisions, artifacts, connected sources, and retrieval scope to the audit output.",
|
|
6066
|
+
roi_visibility: "Add token/time/cost evidence plus an outcome review so ROI is not a narrative claim."
|
|
6067
|
+
};
|
|
6068
|
+
findings.push({
|
|
6069
|
+
dimension,
|
|
6070
|
+
evidence: `Score ${score}/100. Signals: ${JSON.stringify({
|
|
6071
|
+
approvedWritebackTargets: signals.approvedWritebackTargets,
|
|
6072
|
+
completedWorkWithProof: signals.completedWorkWithProof,
|
|
6073
|
+
economicSignals: signals.economicSignals,
|
|
6074
|
+
openLoops: signals.openLoops,
|
|
6075
|
+
outcomeLinkedItems: signals.outcomeLinkedItems,
|
|
6076
|
+
repeatedContextPrompts: signals.repeatedContextPrompts
|
|
6077
|
+
})}`,
|
|
6078
|
+
recommendation: recommendationByDimension[dimension],
|
|
6079
|
+
severity: score < 60 ? "critical" : "warning",
|
|
6080
|
+
title: `${dimension.replace(/_/g, " ")} needs evidence before it can be called 95+`
|
|
6081
|
+
});
|
|
5645
6082
|
}
|
|
5646
|
-
return
|
|
6083
|
+
return findings;
|
|
5647
6084
|
}
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
const
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
6085
|
+
function buildSelfCritique(scores) {
|
|
6086
|
+
return AUDIT_DIMENSIONS.map((dimension) => {
|
|
6087
|
+
const score = scores[dimension];
|
|
6088
|
+
return {
|
|
6089
|
+
dimension,
|
|
6090
|
+
gap: score >= 95 ? "No score gap. Preserve evidence and regression-test this dimension." : `Needs ${95 - score} more points of verified product evidence before claiming 95+.`,
|
|
6091
|
+
passed: score >= 95,
|
|
6092
|
+
score,
|
|
6093
|
+
target: 95
|
|
6094
|
+
};
|
|
6095
|
+
});
|
|
6096
|
+
}
|
|
6097
|
+
function hashPlanPayload(payload) {
|
|
6098
|
+
return createHash3("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
6099
|
+
}
|
|
6100
|
+
function buildSelfAuditPlan(input) {
|
|
6101
|
+
if (input.imports.length === 0) {
|
|
6102
|
+
throw new Error("At least one AI-session import is required to run the Founder Loop audit.");
|
|
6103
|
+
}
|
|
6104
|
+
const items = extractFounderLoopItems(input.imports);
|
|
6105
|
+
const connectedSources = input.connectedSources ?? input.imports.map((source) => source.sourceLabel);
|
|
6106
|
+
const missingSources = input.missingSources ?? [];
|
|
6107
|
+
const signals = buildSelfAuditSignals(input.imports, items, {
|
|
6108
|
+
connectedSources,
|
|
6109
|
+
missingSources
|
|
6110
|
+
});
|
|
6111
|
+
const scores = scoreSelfAudit(signals);
|
|
6112
|
+
const evidenceRefs = items.slice(0, 12).map((item) => item.evidenceRef);
|
|
6113
|
+
const decisions = items.filter((item) => item.type === "decision");
|
|
6114
|
+
const nextAction = items.find((item) => item.type === "next_action");
|
|
6115
|
+
const basePlan = {
|
|
6116
|
+
artifact_type: "ai_native_self_audit_plan",
|
|
6117
|
+
audit_scope: {
|
|
6118
|
+
connected_sources: connectedSources,
|
|
6119
|
+
loop: "founder",
|
|
6120
|
+
missing_sources: missingSources,
|
|
6121
|
+
time_window_days: input.timeWindowDays ?? 30
|
|
6122
|
+
},
|
|
6123
|
+
extracted_items: items,
|
|
6124
|
+
findings: buildFindings(scores, signals),
|
|
6125
|
+
generated_at: input.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6126
|
+
recommended_follow_up: {
|
|
6127
|
+
rollback: "Delete or close the generated OrgX follow-up task if the founder rejects the audit recommendation.",
|
|
6128
|
+
summary: nextAction?.text ?? "Review the audit findings, approve one follow-up action, and attach proof after execution.",
|
|
6129
|
+
title: "Review AI-native self-audit findings and approve first follow-up"
|
|
6130
|
+
},
|
|
6131
|
+
recommended_initiative: {
|
|
6132
|
+
summary: "Generated by @useorgx/wizard audit to close the first Founder Loop from AI-session context, proof artifacts, approved writeback, and outcome review.",
|
|
6133
|
+
title: `Close Founder Loop: ${input.workspace.name} AI-native operating loop`,
|
|
6134
|
+
workstreams: [
|
|
6135
|
+
{
|
|
6136
|
+
purpose: "Capture AI-session context, decisions, commitments, and open loops.",
|
|
6137
|
+
tasks: [
|
|
6138
|
+
{
|
|
6139
|
+
proof_requirement: "AI-session import with cited evidence references.",
|
|
6140
|
+
title: "Import founder AI-session context"
|
|
6141
|
+
}
|
|
6142
|
+
],
|
|
6143
|
+
title: "Founder Context Ingest"
|
|
6144
|
+
},
|
|
6145
|
+
{
|
|
6146
|
+
purpose: "Turn completed work into artifacts with owners, proof, and next actions.",
|
|
6147
|
+
tasks: [
|
|
6148
|
+
{
|
|
6149
|
+
proof_requirement: "Artifact metadata includes owner, evidence refs, and retrieval scope.",
|
|
6150
|
+
title: "Attach proof artifacts to completed work"
|
|
6151
|
+
}
|
|
6152
|
+
],
|
|
6153
|
+
title: "Proof Chain"
|
|
6154
|
+
},
|
|
6155
|
+
{
|
|
6156
|
+
purpose: "Write one approved follow-up action into OrgX with rollback context.",
|
|
6157
|
+
tasks: [
|
|
6158
|
+
{
|
|
6159
|
+
proof_requirement: "Approved OrgX task with rollback and evidence references.",
|
|
6160
|
+
title: "Approve first OrgX follow-up writeback"
|
|
6161
|
+
}
|
|
6162
|
+
],
|
|
6163
|
+
title: "Safe Writeback"
|
|
6164
|
+
},
|
|
6165
|
+
{
|
|
6166
|
+
purpose: "Record outcome and economics so the next plan learns from execution.",
|
|
6167
|
+
tasks: [
|
|
6168
|
+
{
|
|
6169
|
+
proof_requirement: "Founder review with time/token/value estimate and attribution confidence.",
|
|
6170
|
+
title: "Record outcome and economics review"
|
|
6171
|
+
}
|
|
6172
|
+
],
|
|
6173
|
+
title: "Outcome Review"
|
|
6174
|
+
}
|
|
6175
|
+
]
|
|
6176
|
+
},
|
|
6177
|
+
safe_writeback_plan: [
|
|
6178
|
+
{
|
|
6179
|
+
action: "create_follow_up_task",
|
|
6180
|
+
approval: "required",
|
|
6181
|
+
rollback: "Delete or close the generated task and preserve the audit artifact as a rejected recommendation.",
|
|
6182
|
+
target: "orgx"
|
|
5666
6183
|
}
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
}
|
|
5674
|
-
|
|
5675
|
-
|
|
6184
|
+
],
|
|
6185
|
+
schema_version: SELF_AUDIT_SCHEMA_VERSION,
|
|
6186
|
+
scores,
|
|
6187
|
+
self_critique: buildSelfCritique(scores),
|
|
6188
|
+
signals,
|
|
6189
|
+
workspace: input.workspace
|
|
6190
|
+
};
|
|
6191
|
+
const invariant = {
|
|
6192
|
+
decision_refs: decisions.map((item) => item.evidenceRef),
|
|
6193
|
+
evidence_refs: evidenceRefs,
|
|
6194
|
+
goal_ref: `workspace:${input.workspace.id}:ai-native-self-audit`,
|
|
6195
|
+
next_action_ref: nextAction?.evidenceRef ?? "manual-next-action:review-audit",
|
|
6196
|
+
owner_ref: "founder:dri",
|
|
6197
|
+
proof_requirement: "verification",
|
|
6198
|
+
retrieval_scope: "Retrieve the imported AI-session context, extracted Founder Loop items, audit scores, findings, writeback plan, and outcome review."
|
|
6199
|
+
};
|
|
6200
|
+
const artifactHash = hashPlanPayload({ ...basePlan, artifact_invariant: invariant });
|
|
6201
|
+
return {
|
|
6202
|
+
...basePlan,
|
|
6203
|
+
artifact_hash: artifactHash,
|
|
6204
|
+
artifact_invariant: invariant
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
function renderSelfAuditMarkdown(plan) {
|
|
6208
|
+
const lines = [
|
|
6209
|
+
"# AI-Native Founder Loop Self-Audit",
|
|
6210
|
+
"",
|
|
6211
|
+
`Generated: ${plan.generated_at}`,
|
|
6212
|
+
`Workspace: ${plan.workspace.name} (${plan.workspace.id})`,
|
|
6213
|
+
`Artifact hash: ${plan.artifact_hash}`,
|
|
6214
|
+
"",
|
|
6215
|
+
"## Scores",
|
|
6216
|
+
"",
|
|
6217
|
+
"| Dimension | Score | Target | Status |",
|
|
6218
|
+
"| --- | ---: | ---: | --- |",
|
|
6219
|
+
...AUDIT_DIMENSIONS.map((dimension) => {
|
|
6220
|
+
const score = plan.scores[dimension];
|
|
6221
|
+
return `| ${dimension.replace(/_/g, " ")} | ${score} | 95 | ${score >= 95 ? "pass" : "gap"} |`;
|
|
6222
|
+
}),
|
|
6223
|
+
"",
|
|
6224
|
+
"## Self-Critique",
|
|
6225
|
+
"",
|
|
6226
|
+
...plan.self_critique.map((item) => `- ${item.dimension}: ${item.gap}`),
|
|
6227
|
+
"",
|
|
6228
|
+
"## Findings",
|
|
6229
|
+
"",
|
|
6230
|
+
...plan.findings.map((finding) => [
|
|
6231
|
+
`### ${finding.title}`,
|
|
6232
|
+
"",
|
|
6233
|
+
`- Severity: ${finding.severity}`,
|
|
6234
|
+
`- Evidence: ${finding.evidence}`,
|
|
6235
|
+
`- Recommendation: ${finding.recommendation}`,
|
|
6236
|
+
""
|
|
6237
|
+
].join("\n")),
|
|
6238
|
+
"## Extracted Founder Loop Items",
|
|
6239
|
+
"",
|
|
6240
|
+
...plan.extracted_items.map((item) => `- ${item.type}: ${item.text} (${item.evidenceRef})`),
|
|
6241
|
+
"",
|
|
6242
|
+
"## Recommended Initiative",
|
|
6243
|
+
"",
|
|
6244
|
+
`Title: ${plan.recommended_initiative.title}`,
|
|
6245
|
+
"",
|
|
6246
|
+
plan.recommended_initiative.summary,
|
|
6247
|
+
"",
|
|
6248
|
+
"## Approved Follow-Up Candidate",
|
|
6249
|
+
"",
|
|
6250
|
+
`Title: ${plan.recommended_follow_up.title}`,
|
|
6251
|
+
"",
|
|
6252
|
+
plan.recommended_follow_up.summary,
|
|
6253
|
+
"",
|
|
6254
|
+
`Rollback: ${plan.recommended_follow_up.rollback}`,
|
|
6255
|
+
"",
|
|
6256
|
+
"## Artifact Invariant",
|
|
6257
|
+
"",
|
|
6258
|
+
"```json",
|
|
6259
|
+
JSON.stringify(plan.artifact_invariant, null, 2),
|
|
6260
|
+
"```",
|
|
6261
|
+
""
|
|
6262
|
+
];
|
|
6263
|
+
return lines.join("\n");
|
|
6264
|
+
}
|
|
6265
|
+
function parseEntityRef(payload) {
|
|
6266
|
+
const entity = isRecord(payload) && isRecord(payload.data) ? payload.data : payload;
|
|
6267
|
+
if (!isRecord(entity)) {
|
|
6268
|
+
throw new Error("OrgX returned an unexpected entity payload.");
|
|
6269
|
+
}
|
|
6270
|
+
const id = typeof entity.id === "string" ? entity.id : "";
|
|
6271
|
+
const title = typeof entity.title === "string" ? entity.title : typeof entity.name === "string" ? entity.name : "";
|
|
6272
|
+
if (!id || !title) {
|
|
6273
|
+
throw new Error("OrgX returned an incomplete entity payload.");
|
|
5676
6274
|
}
|
|
6275
|
+
return { id, title };
|
|
5677
6276
|
}
|
|
5678
|
-
function
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
}
|
|
6277
|
+
async function parseResponseBody5(response) {
|
|
6278
|
+
const text2 = await response.text();
|
|
6279
|
+
if (!text2) return null;
|
|
6280
|
+
try {
|
|
6281
|
+
return JSON.parse(text2);
|
|
6282
|
+
} catch {
|
|
6283
|
+
return text2;
|
|
5686
6284
|
}
|
|
5687
|
-
return null;
|
|
5688
6285
|
}
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
return {
|
|
5693
|
-
status: "skipped_non_interactive",
|
|
5694
|
-
message: "People-first capture skipped \u2014 not attached to a TTY."
|
|
5695
|
-
};
|
|
6286
|
+
function formatHttpError4(status, body) {
|
|
6287
|
+
if (typeof body === "string" && body.trim().length > 0) {
|
|
6288
|
+
return `HTTP ${status}: ${body}`;
|
|
5696
6289
|
}
|
|
5697
|
-
if (
|
|
5698
|
-
return {
|
|
5699
|
-
status: "skipped_no_workspace",
|
|
5700
|
-
message: "People-first capture skipped \u2014 no workspace resolved."
|
|
5701
|
-
};
|
|
6290
|
+
if (isRecord(body) && typeof body.error === "string" && body.error.trim().length > 0) {
|
|
6291
|
+
return `HTTP ${status}: ${body.error}`;
|
|
5702
6292
|
}
|
|
5703
|
-
if (
|
|
5704
|
-
return {
|
|
5705
|
-
status: "skipped_already_completed",
|
|
5706
|
-
message: "People-first capture already completed for this workspace."
|
|
5707
|
-
};
|
|
6293
|
+
if (isRecord(body) && isRecord(body.error) && typeof body.error.message === "string") {
|
|
6294
|
+
return `HTTP ${status}: ${body.error.message}`;
|
|
5708
6295
|
}
|
|
5709
|
-
|
|
5710
|
-
|
|
6296
|
+
return `HTTP ${status}`;
|
|
6297
|
+
}
|
|
6298
|
+
async function createOrgxEntity(body, options) {
|
|
6299
|
+
if (options.dryRun) {
|
|
5711
6300
|
return {
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
error: "no_auth"
|
|
6301
|
+
id: `dry-run-${String(body.type ?? "entity")}`,
|
|
6302
|
+
title: String(body.title ?? body.name ?? "Dry-run entity")
|
|
5715
6303
|
};
|
|
5716
6304
|
}
|
|
5717
|
-
const
|
|
5718
|
-
if (
|
|
5719
|
-
|
|
5720
|
-
if (row?.peopleFirstCaptureCompletedAt) {
|
|
5721
|
-
return {
|
|
5722
|
-
status: "skipped_already_completed",
|
|
5723
|
-
message: "People-first capture already completed for this workspace."
|
|
5724
|
-
};
|
|
5725
|
-
}
|
|
6305
|
+
const auth = await resolveOrgxAuth(options);
|
|
6306
|
+
if (!auth) {
|
|
6307
|
+
throw new Error("No OrgX API key configured. Run `wizard auth login` before using writeback flags.");
|
|
5726
6308
|
}
|
|
5727
|
-
const
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
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 } : {}
|
|
6309
|
+
const response = await fetch(buildOrgxApiUrl("/entities", auth.baseUrl), {
|
|
6310
|
+
body: JSON.stringify(body),
|
|
6311
|
+
headers: {
|
|
6312
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
6313
|
+
"Content-Type": "application/json"
|
|
5896
6314
|
},
|
|
5897
|
-
|
|
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
|
|
6315
|
+
method: "POST",
|
|
6316
|
+
signal: AbortSignal.timeout(15e3)
|
|
5919
6317
|
});
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
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
|
-
};
|
|
6318
|
+
const responseBody = await parseResponseBody5(response);
|
|
6319
|
+
if (!response.ok) {
|
|
6320
|
+
throw new Error(`Failed to create ${String(body.type ?? "entity")}. ${formatHttpError4(response.status, responseBody)}`);
|
|
5934
6321
|
}
|
|
5935
|
-
|
|
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
|
-
};
|
|
6322
|
+
return parseEntityRef(responseBody);
|
|
5958
6323
|
}
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
}
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
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
|
-
}
|
|
6324
|
+
async function createAuditArtifact(options) {
|
|
6325
|
+
const { initiativeId, markdown, plan } = options;
|
|
6326
|
+
return createOrgxEntity(
|
|
6327
|
+
{
|
|
6328
|
+
artifact_type: "shared.project_handbook",
|
|
6329
|
+
description: "AI-native Founder Loop self-audit generated by @useorgx/wizard audit.",
|
|
6330
|
+
entity_id: initiativeId,
|
|
6331
|
+
entity_type: "initiative",
|
|
6332
|
+
external_url: `orgx-wizard://audit/${plan.artifact_hash}`,
|
|
6333
|
+
initiative_id: initiativeId,
|
|
6334
|
+
metadata: {
|
|
6335
|
+
...plan.artifact_invariant,
|
|
6336
|
+
artifact_hash: plan.artifact_hash,
|
|
6337
|
+
atomic_unit_type: "ai_native_self_audit",
|
|
6338
|
+
completion_state: "generated",
|
|
6339
|
+
schema_validated: true,
|
|
6340
|
+
scores: plan.scores
|
|
6341
|
+
},
|
|
6342
|
+
name: `AI-Native Self-Audit: ${plan.workspace.name}`,
|
|
6343
|
+
preview_markdown: markdown.slice(0, 8e3),
|
|
6344
|
+
status: "in_review",
|
|
6345
|
+
type: "artifact",
|
|
6346
|
+
workspace_id: plan.workspace.id
|
|
6347
|
+
},
|
|
6348
|
+
options
|
|
6349
|
+
);
|
|
6034
6350
|
}
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6351
|
+
async function createInitiativeFromAuditPlan(options) {
|
|
6352
|
+
const { plan } = options;
|
|
6353
|
+
return createOrgxEntity(
|
|
6354
|
+
{
|
|
6355
|
+
metadata: {
|
|
6356
|
+
artifact_hash: plan.artifact_hash,
|
|
6357
|
+
audit_score_snapshot: plan.scores,
|
|
6358
|
+
source: "ai_native_self_audit",
|
|
6359
|
+
source_artifact_type: "ai_native_self_audit_plan"
|
|
6044
6360
|
},
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
}
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
} catch (err) {
|
|
6054
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6055
|
-
return { ok: false, error: message };
|
|
6056
|
-
}
|
|
6361
|
+
status: "active",
|
|
6362
|
+
summary: plan.recommended_initiative.summary,
|
|
6363
|
+
title: plan.recommended_initiative.title,
|
|
6364
|
+
type: "initiative",
|
|
6365
|
+
workspace_id: plan.workspace.id
|
|
6366
|
+
},
|
|
6367
|
+
options
|
|
6368
|
+
);
|
|
6057
6369
|
}
|
|
6058
|
-
async function
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
const
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
}
|
|
6111
|
-
|
|
6112
|
-
|
|
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
|
-
};
|
|
6370
|
+
async function createAuditFollowUpTask(options) {
|
|
6371
|
+
const { initiativeId, milestoneId, plan, workstreamId } = options;
|
|
6372
|
+
const resolvedWorkstreamId = workstreamId?.trim() || (await createOrgxEntity(
|
|
6373
|
+
{
|
|
6374
|
+
initiative_id: initiativeId,
|
|
6375
|
+
metadata: {
|
|
6376
|
+
artifact_hash: plan.artifact_hash,
|
|
6377
|
+
source: "ai_native_self_audit"
|
|
6378
|
+
},
|
|
6379
|
+
status: "active",
|
|
6380
|
+
summary: "Follow-up workstream created by @useorgx/wizard audit so the approved action has execution context.",
|
|
6381
|
+
title: "AI-native self-audit follow-up",
|
|
6382
|
+
type: "workstream",
|
|
6383
|
+
workspace_id: plan.workspace.id
|
|
6384
|
+
},
|
|
6385
|
+
options
|
|
6386
|
+
)).id;
|
|
6387
|
+
const resolvedMilestoneId = milestoneId?.trim() || (await createOrgxEntity(
|
|
6388
|
+
{
|
|
6389
|
+
initiative_id: initiativeId,
|
|
6390
|
+
metadata: {
|
|
6391
|
+
artifact_hash: plan.artifact_hash,
|
|
6392
|
+
source: "ai_native_self_audit"
|
|
6393
|
+
},
|
|
6394
|
+
status: "planned",
|
|
6395
|
+
summary: "Milestone created by @useorgx/wizard audit so the approved follow-up task has proof-chain hierarchy.",
|
|
6396
|
+
title: "AI-native self-audit follow-up",
|
|
6397
|
+
type: "milestone",
|
|
6398
|
+
workspace_id: plan.workspace.id,
|
|
6399
|
+
workstream_id: resolvedWorkstreamId
|
|
6400
|
+
},
|
|
6401
|
+
options
|
|
6402
|
+
)).id;
|
|
6403
|
+
return createOrgxEntity(
|
|
6404
|
+
{
|
|
6405
|
+
description: `${plan.recommended_follow_up.summary}
|
|
6406
|
+
|
|
6407
|
+
Rollback: ${plan.recommended_follow_up.rollback}`,
|
|
6408
|
+
initiative_id: initiativeId,
|
|
6409
|
+
milestone_id: resolvedMilestoneId,
|
|
6410
|
+
metadata: {
|
|
6411
|
+
...plan.artifact_invariant,
|
|
6412
|
+
artifact_hash: plan.artifact_hash,
|
|
6413
|
+
source: "ai_native_self_audit",
|
|
6414
|
+
source_action: "approved_follow_up_writeback"
|
|
6415
|
+
},
|
|
6416
|
+
priority: "high",
|
|
6417
|
+
status: "todo",
|
|
6418
|
+
title: plan.recommended_follow_up.title,
|
|
6419
|
+
type: "task",
|
|
6420
|
+
workstream_id: resolvedWorkstreamId,
|
|
6421
|
+
workspace_id: plan.workspace.id
|
|
6422
|
+
},
|
|
6423
|
+
options
|
|
6424
|
+
);
|
|
6127
6425
|
}
|
|
6128
6426
|
|
|
6129
6427
|
// src/spinner.ts
|
|
@@ -6226,6 +6524,145 @@ function printPluginMutationReport(report) {
|
|
|
6226
6524
|
);
|
|
6227
6525
|
}
|
|
6228
6526
|
}
|
|
6527
|
+
function formatScoreLine(scores) {
|
|
6528
|
+
return Object.entries(scores).map(([dimension, score]) => `${dimension}=${score}`).join(" ");
|
|
6529
|
+
}
|
|
6530
|
+
function readAuditInput(options, interactive) {
|
|
6531
|
+
if (options.input?.trim()) {
|
|
6532
|
+
return readFileSync3(resolve(options.input.trim()), "utf8");
|
|
6533
|
+
}
|
|
6534
|
+
if (!process.stdin.isTTY) {
|
|
6535
|
+
return readFileSync3(0, "utf8");
|
|
6536
|
+
}
|
|
6537
|
+
if (!interactive) {
|
|
6538
|
+
throw new Error("Audit input is required. Pass --input <file> or pipe text into wizard audit.");
|
|
6539
|
+
}
|
|
6540
|
+
return textPrompt({
|
|
6541
|
+
message: "Paste a short AI-session summary, decision log, or founder context excerpt",
|
|
6542
|
+
placeholder: "Decision: Founder Loop first. Artifact: proof ledger attached. Next action: ...",
|
|
6543
|
+
validate: (value) => value?.trim().length ? void 0 : "Audit context is required."
|
|
6544
|
+
}).then((value) => {
|
|
6545
|
+
if (clack.isCancel(value) || typeof value !== "string") {
|
|
6546
|
+
clack.cancel("Audit cancelled.");
|
|
6547
|
+
return "";
|
|
6548
|
+
}
|
|
6549
|
+
return value;
|
|
6550
|
+
});
|
|
6551
|
+
}
|
|
6552
|
+
function requireWriteApproval(options, interactive) {
|
|
6553
|
+
const wantsWrite = Boolean(options.createInitiative || options.attachToInitiative || options.writeFollowUp);
|
|
6554
|
+
if (!wantsWrite || options.yes || options.dryRun) return true;
|
|
6555
|
+
if (!interactive) {
|
|
6556
|
+
throw new Error("Write flags require --yes in non-interactive mode.");
|
|
6557
|
+
}
|
|
6558
|
+
return clack.confirm({
|
|
6559
|
+
message: "Approve OrgX writes for this audit run?"
|
|
6560
|
+
}).then((value) => {
|
|
6561
|
+
if (clack.isCancel(value) || value !== true) {
|
|
6562
|
+
clack.cancel("Audit writeback cancelled.");
|
|
6563
|
+
return false;
|
|
6564
|
+
}
|
|
6565
|
+
return true;
|
|
6566
|
+
});
|
|
6567
|
+
}
|
|
6568
|
+
async function resolveAuditWorkspace(options) {
|
|
6569
|
+
const explicitId = options.workspaceId?.trim();
|
|
6570
|
+
const explicitName = options.workspaceName?.trim();
|
|
6571
|
+
if (explicitId || explicitName) {
|
|
6572
|
+
return {
|
|
6573
|
+
id: explicitId || "manual-workspace",
|
|
6574
|
+
name: explicitName || explicitId || "Manual workspace"
|
|
6575
|
+
};
|
|
6576
|
+
}
|
|
6577
|
+
try {
|
|
6578
|
+
const workspace = await getCurrentWorkspace();
|
|
6579
|
+
if (workspace) {
|
|
6580
|
+
return {
|
|
6581
|
+
id: workspace.id,
|
|
6582
|
+
name: workspace.name
|
|
6583
|
+
};
|
|
6584
|
+
}
|
|
6585
|
+
} catch {
|
|
6586
|
+
}
|
|
6587
|
+
return {
|
|
6588
|
+
id: "local-workspace",
|
|
6589
|
+
name: "Local workspace"
|
|
6590
|
+
};
|
|
6591
|
+
}
|
|
6592
|
+
async function runAuditCommand(options) {
|
|
6593
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
6594
|
+
const text2 = (await readAuditInput(options, interactive)).trim();
|
|
6595
|
+
if (!text2) return;
|
|
6596
|
+
const workspace = await resolveAuditWorkspace(options);
|
|
6597
|
+
const plan = buildSelfAuditPlan({
|
|
6598
|
+
connectedSources: [
|
|
6599
|
+
options.sourceLabel?.trim() || "Manual AI-session import",
|
|
6600
|
+
...workspace.id === "local-workspace" ? [] : ["OrgX workspace"]
|
|
6601
|
+
],
|
|
6602
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6603
|
+
imports: [
|
|
6604
|
+
{
|
|
6605
|
+
sourceId: "wizard-audit-input",
|
|
6606
|
+
sourceLabel: options.sourceLabel?.trim() || "Wizard audit input",
|
|
6607
|
+
text: text2
|
|
6608
|
+
}
|
|
6609
|
+
],
|
|
6610
|
+
missingSources: workspace.id === "local-workspace" ? ["OrgX workspace auth", "automatic AI-session import"] : ["automatic AI-session import"],
|
|
6611
|
+
workspace
|
|
6612
|
+
});
|
|
6613
|
+
const markdown = renderSelfAuditMarkdown(plan);
|
|
6614
|
+
const outputDir = resolve(options.outputDir?.trim() || ".orgx/audits");
|
|
6615
|
+
const timestamp = plan.generated_at.replace(/[:.]/g, "-");
|
|
6616
|
+
const jsonPath = resolve(outputDir, `ai-native-self-audit-${timestamp}.json`);
|
|
6617
|
+
const markdownPath = resolve(outputDir, `ai-native-self-audit-${timestamp}.md`);
|
|
6618
|
+
writeJsonFile(jsonPath, plan);
|
|
6619
|
+
writeTextFile(markdownPath, markdown);
|
|
6620
|
+
if (options.json) {
|
|
6621
|
+
console.log(JSON.stringify({ jsonPath, markdownPath, scores: plan.scores }, null, 2));
|
|
6622
|
+
} else {
|
|
6623
|
+
console.log(` ${ICON.ok} ${pc3.green("audit generated")} ${pc3.dim(markdownPath)}`);
|
|
6624
|
+
console.log(` ${ICON.ok} ${pc3.green("scores ")} ${pc3.dim(formatScoreLine(plan.scores))}`);
|
|
6625
|
+
const belowTarget = plan.self_critique.filter((item) => !item.passed);
|
|
6626
|
+
if (belowTarget.length === 0) {
|
|
6627
|
+
console.log(` ${ICON.ok} ${pc3.green("score gate ")} ${pc3.dim("all dimensions at 95+")}`);
|
|
6628
|
+
} else {
|
|
6629
|
+
console.log(` ${ICON.warn} ${pc3.yellow("score gate ")} ${pc3.dim(`${belowTarget.length} dimension${belowTarget.length === 1 ? "" : "s"} below 95`)}`);
|
|
6630
|
+
}
|
|
6631
|
+
}
|
|
6632
|
+
const approved = await requireWriteApproval(options, interactive);
|
|
6633
|
+
if (!approved) return;
|
|
6634
|
+
let targetInitiativeId = options.attachToInitiative?.trim() || "";
|
|
6635
|
+
if (options.createInitiative) {
|
|
6636
|
+
const initiative = await createInitiativeFromAuditPlan({
|
|
6637
|
+
dryRun: Boolean(options.dryRun),
|
|
6638
|
+
plan
|
|
6639
|
+
});
|
|
6640
|
+
targetInitiativeId = initiative.id;
|
|
6641
|
+
console.log(` ${ICON.ok} ${pc3.green("initiative ")} ${pc3.bold(initiative.title)} ${pc3.dim(initiative.id)}`);
|
|
6642
|
+
}
|
|
6643
|
+
if (targetInitiativeId && (options.attachToInitiative || options.createInitiative)) {
|
|
6644
|
+
const artifact = await createAuditArtifact({
|
|
6645
|
+
dryRun: Boolean(options.dryRun),
|
|
6646
|
+
initiativeId: targetInitiativeId,
|
|
6647
|
+
markdown,
|
|
6648
|
+
plan
|
|
6649
|
+
});
|
|
6650
|
+
console.log(` ${ICON.ok} ${pc3.green("artifact ")} ${pc3.bold(artifact.title)} ${pc3.dim(artifact.id)}`);
|
|
6651
|
+
}
|
|
6652
|
+
if (options.writeFollowUp) {
|
|
6653
|
+
if (!targetInitiativeId) {
|
|
6654
|
+
throw new Error("--write-follow-up requires --attach-to-initiative <id> or --create-initiative.");
|
|
6655
|
+
}
|
|
6656
|
+
const followUp = await createAuditFollowUpTask({
|
|
6657
|
+
dryRun: Boolean(options.dryRun),
|
|
6658
|
+
initiativeId: targetInitiativeId,
|
|
6659
|
+
...options.milestoneId?.trim() ? { milestoneId: options.milestoneId.trim() } : {},
|
|
6660
|
+
plan,
|
|
6661
|
+
...options.workstreamId?.trim() ? { workstreamId: options.workstreamId.trim() } : {}
|
|
6662
|
+
});
|
|
6663
|
+
console.log(` ${ICON.ok} ${pc3.green("follow-up ")} ${pc3.bold(followUp.title)} ${pc3.dim(followUp.id)}`);
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6229
6666
|
async function checkPluginStatusesCompact() {
|
|
6230
6667
|
const spinner = createOrgxSpinner("Checking OrgX companion plugin status");
|
|
6231
6668
|
spinner.start();
|
|
@@ -6520,6 +6957,296 @@ function parseTimeoutSeconds(value) {
|
|
|
6520
6957
|
}
|
|
6521
6958
|
return parsed;
|
|
6522
6959
|
}
|
|
6960
|
+
async function readSingleKey() {
|
|
6961
|
+
const stdin = process.stdin;
|
|
6962
|
+
if (!stdin.isTTY) return null;
|
|
6963
|
+
const previousRawMode = stdin.isRaw === true;
|
|
6964
|
+
return await new Promise((resolve2) => {
|
|
6965
|
+
const cleanup = (result) => {
|
|
6966
|
+
stdin.off("data", onData);
|
|
6967
|
+
if (stdin.isTTY) {
|
|
6968
|
+
stdin.setRawMode(previousRawMode);
|
|
6969
|
+
}
|
|
6970
|
+
stdin.pause();
|
|
6971
|
+
resolve2(result);
|
|
6972
|
+
};
|
|
6973
|
+
const onData = (chunk) => {
|
|
6974
|
+
const text2 = chunk.toString("utf8");
|
|
6975
|
+
const first = text2.charAt(0);
|
|
6976
|
+
if (first === "" || first === "") {
|
|
6977
|
+
cleanup(null);
|
|
6978
|
+
return;
|
|
6979
|
+
}
|
|
6980
|
+
cleanup(first.toLowerCase());
|
|
6981
|
+
};
|
|
6982
|
+
if (stdin.isTTY) {
|
|
6983
|
+
stdin.setRawMode(true);
|
|
6984
|
+
}
|
|
6985
|
+
stdin.resume();
|
|
6986
|
+
stdin.on("data", onData);
|
|
6987
|
+
});
|
|
6988
|
+
}
|
|
6989
|
+
function printIntentPreview(intent, baseUrl) {
|
|
6990
|
+
const render = detectRenderCapabilities();
|
|
6991
|
+
const agent = intent.suggested_agent_slug ?? "xandy";
|
|
6992
|
+
const confidence = resolveConfidenceDecimal(intent.plan_preview);
|
|
6993
|
+
console.log("");
|
|
6994
|
+
console.log(renderRoutingLine(agent, confidence, render));
|
|
6995
|
+
console.log("");
|
|
6996
|
+
console.log(renderPlanPreview(intent.plan_preview, render));
|
|
6997
|
+
console.log("");
|
|
6998
|
+
console.log(
|
|
6999
|
+
dim(
|
|
7000
|
+
` slug ${intent.slug} handoff ${buildIntentHandoffUrl(intent.slug, { baseUrl })}`,
|
|
7001
|
+
render
|
|
7002
|
+
)
|
|
7003
|
+
);
|
|
7004
|
+
console.log("");
|
|
7005
|
+
console.log(renderHotkeyBar(DEFAULT_HOTKEYS, render));
|
|
7006
|
+
}
|
|
7007
|
+
async function maybeCaptureSetupIntent(input) {
|
|
7008
|
+
if (!input.interactive || !input.workspace) {
|
|
7009
|
+
return "skipped";
|
|
7010
|
+
}
|
|
7011
|
+
const prompt = await textPrompt({
|
|
7012
|
+
message: "In one line, what do you want OrgX to move first? (blank to skip \u2014 you can start from the dashboard)",
|
|
7013
|
+
placeholder: "e.g. open a warm-intro loop to 50 design-led SaaS founders",
|
|
7014
|
+
validate: (value) => {
|
|
7015
|
+
const trimmed = (value ?? "").trim();
|
|
7016
|
+
if (!trimmed) return void 0;
|
|
7017
|
+
if (trimmed.length > 4e3) return "Keep it under 4,000 characters.";
|
|
7018
|
+
return void 0;
|
|
7019
|
+
}
|
|
7020
|
+
});
|
|
7021
|
+
if (clack.isCancel(prompt)) {
|
|
7022
|
+
return "cancelled";
|
|
7023
|
+
}
|
|
7024
|
+
const intentText = typeof prompt === "string" ? prompt.trim() : "";
|
|
7025
|
+
if (!intentText) {
|
|
7026
|
+
return "skipped";
|
|
7027
|
+
}
|
|
7028
|
+
const spinner = createOrgxSpinner("Routing");
|
|
7029
|
+
spinner.start();
|
|
7030
|
+
let intent;
|
|
7031
|
+
try {
|
|
7032
|
+
intent = await createIntent({
|
|
7033
|
+
workspace_id: input.workspace.id,
|
|
7034
|
+
text: intentText
|
|
7035
|
+
});
|
|
7036
|
+
spinner.stop();
|
|
7037
|
+
} catch (error) {
|
|
7038
|
+
spinner.fail("Could not classify intent.");
|
|
7039
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7040
|
+
console.log(` ${ICON.warn} ${pc3.yellow("intent")} ${pc3.dim(message)}`);
|
|
7041
|
+
return "failed";
|
|
7042
|
+
}
|
|
7043
|
+
const auth = await resolveOrgxAuth().catch(() => null);
|
|
7044
|
+
const baseUrl = auth?.baseUrl ?? DEFAULT_ORGX_BASE_URL;
|
|
7045
|
+
printIntentPreview(intent, baseUrl);
|
|
7046
|
+
const approveChoice = await clack.confirm({
|
|
7047
|
+
message: "Approve this plan and hand off to OrgX?",
|
|
7048
|
+
initialValue: true
|
|
7049
|
+
});
|
|
7050
|
+
if (clack.isCancel(approveChoice)) {
|
|
7051
|
+
return "cancelled";
|
|
7052
|
+
}
|
|
7053
|
+
if (approveChoice) {
|
|
7054
|
+
const approveSpinner = createOrgxSpinner("Approving");
|
|
7055
|
+
approveSpinner.start();
|
|
7056
|
+
try {
|
|
7057
|
+
await updateIntent(intent.id, { status: "approved" });
|
|
7058
|
+
approveSpinner.stop();
|
|
7059
|
+
} catch (error) {
|
|
7060
|
+
approveSpinner.fail("Approve failed.");
|
|
7061
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7062
|
+
console.log(` ${ICON.warn} ${pc3.yellow("intent")} ${pc3.dim(message)}`);
|
|
7063
|
+
return "failed";
|
|
7064
|
+
}
|
|
7065
|
+
const handoff2 = buildIntentHandoffUrl(intent.slug, { baseUrl });
|
|
7066
|
+
console.log(` ${ICON.ok} ${pc3.green("intent")} ${pc3.dim(`approved \xB7 ${handoff2}`)}`);
|
|
7067
|
+
return "approved";
|
|
7068
|
+
}
|
|
7069
|
+
const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl });
|
|
7070
|
+
console.log(` ${ICON.skip} ${pc3.dim(`intent pending \xB7 ${handoff}`)}`);
|
|
7071
|
+
return "captured";
|
|
7072
|
+
}
|
|
7073
|
+
async function runIntentCommand(options) {
|
|
7074
|
+
const interactive = isInteractive();
|
|
7075
|
+
let intentText = options.initialText?.trim() ?? "";
|
|
7076
|
+
if (!intentText) {
|
|
7077
|
+
if (!interactive) {
|
|
7078
|
+
console.error(
|
|
7079
|
+
pc3.red("Intent text is required when running non-interactively.")
|
|
7080
|
+
);
|
|
7081
|
+
console.error(
|
|
7082
|
+
pc3.dim(' Example: orgx-wizard intent "launch partner outreach campaign"')
|
|
7083
|
+
);
|
|
7084
|
+
process.exitCode = 1;
|
|
7085
|
+
return;
|
|
7086
|
+
}
|
|
7087
|
+
const prompt = await textPrompt({
|
|
7088
|
+
message: "What do you want to move?",
|
|
7089
|
+
placeholder: "e.g. launch partner outreach campaign",
|
|
7090
|
+
validate: (value) => {
|
|
7091
|
+
const trimmed = (value ?? "").trim();
|
|
7092
|
+
if (!trimmed) return "Intent text cannot be empty.";
|
|
7093
|
+
if (trimmed.length > 4e3) return "Intent text exceeds 4,000 characters.";
|
|
7094
|
+
return void 0;
|
|
7095
|
+
}
|
|
7096
|
+
});
|
|
7097
|
+
if (clack.isCancel(prompt) || typeof prompt !== "string") {
|
|
7098
|
+
console.log(pc3.dim("Cancelled."));
|
|
7099
|
+
return;
|
|
7100
|
+
}
|
|
7101
|
+
intentText = prompt.trim();
|
|
7102
|
+
}
|
|
7103
|
+
let workspaceId = options.workspaceId ?? "";
|
|
7104
|
+
let workspaceName = null;
|
|
7105
|
+
let workspaceBaseUrl = null;
|
|
7106
|
+
if (!workspaceId) {
|
|
7107
|
+
const loadLabel = "Loading current OrgX workspace";
|
|
7108
|
+
const spinner = interactive ? createOrgxSpinner(loadLabel) : null;
|
|
7109
|
+
if (spinner) spinner.start();
|
|
7110
|
+
else console.log(pc3.dim(`${loadLabel}...`));
|
|
7111
|
+
try {
|
|
7112
|
+
const current = await getCurrentWorkspace();
|
|
7113
|
+
if (!current) {
|
|
7114
|
+
if (spinner) spinner.fail("No OrgX workspace is configured.");
|
|
7115
|
+
else console.error(pc3.red("No OrgX workspace is configured."));
|
|
7116
|
+
console.log(
|
|
7117
|
+
pc3.dim(" Run `orgx-wizard workspace create <name>` or pass --workspace <id>.")
|
|
7118
|
+
);
|
|
7119
|
+
process.exitCode = 1;
|
|
7120
|
+
return;
|
|
7121
|
+
}
|
|
7122
|
+
workspaceId = current.id;
|
|
7123
|
+
workspaceName = current.name;
|
|
7124
|
+
if (spinner) spinner.stop();
|
|
7125
|
+
} catch (error) {
|
|
7126
|
+
if (spinner) spinner.fail("Failed to load current workspace.");
|
|
7127
|
+
console.error(
|
|
7128
|
+
pc3.red(error instanceof Error ? error.message : String(error))
|
|
7129
|
+
);
|
|
7130
|
+
process.exitCode = 1;
|
|
7131
|
+
return;
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
const classifyLabel = "Routing";
|
|
7135
|
+
const classifySpinner = interactive ? createOrgxSpinner(classifyLabel) : null;
|
|
7136
|
+
if (classifySpinner) classifySpinner.start();
|
|
7137
|
+
else console.log(pc3.dim(`${classifyLabel}...`));
|
|
7138
|
+
let intent;
|
|
7139
|
+
try {
|
|
7140
|
+
intent = await createIntent({ workspace_id: workspaceId, text: intentText });
|
|
7141
|
+
if (classifySpinner) classifySpinner.stop();
|
|
7142
|
+
} catch (error) {
|
|
7143
|
+
if (classifySpinner) classifySpinner.fail("Classification failed.");
|
|
7144
|
+
console.error(
|
|
7145
|
+
pc3.red(error instanceof Error ? error.message : String(error))
|
|
7146
|
+
);
|
|
7147
|
+
process.exitCode = 1;
|
|
7148
|
+
return;
|
|
7149
|
+
}
|
|
7150
|
+
const auth = await resolveOrgxAuth().catch(() => null);
|
|
7151
|
+
const baseUrl = auth?.baseUrl ?? DEFAULT_ORGX_BASE_URL;
|
|
7152
|
+
workspaceBaseUrl = baseUrl;
|
|
7153
|
+
if (options.jsonOutput) {
|
|
7154
|
+
const payload = {
|
|
7155
|
+
intent,
|
|
7156
|
+
handoff_url: buildIntentHandoffUrl(intent.slug, { baseUrl }),
|
|
7157
|
+
workspace: workspaceName ? { id: workspaceId, name: workspaceName } : { id: workspaceId }
|
|
7158
|
+
};
|
|
7159
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
7160
|
+
return;
|
|
7161
|
+
}
|
|
7162
|
+
printIntentPreview(intent, baseUrl);
|
|
7163
|
+
console.log("");
|
|
7164
|
+
if (!interactive) {
|
|
7165
|
+
console.log(
|
|
7166
|
+
pc3.dim(
|
|
7167
|
+
`Run \`orgx-wizard intent --workspace ${workspaceId}\` interactively to approve, edit, or archive.`
|
|
7168
|
+
)
|
|
7169
|
+
);
|
|
7170
|
+
return;
|
|
7171
|
+
}
|
|
7172
|
+
let action = null;
|
|
7173
|
+
while (action === null) {
|
|
7174
|
+
const key = await readSingleKey();
|
|
7175
|
+
if (!key) {
|
|
7176
|
+
action = "quit";
|
|
7177
|
+
break;
|
|
7178
|
+
}
|
|
7179
|
+
action = normalizeHotkey(key);
|
|
7180
|
+
if (action === null) {
|
|
7181
|
+
console.log(
|
|
7182
|
+
pc3.dim(` Unrecognized key. Press a, e, x, or q.`)
|
|
7183
|
+
);
|
|
7184
|
+
}
|
|
7185
|
+
}
|
|
7186
|
+
switch (action) {
|
|
7187
|
+
case "approve": {
|
|
7188
|
+
const approveLabel = "Approving";
|
|
7189
|
+
const spinner = interactive ? createOrgxSpinner(approveLabel) : null;
|
|
7190
|
+
if (spinner) spinner.start();
|
|
7191
|
+
try {
|
|
7192
|
+
await updateIntent(intent.id, { status: "approved" });
|
|
7193
|
+
if (spinner) spinner.stop();
|
|
7194
|
+
} catch (error) {
|
|
7195
|
+
if (spinner) spinner.fail("Approve failed.");
|
|
7196
|
+
console.error(
|
|
7197
|
+
pc3.red(error instanceof Error ? error.message : String(error))
|
|
7198
|
+
);
|
|
7199
|
+
process.exitCode = 1;
|
|
7200
|
+
return;
|
|
7201
|
+
}
|
|
7202
|
+
const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl });
|
|
7203
|
+
console.log("");
|
|
7204
|
+
console.log(`${pc3.green("\u2713")} Approved \xB7 ${handoff}`);
|
|
7205
|
+
return;
|
|
7206
|
+
}
|
|
7207
|
+
case "edit": {
|
|
7208
|
+
const handoff = buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl });
|
|
7209
|
+
console.log("");
|
|
7210
|
+
console.log(`${pc3.yellow("\u270E")} Opening ${handoff}`);
|
|
7211
|
+
const result = openBrowser(handoff);
|
|
7212
|
+
if (!result.ok) {
|
|
7213
|
+
console.log(pc3.dim(` Could not launch browser: ${result.error}`));
|
|
7214
|
+
console.log(pc3.dim(` Visit ${handoff} to finish editing.`));
|
|
7215
|
+
}
|
|
7216
|
+
return;
|
|
7217
|
+
}
|
|
7218
|
+
case "archive": {
|
|
7219
|
+
const archiveLabel = "Archiving";
|
|
7220
|
+
const spinner = interactive ? createOrgxSpinner(archiveLabel) : null;
|
|
7221
|
+
if (spinner) spinner.start();
|
|
7222
|
+
try {
|
|
7223
|
+
await updateIntent(intent.id, { status: "archived" });
|
|
7224
|
+
if (spinner) spinner.stop();
|
|
7225
|
+
} catch (error) {
|
|
7226
|
+
if (spinner) spinner.fail("Archive failed.");
|
|
7227
|
+
console.error(
|
|
7228
|
+
pc3.red(error instanceof Error ? error.message : String(error))
|
|
7229
|
+
);
|
|
7230
|
+
process.exitCode = 1;
|
|
7231
|
+
return;
|
|
7232
|
+
}
|
|
7233
|
+
console.log("");
|
|
7234
|
+
console.log(`${pc3.red("\u2715")} Archived \xB7 intent will not be executed.`);
|
|
7235
|
+
return;
|
|
7236
|
+
}
|
|
7237
|
+
case "quit":
|
|
7238
|
+
default: {
|
|
7239
|
+
console.log("");
|
|
7240
|
+
console.log(pc3.dim(" Exited without saving. Intent remains pending."));
|
|
7241
|
+
console.log(
|
|
7242
|
+
pc3.dim(
|
|
7243
|
+
` Resume at ${buildIntentHandoffUrl(intent.slug, { baseUrl: workspaceBaseUrl ?? baseUrl })}`
|
|
7244
|
+
)
|
|
7245
|
+
);
|
|
7246
|
+
return;
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
6523
7250
|
async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
6524
7251
|
if (!input.interactive || !input.workspace) {
|
|
6525
7252
|
return "skipped";
|
|
@@ -6775,109 +7502,6 @@ async function maybeInstallOptionalCompanionPlugins(input) {
|
|
|
6775
7502
|
...input.telemetry ? { telemetry: input.telemetry } : {}
|
|
6776
7503
|
});
|
|
6777
7504
|
}
|
|
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
7505
|
function printAuthStatus(status) {
|
|
6882
7506
|
if (!status.configured) {
|
|
6883
7507
|
console.log(` ${ICON.warn} ${pc3.yellow("no account")} run ${pc3.cyan(`${getCmd()} auth login`)} to connect`);
|
|
@@ -6956,12 +7580,12 @@ function printDoctorReport(report, assessment) {
|
|
|
6956
7580
|
async function main() {
|
|
6957
7581
|
const program = new Command();
|
|
6958
7582
|
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.
|
|
7583
|
+
const pkgVersion = true ? "0.1.22" : void 0;
|
|
6960
7584
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
6961
7585
|
program.hook("preAction", () => {
|
|
6962
7586
|
console.log(renderBanner(pkgVersion));
|
|
6963
7587
|
});
|
|
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)").
|
|
7588
|
+
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
7589
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
6966
7590
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
6967
7591
|
command: "setup",
|
|
@@ -7183,12 +7807,11 @@ async function main() {
|
|
|
7183
7807
|
} else if (briefResult.status === "failed") {
|
|
7184
7808
|
console.log(` ${ICON.warn} ${pc3.yellow("daily brief")} ${pc3.dim(briefResult.message)}`);
|
|
7185
7809
|
}
|
|
7186
|
-
const
|
|
7810
|
+
const intentResult = await maybeCaptureSetupIntent({
|
|
7187
7811
|
interactive,
|
|
7188
|
-
openInBrowser: Boolean(options.open),
|
|
7189
7812
|
workspace: resolvedWorkspace
|
|
7190
7813
|
});
|
|
7191
|
-
if (
|
|
7814
|
+
if (intentResult === "cancelled") {
|
|
7192
7815
|
return;
|
|
7193
7816
|
}
|
|
7194
7817
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
@@ -7608,6 +8231,27 @@ async function main() {
|
|
|
7608
8231
|
persistContinuityDefaults({ workspace: result.workspace });
|
|
7609
8232
|
printWorkspace(result.workspace);
|
|
7610
8233
|
});
|
|
8234
|
+
program.command("intent").description(
|
|
8235
|
+
"Capture an intent, preview the classified agent + plan, and approve or hand off to the browser."
|
|
8236
|
+
).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) => {
|
|
8237
|
+
const initialText = textParts.join(" ").trim();
|
|
8238
|
+
const workspaceId = options.workspace?.trim() ?? "";
|
|
8239
|
+
await runIntentCommand({
|
|
8240
|
+
...initialText ? { initialText } : {},
|
|
8241
|
+
...workspaceId ? { workspaceId } : {},
|
|
8242
|
+
jsonOutput: Boolean(options.json)
|
|
8243
|
+
});
|
|
8244
|
+
});
|
|
8245
|
+
program.command("audit").description("Run the AI-native Founder Loop self-audit from pasted or file-based AI-session context.").option("--input <path>", "AI-session transcript or summary file; stdin is used when piped").option("--source-label <label>", "label for the imported AI-session source").option("--workspace-id <id>", "workspace id override; defaults to the current OrgX workspace when authenticated").option("--workspace-name <name>", "workspace name override for local-only audits").option("--output-dir <path>", "directory for generated audit JSON and Markdown", ".orgx/audits").option("--attach-to-initiative <id>", "attach the generated audit artifact to an existing OrgX initiative").option("--create-initiative", "create an OrgX initiative from the generated audit plan").option("--write-follow-up", "create one approval-gated OrgX follow-up task from the audit recommendation").option("--workstream-id <id>", "optional workstream id for the generated follow-up task").option("--milestone-id <id>", "optional milestone id for the generated follow-up task").option("--dry-run", "exercise OrgX write paths without sending writes").option("--yes", "approve OrgX write flags in non-interactive mode").option("--json", "emit a JSON command summary").action(async (options) => {
|
|
8246
|
+
await safeTrackWizardTelemetry("audit_started", {
|
|
8247
|
+
attach_to_initiative: Boolean(options.attachToInitiative),
|
|
8248
|
+
command: "audit",
|
|
8249
|
+
create_initiative: Boolean(options.createInitiative),
|
|
8250
|
+
dry_run: Boolean(options.dryRun),
|
|
8251
|
+
write_follow_up: Boolean(options.writeFollowUp)
|
|
8252
|
+
});
|
|
8253
|
+
await runAuditCommand(options);
|
|
8254
|
+
});
|
|
7611
8255
|
program.command("doctor").description("Verify local OrgX surface config and optional remote setup status.").action(async () => {
|
|
7612
8256
|
const spinner = createOrgxSpinner("Running OrgX health check");
|
|
7613
8257
|
spinner.start();
|