@useorgx/wizard 0.1.45 → 0.1.47
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 +808 -572
- package/dist/cli.js.map +1 -1
- package/package.json +10 -9
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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
|
|
6
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
7
7
|
import { hostname } from "os";
|
|
8
8
|
import { resolve as resolve2 } from "path";
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -508,6 +508,31 @@ async function clearWizardAuth(authPath = ORGX_WIZARD_AUTH_PATH, options = {}) {
|
|
|
508
508
|
return secretRemoved || fileRemoved;
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
// src/lib/network.ts
|
|
512
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 12e3;
|
|
513
|
+
function isTimeoutError(error) {
|
|
514
|
+
if (!(error instanceof Error)) return false;
|
|
515
|
+
if (error.name === "TimeoutError" || error.name === "AbortError") return true;
|
|
516
|
+
const message = error.message.toLowerCase();
|
|
517
|
+
return message.includes("aborted due to timeout") || message.includes("operation was aborted");
|
|
518
|
+
}
|
|
519
|
+
async function fetchWithRetry(url, init, options = {}) {
|
|
520
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
521
|
+
const retries = options.retries ?? 1;
|
|
522
|
+
let lastError;
|
|
523
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
524
|
+
try {
|
|
525
|
+
return await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
526
|
+
} catch (error) {
|
|
527
|
+
lastError = error;
|
|
528
|
+
if (!isTimeoutError(error) || attempt === retries) {
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
throw lastError;
|
|
534
|
+
}
|
|
535
|
+
|
|
511
536
|
// src/lib/auth.ts
|
|
512
537
|
function normalizeHost(value) {
|
|
513
538
|
return value.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
@@ -652,14 +677,13 @@ async function parseResponseBody(response) {
|
|
|
652
677
|
async function verifyOrgxAuth(auth) {
|
|
653
678
|
const url = buildOrgxApiUrl("/client/sync", auth.baseUrl);
|
|
654
679
|
try {
|
|
655
|
-
const response = await
|
|
680
|
+
const response = await fetchWithRetry(url, {
|
|
656
681
|
method: "POST",
|
|
657
682
|
headers: {
|
|
658
683
|
Authorization: `Bearer ${auth.apiKey}`,
|
|
659
684
|
"Content-Type": "application/json"
|
|
660
685
|
},
|
|
661
|
-
body: "{}"
|
|
662
|
-
signal: AbortSignal.timeout(7e3)
|
|
686
|
+
body: "{}"
|
|
663
687
|
});
|
|
664
688
|
const data = await parseResponseBody(response);
|
|
665
689
|
return {
|
|
@@ -1177,30 +1201,6 @@ function parseContinuityDefaults(value) {
|
|
|
1177
1201
|
}
|
|
1178
1202
|
return Object.keys(parsed).length > 0 ? parsed : void 0;
|
|
1179
1203
|
}
|
|
1180
|
-
function parseDemoInitiative(value) {
|
|
1181
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1182
|
-
return void 0;
|
|
1183
|
-
}
|
|
1184
|
-
const record = value;
|
|
1185
|
-
if (!isNonEmptyString2(record.id) || !isNonEmptyString2(record.title) || !isNonEmptyString2(record.liveUrl) || !isNonEmptyString2(record.createdAt)) {
|
|
1186
|
-
return void 0;
|
|
1187
|
-
}
|
|
1188
|
-
return {
|
|
1189
|
-
createdAt: record.createdAt.trim(),
|
|
1190
|
-
...isNonEmptyString2(record.artifactId) ? { artifactId: record.artifactId.trim() } : {},
|
|
1191
|
-
...isNonEmptyString2(record.artifactName) ? { artifactName: record.artifactName.trim() } : {},
|
|
1192
|
-
...isNonEmptyString2(record.artifactType) ? { artifactType: record.artifactType.trim() } : {},
|
|
1193
|
-
...isNonEmptyString2(record.artifactUrl) ? { artifactUrl: record.artifactUrl.trim() } : {},
|
|
1194
|
-
...isNonEmptyString2(record.decisionId) ? { decisionId: record.decisionId.trim() } : {},
|
|
1195
|
-
...isNonEmptyString2(record.decisionStatus) ? { decisionStatus: record.decisionStatus.trim() } : {},
|
|
1196
|
-
...isNonEmptyString2(record.decisionTitle) ? { decisionTitle: record.decisionTitle.trim() } : {},
|
|
1197
|
-
id: record.id.trim(),
|
|
1198
|
-
liveUrl: record.liveUrl.trim(),
|
|
1199
|
-
title: record.title.trim(),
|
|
1200
|
-
...isNonEmptyString2(record.workspaceId) ? { workspaceId: record.workspaceId.trim() } : {},
|
|
1201
|
-
...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
|
|
1202
|
-
};
|
|
1203
|
-
}
|
|
1204
1204
|
function parseFirstValueInitiative(value) {
|
|
1205
1205
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1206
1206
|
return void 0;
|
|
@@ -1376,7 +1376,7 @@ function parseDailyBriefOnboarding(value) {
|
|
|
1376
1376
|
};
|
|
1377
1377
|
}
|
|
1378
1378
|
function isSetupPromptKey(value) {
|
|
1379
|
-
return value === "first_initiative" || value === "onboarding_task" || value === "agent_roster" || value === "setup_intent";
|
|
1379
|
+
return value === "first_initiative" || value === "onboarding_task" || value === "agent_roster" || value === "local_skill_discovery" || value === "setup_intent";
|
|
1380
1380
|
}
|
|
1381
1381
|
function parseSetupPromptDecisionEntry(value) {
|
|
1382
1382
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -1421,7 +1421,6 @@ function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
|
1421
1421
|
function sanitizeWizardStateRecord(record) {
|
|
1422
1422
|
const continuity = parseContinuityDefaults(record.continuity);
|
|
1423
1423
|
const agentRoster = parseAgentRoster(record.agentRoster);
|
|
1424
|
-
const demoInitiative = parseDemoInitiative(record.demoInitiative);
|
|
1425
1424
|
const firstValueInitiative = parseFirstValueInitiative(record.firstValueInitiative);
|
|
1426
1425
|
const onboardingTask = parseOnboardingTask(record.onboardingTask);
|
|
1427
1426
|
const skillFiles = parseSkillFiles(record.skillFiles);
|
|
@@ -1434,7 +1433,6 @@ function sanitizeWizardStateRecord(record) {
|
|
|
1434
1433
|
updatedAt: record.updatedAt.trim(),
|
|
1435
1434
|
...continuity ? { continuity } : {},
|
|
1436
1435
|
...agentRoster ? { agentRoster } : {},
|
|
1437
|
-
...demoInitiative ? { demoInitiative } : {},
|
|
1438
1436
|
...firstValueInitiative ? { firstValueInitiative } : {},
|
|
1439
1437
|
...onboardingTask ? { onboardingTask } : {},
|
|
1440
1438
|
...skillFiles ? { skillFiles } : {},
|
|
@@ -1457,8 +1455,6 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
|
1457
1455
|
if (continuity !== void 0) state.continuity = continuity;
|
|
1458
1456
|
const agentRoster = parseAgentRoster(parsed.agentRoster);
|
|
1459
1457
|
if (agentRoster !== void 0) state.agentRoster = agentRoster;
|
|
1460
|
-
const demoInitiative = parseDemoInitiative(parsed.demoInitiative);
|
|
1461
|
-
if (demoInitiative !== void 0) state.demoInitiative = demoInitiative;
|
|
1462
1458
|
const firstValueInitiative = parseFirstValueInitiative(parsed.firstValueInitiative);
|
|
1463
1459
|
if (firstValueInitiative !== void 0) {
|
|
1464
1460
|
state.firstValueInitiative = firstValueInitiative;
|
|
@@ -1949,12 +1945,11 @@ function formatHttpError(status, body) {
|
|
|
1949
1945
|
async function listWorkspaces(options = {}) {
|
|
1950
1946
|
const auth = await requireOrgxAuth(options);
|
|
1951
1947
|
const url = buildOrgxApiUrl("/entities?type=workspace&limit=100", auth.baseUrl);
|
|
1952
|
-
const response = await
|
|
1948
|
+
const response = await fetchWithRetry(url, {
|
|
1953
1949
|
method: "GET",
|
|
1954
1950
|
headers: {
|
|
1955
1951
|
Authorization: `Bearer ${auth.apiKey}`
|
|
1956
|
-
}
|
|
1957
|
-
signal: AbortSignal.timeout(7e3)
|
|
1952
|
+
}
|
|
1958
1953
|
});
|
|
1959
1954
|
const body = await parseResponseBody2(response);
|
|
1960
1955
|
if (!response.ok) {
|
|
@@ -1965,12 +1960,11 @@ async function listWorkspaces(options = {}) {
|
|
|
1965
1960
|
async function getCurrentWorkspace(options = {}) {
|
|
1966
1961
|
const auth = await requireOrgxAuth(options);
|
|
1967
1962
|
const url = buildOrgxApiUrl("/v1/workspaces/current", auth.baseUrl);
|
|
1968
|
-
const response = await
|
|
1963
|
+
const response = await fetchWithRetry(url, {
|
|
1969
1964
|
method: "GET",
|
|
1970
1965
|
headers: {
|
|
1971
1966
|
Authorization: `Bearer ${auth.apiKey}`
|
|
1972
|
-
}
|
|
1973
|
-
signal: AbortSignal.timeout(7e3)
|
|
1967
|
+
}
|
|
1974
1968
|
});
|
|
1975
1969
|
const body = await parseResponseBody2(response);
|
|
1976
1970
|
if (response.ok) {
|
|
@@ -3215,8 +3209,8 @@ function encodeRepoPath2(value) {
|
|
|
3215
3209
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3216
3210
|
}
|
|
3217
3211
|
function isLikelyRepoFilePath(path) {
|
|
3218
|
-
const
|
|
3219
|
-
return
|
|
3212
|
+
const basename5 = path.split("/").pop() ?? path;
|
|
3213
|
+
return basename5.includes(".") && !/^\.[^./]+$/.test(basename5);
|
|
3220
3214
|
}
|
|
3221
3215
|
function buildContentsUrl2(spec, path) {
|
|
3222
3216
|
const encodedPath = encodeRepoPath2(path);
|
|
@@ -4594,15 +4588,17 @@ function skippedOpenClawHealth() {
|
|
|
4594
4588
|
details: []
|
|
4595
4589
|
};
|
|
4596
4590
|
}
|
|
4597
|
-
async function runDoctor() {
|
|
4591
|
+
async function runDoctor(options = {}) {
|
|
4598
4592
|
const surfaces = listSurfaceStatuses();
|
|
4599
4593
|
const openclawSurface = surfaces.find((surface) => surface.name === "openclaw");
|
|
4600
|
-
const auth = await
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4594
|
+
const [auth, hostedMcp, hostedMcpTool, npmRegistry, workspace, openclaw] = await Promise.all([
|
|
4595
|
+
checkOrgxAuth(),
|
|
4596
|
+
checkHostedMcpHealth(),
|
|
4597
|
+
checkHostedMcpToolAccess(),
|
|
4598
|
+
checkNpmRegistryHealth(),
|
|
4599
|
+
options.cachedWorkspace ? Promise.resolve(options.cachedWorkspace) : checkWorkspaceConnectivity(),
|
|
4600
|
+
openclawSurface?.detected ? checkOpenClawHealth(openclawSurface.path) : Promise.resolve(skippedOpenClawHealth())
|
|
4601
|
+
]);
|
|
4606
4602
|
return { surfaces, auth, hostedMcp, hostedMcpTool, npmRegistry, workspace, openclaw };
|
|
4607
4603
|
}
|
|
4608
4604
|
function assessDoctorReport(report) {
|
|
@@ -4745,15 +4741,250 @@ function persistContinuityDefaults(seed = {}, statePath) {
|
|
|
4745
4741
|
);
|
|
4746
4742
|
}
|
|
4747
4743
|
|
|
4744
|
+
// src/lib/setup-workspace.ts
|
|
4745
|
+
var CREATE_WORKSPACE_VALUE = "__create_workspace__";
|
|
4746
|
+
var SKIP_WORKSPACE_VALUE = "__skip_workspace__";
|
|
4747
|
+
var REAUTH_WORKSPACE_VALUE = "__reauth_workspace__";
|
|
4748
|
+
function trimDescription(value) {
|
|
4749
|
+
const trimmed = value.trim();
|
|
4750
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
4751
|
+
}
|
|
4752
|
+
function cancelResult(prompts, message = "Workspace bootstrap cancelled.") {
|
|
4753
|
+
prompts.cancel(message);
|
|
4754
|
+
return {
|
|
4755
|
+
message,
|
|
4756
|
+
status: "cancelled"
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
function buildWorkspaceLabel(workspace, currentWorkspaceId) {
|
|
4760
|
+
const suffixes = [];
|
|
4761
|
+
if (workspace.isDefault) {
|
|
4762
|
+
suffixes.push("default");
|
|
4763
|
+
}
|
|
4764
|
+
if (workspace.id === currentWorkspaceId) {
|
|
4765
|
+
suffixes.push("current");
|
|
4766
|
+
}
|
|
4767
|
+
if (suffixes.length === 0) {
|
|
4768
|
+
return workspace.name;
|
|
4769
|
+
}
|
|
4770
|
+
return `${workspace.name} (${suffixes.join(", ")})`;
|
|
4771
|
+
}
|
|
4772
|
+
function buildWorkspaceSelectOptions(workspaces, currentWorkspaceId) {
|
|
4773
|
+
const options = workspaces.map((workspace) => ({
|
|
4774
|
+
value: workspace.id,
|
|
4775
|
+
label: buildWorkspaceLabel(workspace, currentWorkspaceId),
|
|
4776
|
+
...workspace.description ? { hint: workspace.description } : {}
|
|
4777
|
+
}));
|
|
4778
|
+
options.push(
|
|
4779
|
+
{
|
|
4780
|
+
value: CREATE_WORKSPACE_VALUE,
|
|
4781
|
+
label: "Create a new workspace",
|
|
4782
|
+
hint: "Name it here and set it as the default for this machine."
|
|
4783
|
+
},
|
|
4784
|
+
{
|
|
4785
|
+
value: SKIP_WORKSPACE_VALUE,
|
|
4786
|
+
label: "Skip for now",
|
|
4787
|
+
hint: "Leave workspace selection unchanged and finish setup."
|
|
4788
|
+
}
|
|
4789
|
+
);
|
|
4790
|
+
return options;
|
|
4791
|
+
}
|
|
4792
|
+
async function promptForWorkspaceName(prompts) {
|
|
4793
|
+
return prompts.text({
|
|
4794
|
+
message: "Workspace name",
|
|
4795
|
+
placeholder: "Founders",
|
|
4796
|
+
validate(value) {
|
|
4797
|
+
if (!value || value.trim().length === 0) {
|
|
4798
|
+
return "Workspace name is required.";
|
|
4799
|
+
}
|
|
4800
|
+
return void 0;
|
|
4801
|
+
}
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
async function promptForWorkspaceDescription(prompts) {
|
|
4805
|
+
return prompts.text({
|
|
4806
|
+
message: "Workspace description",
|
|
4807
|
+
placeholder: "Optional"
|
|
4808
|
+
});
|
|
4809
|
+
}
|
|
4810
|
+
async function createAndSelectWorkspace(client, prompts) {
|
|
4811
|
+
const name = await promptForWorkspaceName(prompts);
|
|
4812
|
+
if (prompts.isCancel(name)) {
|
|
4813
|
+
return cancelResult(prompts);
|
|
4814
|
+
}
|
|
4815
|
+
if (typeof name !== "string") {
|
|
4816
|
+
return cancelResult(prompts);
|
|
4817
|
+
}
|
|
4818
|
+
const description = await promptForWorkspaceDescription(prompts);
|
|
4819
|
+
if (prompts.isCancel(description)) {
|
|
4820
|
+
return cancelResult(prompts);
|
|
4821
|
+
}
|
|
4822
|
+
if (typeof description !== "string") {
|
|
4823
|
+
return cancelResult(prompts);
|
|
4824
|
+
}
|
|
4825
|
+
const trimmedDescription = trimDescription(description);
|
|
4826
|
+
const createWorkspaceInput = trimmedDescription ? { name, description: trimmedDescription } : { name };
|
|
4827
|
+
const created = await client.createWorkspace(createWorkspaceInput);
|
|
4828
|
+
if (created.isDefault) {
|
|
4829
|
+
return {
|
|
4830
|
+
created: true,
|
|
4831
|
+
defaultChanged: false,
|
|
4832
|
+
message: `Created "${created.name}" and it is already the default OrgX workspace.`,
|
|
4833
|
+
status: "updated",
|
|
4834
|
+
workspace: created
|
|
4835
|
+
};
|
|
4836
|
+
}
|
|
4837
|
+
const promoted = await client.setDefaultWorkspace({ id: created.id });
|
|
4838
|
+
return {
|
|
4839
|
+
created: true,
|
|
4840
|
+
defaultChanged: promoted.changed,
|
|
4841
|
+
message: `Created "${promoted.workspace.name}" and set it as the default OrgX workspace.`,
|
|
4842
|
+
status: "updated",
|
|
4843
|
+
workspace: promoted.workspace
|
|
4844
|
+
};
|
|
4845
|
+
}
|
|
4846
|
+
async function runWorkspaceSetup(client, prompts, options) {
|
|
4847
|
+
if (!options.interactive) {
|
|
4848
|
+
return {
|
|
4849
|
+
message: "Interactive workspace bootstrap skipped because this shell is not attached to a TTY.",
|
|
4850
|
+
status: "skipped"
|
|
4851
|
+
};
|
|
4852
|
+
}
|
|
4853
|
+
const workspaces = await client.listWorkspaces();
|
|
4854
|
+
const currentWorkspace = workspaces.length > 0 ? await client.getCurrentWorkspace().catch(() => workspaces.find((workspace) => workspace.isDefault) ?? null) : null;
|
|
4855
|
+
if (workspaces.length === 0) {
|
|
4856
|
+
const action = await prompts.select({
|
|
4857
|
+
message: "OrgX authenticated, but returned 0 workspaces for this key. How should setup proceed?",
|
|
4858
|
+
options: [
|
|
4859
|
+
{
|
|
4860
|
+
value: REAUTH_WORKSPACE_VALUE,
|
|
4861
|
+
label: "Re-authenticate (recommended if you expected workspaces)",
|
|
4862
|
+
hint: "Run `wizard auth login` to re-link via OAuth if your API key is bound to a different user identity."
|
|
4863
|
+
},
|
|
4864
|
+
{
|
|
4865
|
+
value: CREATE_WORKSPACE_VALUE,
|
|
4866
|
+
label: "Create a new workspace",
|
|
4867
|
+
hint: "Use this only for a truly new account \u2014 this will fork data if your key is misbound."
|
|
4868
|
+
},
|
|
4869
|
+
{
|
|
4870
|
+
value: SKIP_WORKSPACE_VALUE,
|
|
4871
|
+
label: "Skip for now",
|
|
4872
|
+
hint: "Finish surface setup without touching workspaces."
|
|
4873
|
+
}
|
|
4874
|
+
],
|
|
4875
|
+
initialValue: REAUTH_WORKSPACE_VALUE
|
|
4876
|
+
});
|
|
4877
|
+
if (prompts.isCancel(action)) {
|
|
4878
|
+
return cancelResult(prompts);
|
|
4879
|
+
}
|
|
4880
|
+
if (action === REAUTH_WORKSPACE_VALUE) {
|
|
4881
|
+
return {
|
|
4882
|
+
message: "Re-authentication requested. Run `wizard auth login`, then rerun `wizard setup`.",
|
|
4883
|
+
status: "reauth_requested"
|
|
4884
|
+
};
|
|
4885
|
+
}
|
|
4886
|
+
if (action === SKIP_WORKSPACE_VALUE) {
|
|
4887
|
+
return {
|
|
4888
|
+
message: "Workspace bootstrap skipped.",
|
|
4889
|
+
status: "skipped"
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
return createAndSelectWorkspace(client, prompts);
|
|
4893
|
+
}
|
|
4894
|
+
if (options.skipIfConfigured && currentWorkspace) {
|
|
4895
|
+
return {
|
|
4896
|
+
defaultChanged: false,
|
|
4897
|
+
message: `Using "${currentWorkspace.name}" as the default OrgX workspace.`,
|
|
4898
|
+
status: "unchanged",
|
|
4899
|
+
workspace: currentWorkspace
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4902
|
+
const initialWorkspaceId = currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id ?? workspaces[0]?.id;
|
|
4903
|
+
const selected = await prompts.select({
|
|
4904
|
+
message: "Choose the OrgX workspace this machine should use by default.",
|
|
4905
|
+
options: buildWorkspaceSelectOptions(
|
|
4906
|
+
workspaces,
|
|
4907
|
+
currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id
|
|
4908
|
+
),
|
|
4909
|
+
...initialWorkspaceId ? { initialValue: initialWorkspaceId } : {}
|
|
4910
|
+
});
|
|
4911
|
+
if (prompts.isCancel(selected)) {
|
|
4912
|
+
return cancelResult(prompts);
|
|
4913
|
+
}
|
|
4914
|
+
if (typeof selected !== "string") {
|
|
4915
|
+
return cancelResult(prompts);
|
|
4916
|
+
}
|
|
4917
|
+
if (selected === SKIP_WORKSPACE_VALUE) {
|
|
4918
|
+
return {
|
|
4919
|
+
message: "Workspace bootstrap skipped.",
|
|
4920
|
+
status: "skipped",
|
|
4921
|
+
...currentWorkspace ? { workspace: currentWorkspace } : {}
|
|
4922
|
+
};
|
|
4923
|
+
}
|
|
4924
|
+
if (selected === CREATE_WORKSPACE_VALUE) {
|
|
4925
|
+
return createAndSelectWorkspace(client, prompts);
|
|
4926
|
+
}
|
|
4927
|
+
const chosenWorkspace = workspaces.find((workspace) => workspace.id === selected);
|
|
4928
|
+
if (!chosenWorkspace) {
|
|
4929
|
+
throw new Error(`Selected workspace ${selected} is no longer available.`);
|
|
4930
|
+
}
|
|
4931
|
+
if (chosenWorkspace.isDefault) {
|
|
4932
|
+
return {
|
|
4933
|
+
defaultChanged: false,
|
|
4934
|
+
message: `"${chosenWorkspace.name}" is already the default OrgX workspace.`,
|
|
4935
|
+
status: "unchanged",
|
|
4936
|
+
workspace: chosenWorkspace
|
|
4937
|
+
};
|
|
4938
|
+
}
|
|
4939
|
+
const promoted = await client.setDefaultWorkspace({ id: chosenWorkspace.id });
|
|
4940
|
+
return {
|
|
4941
|
+
defaultChanged: promoted.changed,
|
|
4942
|
+
message: `Set "${promoted.workspace.name}" as the default OrgX workspace.`,
|
|
4943
|
+
status: promoted.changed ? "updated" : "unchanged",
|
|
4944
|
+
workspace: promoted.workspace
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4948
|
+
// src/lib/founder-preset.ts
|
|
4949
|
+
async function runFounderPreset(prompts, options) {
|
|
4950
|
+
const surfaceResults = await setupDetectedSurfaces();
|
|
4951
|
+
const pluginTargets = options.pluginTargets ?? (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
4952
|
+
const skillReport = await installOrgxSkills({
|
|
4953
|
+
pluginTargets,
|
|
4954
|
+
skillNames: [...DEFAULT_ORGX_SKILL_PACKS]
|
|
4955
|
+
});
|
|
4956
|
+
let workspaceSetup;
|
|
4957
|
+
let workspace = await getCurrentWorkspace().catch(() => null);
|
|
4958
|
+
if (workspace || options.interactive) {
|
|
4959
|
+
workspaceSetup = await runWorkspaceSetup(
|
|
4960
|
+
{
|
|
4961
|
+
createWorkspace,
|
|
4962
|
+
getCurrentWorkspace,
|
|
4963
|
+
listWorkspaces,
|
|
4964
|
+
setDefaultWorkspace
|
|
4965
|
+
},
|
|
4966
|
+
prompts,
|
|
4967
|
+
options
|
|
4968
|
+
);
|
|
4969
|
+
if (workspaceSetup.status === "cancelled") {
|
|
4970
|
+
return workspaceSetup;
|
|
4971
|
+
}
|
|
4972
|
+
workspace = workspaceSetup.workspace ?? workspace ?? await getCurrentWorkspace().catch(() => null);
|
|
4973
|
+
}
|
|
4974
|
+
const continuity = persistContinuityDefaults({
|
|
4975
|
+
statuses: listSurfaceStatuses(),
|
|
4976
|
+
workspace
|
|
4977
|
+
});
|
|
4978
|
+
return {
|
|
4979
|
+
continuity,
|
|
4980
|
+
skillReport,
|
|
4981
|
+
surfaceResults,
|
|
4982
|
+
workspace,
|
|
4983
|
+
...workspaceSetup ? { workspaceSetup } : {}
|
|
4984
|
+
};
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4748
4987
|
// src/lib/initiatives.ts
|
|
4749
|
-
var FOUNDER_DEMO_INITIATIVE_TITLE = "Founder Demo Initiative";
|
|
4750
|
-
var FOUNDER_DEMO_INITIATIVE_SUMMARY = "Starter initiative created by @useorgx/wizard to validate workspace routing, live views, and the default OrgX skill pack.";
|
|
4751
|
-
var FOUNDER_DEMO_DECISION_TITLE = "Approve founder demo workspace";
|
|
4752
|
-
var FOUNDER_DEMO_DECISION_SUMMARY = "Initial decision created by @useorgx/wizard so the founder preset leaves the workspace with a resolved approval trail.";
|
|
4753
|
-
var FOUNDER_DEMO_DECISION_RESOLUTION = "Approved automatically by @useorgx/wizard after the founder preset finished creating the live demo workspace.";
|
|
4754
|
-
var FOUNDER_DEMO_ARTIFACT_NAME = "Founder Demo Live View";
|
|
4755
|
-
var FOUNDER_DEMO_ARTIFACT_TYPE = "document";
|
|
4756
|
-
var FOUNDER_DEMO_ARTIFACT_DESCRIPTION = "Live founder demo generated by @useorgx/wizard after workspace bootstrap completed.";
|
|
4757
4988
|
var ONBOARDING_TASK_TITLE = "Complete OrgX onboarding";
|
|
4758
4989
|
var ONBOARDING_TASK_SUMMARY = "Starter onboarding task created by @useorgx/wizard so the first workspace has a clear follow-up after setup.";
|
|
4759
4990
|
var ONBOARDING_WORKSTREAM_TITLE = "OrgX onboarding";
|
|
@@ -4799,36 +5030,6 @@ function parseInitiative(payload) {
|
|
|
4799
5030
|
...typeof entity.summary === "string" && entity.summary.trim().length > 0 ? { summary: entity.summary.trim() } : {}
|
|
4800
5031
|
};
|
|
4801
5032
|
}
|
|
4802
|
-
function parseDecision(payload) {
|
|
4803
|
-
const entity = extractEntity(payload);
|
|
4804
|
-
const id = typeof entity.id === "string" ? entity.id.trim() : "";
|
|
4805
|
-
const title = typeof entity.title === "string" ? entity.title.trim() : typeof entity.name === "string" ? entity.name.trim() : "";
|
|
4806
|
-
if (!id || !title) {
|
|
4807
|
-
throw new Error("OrgX returned an incomplete decision payload.");
|
|
4808
|
-
}
|
|
4809
|
-
return {
|
|
4810
|
-
id,
|
|
4811
|
-
title,
|
|
4812
|
-
...typeof entity.status === "string" && entity.status.trim().length > 0 ? { status: entity.status.trim() } : {},
|
|
4813
|
-
...typeof entity.summary === "string" && entity.summary.trim().length > 0 ? { summary: entity.summary.trim() } : {}
|
|
4814
|
-
};
|
|
4815
|
-
}
|
|
4816
|
-
function parseArtifact(payload) {
|
|
4817
|
-
const entity = extractEntity(payload);
|
|
4818
|
-
const id = typeof entity.id === "string" ? entity.id.trim() : "";
|
|
4819
|
-
const name = typeof entity.name === "string" ? entity.name.trim() : typeof entity.title === "string" ? entity.title.trim() : "";
|
|
4820
|
-
const type = typeof entity.artifact_type === "string" ? entity.artifact_type.trim() : typeof entity.type === "string" ? entity.type.trim() : "";
|
|
4821
|
-
const url = typeof entity.external_url === "string" ? entity.external_url.trim() : typeof entity.url === "string" ? entity.url.trim() : "";
|
|
4822
|
-
if (!id || !name) {
|
|
4823
|
-
throw new Error("OrgX returned an incomplete artifact payload.");
|
|
4824
|
-
}
|
|
4825
|
-
return {
|
|
4826
|
-
id,
|
|
4827
|
-
name,
|
|
4828
|
-
...type ? { type } : {},
|
|
4829
|
-
...url ? { url } : {}
|
|
4830
|
-
};
|
|
4831
|
-
}
|
|
4832
5033
|
function parseTask(payload) {
|
|
4833
5034
|
const entity = extractEntity(payload);
|
|
4834
5035
|
const id = typeof entity.id === "string" ? entity.id.trim() : "";
|
|
@@ -4852,23 +5053,6 @@ function parseWorkstream(payload) {
|
|
|
4852
5053
|
}
|
|
4853
5054
|
return { id, title };
|
|
4854
5055
|
}
|
|
4855
|
-
function toDemoInitiativeRecord(artifact, decision, initiative, liveUrl, workspace) {
|
|
4856
|
-
return {
|
|
4857
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4858
|
-
artifactId: artifact.id,
|
|
4859
|
-
artifactName: artifact.name,
|
|
4860
|
-
...artifact.type ? { artifactType: artifact.type } : {},
|
|
4861
|
-
...artifact.url ? { artifactUrl: artifact.url } : {},
|
|
4862
|
-
decisionId: decision.id,
|
|
4863
|
-
...decision.status ? { decisionStatus: decision.status } : {},
|
|
4864
|
-
decisionTitle: decision.title,
|
|
4865
|
-
id: initiative.id,
|
|
4866
|
-
liveUrl,
|
|
4867
|
-
title: initiative.title,
|
|
4868
|
-
workspaceId: workspace.id,
|
|
4869
|
-
workspaceName: workspace.name
|
|
4870
|
-
};
|
|
4871
|
-
}
|
|
4872
5056
|
function toOnboardingTaskRecord(task, workspace, options = {}) {
|
|
4873
5057
|
return {
|
|
4874
5058
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4921,27 +5105,6 @@ async function createEntity(type, body, parse2, options = {}) {
|
|
|
4921
5105
|
}
|
|
4922
5106
|
return parse2(responseBody);
|
|
4923
5107
|
}
|
|
4924
|
-
async function updateEntity(type, id, body, parse2, options = {}) {
|
|
4925
|
-
const auth = await requireOrgxAuth2(options);
|
|
4926
|
-
const response = await fetch(buildOrgxApiUrl("/entities", auth.baseUrl), {
|
|
4927
|
-
method: "PATCH",
|
|
4928
|
-
headers: {
|
|
4929
|
-
Authorization: `Bearer ${auth.apiKey}`,
|
|
4930
|
-
"Content-Type": "application/json"
|
|
4931
|
-
},
|
|
4932
|
-
body: JSON.stringify({
|
|
4933
|
-
type,
|
|
4934
|
-
id,
|
|
4935
|
-
...body
|
|
4936
|
-
}),
|
|
4937
|
-
signal: AbortSignal.timeout(7e3)
|
|
4938
|
-
});
|
|
4939
|
-
const responseBody = parseResponseBody3(await response.text());
|
|
4940
|
-
if (!response.ok) {
|
|
4941
|
-
throw new Error(`Failed to update ${type}. ${formatHttpError2(response.status, responseBody)}`);
|
|
4942
|
-
}
|
|
4943
|
-
return parse2(responseBody);
|
|
4944
|
-
}
|
|
4945
5108
|
function buildLiveUrl(baseUrl, initiativeId) {
|
|
4946
5109
|
const parsed = new URL(normalizeOrgxBaseUrl(baseUrl));
|
|
4947
5110
|
parsed.pathname = `/live/${initiativeId}`;
|
|
@@ -4949,48 +5112,6 @@ function buildLiveUrl(baseUrl, initiativeId) {
|
|
|
4949
5112
|
parsed.hash = "";
|
|
4950
5113
|
return parsed.toString();
|
|
4951
5114
|
}
|
|
4952
|
-
async function createFounderDemoDecision(initiative, workspaceId, options = {}) {
|
|
4953
|
-
return createEntity(
|
|
4954
|
-
"decision",
|
|
4955
|
-
{
|
|
4956
|
-
initiative_id: initiative.id,
|
|
4957
|
-
summary: FOUNDER_DEMO_DECISION_SUMMARY,
|
|
4958
|
-
title: FOUNDER_DEMO_DECISION_TITLE,
|
|
4959
|
-
workspace_id: workspaceId
|
|
4960
|
-
},
|
|
4961
|
-
parseDecision,
|
|
4962
|
-
options
|
|
4963
|
-
);
|
|
4964
|
-
}
|
|
4965
|
-
async function approveFounderDemoDecision(decisionId, options = {}) {
|
|
4966
|
-
return updateEntity(
|
|
4967
|
-
"decision",
|
|
4968
|
-
decisionId,
|
|
4969
|
-
{
|
|
4970
|
-
resolution_summary: FOUNDER_DEMO_DECISION_RESOLUTION,
|
|
4971
|
-
status: "approved"
|
|
4972
|
-
},
|
|
4973
|
-
parseDecision,
|
|
4974
|
-
options
|
|
4975
|
-
);
|
|
4976
|
-
}
|
|
4977
|
-
async function createFounderDemoArtifact(initiative, liveUrl, workspaceId, options = {}) {
|
|
4978
|
-
return createEntity(
|
|
4979
|
-
"artifact",
|
|
4980
|
-
{
|
|
4981
|
-
artifact_type: FOUNDER_DEMO_ARTIFACT_TYPE,
|
|
4982
|
-
description: FOUNDER_DEMO_ARTIFACT_DESCRIPTION,
|
|
4983
|
-
entity_id: initiative.id,
|
|
4984
|
-
entity_type: "initiative",
|
|
4985
|
-
external_url: liveUrl,
|
|
4986
|
-
initiative_id: initiative.id,
|
|
4987
|
-
name: FOUNDER_DEMO_ARTIFACT_NAME,
|
|
4988
|
-
workspace_id: workspaceId
|
|
4989
|
-
},
|
|
4990
|
-
parseArtifact,
|
|
4991
|
-
options
|
|
4992
|
-
);
|
|
4993
|
-
}
|
|
4994
5115
|
async function createInitiative(input, options = {}) {
|
|
4995
5116
|
const title = input.title.trim();
|
|
4996
5117
|
if (!title) {
|
|
@@ -5008,52 +5129,6 @@ async function createInitiative(input, options = {}) {
|
|
|
5008
5129
|
options
|
|
5009
5130
|
);
|
|
5010
5131
|
}
|
|
5011
|
-
async function ensureFounderDemoInitiative(workspace, options = {}) {
|
|
5012
|
-
const existingRecord = readWizardState(options.statePath)?.demoInitiative;
|
|
5013
|
-
const matchingRecord = existingRecord?.workspaceId === workspace.id ? existingRecord : void 0;
|
|
5014
|
-
const auth = await requireOrgxAuth2(options);
|
|
5015
|
-
const initiative = matchingRecord ? {
|
|
5016
|
-
id: matchingRecord.id,
|
|
5017
|
-
title: matchingRecord.title
|
|
5018
|
-
} : await createInitiative(
|
|
5019
|
-
{
|
|
5020
|
-
title: FOUNDER_DEMO_INITIATIVE_TITLE,
|
|
5021
|
-
summary: FOUNDER_DEMO_INITIATIVE_SUMMARY,
|
|
5022
|
-
workspaceId: workspace.id
|
|
5023
|
-
},
|
|
5024
|
-
options
|
|
5025
|
-
);
|
|
5026
|
-
const liveUrl = matchingRecord?.liveUrl || buildLiveUrl(auth.baseUrl, initiative.id);
|
|
5027
|
-
const decision = matchingRecord?.decisionId ? matchingRecord.decisionStatus === "approved" && matchingRecord.decisionTitle ? {
|
|
5028
|
-
id: matchingRecord.decisionId,
|
|
5029
|
-
status: matchingRecord.decisionStatus,
|
|
5030
|
-
title: matchingRecord.decisionTitle
|
|
5031
|
-
} : await approveFounderDemoDecision(matchingRecord.decisionId, options) : await approveFounderDemoDecision(
|
|
5032
|
-
(await createFounderDemoDecision(initiative, workspace.id, options)).id,
|
|
5033
|
-
options
|
|
5034
|
-
);
|
|
5035
|
-
const artifact = matchingRecord?.artifactId && matchingRecord.artifactName ? {
|
|
5036
|
-
id: matchingRecord.artifactId,
|
|
5037
|
-
name: matchingRecord.artifactName,
|
|
5038
|
-
...matchingRecord.artifactType ? { type: matchingRecord.artifactType } : {},
|
|
5039
|
-
...matchingRecord.artifactUrl ? { url: matchingRecord.artifactUrl } : {}
|
|
5040
|
-
} : await createFounderDemoArtifact(initiative, liveUrl, workspace.id, options);
|
|
5041
|
-
const record = toDemoInitiativeRecord(artifact, decision, initiative, liveUrl, workspace);
|
|
5042
|
-
updateWizardState(
|
|
5043
|
-
(current) => ({
|
|
5044
|
-
...current,
|
|
5045
|
-
demoInitiative: record
|
|
5046
|
-
}),
|
|
5047
|
-
options.statePath
|
|
5048
|
-
);
|
|
5049
|
-
return {
|
|
5050
|
-
artifact,
|
|
5051
|
-
created: !matchingRecord,
|
|
5052
|
-
decision,
|
|
5053
|
-
initiative,
|
|
5054
|
-
liveUrl
|
|
5055
|
-
};
|
|
5056
|
-
}
|
|
5057
5132
|
async function ensureFirstValueInitiative(workspace, options = {}) {
|
|
5058
5133
|
const existingRecord = readWizardState(options.statePath)?.firstValueInitiative;
|
|
5059
5134
|
const matchingRecord = existingRecord?.workspaceId === workspace.id ? existingRecord : void 0;
|
|
@@ -5143,253 +5218,206 @@ async function ensureOnboardingTask(workspace, options = {}) {
|
|
|
5143
5218
|
);
|
|
5144
5219
|
return task;
|
|
5145
5220
|
}
|
|
5146
|
-
|
|
5147
|
-
// src/lib/
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
}
|
|
5161
|
-
}
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
}
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
);
|
|
5193
|
-
return
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
}
|
|
5205
|
-
|
|
5206
|
-
}
|
|
5207
|
-
async function promptForWorkspaceDescription(prompts) {
|
|
5208
|
-
return prompts.text({
|
|
5209
|
-
message: "Workspace description",
|
|
5210
|
-
placeholder: "Optional"
|
|
5211
|
-
});
|
|
5212
|
-
}
|
|
5213
|
-
async function createAndSelectWorkspace(client, prompts) {
|
|
5214
|
-
const name = await promptForWorkspaceName(prompts);
|
|
5215
|
-
if (prompts.isCancel(name)) {
|
|
5216
|
-
return cancelResult(prompts);
|
|
5217
|
-
}
|
|
5218
|
-
if (typeof name !== "string") {
|
|
5219
|
-
return cancelResult(prompts);
|
|
5220
|
-
}
|
|
5221
|
-
const description = await promptForWorkspaceDescription(prompts);
|
|
5222
|
-
if (prompts.isCancel(description)) {
|
|
5223
|
-
return cancelResult(prompts);
|
|
5224
|
-
}
|
|
5225
|
-
if (typeof description !== "string") {
|
|
5226
|
-
return cancelResult(prompts);
|
|
5227
|
-
}
|
|
5228
|
-
const trimmedDescription = trimDescription(description);
|
|
5229
|
-
const createWorkspaceInput = trimmedDescription ? { name, description: trimmedDescription } : { name };
|
|
5230
|
-
const created = await client.createWorkspace(createWorkspaceInput);
|
|
5231
|
-
if (created.isDefault) {
|
|
5232
|
-
return {
|
|
5233
|
-
created: true,
|
|
5234
|
-
defaultChanged: false,
|
|
5235
|
-
message: `Created "${created.name}" and it is already the default OrgX workspace.`,
|
|
5236
|
-
status: "updated",
|
|
5237
|
-
workspace: created
|
|
5238
|
-
};
|
|
5239
|
-
}
|
|
5240
|
-
const promoted = await client.setDefaultWorkspace({ id: created.id });
|
|
5241
|
-
return {
|
|
5242
|
-
created: true,
|
|
5243
|
-
defaultChanged: promoted.changed,
|
|
5244
|
-
message: `Created "${promoted.workspace.name}" and set it as the default OrgX workspace.`,
|
|
5245
|
-
status: "updated",
|
|
5246
|
-
workspace: promoted.workspace
|
|
5247
|
-
};
|
|
5248
|
-
}
|
|
5249
|
-
async function runWorkspaceSetup(client, prompts, options) {
|
|
5250
|
-
if (!options.interactive) {
|
|
5251
|
-
return {
|
|
5252
|
-
message: "Interactive workspace bootstrap skipped because this shell is not attached to a TTY.",
|
|
5253
|
-
status: "skipped"
|
|
5254
|
-
};
|
|
5255
|
-
}
|
|
5256
|
-
const workspaces = await client.listWorkspaces();
|
|
5257
|
-
const currentWorkspace = workspaces.length > 0 ? await client.getCurrentWorkspace().catch(() => workspaces.find((workspace) => workspace.isDefault) ?? null) : null;
|
|
5258
|
-
if (workspaces.length === 0) {
|
|
5259
|
-
const action = await prompts.select({
|
|
5260
|
-
message: "OrgX authenticated, but returned 0 workspaces for this key. How should setup proceed?",
|
|
5261
|
-
options: [
|
|
5262
|
-
{
|
|
5263
|
-
value: REAUTH_WORKSPACE_VALUE,
|
|
5264
|
-
label: "Re-authenticate (recommended if you expected workspaces)",
|
|
5265
|
-
hint: "Run `wizard auth login` to re-link via OAuth if your API key is bound to a different user identity."
|
|
5266
|
-
},
|
|
5267
|
-
{
|
|
5268
|
-
value: CREATE_WORKSPACE_VALUE,
|
|
5269
|
-
label: "Create a new workspace",
|
|
5270
|
-
hint: "Use this only for a truly new account \u2014 this will fork data if your key is misbound."
|
|
5271
|
-
},
|
|
5272
|
-
{
|
|
5273
|
-
value: SKIP_WORKSPACE_VALUE,
|
|
5274
|
-
label: "Skip for now",
|
|
5275
|
-
hint: "Finish surface setup without touching workspaces."
|
|
5276
|
-
}
|
|
5277
|
-
],
|
|
5278
|
-
initialValue: REAUTH_WORKSPACE_VALUE
|
|
5279
|
-
});
|
|
5280
|
-
if (prompts.isCancel(action)) {
|
|
5281
|
-
return cancelResult(prompts);
|
|
5282
|
-
}
|
|
5283
|
-
if (action === REAUTH_WORKSPACE_VALUE) {
|
|
5284
|
-
return {
|
|
5285
|
-
message: "Re-authentication requested. Run `wizard auth login`, then rerun `wizard setup`.",
|
|
5286
|
-
status: "reauth_requested"
|
|
5287
|
-
};
|
|
5221
|
+
|
|
5222
|
+
// src/lib/local-skill-discovery.ts
|
|
5223
|
+
import { createHash as createHash3 } from "crypto";
|
|
5224
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
5225
|
+
import { basename as basename2, join as join4, relative as relative2 } from "path";
|
|
5226
|
+
var DEFAULT_MAX_BYTES = 48e3;
|
|
5227
|
+
var DEFAULT_LIMIT = 12;
|
|
5228
|
+
var IGNORED_DIRS = /* @__PURE__ */ new Set([".git", ".next", ".turbo", "build", "dist", "node_modules"]);
|
|
5229
|
+
var LOCAL_SKILL_SOURCES = ["opencode", "claude", "codex", "agents", "workspace"];
|
|
5230
|
+
var DOMAIN_KEYWORDS = [
|
|
5231
|
+
{ domain: "engineering", pattern: /\b(eval|benchmark|test|ci|code|github|repo|runtime|api|llm|model)\b/i },
|
|
5232
|
+
{ domain: "product", pattern: /\b(customer|workflow|roadmap|prd|user|adoption|value|requirements?)\b/i },
|
|
5233
|
+
{ domain: "operations", pattern: /\b(runbook|incident|sla|dashboard|superset|metric|monitor|ops)\b/i },
|
|
5234
|
+
{ domain: "design", pattern: /\b(ui|ux|design|accessibility|component|visual)\b/i },
|
|
5235
|
+
{ domain: "marketing", pattern: /\b(launch|campaign|positioning|gtm|content|story)\b/i },
|
|
5236
|
+
{ domain: "sales", pattern: /\b(deal|pipeline|prospect|meddic|outreach|buyer)\b/i }
|
|
5237
|
+
];
|
|
5238
|
+
function hash(value, length = 10) {
|
|
5239
|
+
return createHash3("sha256").update(value).digest("hex").slice(0, length);
|
|
5240
|
+
}
|
|
5241
|
+
function safeStat(path) {
|
|
5242
|
+
try {
|
|
5243
|
+
return statSync3(path);
|
|
5244
|
+
} catch {
|
|
5245
|
+
return null;
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
function defaultRoots(input) {
|
|
5249
|
+
return {
|
|
5250
|
+
agents: [join4(input.home, ".agents", "skills")],
|
|
5251
|
+
claude: [join4(input.home, ".claude", "skills"), join4(input.cwd, ".claude", "skills")],
|
|
5252
|
+
codex: [join4(input.home, ".codex", "skills"), join4(input.cwd, ".codex", "skills")],
|
|
5253
|
+
opencode: [
|
|
5254
|
+
join4(input.home, ".opencode", "skills"),
|
|
5255
|
+
join4(input.home, ".config", "opencode", "skills"),
|
|
5256
|
+
join4(input.home, "Library", "Application Support", "opencode", "skills"),
|
|
5257
|
+
join4(input.cwd, ".opencode", "skills")
|
|
5258
|
+
],
|
|
5259
|
+
workspace: [
|
|
5260
|
+
join4(input.cwd, "skills"),
|
|
5261
|
+
join4(input.cwd, ".agents", "skills"),
|
|
5262
|
+
join4(input.cwd, ".orgx", "skills")
|
|
5263
|
+
]
|
|
5264
|
+
};
|
|
5265
|
+
}
|
|
5266
|
+
function walkSkillFiles(root, maxFiles = 200) {
|
|
5267
|
+
const rootStats = safeStat(root);
|
|
5268
|
+
if (!rootStats) return [];
|
|
5269
|
+
if (rootStats.isFile()) return [root];
|
|
5270
|
+
if (!rootStats.isDirectory()) return [];
|
|
5271
|
+
const files = [];
|
|
5272
|
+
const stack = [root];
|
|
5273
|
+
while (stack.length > 0 && files.length < maxFiles) {
|
|
5274
|
+
const current = stack.pop();
|
|
5275
|
+
if (!current) continue;
|
|
5276
|
+
let entries;
|
|
5277
|
+
try {
|
|
5278
|
+
entries = readdirSync3(current, { withFileTypes: true });
|
|
5279
|
+
} catch {
|
|
5280
|
+
continue;
|
|
5288
5281
|
}
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5282
|
+
for (const entry of entries) {
|
|
5283
|
+
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5284
|
+
const path = join4(current, entry.name);
|
|
5285
|
+
if (entry.isDirectory()) {
|
|
5286
|
+
stack.push(path);
|
|
5287
|
+
} else if (entry.isFile() && /\.(md|mdc|txt)$/i.test(entry.name)) {
|
|
5288
|
+
files.push(path);
|
|
5289
|
+
}
|
|
5294
5290
|
}
|
|
5295
|
-
return createAndSelectWorkspace(client, prompts);
|
|
5296
|
-
}
|
|
5297
|
-
if (options.skipIfConfigured && currentWorkspace) {
|
|
5298
|
-
return {
|
|
5299
|
-
defaultChanged: false,
|
|
5300
|
-
message: `Using "${currentWorkspace.name}" as the default OrgX workspace.`,
|
|
5301
|
-
status: "unchanged",
|
|
5302
|
-
workspace: currentWorkspace
|
|
5303
|
-
};
|
|
5304
|
-
}
|
|
5305
|
-
const initialWorkspaceId = currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id ?? workspaces[0]?.id;
|
|
5306
|
-
const selected = await prompts.select({
|
|
5307
|
-
message: "Choose the OrgX workspace this machine should use by default.",
|
|
5308
|
-
options: buildWorkspaceSelectOptions(
|
|
5309
|
-
workspaces,
|
|
5310
|
-
currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id
|
|
5311
|
-
),
|
|
5312
|
-
...initialWorkspaceId ? { initialValue: initialWorkspaceId } : {}
|
|
5313
|
-
});
|
|
5314
|
-
if (prompts.isCancel(selected)) {
|
|
5315
|
-
return cancelResult(prompts);
|
|
5316
5291
|
}
|
|
5317
|
-
|
|
5318
|
-
|
|
5292
|
+
return files;
|
|
5293
|
+
}
|
|
5294
|
+
function readWindow(path, maxBytes) {
|
|
5295
|
+
const stats = safeStat(path);
|
|
5296
|
+
if (!stats?.isFile() || stats.size === 0) return null;
|
|
5297
|
+
try {
|
|
5298
|
+
const text2 = readFileSync3(path, "utf8");
|
|
5299
|
+
return text2.slice(0, maxBytes);
|
|
5300
|
+
} catch {
|
|
5301
|
+
return null;
|
|
5319
5302
|
}
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5303
|
+
}
|
|
5304
|
+
function titleFrom(path, text2) {
|
|
5305
|
+
const heading = text2.match(/^#\s+(.+)$/m)?.[1]?.trim();
|
|
5306
|
+
if (heading) return heading.slice(0, 120);
|
|
5307
|
+
return basename2(path).replace(/\.(md|mdc|txt)$/i, "").replace(/[-_]+/g, " ");
|
|
5308
|
+
}
|
|
5309
|
+
function snippetFrom(text2) {
|
|
5310
|
+
const lines = text2.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("---") && !/^#+\s/.test(line));
|
|
5311
|
+
return lines.slice(0, 4).join(" ").replace(/\s+/g, " ").slice(0, 420);
|
|
5312
|
+
}
|
|
5313
|
+
function tokenize(value) {
|
|
5314
|
+
return value.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length >= 3);
|
|
5315
|
+
}
|
|
5316
|
+
function scoreCandidate(text2, context, source) {
|
|
5317
|
+
const haystack = text2.toLowerCase();
|
|
5318
|
+
const contextTokens = [...new Set(tokenize(context))];
|
|
5319
|
+
const contextHits = contextTokens.filter((token) => haystack.includes(token)).length;
|
|
5320
|
+
const explicitSkillSignal = /\b(skill|agent|workflow|instruction|rule|prompt|playbook)\b/i.test(text2) ? 2 : 0;
|
|
5321
|
+
const sourceBoost = source === "opencode" ? 2 : source === "workspace" ? 1 : 0;
|
|
5322
|
+
const score = contextHits * 3 + explicitSkillSignal + sourceBoost;
|
|
5323
|
+
const reasonParts = [
|
|
5324
|
+
contextHits > 0 ? `${contextHits} context match${contextHits === 1 ? "" : "es"}` : "local skill file",
|
|
5325
|
+
sourceBoost > 0 ? `${source} source` : ""
|
|
5326
|
+
].filter(Boolean);
|
|
5327
|
+
return { reason: reasonParts.join("; "), score };
|
|
5328
|
+
}
|
|
5329
|
+
function inferDomains(text2, context) {
|
|
5330
|
+
const joined = `${text2}
|
|
5331
|
+
${context}`;
|
|
5332
|
+
const domains = DOMAIN_KEYWORDS.filter((entry) => entry.pattern.test(joined)).map((entry) => entry.domain);
|
|
5333
|
+
return domains.length > 0 ? [...new Set(domains)] : ["orchestrator"];
|
|
5334
|
+
}
|
|
5335
|
+
function parseLocalSkillSources(value) {
|
|
5336
|
+
if (!value?.trim() || value.trim().toLowerCase() === "all") {
|
|
5337
|
+
return [...LOCAL_SKILL_SOURCES];
|
|
5326
5338
|
}
|
|
5327
|
-
|
|
5328
|
-
|
|
5339
|
+
const requested = value.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
|
|
5340
|
+
const invalid = requested.filter((source) => !LOCAL_SKILL_SOURCES.includes(source));
|
|
5341
|
+
if (invalid.length > 0) {
|
|
5342
|
+
throw new Error(`Unsupported local skill source: ${invalid.join(", ")}. Use ${LOCAL_SKILL_SOURCES.join(", ")}, or all.`);
|
|
5329
5343
|
}
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5344
|
+
return [...new Set(requested)];
|
|
5345
|
+
}
|
|
5346
|
+
function discoverLocalSkills(options = {}) {
|
|
5347
|
+
const cwd = options.cwd ?? process.cwd();
|
|
5348
|
+
const home = options.home ?? process.env.HOME ?? "";
|
|
5349
|
+
const sources = options.sources ?? [...LOCAL_SKILL_SOURCES];
|
|
5350
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
5351
|
+
const context = options.context?.trim() ?? "";
|
|
5352
|
+
const roots = defaultRoots({ cwd, home });
|
|
5353
|
+
for (const [source, overrides] of Object.entries(options.roots ?? {})) {
|
|
5354
|
+
roots[source] = overrides;
|
|
5333
5355
|
}
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5356
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5357
|
+
const candidates = [];
|
|
5358
|
+
for (const source of sources) {
|
|
5359
|
+
for (const root of roots[source] ?? []) {
|
|
5360
|
+
for (const path of walkSkillFiles(root)) {
|
|
5361
|
+
if (seen.has(path)) continue;
|
|
5362
|
+
seen.add(path);
|
|
5363
|
+
const text2 = readWindow(path, maxBytes);
|
|
5364
|
+
if (!text2 || /ORGX SKILL COMPOSED v1/.test(text2)) continue;
|
|
5365
|
+
const title = titleFrom(path, text2);
|
|
5366
|
+
const snippet = snippetFrom(text2);
|
|
5367
|
+
const scored = scoreCandidate(`${title}
|
|
5368
|
+
${snippet}
|
|
5369
|
+
${text2}`, context, source);
|
|
5370
|
+
candidates.push({
|
|
5371
|
+
agentDomains: inferDomains(`${title}
|
|
5372
|
+
${snippet}`, context),
|
|
5373
|
+
id: `${source}-${hash(path)}`,
|
|
5374
|
+
path,
|
|
5375
|
+
reason: scored.reason,
|
|
5376
|
+
score: scored.score,
|
|
5377
|
+
snippet,
|
|
5378
|
+
source,
|
|
5379
|
+
title
|
|
5380
|
+
});
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5341
5383
|
}
|
|
5342
|
-
|
|
5343
|
-
return {
|
|
5344
|
-
defaultChanged: promoted.changed,
|
|
5345
|
-
message: `Set "${promoted.workspace.name}" as the default OrgX workspace.`,
|
|
5346
|
-
status: promoted.changed ? "updated" : "unchanged",
|
|
5347
|
-
workspace: promoted.workspace
|
|
5348
|
-
};
|
|
5384
|
+
return candidates.sort((left, right) => right.score - left.score || left.title.localeCompare(right.title)).slice(0, Math.max(1, options.limit ?? DEFAULT_LIMIT));
|
|
5349
5385
|
}
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
const
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
let workspaceSetup;
|
|
5360
|
-
let workspace = await getCurrentWorkspace().catch(() => null);
|
|
5361
|
-
if (workspace || options.interactive) {
|
|
5362
|
-
workspaceSetup = await runWorkspaceSetup(
|
|
5363
|
-
{
|
|
5364
|
-
createWorkspace,
|
|
5365
|
-
getCurrentWorkspace,
|
|
5366
|
-
listWorkspaces,
|
|
5367
|
-
setDefaultWorkspace
|
|
5368
|
-
},
|
|
5369
|
-
prompts,
|
|
5370
|
-
options
|
|
5371
|
-
);
|
|
5372
|
-
if (workspaceSetup.status === "cancelled") {
|
|
5373
|
-
return workspaceSetup;
|
|
5386
|
+
function selectLocalSkillCandidates(candidates, selection) {
|
|
5387
|
+
const wanted = selection.split(",").map((item) => item.trim()).filter(Boolean);
|
|
5388
|
+
const selected = [];
|
|
5389
|
+
for (const item of wanted) {
|
|
5390
|
+
const byIndex = /^\d+$/.test(item) ? candidates[Number(item) - 1] : void 0;
|
|
5391
|
+
const byId = candidates.find((candidate) => candidate.id === item);
|
|
5392
|
+
const match = byIndex ?? byId;
|
|
5393
|
+
if (!match) {
|
|
5394
|
+
throw new Error(`No local skill candidate matched '${item}'.`);
|
|
5374
5395
|
}
|
|
5375
|
-
|
|
5396
|
+
selected.push(match);
|
|
5376
5397
|
}
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5398
|
+
return [...new Map(selected.map((candidate) => [candidate.id, candidate])).values()];
|
|
5399
|
+
}
|
|
5400
|
+
function buildLocalSkillExtensionContent(candidates, context) {
|
|
5401
|
+
const lines = [
|
|
5402
|
+
"# Local Skill Preferences",
|
|
5403
|
+
"",
|
|
5404
|
+
"Use these opt-in local preferences when they are relevant to the current OrgX initiative. Do not override explicit user instructions or repo guardrails."
|
|
5405
|
+
];
|
|
5406
|
+
const trimmedContext = context?.trim();
|
|
5407
|
+
if (trimmedContext) {
|
|
5408
|
+
lines.push("", `Context: ${trimmedContext}`);
|
|
5384
5409
|
}
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5410
|
+
for (const candidate of candidates) {
|
|
5411
|
+
lines.push(
|
|
5412
|
+
"",
|
|
5413
|
+
`## ${candidate.title}`,
|
|
5414
|
+
"",
|
|
5415
|
+
`- Source: ${candidate.source} (${relative2(process.cwd(), candidate.path)})`,
|
|
5416
|
+
`- Suggested agents: ${candidate.agentDomains.join(", ")}`,
|
|
5417
|
+
`- Preserve: ${candidate.snippet || "local workflow preference from this skill file."}`
|
|
5418
|
+
);
|
|
5419
|
+
}
|
|
5420
|
+
return lines.join("\n");
|
|
5393
5421
|
}
|
|
5394
5422
|
|
|
5395
5423
|
// src/lib/mutation-output.ts
|
|
@@ -5406,6 +5434,9 @@ var HOSTED_MCP_OUTAGE_TITLE = "Hosted OrgX MCP is unreachable.";
|
|
|
5406
5434
|
function getSetupVerificationHeadline(summary) {
|
|
5407
5435
|
switch (summary.status) {
|
|
5408
5436
|
case "degraded":
|
|
5437
|
+
if (summary.transientTimeouts) {
|
|
5438
|
+
return "OrgX servers were slow to respond \u2014 setup applied, but the final health check timed out. Re-run `wizard doctor` in a moment to confirm.";
|
|
5439
|
+
}
|
|
5409
5440
|
return "Hosted OrgX MCP is down; local setup can still continue.";
|
|
5410
5441
|
case "error":
|
|
5411
5442
|
return "Issues detected";
|
|
@@ -5415,18 +5446,50 @@ function getSetupVerificationHeadline(summary) {
|
|
|
5415
5446
|
return "All systems ready.";
|
|
5416
5447
|
}
|
|
5417
5448
|
}
|
|
5418
|
-
function
|
|
5449
|
+
function isTimeoutErrorString(value) {
|
|
5450
|
+
if (!value) return false;
|
|
5451
|
+
return isTimeoutError(new Error(value));
|
|
5452
|
+
}
|
|
5453
|
+
function reportErrorsAreOnlyTimeouts(report) {
|
|
5454
|
+
if (!report) return false;
|
|
5455
|
+
const authTimedOut = !report.auth.ok && !report.auth.skipped && isTimeoutErrorString(report.auth.error);
|
|
5456
|
+
const workspaceTimedOut = !report.workspace.ok && !report.workspace.skipped && isTimeoutErrorString(report.workspace.error);
|
|
5457
|
+
const reachableServicesOk = (report.hostedMcp.skipped || report.hostedMcp.ok) && (report.openclaw.skipped || report.openclaw.ok);
|
|
5458
|
+
return reachableServicesOk && (authTimedOut || workspaceTimedOut);
|
|
5459
|
+
}
|
|
5460
|
+
function summarizeSetupVerification(assessment, report) {
|
|
5419
5461
|
const errors = assessment.issues.filter((issue) => issue.level === "error");
|
|
5420
5462
|
if (errors.length === 0) {
|
|
5421
5463
|
return {
|
|
5422
5464
|
hostedMcpDegraded: false,
|
|
5465
|
+
transientTimeouts: false,
|
|
5423
5466
|
status: assessment.issues.length > 0 ? "warning" : "ok"
|
|
5424
5467
|
};
|
|
5425
5468
|
}
|
|
5426
5469
|
const hostedMcpDegraded = errors.every((issue) => issue.title === HOSTED_MCP_OUTAGE_TITLE);
|
|
5470
|
+
if (hostedMcpDegraded) {
|
|
5471
|
+
return {
|
|
5472
|
+
hostedMcpDegraded: true,
|
|
5473
|
+
transientTimeouts: false,
|
|
5474
|
+
status: "degraded"
|
|
5475
|
+
};
|
|
5476
|
+
}
|
|
5477
|
+
const authOrWorkspaceTitles = /* @__PURE__ */ new Set([
|
|
5478
|
+
"OrgX user auth could not be verified.",
|
|
5479
|
+
"Current workspace lookup failed."
|
|
5480
|
+
]);
|
|
5481
|
+
const onlyAuthOrWorkspaceErrors = errors.every((issue) => authOrWorkspaceTitles.has(issue.title));
|
|
5482
|
+
if (onlyAuthOrWorkspaceErrors && reportErrorsAreOnlyTimeouts(report)) {
|
|
5483
|
+
return {
|
|
5484
|
+
hostedMcpDegraded: false,
|
|
5485
|
+
transientTimeouts: true,
|
|
5486
|
+
status: "degraded"
|
|
5487
|
+
};
|
|
5488
|
+
}
|
|
5427
5489
|
return {
|
|
5428
|
-
hostedMcpDegraded,
|
|
5429
|
-
|
|
5490
|
+
hostedMcpDegraded: false,
|
|
5491
|
+
transientTimeouts: false,
|
|
5492
|
+
status: "error"
|
|
5430
5493
|
};
|
|
5431
5494
|
}
|
|
5432
5495
|
|
|
@@ -5468,16 +5531,6 @@ function buildAgentRosterTelemetryProperties(input, base = {}) {
|
|
|
5468
5531
|
base
|
|
5469
5532
|
);
|
|
5470
5533
|
}
|
|
5471
|
-
function buildFounderDemoTelemetryProperties(result, base = {}) {
|
|
5472
|
-
return withBaseProperties(
|
|
5473
|
-
{
|
|
5474
|
-
created: result.created,
|
|
5475
|
-
decision_status: result.decision.status ?? "unknown",
|
|
5476
|
-
has_artifact_url: Boolean(result.artifact.url)
|
|
5477
|
-
},
|
|
5478
|
-
base
|
|
5479
|
-
);
|
|
5480
|
-
}
|
|
5481
5534
|
function buildFirstValueInitiativeTelemetryProperties(result, base = {}) {
|
|
5482
5535
|
return withBaseProperties(
|
|
5483
5536
|
{
|
|
@@ -5500,6 +5553,7 @@ function buildDoctorTelemetryProperties(report, assessment, verification, base =
|
|
|
5500
5553
|
hosted_mcp_degraded: verification.hostedMcpDegraded,
|
|
5501
5554
|
hosted_mcp_ok: report.hostedMcp.ok,
|
|
5502
5555
|
hosted_mcp_tool_ok: report.hostedMcpTool.ok,
|
|
5556
|
+
transient_timeouts: verification.transientTimeouts,
|
|
5503
5557
|
issue_count: assessment.issues.length,
|
|
5504
5558
|
openclaw_available: !report.openclaw.skipped,
|
|
5505
5559
|
openclaw_ok: report.openclaw.ok,
|
|
@@ -5913,6 +5967,40 @@ function normalizeHotkey(input) {
|
|
|
5913
5967
|
}
|
|
5914
5968
|
}
|
|
5915
5969
|
|
|
5970
|
+
// src/lib/setup-profiles.ts
|
|
5971
|
+
var SETUP_PROFILES = {
|
|
5972
|
+
"local-ai-workflow": {
|
|
5973
|
+
id: "local-ai-workflow",
|
|
5974
|
+
label: "Local AI workflow",
|
|
5975
|
+
firstInitiativeTitle: "Make local AI work visible and shippable",
|
|
5976
|
+
firstInitiativeSummary: [
|
|
5977
|
+
"First OrgX initiative tailored for a local AI-assisted workflow.",
|
|
5978
|
+
"Use local AI-session evidence, Git/GitHub proof, and existing project context to create a live work graph, a concrete onboarding task, and a path to cloud execution once GitHub is connected."
|
|
5979
|
+
].join(" "),
|
|
5980
|
+
handoffPrompt: "Use OrgX to continue this local AI-workflow initiative. Start with the onboarding task, inspect local AI-client and GitHub proof, preserve selected local skills, and show the next action plus the cloud handoff once GitHub is connected.",
|
|
5981
|
+
localProofCommand: "orgx-wizard sessions reconcile --from opencode,github --public-share --yes",
|
|
5982
|
+
skillDiscoveryCommand: `orgx-wizard skills discover-local --from opencode,claude,codex,workspace --context "Describe this person's domain, tools, and workflow"`
|
|
5983
|
+
}
|
|
5984
|
+
};
|
|
5985
|
+
function resolveSetupProfile(id) {
|
|
5986
|
+
const normalized = id?.trim().toLowerCase();
|
|
5987
|
+
if (!normalized) return null;
|
|
5988
|
+
return SETUP_PROFILES[normalized] ?? null;
|
|
5989
|
+
}
|
|
5990
|
+
function supportedSetupProfileIds() {
|
|
5991
|
+
return Object.keys(SETUP_PROFILES).sort();
|
|
5992
|
+
}
|
|
5993
|
+
function buildProfileSummary(profile, context) {
|
|
5994
|
+
const trimmedContext = context?.trim();
|
|
5995
|
+
if (!trimmedContext) return profile.firstInitiativeSummary;
|
|
5996
|
+
return `${profile.firstInitiativeSummary} Context: ${trimmedContext}`;
|
|
5997
|
+
}
|
|
5998
|
+
function buildProfileHandoffPrompt(profile, fallbackPrompt, context) {
|
|
5999
|
+
if (!profile) return fallbackPrompt;
|
|
6000
|
+
const trimmedContext = context?.trim();
|
|
6001
|
+
return trimmedContext ? `${profile.handoffPrompt} Context: ${trimmedContext}` : profile.handoffPrompt;
|
|
6002
|
+
}
|
|
6003
|
+
|
|
5916
6004
|
// src/lib/daily-brief-onboarding.ts
|
|
5917
6005
|
function extractErrorHint(body) {
|
|
5918
6006
|
if (!body) return null;
|
|
@@ -6222,8 +6310,8 @@ async function fetchOnboardingState(auth) {
|
|
|
6222
6310
|
}
|
|
6223
6311
|
|
|
6224
6312
|
// src/lib/ai-session-import.ts
|
|
6225
|
-
import { existsSync as
|
|
6226
|
-
import { basename as
|
|
6313
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
6314
|
+
import { basename as basename3, join as join5, relative as relative3 } from "path";
|
|
6227
6315
|
var AI_SESSION_SOURCES = ["codex", "claude"];
|
|
6228
6316
|
var DEFAULT_LIMIT_PER_SOURCE = 3;
|
|
6229
6317
|
var DEFAULT_SINCE_DAYS = 30;
|
|
@@ -6376,7 +6464,7 @@ function keepAuditRelevantLines(text2) {
|
|
|
6376
6464
|
return text2.split(/\r?\n/).map((line) => normalizeAuditRelevantLine(line)).filter((line) => Boolean(line));
|
|
6377
6465
|
}
|
|
6378
6466
|
function collectJsonlFiles(root, source) {
|
|
6379
|
-
if (!
|
|
6467
|
+
if (!existsSync6(root)) return [];
|
|
6380
6468
|
const files = [];
|
|
6381
6469
|
const stack = [root];
|
|
6382
6470
|
while (stack.length > 0) {
|
|
@@ -6384,15 +6472,15 @@ function collectJsonlFiles(root, source) {
|
|
|
6384
6472
|
if (!current) continue;
|
|
6385
6473
|
let entries;
|
|
6386
6474
|
try {
|
|
6387
|
-
entries =
|
|
6475
|
+
entries = readdirSync4(current);
|
|
6388
6476
|
} catch {
|
|
6389
6477
|
continue;
|
|
6390
6478
|
}
|
|
6391
6479
|
for (const entry of entries) {
|
|
6392
|
-
const path =
|
|
6480
|
+
const path = join5(current, entry);
|
|
6393
6481
|
let stats;
|
|
6394
6482
|
try {
|
|
6395
|
-
stats =
|
|
6483
|
+
stats = statSync4(path);
|
|
6396
6484
|
} catch {
|
|
6397
6485
|
continue;
|
|
6398
6486
|
}
|
|
@@ -6410,13 +6498,13 @@ function collectJsonlFiles(root, source) {
|
|
|
6410
6498
|
function readSessionImport(candidate, root, options) {
|
|
6411
6499
|
let stats;
|
|
6412
6500
|
try {
|
|
6413
|
-
stats =
|
|
6501
|
+
stats = statSync4(candidate.path);
|
|
6414
6502
|
} catch {
|
|
6415
6503
|
return null;
|
|
6416
6504
|
}
|
|
6417
6505
|
if (stats.size > options.maxBytesPerFile) return null;
|
|
6418
6506
|
const extractor = candidate.source === "codex" ? extractCodexMessageText : extractClaudeMessageText;
|
|
6419
|
-
const lines =
|
|
6507
|
+
const lines = readFileSync4(candidate.path, "utf8").split(/\r?\n/);
|
|
6420
6508
|
const relevantLines = [];
|
|
6421
6509
|
let messageCount = 0;
|
|
6422
6510
|
for (const line of lines) {
|
|
@@ -6428,10 +6516,10 @@ function readSessionImport(candidate, root, options) {
|
|
|
6428
6516
|
}
|
|
6429
6517
|
const deduped = [...new Set(relevantLines)].slice(0, 80);
|
|
6430
6518
|
if (deduped.length === 0) return null;
|
|
6431
|
-
const relativePath =
|
|
6519
|
+
const relativePath = relative3(root, candidate.path);
|
|
6432
6520
|
return {
|
|
6433
6521
|
import: {
|
|
6434
|
-
sourceId: `${candidate.source}:${
|
|
6522
|
+
sourceId: `${candidate.source}:${basename3(candidate.path, ".jsonl")}`,
|
|
6435
6523
|
sourceLabel: `${candidate.source === "codex" ? "Codex" : "Claude"} session ${relativePath}`,
|
|
6436
6524
|
metadata: {
|
|
6437
6525
|
bytes: stats.size,
|
|
@@ -6501,11 +6589,11 @@ function loadAiSessionImports(options) {
|
|
|
6501
6589
|
}
|
|
6502
6590
|
|
|
6503
6591
|
// src/lib/work-graph-source-adapters.ts
|
|
6504
|
-
import { createHash as
|
|
6592
|
+
import { createHash as createHash4 } from "crypto";
|
|
6505
6593
|
import { execFileSync } from "child_process";
|
|
6506
|
-
import { closeSync, existsSync as
|
|
6594
|
+
import { closeSync, existsSync as existsSync7, openSync, readFileSync as readFileSync5, readdirSync as readdirSync5, readSync, statSync as statSync5 } from "fs";
|
|
6507
6595
|
import { homedir as homedir2 } from "os";
|
|
6508
|
-
import { basename as
|
|
6596
|
+
import { basename as basename4, join as join6, resolve } from "path";
|
|
6509
6597
|
var CLIENT_SOURCES = ["claude_code", "codex", "opencode", "goose", "cursor", "github", "slack"];
|
|
6510
6598
|
var DEFAULT_LIMIT_PER_SOURCE2 = 8;
|
|
6511
6599
|
var DEFAULT_SINCE_DAYS2 = 45;
|
|
@@ -6524,21 +6612,21 @@ function parseInvestigationSourceList(value) {
|
|
|
6524
6612
|
}
|
|
6525
6613
|
return deduped;
|
|
6526
6614
|
}
|
|
6527
|
-
function
|
|
6528
|
-
return
|
|
6615
|
+
function hash2(value, length = 24) {
|
|
6616
|
+
return createHash4("sha256").update(JSON.stringify(value)).digest("hex").slice(0, length);
|
|
6529
6617
|
}
|
|
6530
6618
|
function expandPath(path, env) {
|
|
6531
6619
|
return path.replace(/^~(?=\/|$)/, env.home).replace(/\$CWD/g, env.cwd).replace(/\$HOME/g, env.home);
|
|
6532
6620
|
}
|
|
6533
|
-
function
|
|
6621
|
+
function safeStat2(path) {
|
|
6534
6622
|
try {
|
|
6535
|
-
return
|
|
6623
|
+
return statSync5(path);
|
|
6536
6624
|
} catch {
|
|
6537
6625
|
return null;
|
|
6538
6626
|
}
|
|
6539
6627
|
}
|
|
6540
6628
|
function walkFiles(root, predicate, maxFiles = 500) {
|
|
6541
|
-
if (!
|
|
6629
|
+
if (!existsSync7(root)) return [];
|
|
6542
6630
|
const files = [];
|
|
6543
6631
|
const stack = [root];
|
|
6544
6632
|
const ignored = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist", "build", ".turbo"]);
|
|
@@ -6547,14 +6635,14 @@ function walkFiles(root, predicate, maxFiles = 500) {
|
|
|
6547
6635
|
if (!current) continue;
|
|
6548
6636
|
let entries;
|
|
6549
6637
|
try {
|
|
6550
|
-
entries =
|
|
6638
|
+
entries = readdirSync5(current);
|
|
6551
6639
|
} catch {
|
|
6552
6640
|
continue;
|
|
6553
6641
|
}
|
|
6554
6642
|
for (const entry of entries) {
|
|
6555
6643
|
if (ignored.has(entry)) continue;
|
|
6556
|
-
const path =
|
|
6557
|
-
const stats =
|
|
6644
|
+
const path = join6(current, entry);
|
|
6645
|
+
const stats = safeStat2(path);
|
|
6558
6646
|
if (!stats) continue;
|
|
6559
6647
|
if (stats.isDirectory()) {
|
|
6560
6648
|
stack.push(path);
|
|
@@ -6606,10 +6694,10 @@ function nowWindow(timestamp, now) {
|
|
|
6606
6694
|
return "older";
|
|
6607
6695
|
}
|
|
6608
6696
|
function makeRawEvent(input) {
|
|
6609
|
-
const contentHash =
|
|
6697
|
+
const contentHash = hash2(input.payload, 64);
|
|
6610
6698
|
const uri = `${input.client}:${input.sessionId}:${input.uriSuffix}`;
|
|
6611
6699
|
return {
|
|
6612
|
-
event_id: `evt_${
|
|
6700
|
+
event_id: `evt_${hash2([uri, contentHash], 24)}`,
|
|
6613
6701
|
source_ref: {
|
|
6614
6702
|
source_id: input.client,
|
|
6615
6703
|
uri,
|
|
@@ -6652,7 +6740,7 @@ function parseJsonLine2(line) {
|
|
|
6652
6740
|
}
|
|
6653
6741
|
function readTextWindow(path, stats, maxBytes) {
|
|
6654
6742
|
if (stats.size <= maxBytes) {
|
|
6655
|
-
return { text:
|
|
6743
|
+
return { text: readFileSync5(path, "utf8"), truncated: false };
|
|
6656
6744
|
}
|
|
6657
6745
|
const bytesToRead = Math.min(stats.size, maxBytes);
|
|
6658
6746
|
const buffer = Buffer.alloc(bytesToRead);
|
|
@@ -6796,7 +6884,7 @@ function mapClaudeRecord(record, fallbackTimestamp) {
|
|
|
6796
6884
|
return out;
|
|
6797
6885
|
}
|
|
6798
6886
|
function readJsonlCandidate(candidate, options) {
|
|
6799
|
-
const stats =
|
|
6887
|
+
const stats = safeStat2(candidate.path);
|
|
6800
6888
|
if (!stats) {
|
|
6801
6889
|
return {
|
|
6802
6890
|
collectionMethods: [],
|
|
@@ -6810,7 +6898,7 @@ function readJsonlCandidate(candidate, options) {
|
|
|
6810
6898
|
const window = readTextWindow(candidate.path, stats, options.maxBytesPerFile);
|
|
6811
6899
|
const lines = window.text.split(/\r?\n/);
|
|
6812
6900
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
6813
|
-
const sessionId =
|
|
6901
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6814
6902
|
const events = [];
|
|
6815
6903
|
for (const [index, line] of lines.entries()) {
|
|
6816
6904
|
if (!line.trim()) continue;
|
|
@@ -6873,7 +6961,7 @@ function mapGenericJsonRecord(record, fallbackTimestamp) {
|
|
|
6873
6961
|
}];
|
|
6874
6962
|
}
|
|
6875
6963
|
function readJsonCandidate(candidate, options) {
|
|
6876
|
-
const stats =
|
|
6964
|
+
const stats = safeStat2(candidate.path);
|
|
6877
6965
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6878
6966
|
return {
|
|
6879
6967
|
collectionMethods: [],
|
|
@@ -6886,7 +6974,7 @@ function readJsonCandidate(candidate, options) {
|
|
|
6886
6974
|
}
|
|
6887
6975
|
let parsed;
|
|
6888
6976
|
try {
|
|
6889
|
-
parsed = JSON.parse(
|
|
6977
|
+
parsed = JSON.parse(readFileSync5(candidate.path, "utf8"));
|
|
6890
6978
|
} catch {
|
|
6891
6979
|
return {
|
|
6892
6980
|
collectionMethods: [],
|
|
@@ -6899,7 +6987,7 @@ function readJsonCandidate(candidate, options) {
|
|
|
6899
6987
|
}
|
|
6900
6988
|
const records = flattenPotentialMessages(parsed).slice(0, 800);
|
|
6901
6989
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
6902
|
-
const sessionId =
|
|
6990
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6903
6991
|
const events = records.flatMap(
|
|
6904
6992
|
(record, index) => mapGenericJsonRecord(record, fallbackTimestamp).map(
|
|
6905
6993
|
(item, partIndex) => makeRawEvent({
|
|
@@ -6952,7 +7040,7 @@ function flattenPotentialMessages(value) {
|
|
|
6952
7040
|
return out;
|
|
6953
7041
|
}
|
|
6954
7042
|
function readMarkdownCandidate(candidate, options) {
|
|
6955
|
-
const stats =
|
|
7043
|
+
const stats = safeStat2(candidate.path);
|
|
6956
7044
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6957
7045
|
return {
|
|
6958
7046
|
collectionMethods: [],
|
|
@@ -6963,8 +7051,8 @@ function readMarkdownCandidate(candidate, options) {
|
|
|
6963
7051
|
searchedSessions: 0
|
|
6964
7052
|
};
|
|
6965
7053
|
}
|
|
6966
|
-
const text2 =
|
|
6967
|
-
const sessionId =
|
|
7054
|
+
const text2 = readFileSync5(candidate.path, "utf8");
|
|
7055
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6968
7056
|
const timestamp = new Date(stats.mtimeMs).toISOString();
|
|
6969
7057
|
const event = makeRawEvent({
|
|
6970
7058
|
client: candidate.source,
|
|
@@ -6993,7 +7081,7 @@ function readMarkdownCandidate(candidate, options) {
|
|
|
6993
7081
|
};
|
|
6994
7082
|
}
|
|
6995
7083
|
function readGitReflogCandidate(candidate, options) {
|
|
6996
|
-
const stats =
|
|
7084
|
+
const stats = safeStat2(candidate.path);
|
|
6997
7085
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6998
7086
|
return {
|
|
6999
7087
|
collectionMethods: [],
|
|
@@ -7004,7 +7092,7 @@ function readGitReflogCandidate(candidate, options) {
|
|
|
7004
7092
|
searchedSessions: 0
|
|
7005
7093
|
};
|
|
7006
7094
|
}
|
|
7007
|
-
const lines =
|
|
7095
|
+
const lines = readFileSync5(candidate.path, "utf8").split(/\r?\n/).filter(Boolean).slice(-250);
|
|
7008
7096
|
const events = [];
|
|
7009
7097
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
7010
7098
|
for (const [index, line] of lines.entries()) {
|
|
@@ -7150,10 +7238,10 @@ function discoverCandidates(source, env, sinceMs) {
|
|
|
7150
7238
|
for (const rootPattern of paths) {
|
|
7151
7239
|
const expanded = expandPath(rootPattern, env);
|
|
7152
7240
|
const root = expanded.includes("*") ? expanded.slice(0, expanded.indexOf("*")).replace(/\/$/, "") : expanded;
|
|
7153
|
-
const exactStats =
|
|
7241
|
+
const exactStats = safeStat2(expanded);
|
|
7154
7242
|
const found = exactStats?.isFile() ? [expanded] : walkFiles(root, predicate);
|
|
7155
7243
|
for (const path of found) {
|
|
7156
|
-
const stats =
|
|
7244
|
+
const stats = safeStat2(path);
|
|
7157
7245
|
if (!stats || stats.mtimeMs < sinceMs) continue;
|
|
7158
7246
|
candidates.push({ extractionMode, mtimeMs: stats.mtimeMs, path, source });
|
|
7159
7247
|
}
|
|
@@ -7221,7 +7309,7 @@ function discoverOverrideCandidates(source, root, sinceMs) {
|
|
|
7221
7309
|
const files = walkFiles(root, (path) => path.endsWith(".jsonl") || path.endsWith(".json"));
|
|
7222
7310
|
const candidates = [];
|
|
7223
7311
|
for (const path of files) {
|
|
7224
|
-
const stats =
|
|
7312
|
+
const stats = safeStat2(path);
|
|
7225
7313
|
if (!stats || stats.mtimeMs < sinceMs) continue;
|
|
7226
7314
|
candidates.push({ extractionMode, mtimeMs: stats.mtimeMs, path, source });
|
|
7227
7315
|
}
|
|
@@ -7296,7 +7384,7 @@ function extractionFromEvents(input) {
|
|
|
7296
7384
|
}
|
|
7297
7385
|
return {
|
|
7298
7386
|
schema_version: "2.0.0.investigation",
|
|
7299
|
-
extraction_id: `${input.client}:investigation:${
|
|
7387
|
+
extraction_id: `${input.client}:investigation:${hash2([input.client, input.events.map((event) => event.event_id)], 12)}`,
|
|
7300
7388
|
source_client: workGraphSourceClient(input.client),
|
|
7301
7389
|
source_label: clientLabel(input.client),
|
|
7302
7390
|
collection_methods: [...new Set(input.collectionMethods)].sort(),
|
|
@@ -7389,7 +7477,7 @@ function loadWorkGraphInvestigationSourceData(options) {
|
|
|
7389
7477
|
}
|
|
7390
7478
|
|
|
7391
7479
|
// src/lib/self-audit.ts
|
|
7392
|
-
import { createHash as
|
|
7480
|
+
import { createHash as createHash5 } from "crypto";
|
|
7393
7481
|
var SELF_AUDIT_SCHEMA_VERSION = "2026-04-27";
|
|
7394
7482
|
var AUDIT_DIMENSIONS = [
|
|
7395
7483
|
"queryability",
|
|
@@ -7556,7 +7644,7 @@ function buildSelfCritique(scores) {
|
|
|
7556
7644
|
});
|
|
7557
7645
|
}
|
|
7558
7646
|
function hashPlanPayload(payload) {
|
|
7559
|
-
return
|
|
7647
|
+
return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
7560
7648
|
}
|
|
7561
7649
|
function buildSelfAuditPlan(input) {
|
|
7562
7650
|
if (input.imports.length === 0) {
|
|
@@ -7886,10 +7974,10 @@ Rollback: ${plan.recommended_follow_up.rollback}`,
|
|
|
7886
7974
|
}
|
|
7887
7975
|
|
|
7888
7976
|
// src/lib/work-graph.ts
|
|
7889
|
-
import { createHash as
|
|
7977
|
+
import { createHash as createHash7 } from "crypto";
|
|
7890
7978
|
|
|
7891
7979
|
// src/lib/work-graph-investigation.ts
|
|
7892
|
-
import { createHash as
|
|
7980
|
+
import { createHash as createHash6 } from "crypto";
|
|
7893
7981
|
var WORK_GRAPH_INVESTIGATION_SCHEMA_VERSION = "2.0.0";
|
|
7894
7982
|
var WORK_GRAPH_INVESTIGATION_CLIENTS = [
|
|
7895
7983
|
"claude_code",
|
|
@@ -8021,8 +8109,8 @@ var CAPABILITY_CEILINGS = {
|
|
|
8021
8109
|
decision_lineage: "high"
|
|
8022
8110
|
}
|
|
8023
8111
|
};
|
|
8024
|
-
function
|
|
8025
|
-
return
|
|
8112
|
+
function hash3(value, length = 16) {
|
|
8113
|
+
return createHash6("sha256").update(JSON.stringify(value)).digest("hex").slice(0, length);
|
|
8026
8114
|
}
|
|
8027
8115
|
function clamp(value, min = 0, max = 1) {
|
|
8028
8116
|
return Math.max(min, Math.min(max, value));
|
|
@@ -8075,8 +8163,8 @@ function loopTopicKey(loop) {
|
|
|
8075
8163
|
for (const [pattern, topic] of topicRules) {
|
|
8076
8164
|
if (pattern.test(text2)) return topic;
|
|
8077
8165
|
}
|
|
8078
|
-
if (!intent) return `unclassified:${
|
|
8079
|
-
return `topic:${
|
|
8166
|
+
if (!intent) return `unclassified:${hash3(loop.loop_id, 10)}`;
|
|
8167
|
+
return `topic:${hash3(intent.toLowerCase(), 10)}`;
|
|
8080
8168
|
}
|
|
8081
8169
|
function bestFamilyCentroid(group) {
|
|
8082
8170
|
const candidates = group.map((loop) => cleanLoopIntent(loop.origin.intent, "")).filter(Boolean).map((intent) => {
|
|
@@ -8140,7 +8228,7 @@ function windowFor(timestamp, now) {
|
|
|
8140
8228
|
function rawEventFromFinding(finding, index, generatedAt) {
|
|
8141
8229
|
const sourceClient = normalizeClient(finding.source_client);
|
|
8142
8230
|
const timestamp = typeof finding.metadata.occurred_at === "string" ? finding.metadata.occurred_at : generatedAt;
|
|
8143
|
-
const eventId = `evt_${
|
|
8231
|
+
const eventId = `evt_${hash3([finding.evidence_ref, finding.title, index], 24)}`;
|
|
8144
8232
|
const payload = {
|
|
8145
8233
|
title: finding.title,
|
|
8146
8234
|
summary: finding.summary,
|
|
@@ -8172,7 +8260,7 @@ function rawEventFromFinding(finding, index, generatedAt) {
|
|
|
8172
8260
|
payload,
|
|
8173
8261
|
raw_byte_offset: null,
|
|
8174
8262
|
raw_row_id: null,
|
|
8175
|
-
content_hash:
|
|
8263
|
+
content_hash: hash3(payload, 64),
|
|
8176
8264
|
redaction_applied: true
|
|
8177
8265
|
};
|
|
8178
8266
|
}
|
|
@@ -8184,7 +8272,7 @@ function rawEventFromSourceEvent(event, index, generatedAt) {
|
|
|
8184
8272
|
text_summary: event.text.slice(0, 420)
|
|
8185
8273
|
};
|
|
8186
8274
|
return {
|
|
8187
|
-
event_id: `evt_${
|
|
8275
|
+
event_id: `evt_${hash3([event.evidence_ref, index], 24)}`,
|
|
8188
8276
|
source_ref: {
|
|
8189
8277
|
source_id: sourceClient,
|
|
8190
8278
|
uri: event.evidence_ref,
|
|
@@ -8202,7 +8290,7 @@ function rawEventFromSourceEvent(event, index, generatedAt) {
|
|
|
8202
8290
|
payload,
|
|
8203
8291
|
raw_byte_offset: null,
|
|
8204
8292
|
raw_row_id: null,
|
|
8205
|
-
content_hash:
|
|
8293
|
+
content_hash: hash3(payload, 64),
|
|
8206
8294
|
redaction_applied: true
|
|
8207
8295
|
};
|
|
8208
8296
|
}
|
|
@@ -8333,7 +8421,7 @@ function buildWorkLoops(input) {
|
|
|
8333
8421
|
trail.confidence || matchedFindings.reduce((total, finding) => total + finding.confidence, 0) / Math.max(1, matchedFindings.length)
|
|
8334
8422
|
);
|
|
8335
8423
|
return {
|
|
8336
|
-
loop_id: `loop_${
|
|
8424
|
+
loop_id: `loop_${hash3([trail.id, index], 18)}`,
|
|
8337
8425
|
cites: eventIds,
|
|
8338
8426
|
origin: {
|
|
8339
8427
|
event_id: eventIds[0] ?? `evt_missing_${index}`,
|
|
@@ -8419,7 +8507,7 @@ function buildLoopFamilies(loops, events, impact) {
|
|
|
8419
8507
|
(loop) => loop.cites.map((cite) => events.find((event) => event.event_id === cite)?.source_id).filter(Boolean)
|
|
8420
8508
|
)
|
|
8421
8509
|
);
|
|
8422
|
-
const familyId = `family_${
|
|
8510
|
+
const familyId = `family_${hash3(key, 16)}`;
|
|
8423
8511
|
const timestamps = group.map((loop) => Date.parse(loop.origin.timestamp)).filter(Number.isFinite);
|
|
8424
8512
|
const spanDays = timestamps.length > 1 ? Math.max(1, Math.ceil((Math.max(...timestamps) - Math.min(...timestamps)) / 864e5)) : 0;
|
|
8425
8513
|
const publicLoopCount = group.filter((loop) => loop.public_surface).length;
|
|
@@ -8772,7 +8860,7 @@ function counterfactualForLoop(loop, family) {
|
|
|
8772
8860
|
orgx_outcome: repair.expected_outcome,
|
|
8773
8861
|
resulting_entity: {
|
|
8774
8862
|
kind: entityKind,
|
|
8775
|
-
inferred_id: `orgx_${entityKind}_${
|
|
8863
|
+
inferred_id: `orgx_${entityKind}_${hash3(loop.loop_id, 12)}`,
|
|
8776
8864
|
would_link_to: loop.cites
|
|
8777
8865
|
},
|
|
8778
8866
|
realism_score: Number(realism.toFixed(2)),
|
|
@@ -8983,7 +9071,7 @@ function buildMirror(input) {
|
|
|
8983
9071
|
};
|
|
8984
9072
|
}
|
|
8985
9073
|
function buildWorkGraphInvestigation(input) {
|
|
8986
|
-
const auditId = `wgi_${
|
|
9074
|
+
const auditId = `wgi_${hash3([input.fingerprint, input.generatedAt], 24)}`;
|
|
8987
9075
|
const rawEvents = buildRawEvents(input);
|
|
8988
9076
|
const corpus = buildCorpusManifest({
|
|
8989
9077
|
auditId,
|
|
@@ -9124,7 +9212,7 @@ function clampScore2(value) {
|
|
|
9124
9212
|
return Math.max(0, Math.min(100, Math.round(value)));
|
|
9125
9213
|
}
|
|
9126
9214
|
function hashJson(value) {
|
|
9127
|
-
return
|
|
9215
|
+
return createHash7("sha256").update(JSON.stringify(value)).digest("hex");
|
|
9128
9216
|
}
|
|
9129
9217
|
function normalizeFingerprintText(value) {
|
|
9130
9218
|
return value.toLowerCase().replace(/https?:\/\/\S+/g, "url").replace(/[0-9a-f]{12,}/g, "hash").replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/g, "uuid").replace(/\s+/g, " ").trim().slice(0, 600);
|
|
@@ -12215,14 +12303,14 @@ function renderWorkGraphMarkdown(report, options = {}) {
|
|
|
12215
12303
|
}
|
|
12216
12304
|
|
|
12217
12305
|
// src/lib/work-graph-publish.ts
|
|
12218
|
-
import { createHash as
|
|
12306
|
+
import { createHash as createHash8, randomUUID as randomUUID2 } from "crypto";
|
|
12219
12307
|
import { gzipSync } from "zlib";
|
|
12220
12308
|
var WORK_GRAPH_REPORT_GZIP_THRESHOLD_BYTES = 4e6;
|
|
12221
12309
|
var WORK_GRAPH_REPORT_CHUNK_UPLOAD_THRESHOLD_BYTES = 5e5;
|
|
12222
12310
|
var WORK_GRAPH_REPORT_CHUNK_CHARS = 3e4;
|
|
12223
12311
|
var WORK_GRAPH_REPORT_CHUNK_UPLOAD_TIMEOUT_MS = 3e5;
|
|
12224
12312
|
function hashText(value) {
|
|
12225
|
-
return
|
|
12313
|
+
return createHash8("sha256").update(value).digest("hex");
|
|
12226
12314
|
}
|
|
12227
12315
|
function buildWorkGraphReportPostPayload(report, options = {}) {
|
|
12228
12316
|
return {
|
|
@@ -12429,8 +12517,8 @@ async function publishWorkGraphEvents(fingerprint, patch, options = {}) {
|
|
|
12429
12517
|
}
|
|
12430
12518
|
|
|
12431
12519
|
// src/lib/work-graph-hook-events.ts
|
|
12432
|
-
import { createHash as
|
|
12433
|
-
import { existsSync as
|
|
12520
|
+
import { createHash as createHash9 } from "crypto";
|
|
12521
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
12434
12522
|
var SOURCE_CLIENTS = [
|
|
12435
12523
|
"codex",
|
|
12436
12524
|
"claude",
|
|
@@ -12464,7 +12552,7 @@ function asStringArray(value) {
|
|
|
12464
12552
|
return value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
12465
12553
|
}
|
|
12466
12554
|
function stableHash(value) {
|
|
12467
|
-
return
|
|
12555
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, 20);
|
|
12468
12556
|
}
|
|
12469
12557
|
function normalizeSourceClient2(value) {
|
|
12470
12558
|
const raw = asString2(value)?.toLowerCase();
|
|
@@ -12531,8 +12619,8 @@ function readHookRecord(line) {
|
|
|
12531
12619
|
}
|
|
12532
12620
|
}
|
|
12533
12621
|
function readRuntimeHookOutbox(path, limit = 200) {
|
|
12534
|
-
if (!
|
|
12535
|
-
const lines =
|
|
12622
|
+
if (!existsSync8(path)) return { path, records: [], skipped: 0 };
|
|
12623
|
+
const lines = readFileSync6(path, "utf8").split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
12536
12624
|
const selected = lines.slice(Math.max(0, lines.length - Math.max(1, limit)));
|
|
12537
12625
|
const records = [];
|
|
12538
12626
|
let skipped = Math.max(0, lines.length - selected.length);
|
|
@@ -12668,20 +12756,20 @@ function buildWorkGraphHookReplayPatch(readResult) {
|
|
|
12668
12756
|
}
|
|
12669
12757
|
|
|
12670
12758
|
// src/lib/runtime-hooks.ts
|
|
12671
|
-
import { copyFileSync, existsSync as
|
|
12759
|
+
import { copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "fs";
|
|
12672
12760
|
import { homedir as homedir3 } from "os";
|
|
12673
|
-
import { dirname as dirname4, join as
|
|
12761
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
12674
12762
|
var HOOK_MARKER = "orgx-session-hook.mjs";
|
|
12675
12763
|
var HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PermissionRequest", "Stop"];
|
|
12676
12764
|
var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "SubagentStop", "Stop", "SessionEnd"];
|
|
12677
12765
|
function defaultPaths(options = {}) {
|
|
12678
|
-
const hookDir =
|
|
12766
|
+
const hookDir = join7(ORGX_WIZARD_CONFIG_HOME, "hooks");
|
|
12679
12767
|
return {
|
|
12680
|
-
claudeSettingsPath: options.claudeSettingsPath ??
|
|
12681
|
-
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ??
|
|
12682
|
-
codexHooksPath: options.codexHooksPath ??
|
|
12683
|
-
hookScriptPath: options.hookScriptPath ??
|
|
12684
|
-
outboxPath: options.outboxPath ??
|
|
12768
|
+
claudeSettingsPath: options.claudeSettingsPath ?? join7(CLAUDE_DIR, "settings.json"),
|
|
12769
|
+
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ?? join7(CODEX_DIR, "config.toml"),
|
|
12770
|
+
codexHooksPath: options.codexHooksPath ?? join7(CODEX_DIR, "hooks.json"),
|
|
12771
|
+
hookScriptPath: options.hookScriptPath ?? join7(hookDir, HOOK_MARKER),
|
|
12772
|
+
outboxPath: options.outboxPath ?? join7(hookDir, "events.jsonl")
|
|
12685
12773
|
};
|
|
12686
12774
|
}
|
|
12687
12775
|
function countJsonlLines(path) {
|
|
@@ -12694,7 +12782,7 @@ function backupPath(path, now) {
|
|
|
12694
12782
|
return `${path}.bak.${timestamp}`;
|
|
12695
12783
|
}
|
|
12696
12784
|
function backupExisting(path, now) {
|
|
12697
|
-
if (!
|
|
12785
|
+
if (!existsSync9(path)) return null;
|
|
12698
12786
|
const backup = backupPath(path, now);
|
|
12699
12787
|
copyFileSync(path, backup);
|
|
12700
12788
|
return backup;
|
|
@@ -12892,7 +12980,7 @@ function inspectRuntimeHooks(options = {}) {
|
|
|
12892
12980
|
installed: {
|
|
12893
12981
|
claudeCode: hasOrgxHook(claudeSettingsRaw),
|
|
12894
12982
|
codex: hasOrgxHook(codexHooksRaw),
|
|
12895
|
-
hookScript:
|
|
12983
|
+
hookScript: existsSync9(paths.hookScriptPath)
|
|
12896
12984
|
},
|
|
12897
12985
|
codex: {
|
|
12898
12986
|
configExists: Boolean(codexConfigRaw),
|
|
@@ -13154,10 +13242,10 @@ async function runHookReplayCommand(options) {
|
|
|
13154
13242
|
}
|
|
13155
13243
|
function readAuditInput(options, interactive) {
|
|
13156
13244
|
if (options.input?.trim()) {
|
|
13157
|
-
return
|
|
13245
|
+
return readFileSync8(resolve2(options.input.trim()), "utf8");
|
|
13158
13246
|
}
|
|
13159
13247
|
if (!process.stdin.isTTY) {
|
|
13160
|
-
return
|
|
13248
|
+
return readFileSync8(0, "utf8");
|
|
13161
13249
|
}
|
|
13162
13250
|
if (!interactive) {
|
|
13163
13251
|
throw new Error("Audit input is required. Pass --input <file> or pipe text into wizard audit.");
|
|
@@ -13190,7 +13278,7 @@ function collectPathOption(value, previous = []) {
|
|
|
13190
13278
|
}
|
|
13191
13279
|
function parseClientExtractionFile(path) {
|
|
13192
13280
|
const resolvedPath = resolve2(path);
|
|
13193
|
-
const parsed = JSON.parse(
|
|
13281
|
+
const parsed = JSON.parse(readFileSync8(resolvedPath, "utf8"));
|
|
13194
13282
|
if (!isRecord(parsed)) {
|
|
13195
13283
|
throw new Error(`AI-client extraction must be a JSON object: ${resolvedPath}`);
|
|
13196
13284
|
}
|
|
@@ -13675,6 +13763,40 @@ function printSkillExtensions(extensions) {
|
|
|
13675
13763
|
);
|
|
13676
13764
|
}
|
|
13677
13765
|
}
|
|
13766
|
+
function printLocalSkillCandidates(candidates) {
|
|
13767
|
+
if (candidates.length === 0) {
|
|
13768
|
+
console.log(` ${ICON.skip} ${pc3.dim("no local skill files found")}`);
|
|
13769
|
+
return;
|
|
13770
|
+
}
|
|
13771
|
+
candidates.forEach((candidate, index) => {
|
|
13772
|
+
const domains = candidate.agentDomains.join(", ");
|
|
13773
|
+
console.log(
|
|
13774
|
+
` ${ICON.ok} ${pc3.bold(String(index + 1).padStart(2, " "))} ${pc3.bold(candidate.title)} ${pc3.dim(candidate.id)}`
|
|
13775
|
+
);
|
|
13776
|
+
console.log(` ${pc3.dim(`${candidate.source} \xB7 ${domains} \xB7 ${candidate.reason}`)}`);
|
|
13777
|
+
console.log(` ${pc3.dim(candidate.path)}`);
|
|
13778
|
+
if (candidate.snippet) {
|
|
13779
|
+
console.log(` ${pc3.dim(candidate.snippet)}`);
|
|
13780
|
+
}
|
|
13781
|
+
});
|
|
13782
|
+
}
|
|
13783
|
+
function writeLocalSkillSelection(input) {
|
|
13784
|
+
const scope = input.scope ?? "user";
|
|
13785
|
+
const nextContent = buildLocalSkillExtensionContent(input.candidates, input.context);
|
|
13786
|
+
const existing = listSkillExtensions().find(
|
|
13787
|
+
(extension) => extension.skillId === "orgx" && extension.scope === scope
|
|
13788
|
+
);
|
|
13789
|
+
const content = existing?.content.trim() ? `${existing.content.trimEnd()}
|
|
13790
|
+
|
|
13791
|
+
${nextContent}` : nextContent;
|
|
13792
|
+
return addSkillExtension({
|
|
13793
|
+
content,
|
|
13794
|
+
overwrite: true,
|
|
13795
|
+
scope,
|
|
13796
|
+
skillId: "orgx",
|
|
13797
|
+
title: "Local skill preferences"
|
|
13798
|
+
});
|
|
13799
|
+
}
|
|
13678
13800
|
function printSkillExtensionWrite(result) {
|
|
13679
13801
|
const action = result.created ? "created" : result.changed ? "updated" : "unchanged";
|
|
13680
13802
|
const color = result.created || result.changed ? pc3.green : pc3.dim;
|
|
@@ -13740,6 +13862,8 @@ function printSetupScopeNote() {
|
|
|
13740
13862
|
}
|
|
13741
13863
|
function printFirstValueHandoff(input) {
|
|
13742
13864
|
const cmd = getCmd();
|
|
13865
|
+
const fallbackPrompt = `Use OrgX to continue "${input.initiative.initiative.title}" in ${input.workspace.name}. Show the next action, then start with the onboarding task.`;
|
|
13866
|
+
const handoffPrompt = buildProfileHandoffPrompt(input.profile, fallbackPrompt, input.context);
|
|
13743
13867
|
console.log("");
|
|
13744
13868
|
console.log(pc3.bold("first OrgX handoff"));
|
|
13745
13869
|
console.log(
|
|
@@ -13748,9 +13872,13 @@ function printFirstValueHandoff(input) {
|
|
|
13748
13872
|
console.log(` live: ${input.initiative.liveUrl}`);
|
|
13749
13873
|
console.log(
|
|
13750
13874
|
` ${pc3.dim("ask your AI tool:")} ${pc3.cyan(
|
|
13751
|
-
|
|
13875
|
+
handoffPrompt
|
|
13752
13876
|
)}`
|
|
13753
13877
|
);
|
|
13878
|
+
if (input.profile) {
|
|
13879
|
+
console.log(` ${pc3.dim("local proof:")} ${pc3.cyan(input.profile.localProofCommand)}`);
|
|
13880
|
+
console.log(` ${pc3.dim("skills:")} ${pc3.cyan(input.profile.skillDiscoveryCommand)}`);
|
|
13881
|
+
}
|
|
13754
13882
|
console.log(` ${pc3.dim("later:")} ${pc3.cyan(`${cmd} doctor`)} ${pc3.dim("checks tool wiring")}`);
|
|
13755
13883
|
}
|
|
13756
13884
|
function firstValueRecordToResult(record) {
|
|
@@ -13775,20 +13903,6 @@ function printFounderPresetResult(result) {
|
|
|
13775
13903
|
console.log("");
|
|
13776
13904
|
printWorkspaceSetupResult(result.workspaceSetup);
|
|
13777
13905
|
}
|
|
13778
|
-
if (result.demoInitiative) {
|
|
13779
|
-
console.log("");
|
|
13780
|
-
console.log(pc3.bold("demo initiative"));
|
|
13781
|
-
console.log(
|
|
13782
|
-
` ${result.demoInitiative.created ? pc3.green("created") : pc3.yellow("unchanged")} ${result.demoInitiative.initiative.title}`
|
|
13783
|
-
);
|
|
13784
|
-
console.log(` live: ${result.demoInitiative.liveUrl}`);
|
|
13785
|
-
console.log(
|
|
13786
|
-
` decision: ${result.demoInitiative.decision.title} ${pc3.dim(`(${result.demoInitiative.decision.status ?? "pending"})`)}`
|
|
13787
|
-
);
|
|
13788
|
-
console.log(
|
|
13789
|
-
` artifact: ${result.demoInitiative.artifact.name}${result.demoInitiative.artifact.url ? ` ${pc3.dim(result.demoInitiative.artifact.url)}` : ""}`
|
|
13790
|
-
);
|
|
13791
|
-
}
|
|
13792
13906
|
}
|
|
13793
13907
|
function normalizePromptResult(value) {
|
|
13794
13908
|
return value;
|
|
@@ -14213,10 +14327,9 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14213
14327
|
}
|
|
14214
14328
|
const existingState = readWizardState();
|
|
14215
14329
|
const providedInitiativeId = input.initiativeId?.trim();
|
|
14216
|
-
const storedDemoInitiative = existingState?.demoInitiative?.workspaceId === input.workspace.id ? existingState.demoInitiative : void 0;
|
|
14217
14330
|
const storedFirstValueInitiative = existingState?.firstValueInitiative?.workspaceId === input.workspace.id ? existingState.firstValueInitiative : void 0;
|
|
14218
|
-
let effectiveInitiativeId = providedInitiativeId ||
|
|
14219
|
-
let firstValueInitiative = providedInitiativeId
|
|
14331
|
+
let effectiveInitiativeId = providedInitiativeId || storedFirstValueInitiative?.id;
|
|
14332
|
+
let firstValueInitiative = providedInitiativeId ? null : firstValueRecordToResult(storedFirstValueInitiative);
|
|
14220
14333
|
const firstInitiativeSkipped = hasSetupPromptSkip(
|
|
14221
14334
|
input.workspace.id,
|
|
14222
14335
|
"first_initiative"
|
|
@@ -14240,7 +14353,7 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14240
14353
|
}
|
|
14241
14354
|
if (firstInitiativeChoice === "yes") {
|
|
14242
14355
|
const title = await textPrompt({
|
|
14243
|
-
initialValue: FIRST_VALUE_INITIATIVE_TITLE,
|
|
14356
|
+
initialValue: input.profile?.firstInitiativeTitle ?? FIRST_VALUE_INITIATIVE_TITLE,
|
|
14244
14357
|
message: "What should OrgX help you move forward first?",
|
|
14245
14358
|
validate: (value) => {
|
|
14246
14359
|
if (!value || value.trim().length === 0) {
|
|
@@ -14257,6 +14370,7 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14257
14370
|
spinner.start();
|
|
14258
14371
|
try {
|
|
14259
14372
|
firstValueInitiative = await ensureFirstValueInitiative(input.workspace, {
|
|
14373
|
+
...input.context || input.profile ? { summary: input.profile ? buildProfileSummary(input.profile, input.context) : input.context } : {},
|
|
14260
14374
|
title: String(title)
|
|
14261
14375
|
});
|
|
14262
14376
|
spinner.succeed(
|
|
@@ -14347,7 +14461,9 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14347
14461
|
}
|
|
14348
14462
|
if (firstValueInitiative) {
|
|
14349
14463
|
printFirstValueHandoff({
|
|
14464
|
+
...input.context ? { context: input.context } : {},
|
|
14350
14465
|
initiative: firstValueInitiative,
|
|
14466
|
+
...input.profile !== void 0 ? { profile: input.profile } : {},
|
|
14351
14467
|
workspace: input.workspace
|
|
14352
14468
|
});
|
|
14353
14469
|
}
|
|
@@ -14420,6 +14536,64 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14420
14536
|
});
|
|
14421
14537
|
}
|
|
14422
14538
|
}
|
|
14539
|
+
const localSkillDiscoverySkipped = hasSetupPromptSkip(
|
|
14540
|
+
input.workspace.id,
|
|
14541
|
+
"local_skill_discovery"
|
|
14542
|
+
);
|
|
14543
|
+
if (!localSkillDiscoverySkipped) {
|
|
14544
|
+
const context = input.context?.trim();
|
|
14545
|
+
const candidates = discoverLocalSkills({
|
|
14546
|
+
...context ? { context } : {},
|
|
14547
|
+
limit: 8
|
|
14548
|
+
});
|
|
14549
|
+
if (candidates.length > 0) {
|
|
14550
|
+
const selectedSkillIds = await multiselectPrompt({
|
|
14551
|
+
message: "Bring existing local skills into your OrgX agents?",
|
|
14552
|
+
options: [
|
|
14553
|
+
...candidates.map((candidate, index) => ({
|
|
14554
|
+
value: candidate.id,
|
|
14555
|
+
label: `${index + 1}. ${candidate.title}`,
|
|
14556
|
+
hint: `${candidate.source} \xB7 ${candidate.agentDomains.join(", ")} \xB7 ${candidate.reason}`
|
|
14557
|
+
})),
|
|
14558
|
+
{
|
|
14559
|
+
value: "__skip__",
|
|
14560
|
+
label: "Skip local skill import",
|
|
14561
|
+
hint: "You can run `orgx-wizard skills discover-local` later."
|
|
14562
|
+
}
|
|
14563
|
+
],
|
|
14564
|
+
required: false
|
|
14565
|
+
});
|
|
14566
|
+
if (clack.isCancel(selectedSkillIds)) {
|
|
14567
|
+
clack.cancel("Setup cancelled.");
|
|
14568
|
+
return "cancelled";
|
|
14569
|
+
}
|
|
14570
|
+
const selected = candidates.filter((candidate) => selectedSkillIds.includes(candidate.id));
|
|
14571
|
+
if (selectedSkillIds.includes("__skip__") || selected.length === 0) {
|
|
14572
|
+
recordSetupPromptSkip({
|
|
14573
|
+
promptKey: "local_skill_discovery",
|
|
14574
|
+
workspaceId: input.workspace.id,
|
|
14575
|
+
workspaceName: input.workspace.name
|
|
14576
|
+
});
|
|
14577
|
+
console.log(` ${ICON.skip} ${pc3.dim("local skills skipped")}`);
|
|
14578
|
+
} else {
|
|
14579
|
+
const result = writeLocalSkillSelection({
|
|
14580
|
+
candidates: selected,
|
|
14581
|
+
...context ? { context } : {}
|
|
14582
|
+
});
|
|
14583
|
+
printSkillExtensionWrite(result);
|
|
14584
|
+
console.log(
|
|
14585
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply selected local preferences to configured tools.`)}`
|
|
14586
|
+
);
|
|
14587
|
+
await safeTrackWizardTelemetry("local_skills_configured", {
|
|
14588
|
+
candidate_count: candidates.length,
|
|
14589
|
+
command: input.telemetry?.command ?? "setup",
|
|
14590
|
+
selected_count: selected.length,
|
|
14591
|
+
...input.telemetry?.preset ? { preset: input.telemetry.preset } : {},
|
|
14592
|
+
profile: input.profile?.id ?? "none"
|
|
14593
|
+
});
|
|
14594
|
+
}
|
|
14595
|
+
}
|
|
14596
|
+
}
|
|
14423
14597
|
return "configured";
|
|
14424
14598
|
}
|
|
14425
14599
|
async function promptOptionalCompanionPluginTargets(input) {
|
|
@@ -14509,7 +14683,7 @@ function printAuthStatus(status) {
|
|
|
14509
14683
|
}
|
|
14510
14684
|
}
|
|
14511
14685
|
function printDoctorReport(report, assessment) {
|
|
14512
|
-
const verification = summarizeSetupVerification(assessment);
|
|
14686
|
+
const verification = summarizeSetupVerification(assessment, report);
|
|
14513
14687
|
console.log(pc3.dim(" surfaces"));
|
|
14514
14688
|
printSurfaceTable(report.surfaces);
|
|
14515
14689
|
console.log("");
|
|
@@ -14557,6 +14731,9 @@ function printDoctorReport(report, assessment) {
|
|
|
14557
14731
|
} else {
|
|
14558
14732
|
console.log(` ${pc3.dim("\u2192")} ${pc3.dim(`OrgX is active across ${configuredCount} editor${configuredCount !== 1 ? "s" : ""}`)}`);
|
|
14559
14733
|
}
|
|
14734
|
+
} else if (verification.transientTimeouts) {
|
|
14735
|
+
console.log(` ${ICON.warn} ${pc3.yellow(getSetupVerificationHeadline(verification))}`);
|
|
14736
|
+
console.log(` ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} doctor`)} ${pc3.dim("re-runs the health checks")}`);
|
|
14560
14737
|
} else {
|
|
14561
14738
|
const headlineText = getSetupVerificationHeadline(verification);
|
|
14562
14739
|
const headline = verification.status === "error" ? `${ICON.err} ${pc3.red(headlineText)}` : `${ICON.warn} ${pc3.yellow(headlineText)}`;
|
|
@@ -14573,20 +14750,26 @@ function printDoctorReport(report, assessment) {
|
|
|
14573
14750
|
async function main() {
|
|
14574
14751
|
const program = new Command();
|
|
14575
14752
|
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
14576
|
-
const pkgVersion = true ? "0.1.
|
|
14753
|
+
const pkgVersion = true ? "0.1.47" : void 0;
|
|
14577
14754
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
14578
14755
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
14579
14756
|
if (Boolean(actionCommand.optsWithGlobals().json)) return;
|
|
14580
14757
|
console.log(renderBanner(pkgVersion));
|
|
14581
14758
|
});
|
|
14582
|
-
program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").option("--workspace", "choose or change the default workspace during setup").option("--daily-brief", "configure Daily Brief even if setup already handled it").option("--skip-daily-brief", "skip Daily Brief prompts and remember the skip").action(async (options) => {
|
|
14759
|
+
program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").option("--profile <name>", `tailor setup for a workflow profile (${supportedSetupProfileIds().join(", ")})`).option("--context <text>", "extra workflow context to include in the first initiative and handoff").option("--workspace", "choose or change the default workspace during setup").option("--daily-brief", "configure Daily Brief even if setup already handled it").option("--skip-daily-brief", "skip Daily Brief prompts and remember the skip").action(async (options) => {
|
|
14583
14760
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
14584
14761
|
if (options.dailyBrief && options.skipDailyBrief) {
|
|
14585
14762
|
throw new Error("Use either --daily-brief or --skip-daily-brief, not both.");
|
|
14586
14763
|
}
|
|
14764
|
+
const setupProfile = resolveSetupProfile(options.profile);
|
|
14765
|
+
if (options.profile && !setupProfile) {
|
|
14766
|
+
throw new Error(`Unknown setup profile '${options.profile}'. Supported profiles: ${supportedSetupProfileIds().join(", ")}.`);
|
|
14767
|
+
}
|
|
14768
|
+
const setupContext = options.context?.trim() || void 0;
|
|
14587
14769
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
14588
14770
|
command: "setup",
|
|
14589
14771
|
interactive,
|
|
14772
|
+
profile: setupProfile?.id ?? "none",
|
|
14590
14773
|
preset: options.preset ?? "standard"
|
|
14591
14774
|
});
|
|
14592
14775
|
printSetupScopeNote();
|
|
@@ -14646,20 +14829,12 @@ async function main() {
|
|
|
14646
14829
|
})
|
|
14647
14830
|
);
|
|
14648
14831
|
}
|
|
14649
|
-
if (presetResult.demoInitiative) {
|
|
14650
|
-
await safeTrackWizardTelemetry(
|
|
14651
|
-
"founder_demo_ready",
|
|
14652
|
-
buildFounderDemoTelemetryProperties(presetResult.demoInitiative, {
|
|
14653
|
-
command: "setup",
|
|
14654
|
-
preset: "founder"
|
|
14655
|
-
})
|
|
14656
|
-
);
|
|
14657
|
-
}
|
|
14658
14832
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
14833
|
+
...setupContext ? { context: setupContext } : {},
|
|
14659
14834
|
interactive,
|
|
14835
|
+
profile: setupProfile,
|
|
14660
14836
|
telemetry: { command: "setup", preset: "founder" },
|
|
14661
|
-
workspace: presetResult.workspace
|
|
14662
|
-
...presetResult.demoInitiative ? { initiativeId: presetResult.demoInitiative.initiative.id } : {}
|
|
14837
|
+
workspace: presetResult.workspace
|
|
14663
14838
|
});
|
|
14664
14839
|
if (addOnResult === "cancelled") {
|
|
14665
14840
|
return;
|
|
@@ -14671,7 +14846,7 @@ async function main() {
|
|
|
14671
14846
|
console.log("");
|
|
14672
14847
|
const doctor2 = await runDoctor();
|
|
14673
14848
|
const assessment2 = assessDoctorReport(doctor2);
|
|
14674
|
-
const verification2 = summarizeSetupVerification(assessment2);
|
|
14849
|
+
const verification2 = summarizeSetupVerification(assessment2, doctor2);
|
|
14675
14850
|
await safeTrackWizardTelemetry(
|
|
14676
14851
|
"setup_verified",
|
|
14677
14852
|
buildDoctorTelemetryProperties(doctor2, assessment2, verification2, {
|
|
@@ -14698,6 +14873,7 @@ async function main() {
|
|
|
14698
14873
|
});
|
|
14699
14874
|
const wasAlreadyPaired = await resolveOrgxAuth() !== null;
|
|
14700
14875
|
let resolvedAuth = await resolveOrgxAuth();
|
|
14876
|
+
let cachedWorkspaceCheck;
|
|
14701
14877
|
if (!resolvedAuth) {
|
|
14702
14878
|
console.log("");
|
|
14703
14879
|
if (interactive) {
|
|
@@ -14781,6 +14957,20 @@ async function main() {
|
|
|
14781
14957
|
})
|
|
14782
14958
|
);
|
|
14783
14959
|
const resolvedWorkspace = workspaceSetup.workspace ?? await getCurrentWorkspace().catch(() => null);
|
|
14960
|
+
if (resolvedWorkspace && resolvedAuth) {
|
|
14961
|
+
cachedWorkspaceCheck = {
|
|
14962
|
+
configured: true,
|
|
14963
|
+
ok: true,
|
|
14964
|
+
skipped: false,
|
|
14965
|
+
source: resolvedAuth.source,
|
|
14966
|
+
baseUrl: resolvedAuth.baseUrl,
|
|
14967
|
+
workspace: resolvedWorkspace,
|
|
14968
|
+
details: [
|
|
14969
|
+
`workspace id: ${resolvedWorkspace.id}`,
|
|
14970
|
+
...resolvedWorkspace.isDefault ? ["workspace is marked as default"] : []
|
|
14971
|
+
]
|
|
14972
|
+
};
|
|
14973
|
+
}
|
|
14784
14974
|
if (resolvedWorkspace) {
|
|
14785
14975
|
persistContinuityDefaults({ workspace: resolvedWorkspace });
|
|
14786
14976
|
}
|
|
@@ -14817,7 +15007,9 @@ async function main() {
|
|
|
14817
15007
|
return;
|
|
14818
15008
|
}
|
|
14819
15009
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
15010
|
+
...setupContext ? { context: setupContext } : {},
|
|
14820
15011
|
interactive,
|
|
15012
|
+
profile: setupProfile,
|
|
14821
15013
|
telemetry: { command: "setup", preset: "standard" },
|
|
14822
15014
|
workspace: resolvedWorkspace
|
|
14823
15015
|
});
|
|
@@ -14833,9 +15025,11 @@ async function main() {
|
|
|
14833
15025
|
return;
|
|
14834
15026
|
}
|
|
14835
15027
|
}
|
|
14836
|
-
const doctor = await runDoctor(
|
|
15028
|
+
const doctor = await runDoctor(
|
|
15029
|
+
cachedWorkspaceCheck ? { cachedWorkspace: cachedWorkspaceCheck } : {}
|
|
15030
|
+
);
|
|
14837
15031
|
const assessment = assessDoctorReport(doctor);
|
|
14838
|
-
const verification = summarizeSetupVerification(assessment);
|
|
15032
|
+
const verification = summarizeSetupVerification(assessment, doctor);
|
|
14839
15033
|
await safeTrackWizardTelemetry(
|
|
14840
15034
|
"setup_verified",
|
|
14841
15035
|
buildDoctorTelemetryProperties(doctor, assessment, verification, {
|
|
@@ -15352,7 +15546,7 @@ async function main() {
|
|
|
15352
15546
|
const report = await runDoctor();
|
|
15353
15547
|
spinner.stop();
|
|
15354
15548
|
const assessment = assessDoctorReport(report);
|
|
15355
|
-
const verification = summarizeSetupVerification(assessment);
|
|
15549
|
+
const verification = summarizeSetupVerification(assessment, report);
|
|
15356
15550
|
await safeTrackWizardTelemetry(
|
|
15357
15551
|
"doctor_ran",
|
|
15358
15552
|
buildDoctorTelemetryProperties(report, assessment, verification, {
|
|
@@ -15421,6 +15615,48 @@ async function main() {
|
|
|
15421
15615
|
}
|
|
15422
15616
|
}
|
|
15423
15617
|
});
|
|
15618
|
+
skills.command("discover-local").description("Inventory local skill files and optionally fold selected ones into the OrgX base skill extension.").option("--from <sources>", "local sources to scan: opencode, claude, codex, agents, workspace, or all", "all").option("--context <text>", "workflow context used to rank and annotate discovered skills").option("--limit <count>", "max candidates to show", "12").option("--apply <selection>", "comma-separated candidate numbers or ids to opt into the OrgX base skill extension").option("--scope <scope>", "extension scope: user, workspace, or project", "user").option("--json", "emit a JSON summary").action(async (options) => {
|
|
15619
|
+
const sources = parseLocalSkillSources(options.from);
|
|
15620
|
+
const limit = parsePositiveInteger(options.limit, 12, "--limit");
|
|
15621
|
+
const candidates = discoverLocalSkills({
|
|
15622
|
+
...options.context?.trim() ? { context: options.context.trim() } : {},
|
|
15623
|
+
limit,
|
|
15624
|
+
sources
|
|
15625
|
+
});
|
|
15626
|
+
let extensionWrite = null;
|
|
15627
|
+
if (options.apply?.trim()) {
|
|
15628
|
+
const selected = selectLocalSkillCandidates(candidates, options.apply);
|
|
15629
|
+
extensionWrite = writeLocalSkillSelection({
|
|
15630
|
+
candidates: selected,
|
|
15631
|
+
...options.context?.trim() ? { context: options.context.trim() } : {},
|
|
15632
|
+
scope: options.scope ?? "user"
|
|
15633
|
+
});
|
|
15634
|
+
}
|
|
15635
|
+
if (options.json) {
|
|
15636
|
+
console.log(JSON.stringify({
|
|
15637
|
+
applied: extensionWrite ? {
|
|
15638
|
+
changed: extensionWrite.changed,
|
|
15639
|
+
created: extensionWrite.created,
|
|
15640
|
+
path: extensionWrite.path
|
|
15641
|
+
} : null,
|
|
15642
|
+
candidates
|
|
15643
|
+
}, null, 2));
|
|
15644
|
+
return;
|
|
15645
|
+
}
|
|
15646
|
+
printLocalSkillCandidates(candidates);
|
|
15647
|
+
if (extensionWrite) {
|
|
15648
|
+
console.log("");
|
|
15649
|
+
printSkillExtensionWrite(extensionWrite);
|
|
15650
|
+
console.log(
|
|
15651
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply selected local preferences to configured tools.`)}`
|
|
15652
|
+
);
|
|
15653
|
+
} else if (candidates.length > 0) {
|
|
15654
|
+
console.log("");
|
|
15655
|
+
console.log(
|
|
15656
|
+
` ${ICON.skip} ${pc3.dim(`Opt in with ${getCmd()} skills discover-local --apply 1,2, then run ${getCmd()} skills sync.`)}`
|
|
15657
|
+
);
|
|
15658
|
+
}
|
|
15659
|
+
});
|
|
15424
15660
|
const skillExtensions = skills.command("extensions").description("Create, edit, and sync user extensions appended after OrgX core skills.");
|
|
15425
15661
|
skillExtensions.command("list").description("List local OrgX skill extensions.").action(() => {
|
|
15426
15662
|
printSkillExtensions(listSkillExtensions());
|