@useorgx/wizard 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -940,6 +940,7 @@ function parseOnboardingTask(value) {
940
940
  ...isNonEmptyString2(record.initiativeId) ? { initiativeId: record.initiativeId.trim() } : {},
941
941
  ...isNonEmptyString2(record.status) ? { status: record.status.trim() } : {},
942
942
  title: record.title.trim(),
943
+ ...isNonEmptyString2(record.workstreamId) ? { workstreamId: record.workstreamId.trim() } : {},
943
944
  ...isNonEmptyString2(record.workspaceId) ? { workspaceId: record.workspaceId.trim() } : {},
944
945
  ...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
945
946
  };
@@ -1045,6 +1046,9 @@ function getOrCreateWizardInstallationId(statePath = ORGX_WIZARD_STATE_PATH) {
1045
1046
  writeWizardState(record, statePath);
1046
1047
  return record.installationId;
1047
1048
  }
1049
+ function clearWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1050
+ return deleteFileIfExists(statePath);
1051
+ }
1048
1052
 
1049
1053
  // src/lib/agent-roster.ts
1050
1054
  var AGENT_ROSTER_PROFILES = [
@@ -1239,39 +1243,6 @@ async function checkHostedMcpHealth() {
1239
1243
 
1240
1244
  // src/lib/hosted-mcp-tool-check.ts
1241
1245
  var DEFAULT_TOOL_NAME = "get_setup_status";
1242
- function buildHeaders(apiKey, sessionId) {
1243
- const headers = {
1244
- Authorization: `Bearer ${apiKey}`,
1245
- "Content-Type": "application/json",
1246
- Accept: "application/json, text/event-stream"
1247
- };
1248
- if (sessionId) {
1249
- headers["Mcp-Session-Id"] = sessionId;
1250
- }
1251
- return headers;
1252
- }
1253
- async function readJsonSafe(response) {
1254
- const text2 = await response.text();
1255
- if (!text2) return null;
1256
- try {
1257
- return JSON.parse(text2);
1258
- } catch {
1259
- return text2;
1260
- }
1261
- }
1262
- function readJsonRpcError(payload) {
1263
- if (!payload || typeof payload !== "object") {
1264
- return void 0;
1265
- }
1266
- const maybeError = payload.error;
1267
- if (!maybeError || typeof maybeError !== "object") {
1268
- return void 0;
1269
- }
1270
- return typeof maybeError.message === "string" ? maybeError.message : "Unknown MCP JSON-RPC error.";
1271
- }
1272
- function readSessionId(response) {
1273
- return response.headers.get("mcp-session-id") ?? response.headers.get("Mcp-Session-Id") ?? void 0;
1274
- }
1275
1246
  async function checkHostedMcpToolAccess(options = {}, toolName = DEFAULT_TOOL_NAME) {
1276
1247
  const auth = await resolveOrgxAuth(options);
1277
1248
  if (!auth) {
@@ -1286,157 +1257,20 @@ async function checkHostedMcpToolAccess(options = {}, toolName = DEFAULT_TOOL_NA
1286
1257
  details: []
1287
1258
  };
1288
1259
  }
1289
- try {
1290
- const initializeResponse = await fetch(ORGX_HOSTED_MCP_URL, {
1291
- method: "POST",
1292
- headers: buildHeaders(auth.apiKey),
1293
- body: JSON.stringify({
1294
- jsonrpc: "2.0",
1295
- id: 1,
1296
- method: "initialize",
1297
- params: {
1298
- protocolVersion: "2024-11-05",
1299
- clientInfo: {
1300
- name: "orgx-wizard",
1301
- version: "0.1.0"
1302
- },
1303
- capabilities: {}
1304
- }
1305
- }),
1306
- signal: AbortSignal.timeout(1e4)
1307
- });
1308
- const initializePayload = await readJsonSafe(initializeResponse);
1309
- const initializeError = readJsonRpcError(initializePayload);
1310
- const sessionId = readSessionId(initializeResponse);
1311
- if (!initializeResponse.ok) {
1312
- return {
1313
- configured: true,
1314
- ok: false,
1315
- skipped: false,
1316
- source: auth.source,
1317
- toolName,
1318
- url: ORGX_HOSTED_MCP_URL,
1319
- baseUrl: auth.baseUrl,
1320
- initializeStatus: initializeResponse.status,
1321
- error: `MCP initialize failed with HTTP ${initializeResponse.status}.`,
1322
- details: [`auth source: ${auth.source}`],
1323
- response: initializePayload
1324
- };
1325
- }
1326
- if (initializeError) {
1327
- return {
1328
- configured: true,
1329
- ok: false,
1330
- skipped: false,
1331
- source: auth.source,
1332
- toolName,
1333
- url: ORGX_HOSTED_MCP_URL,
1334
- baseUrl: auth.baseUrl,
1335
- initializeStatus: initializeResponse.status,
1336
- error: `MCP initialize returned JSON-RPC error: ${initializeError}`,
1337
- details: [`auth source: ${auth.source}`],
1338
- response: initializePayload
1339
- };
1340
- }
1341
- if (!sessionId) {
1342
- return {
1343
- configured: true,
1344
- ok: false,
1345
- skipped: false,
1346
- source: auth.source,
1347
- toolName,
1348
- url: ORGX_HOSTED_MCP_URL,
1349
- baseUrl: auth.baseUrl,
1350
- initializeStatus: initializeResponse.status,
1351
- error: "MCP initialize succeeded but no Mcp-Session-Id header was returned.",
1352
- details: [`auth source: ${auth.source}`],
1353
- response: initializePayload
1354
- };
1355
- }
1356
- const callResponse = await fetch(ORGX_HOSTED_MCP_URL, {
1357
- method: "POST",
1358
- headers: buildHeaders(auth.apiKey, sessionId),
1359
- body: JSON.stringify({
1360
- jsonrpc: "2.0",
1361
- id: 2,
1362
- method: "tools/call",
1363
- params: {
1364
- name: toolName,
1365
- arguments: {}
1366
- }
1367
- }),
1368
- signal: AbortSignal.timeout(1e4)
1369
- });
1370
- const callPayload = await readJsonSafe(callResponse);
1371
- const callError = readJsonRpcError(callPayload);
1372
- if (!callResponse.ok) {
1373
- return {
1374
- configured: true,
1375
- ok: false,
1376
- skipped: false,
1377
- source: auth.source,
1378
- toolName,
1379
- url: ORGX_HOSTED_MCP_URL,
1380
- baseUrl: auth.baseUrl,
1381
- initializeStatus: initializeResponse.status,
1382
- callStatus: callResponse.status,
1383
- error: `MCP tool call failed with HTTP ${callResponse.status}.`,
1384
- details: [
1385
- `auth source: ${auth.source}`,
1386
- `session established: ${sessionId}`
1387
- ],
1388
- response: callPayload
1389
- };
1390
- }
1391
- if (callError) {
1392
- return {
1393
- configured: true,
1394
- ok: false,
1395
- skipped: false,
1396
- source: auth.source,
1397
- toolName,
1398
- url: ORGX_HOSTED_MCP_URL,
1399
- baseUrl: auth.baseUrl,
1400
- initializeStatus: initializeResponse.status,
1401
- callStatus: callResponse.status,
1402
- error: `MCP tool call returned JSON-RPC error: ${callError}`,
1403
- details: [
1404
- `auth source: ${auth.source}`,
1405
- `session established: ${sessionId}`
1406
- ],
1407
- response: callPayload
1408
- };
1409
- }
1410
- return {
1411
- configured: true,
1412
- ok: true,
1413
- skipped: false,
1414
- source: auth.source,
1415
- toolName,
1416
- url: ORGX_HOSTED_MCP_URL,
1417
- baseUrl: auth.baseUrl,
1418
- initializeStatus: initializeResponse.status,
1419
- callStatus: callResponse.status,
1420
- details: [
1421
- `auth source: ${auth.source}`,
1422
- `session established: ${sessionId}`,
1423
- `tool call: ${toolName}`
1424
- ],
1425
- response: callPayload
1426
- };
1427
- } catch (error) {
1428
- return {
1429
- configured: true,
1430
- ok: false,
1431
- skipped: false,
1432
- source: auth.source,
1433
- toolName,
1434
- url: ORGX_HOSTED_MCP_URL,
1435
- baseUrl: auth.baseUrl,
1436
- error: error instanceof Error ? error.message : String(error),
1437
- details: [`auth source: ${auth.source}`]
1438
- };
1439
- }
1260
+ return {
1261
+ configured: true,
1262
+ ok: false,
1263
+ skipped: true,
1264
+ source: auth.source,
1265
+ toolName,
1266
+ url: ORGX_HOSTED_MCP_URL,
1267
+ baseUrl: auth.baseUrl,
1268
+ error: "Hosted OrgX MCP uses OAuth; API-key tool verification is skipped.",
1269
+ details: [
1270
+ `auth source: ${auth.source}`,
1271
+ "Hosted OrgX MCP connectors complete OAuth during client setup, so the wizard cannot preflight tools with an oxk_ API key."
1272
+ ]
1273
+ };
1440
1274
  }
1441
1275
 
1442
1276
  // src/lib/npm-registry-health.ts
@@ -1633,7 +1467,7 @@ async function getCurrentWorkspace(options = {}) {
1633
1467
  }
1634
1468
  return workspace;
1635
1469
  }
1636
- if (response.status === 404) {
1470
+ if (response.status === 401 || response.status === 404) {
1637
1471
  const workspaces = await listWorkspaces(options);
1638
1472
  return workspaces[0] ?? null;
1639
1473
  }
@@ -2334,7 +2168,10 @@ function buildChatgptManualStatus(detection, authHint) {
2334
2168
  "Manual step: in ChatGPT desktop developer mode, add a custom connector pointing at the hosted OrgX MCP URL."
2335
2169
  );
2336
2170
  details.push(
2337
- "After connecting ChatGPT, run `orgx-wizard doctor` to verify hosted MCP tool access."
2171
+ "ChatGPT completes OAuth during connector setup; the wizard cannot preflight hosted MCP tools with an oxk_ API key."
2172
+ );
2173
+ details.push(
2174
+ "After connecting ChatGPT, run `orgx-wizard doctor` to verify hosted MCP health from this machine."
2338
2175
  );
2339
2176
  } else {
2340
2177
  details.push(
@@ -2369,7 +2206,7 @@ function buildChatgptAddResult(path, authHint, toolCheck) {
2369
2206
  message: `Run \`${AUTH_SETUP_HINT}\` or \`${AUTH_SET_KEY_HINT}\` first, then add ${ORGX_HOSTED_MCP_URL} as a custom connector in ChatGPT developer mode.`
2370
2207
  };
2371
2208
  }
2372
- if (!toolCheck || !toolCheck.ok) {
2209
+ if (toolCheck && !toolCheck.ok && !toolCheck.skipped) {
2373
2210
  const failure = toolCheck?.error ?? "hosted MCP verification did not complete.";
2374
2211
  return {
2375
2212
  name: "chatgpt",
@@ -2382,7 +2219,7 @@ function buildChatgptAddResult(path, authHint, toolCheck) {
2382
2219
  name: "chatgpt",
2383
2220
  changed: false,
2384
2221
  ...path ? { path } : {},
2385
- message: `OrgX auth and hosted MCP access are verified. Add ${ORGX_HOSTED_MCP_URL} as a custom connector in ChatGPT developer mode, then run \`${DOCTOR_HINT}\` to confirm \`${toolCheck.toolName}\`.`
2222
+ message: `OrgX auth is ready via ${formatAuthHintSource(authHint)}. Add ${ORGX_HOSTED_MCP_URL} as a custom connector in ChatGPT developer mode; ChatGPT will complete the OAuth flow there. Then run \`${DOCTOR_HINT}\` to verify hosted MCP health from this machine.`
2386
2223
  };
2387
2224
  }
2388
2225
  function buildChatgptRemoveResult(path) {
@@ -2520,8 +2357,7 @@ async function addAutomatedSurface(name) {
2520
2357
  if (!authHint) {
2521
2358
  return buildChatgptAddResult(path, null);
2522
2359
  }
2523
- const toolCheck = await checkHostedMcpToolAccess();
2524
- return buildChatgptAddResult(path, authHint, toolCheck);
2360
+ return buildChatgptAddResult(path, authHint);
2525
2361
  }
2526
2362
  default:
2527
2363
  return {
@@ -2827,6 +2663,8 @@ var FOUNDER_DEMO_ARTIFACT_TYPE = "document";
2827
2663
  var FOUNDER_DEMO_ARTIFACT_DESCRIPTION = "Live founder demo generated by @useorgx/wizard after workspace bootstrap completed.";
2828
2664
  var ONBOARDING_TASK_TITLE = "Complete OrgX onboarding";
2829
2665
  var ONBOARDING_TASK_SUMMARY = "Starter onboarding task created by @useorgx/wizard so the first workspace has a clear follow-up after setup.";
2666
+ var ONBOARDING_WORKSTREAM_TITLE = "OrgX onboarding";
2667
+ var ONBOARDING_WORKSTREAM_SUMMARY = "Starter onboarding workstream created by @useorgx/wizard so the first workspace has a home for setup follow-up tasks.";
2830
2668
  function parseResponseBody3(text2) {
2831
2669
  if (!text2) {
2832
2670
  return null;
@@ -2910,6 +2748,15 @@ function parseTask(payload) {
2910
2748
  ...typeof entity.summary === "string" && entity.summary.trim().length > 0 ? { summary: entity.summary.trim() } : {}
2911
2749
  };
2912
2750
  }
2751
+ function parseWorkstream(payload) {
2752
+ const entity = extractEntity(payload);
2753
+ const id = typeof entity.id === "string" ? entity.id.trim() : "";
2754
+ const title = typeof entity.title === "string" ? entity.title.trim() : typeof entity.name === "string" ? entity.name.trim() : "";
2755
+ if (!id || !title) {
2756
+ throw new Error("OrgX returned an incomplete workstream payload.");
2757
+ }
2758
+ return { id, title };
2759
+ }
2913
2760
  function toDemoInitiativeRecord(artifact, decision, initiative, liveUrl, workspace) {
2914
2761
  return {
2915
2762
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2927,13 +2774,14 @@ function toDemoInitiativeRecord(artifact, decision, initiative, liveUrl, workspa
2927
2774
  workspaceName: workspace.name
2928
2775
  };
2929
2776
  }
2930
- function toOnboardingTaskRecord(task, workspace, initiativeId) {
2777
+ function toOnboardingTaskRecord(task, workspace, options = {}) {
2931
2778
  return {
2932
2779
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2933
2780
  id: task.id,
2934
- ...initiativeId ? { initiativeId } : {},
2781
+ ...options.initiativeId ? { initiativeId: options.initiativeId } : {},
2935
2782
  ...task.status ? { status: task.status } : {},
2936
2783
  title: task.title,
2784
+ ...options.workstreamId ? { workstreamId: options.workstreamId } : {},
2937
2785
  workspaceId: workspace.id,
2938
2786
  workspaceName: workspace.name
2939
2787
  };
@@ -3112,14 +2960,33 @@ async function ensureOnboardingTask(workspace, options = {}) {
3112
2960
  ...existingRecord.status ? { status: existingRecord.status } : {}
3113
2961
  };
3114
2962
  }
2963
+ const initiativeId = options.initiativeId?.trim();
2964
+ if (!initiativeId) {
2965
+ throw new Error(
2966
+ "Starter onboarding task requires an initiative context. Re-run setup with the founder preset or create an initiative before requesting onboarding tasks."
2967
+ );
2968
+ }
2969
+ const workstream = await createEntity(
2970
+ "workstream",
2971
+ {
2972
+ initiative_id: initiativeId,
2973
+ status: "active",
2974
+ summary: ONBOARDING_WORKSTREAM_SUMMARY,
2975
+ title: ONBOARDING_WORKSTREAM_TITLE,
2976
+ workspace_id: workspace.id
2977
+ },
2978
+ parseWorkstream,
2979
+ options
2980
+ );
3115
2981
  const task = await createEntity(
3116
2982
  "task",
3117
2983
  {
2984
+ initiative_id: initiativeId,
3118
2985
  status: "todo",
3119
2986
  summary: ONBOARDING_TASK_SUMMARY,
3120
2987
  title: ONBOARDING_TASK_TITLE,
3121
- workspace_id: workspace.id,
3122
- ...options.initiativeId ? { initiative_id: options.initiativeId } : {}
2988
+ workstream_id: workstream.id,
2989
+ workspace_id: workspace.id
3123
2990
  },
3124
2991
  parseTask,
3125
2992
  options
@@ -3127,7 +2994,10 @@ async function ensureOnboardingTask(workspace, options = {}) {
3127
2994
  updateWizardState(
3128
2995
  (current) => ({
3129
2996
  ...current,
3130
- onboardingTask: toOnboardingTaskRecord(task, workspace, options.initiativeId)
2997
+ onboardingTask: toOnboardingTaskRecord(task, workspace, {
2998
+ initiativeId,
2999
+ workstreamId: workstream.id
3000
+ })
3131
3001
  }),
3132
3002
  options.statePath
3133
3003
  );
@@ -3414,7 +3284,7 @@ import {
3414
3284
  } from "fs";
3415
3285
  import { tmpdir } from "os";
3416
3286
  import { dirname as dirname3, join as join3, relative } from "path";
3417
- var DEFAULT_ORGX_PLUGIN_TARGETS = ["claude", "codex", "openclaw"];
3287
+ var DEFAULT_ORGX_PLUGIN_TARGETS = ["cursor", "claude", "codex", "openclaw"];
3418
3288
  var ORGX_PLUGIN_GITHUB_OWNER = "useorgx";
3419
3289
  var ORGX_PLUGIN_GITHUB_REF = "main";
3420
3290
  var ORGX_CLAUDE_PLUGIN_NAME = "orgx-claude-code-plugin";
@@ -3453,7 +3323,8 @@ function defaultPluginPaths() {
3453
3323
  claudeMarketplaceManifestPath: CLAUDE_MANAGED_MARKETPLACE_MANIFEST_PATH,
3454
3324
  claudePluginDir: CLAUDE_MANAGED_PLUGIN_DIR,
3455
3325
  codexMarketplacePath: CODEX_MARKETPLACE_PATH,
3456
- codexPluginDir: CODEX_ORGX_PLUGIN_DIR
3326
+ codexPluginDir: CODEX_ORGX_PLUGIN_DIR,
3327
+ cursorRulePath: CURSOR_ORGX_RULE_PATH
3457
3328
  };
3458
3329
  }
3459
3330
  function resolvePluginPaths(paths = {}) {
@@ -3873,6 +3744,32 @@ async function getOpenclawInstallState(runner) {
3873
3744
  installed: extractOpenclawPluginIds(result.stdout).includes(ORGX_OPENCLAW_PLUGIN_ID)
3874
3745
  };
3875
3746
  }
3747
+ function buildCursorStatus(paths) {
3748
+ const existingRules = readTextIfExists(paths.cursorRulePath);
3749
+ const available = detectSurface("cursor").detected || existingRules !== null;
3750
+ if (existingRules === CURSOR_RULES_CONTENT) {
3751
+ return {
3752
+ target: "cursor",
3753
+ available: true,
3754
+ installed: true,
3755
+ message: "Cursor OrgX rules are installed."
3756
+ };
3757
+ }
3758
+ if (existingRules !== null) {
3759
+ return {
3760
+ target: "cursor",
3761
+ available: true,
3762
+ installed: false,
3763
+ message: "Cursor OrgX rules file exists, but differs from the managed rules."
3764
+ };
3765
+ }
3766
+ return {
3767
+ target: "cursor",
3768
+ available,
3769
+ installed: false,
3770
+ message: available ? "Cursor is available and ready for OrgX rules install." : "Cursor was not detected."
3771
+ };
3772
+ }
3876
3773
  async function buildClaudeStatus(paths, runner) {
3877
3774
  const state = await getClaudeInstallState(runner);
3878
3775
  if (state.installed) {
@@ -3988,6 +3885,30 @@ async function resolveOpenclawTarball(fetchImpl) {
3988
3885
  version: latestVersion
3989
3886
  };
3990
3887
  }
3888
+ function installCursorPlugin(paths) {
3889
+ const existingRules = readTextIfExists(paths.cursorRulePath);
3890
+ const available = detectSurface("cursor").detected || existingRules !== null;
3891
+ if (!available) {
3892
+ return {
3893
+ target: "cursor",
3894
+ changed: false,
3895
+ message: "Cursor is not available on this machine."
3896
+ };
3897
+ }
3898
+ if (existingRules === CURSOR_RULES_CONTENT) {
3899
+ return {
3900
+ target: "cursor",
3901
+ changed: false,
3902
+ message: "Cursor OrgX rules are already installed."
3903
+ };
3904
+ }
3905
+ writeTextFile(paths.cursorRulePath, CURSOR_RULES_CONTENT);
3906
+ return {
3907
+ target: "cursor",
3908
+ changed: true,
3909
+ message: "Installed the managed Cursor OrgX rules."
3910
+ };
3911
+ }
3991
3912
  async function installClaudePlugin(paths, fetchImpl, runner) {
3992
3913
  const state = await getClaudeInstallState(runner);
3993
3914
  if (!state.available) {
@@ -4094,6 +4015,29 @@ async function installOpenclawPlugin(fetchImpl, runner) {
4094
4015
  message: `Installed OpenClaw plugin ${ORGX_OPENCLAW_PLUGIN_ID} from ${ORGX_OPENCLAW_PLUGIN_PACKAGE_NAME}@${version}.`
4095
4016
  };
4096
4017
  }
4018
+ function uninstallCursorPlugin(paths) {
4019
+ const existingRules = readTextIfExists(paths.cursorRulePath);
4020
+ if (existingRules === null) {
4021
+ return {
4022
+ target: "cursor",
4023
+ changed: false,
4024
+ message: "Cursor OrgX rules were not installed."
4025
+ };
4026
+ }
4027
+ if (existingRules !== CURSOR_RULES_CONTENT) {
4028
+ return {
4029
+ target: "cursor",
4030
+ changed: false,
4031
+ message: "Cursor rules file differs from the managed OrgX rules, so it was left in place."
4032
+ };
4033
+ }
4034
+ const changed = deleteFileIfExists(paths.cursorRulePath);
4035
+ return {
4036
+ target: "cursor",
4037
+ changed,
4038
+ message: changed ? "Removed the managed Cursor OrgX rules." : "Cursor OrgX rules were not installed."
4039
+ };
4040
+ }
4097
4041
  async function uninstallClaudePlugin(paths, runner) {
4098
4042
  const state = await getClaudeInstallState(runner);
4099
4043
  let changed = false;
@@ -4189,6 +4133,7 @@ async function listOrgxPluginStatuses(options = {}) {
4189
4133
  const paths = resolvePluginPaths(options.paths);
4190
4134
  const runner = resolveCommandRunner(options.commandRunner);
4191
4135
  return await Promise.all([
4136
+ buildCursorStatus(paths),
4192
4137
  buildClaudeStatus(paths, runner),
4193
4138
  buildCodexStatus(paths, runner),
4194
4139
  buildOpenclawStatus(runner)
@@ -4205,6 +4150,9 @@ async function installOrgxPlugins(options = {}) {
4205
4150
  const results = [];
4206
4151
  for (const target of targets) {
4207
4152
  switch (target) {
4153
+ case "cursor":
4154
+ results.push(installCursorPlugin(paths));
4155
+ break;
4208
4156
  case "claude":
4209
4157
  results.push(await installClaudePlugin(paths, fetchImpl, runner));
4210
4158
  break;
@@ -4225,6 +4173,9 @@ async function uninstallOrgxPlugins(options = {}) {
4225
4173
  const results = [];
4226
4174
  for (const target of targets) {
4227
4175
  switch (target) {
4176
+ case "cursor":
4177
+ results.push(uninstallCursorPlugin(paths));
4178
+ break;
4228
4179
  case "claude":
4229
4180
  results.push(await uninstallClaudePlugin(paths, runner));
4230
4181
  break;
@@ -4691,6 +4642,8 @@ function formatAuthSource(source) {
4691
4642
  }
4692
4643
  function formatPluginTargetLabel(target) {
4693
4644
  switch (target) {
4645
+ case "cursor":
4646
+ return "Cursor rules";
4694
4647
  case "claude":
4695
4648
  return "Claude Code";
4696
4649
  case "codex":
@@ -4735,6 +4688,16 @@ function printPluginMutationReport(report) {
4735
4688
  );
4736
4689
  }
4737
4690
  }
4691
+ async function printPluginStatusSection() {
4692
+ const spinner = createOrgxSpinner("Checking OrgX plugin and Cursor rules status");
4693
+ spinner.start();
4694
+ const statuses = await listOrgxPluginStatuses();
4695
+ spinner.succeed("OrgX plugin and Cursor rules status checked");
4696
+ console.log("");
4697
+ console.log(pc3.dim(" plugins"));
4698
+ printPluginStatusReport(statuses);
4699
+ return statuses;
4700
+ }
4738
4701
  function printSkillInstallReport(report) {
4739
4702
  for (const write of report.writes) {
4740
4703
  const icon = write.changed ? ICON.ok : ICON.skip;
@@ -4837,8 +4800,9 @@ async function textPrompt(input) {
4837
4800
  }
4838
4801
  async function multiselectPrompt(input) {
4839
4802
  const promptInput = {
4840
- message: input.message,
4803
+ message: `${input.message} ${pc3.dim("Space selects items; Enter continues.")}`,
4841
4804
  options: input.options,
4805
+ ...input.initialValues ? { initialValues: input.initialValues } : {},
4842
4806
  ...input.required !== void 0 ? { required: input.required } : {}
4843
4807
  };
4844
4808
  return normalizePromptResult(await clack.multiselect(promptInput));
@@ -4943,8 +4907,9 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
4943
4907
  return "skipped";
4944
4908
  }
4945
4909
  const existingState = readWizardState();
4910
+ const effectiveInitiativeId = input.initiativeId?.trim() || (existingState?.demoInitiative?.workspaceId === input.workspace.id ? existingState.demoInitiative.id : void 0);
4946
4911
  const hasOnboardingTask = existingState?.onboardingTask?.workspaceId === input.workspace.id;
4947
- if (!hasOnboardingTask) {
4912
+ if (!hasOnboardingTask && effectiveInitiativeId) {
4948
4913
  const onboardingChoice = await selectPrompt({
4949
4914
  message: `Create a starter onboarding task for ${input.workspace.name}?`,
4950
4915
  options: [
@@ -4957,34 +4922,40 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
4957
4922
  return "cancelled";
4958
4923
  }
4959
4924
  if (onboardingChoice === "yes") {
4960
- const task = await ensureOnboardingTask(input.workspace, {
4961
- ...input.initiativeId ? { initiativeId: input.initiativeId } : {}
4962
- });
4963
- console.log(` ${ICON.ok} ${pc3.green("onboarding")} ${pc3.bold(task.title)}`);
4964
- await safeTrackWizardTelemetry(
4965
- "onboarding_task_created",
4966
- buildOnboardingTaskTelemetryProperties(
4967
- {
4968
- created: true,
4969
- hasInitiative: Boolean(input.initiativeId),
4970
- task
4971
- },
4972
- {
4973
- command: input.telemetry?.command ?? "setup",
4974
- ...input.telemetry?.preset ? { preset: input.telemetry.preset } : {}
4975
- }
4976
- )
4977
- );
4925
+ try {
4926
+ const task = await ensureOnboardingTask(input.workspace, {
4927
+ initiativeId: effectiveInitiativeId
4928
+ });
4929
+ console.log(` ${ICON.ok} ${pc3.green("onboarding")} ${pc3.bold(task.title)}`);
4930
+ await safeTrackWizardTelemetry(
4931
+ "onboarding_task_created",
4932
+ buildOnboardingTaskTelemetryProperties(
4933
+ {
4934
+ created: true,
4935
+ hasInitiative: true,
4936
+ task
4937
+ },
4938
+ {
4939
+ command: input.telemetry?.command ?? "setup",
4940
+ ...input.telemetry?.preset ? { preset: input.telemetry.preset } : {}
4941
+ }
4942
+ )
4943
+ );
4944
+ } catch (error) {
4945
+ const message = error instanceof Error ? error.message : String(error);
4946
+ console.log(` ${ICON.warn} ${pc3.yellow("onboarding")} ${pc3.dim(message)}`);
4947
+ }
4978
4948
  }
4979
4949
  }
4980
4950
  const refreshedState = readWizardState();
4981
4951
  const hasAgentRoster = refreshedState?.agentRoster?.workspaceId === input.workspace.id;
4982
4952
  if (!hasAgentRoster) {
4983
4953
  const rosterChoice = await selectPrompt({
4954
+ initialValue: "default",
4984
4955
  message: `Set up an OrgX agent roster for ${input.workspace.name}?`,
4985
4956
  options: [
4986
- { value: "guided", label: "Choose agents and domains", hint: "recommended" },
4987
- { value: "default", label: "Install the full default roster" },
4957
+ { value: "default", label: "Install the full default roster", hint: "recommended" },
4958
+ { value: "guided", label: "Choose agents and domains" },
4988
4959
  { value: "no", label: "Skip roster setup" }
4989
4960
  ]
4990
4961
  });
@@ -5039,7 +5010,13 @@ async function promptOptionalCompanionPluginTargets(input) {
5039
5010
  if (!input.interactive) {
5040
5011
  return [];
5041
5012
  }
5042
- const statuses = await listOrgxPluginStatuses();
5013
+ let statuses = input.statuses;
5014
+ if (!statuses) {
5015
+ const spinner = createOrgxSpinner("Checking optional OrgX plugin and Cursor rules status");
5016
+ spinner.start();
5017
+ statuses = await listOrgxPluginStatuses();
5018
+ spinner.succeed("Optional OrgX plugin and Cursor rules status checked");
5019
+ }
5043
5020
  const installable = statuses.filter((status) => status.available && !status.installed);
5044
5021
  if (installable.length === 0) {
5045
5022
  return [];
@@ -5090,7 +5067,8 @@ async function installSelectedCompanionPlugins(input) {
5090
5067
  }
5091
5068
  async function maybeInstallOptionalCompanionPlugins(input) {
5092
5069
  const selection = await promptOptionalCompanionPluginTargets({
5093
- interactive: input.interactive
5070
+ interactive: input.interactive,
5071
+ ...input.statuses ? { statuses: input.statuses } : {}
5094
5072
  });
5095
5073
  if (selection === "cancelled") {
5096
5074
  return "cancelled";
@@ -5178,7 +5156,7 @@ function printDoctorReport(report, assessment) {
5178
5156
  async function main() {
5179
5157
  const program = new Command();
5180
5158
  program.name("orgx-wizard").description("One-line CLI onboarding for OrgX surfaces.").showHelpAfterError();
5181
- const pkgVersion = true ? "0.1.8" : void 0;
5159
+ const pkgVersion = true ? "0.1.10" : void 0;
5182
5160
  program.version(pkgVersion ?? "unknown", "-V, --version");
5183
5161
  program.hook("preAction", () => {
5184
5162
  console.log(renderBanner(pkgVersion));
@@ -5289,6 +5267,7 @@ async function main() {
5289
5267
  const results = await setupDetectedSurfaces();
5290
5268
  spinner.succeed("Detected surfaces configured");
5291
5269
  printMutationResults(results);
5270
+ const pluginStatuses = await printPluginStatusSection();
5292
5271
  await safeTrackWizardTelemetry("mcp_injected", {
5293
5272
  changed_count: results.filter((result) => result.changed).length,
5294
5273
  preset: "standard",
@@ -5377,6 +5356,7 @@ async function main() {
5377
5356
  }
5378
5357
  const pluginInstallResult = await maybeInstallOptionalCompanionPlugins({
5379
5358
  interactive,
5359
+ statuses: pluginStatuses,
5380
5360
  telemetry: { command: "setup", preset: "standard" }
5381
5361
  });
5382
5362
  if (pluginInstallResult === "cancelled") {
@@ -5547,6 +5527,51 @@ async function main() {
5547
5527
  );
5548
5528
  }
5549
5529
  });
5530
+ program.command("uninstall").description("Remove OrgX-managed surfaces, companion plugins/rules, auth, and wizard state from this machine.").option("--keep-auth", "Keep the wizard-local saved OrgX API key.").option("--keep-state", "Keep wizard-local setup state.").option("--skip-plugins", "Skip companion plugin and Cursor rules removal.").option("--skip-surfaces", "Skip MCP surface config removal.").action(async (options) => {
5531
+ await safeTrackWizardTelemetry("wizard_uninstalled", {
5532
+ keep_auth: Boolean(options.keepAuth),
5533
+ keep_state: Boolean(options.keepState),
5534
+ skip_plugins: Boolean(options.skipPlugins),
5535
+ skip_surfaces: Boolean(options.skipSurfaces)
5536
+ });
5537
+ console.log(pc3.bold("Removing OrgX wizard-managed configuration"));
5538
+ if (options.skipSurfaces) {
5539
+ console.log(` ${ICON.skip} ${pc3.bold("surfaces".padEnd(10))} ${pc3.dim("skipped")}`);
5540
+ } else {
5541
+ console.log("");
5542
+ console.log(pc3.dim(" surfaces"));
5543
+ const surfaceResults = removeSurface(["all"]);
5544
+ printMutationResults(surfaceResults);
5545
+ }
5546
+ if (options.skipPlugins) {
5547
+ console.log(` ${ICON.skip} ${pc3.bold("plugins".padEnd(12))} ${pc3.dim("skipped")}`);
5548
+ } else {
5549
+ console.log("");
5550
+ console.log(pc3.dim(" plugins"));
5551
+ const spinner = createOrgxSpinner("Removing OrgX companion plugins and rules");
5552
+ spinner.start();
5553
+ const pluginReport = await uninstallOrgxPlugins({ targets: ["all"] });
5554
+ spinner.succeed("OrgX companion plugins and rules processed");
5555
+ printPluginMutationReport(pluginReport);
5556
+ }
5557
+ console.log("");
5558
+ if (options.keepAuth) {
5559
+ console.log(` ${ICON.skip} ${pc3.bold("auth".padEnd(12))} ${pc3.dim("kept")}`);
5560
+ } else {
5561
+ const removedAuth = await clearWizardAuth();
5562
+ const state = removedAuth ? pc3.green("updated ") : pc3.dim("unchanged");
5563
+ const message = removedAuth ? "Removed the wizard-local OrgX API key." : "No wizard-local OrgX API key was stored.";
5564
+ console.log(` ${removedAuth ? ICON.ok : ICON.skip} ${pc3.bold("auth".padEnd(12))} ${state} ${pc3.dim(message)}`);
5565
+ }
5566
+ if (options.keepState) {
5567
+ console.log(` ${ICON.skip} ${pc3.bold("state".padEnd(12))} ${pc3.dim("kept")}`);
5568
+ } else {
5569
+ const removedState = clearWizardState();
5570
+ const state = removedState ? pc3.green("updated ") : pc3.dim("unchanged");
5571
+ const message = removedState ? "Removed wizard-local setup state." : "No wizard-local setup state was stored.";
5572
+ console.log(` ${removedState ? ICON.ok : ICON.skip} ${pc3.bold("state".padEnd(12))} ${state} ${pc3.dim(message)}`);
5573
+ }
5574
+ });
5550
5575
  const surface = program.command("surface").description("Manage supported OrgX surfaces.");
5551
5576
  surface.command("list").description("Show supported surfaces and their current status.").action(() => {
5552
5577
  printSurfaceTable(listSurfaceStatuses());
@@ -5568,15 +5593,15 @@ async function main() {
5568
5593
  const results = removeMcpSurface(names);
5569
5594
  printMutationResults(results);
5570
5595
  });
5571
- const plugins = program.command("plugins").description("Install or remove companion OrgX plugins for Claude Code, Codex, and OpenClaw.");
5596
+ const plugins = program.command("plugins").description("Install or remove Cursor rules and companion OrgX plugins for Claude Code, Codex, and OpenClaw.");
5572
5597
  plugins.command("list").description("Show companion plugin availability and install status.").action(async () => {
5573
- const spinner = createOrgxSpinner("Checking companion plugin status");
5598
+ const spinner = createOrgxSpinner("Checking OrgX plugin and Cursor rules status");
5574
5599
  spinner.start();
5575
5600
  const statuses = await listOrgxPluginStatuses();
5576
- spinner.stop();
5601
+ spinner.succeed("OrgX plugin and Cursor rules status checked");
5577
5602
  printPluginStatusReport(statuses);
5578
5603
  });
5579
- plugins.command("add").description("Install OrgX companion plugins into Claude Code, Codex, or OpenClaw.").argument("[targets...]", "claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
5604
+ plugins.command("add").description("Install Cursor OrgX rules or companion plugins into Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
5580
5605
  const spinner = createOrgxSpinner("Installing OrgX companion plugins");
5581
5606
  spinner.start();
5582
5607
  const report = await installOrgxPlugins({ targets });
@@ -5590,7 +5615,7 @@ async function main() {
5590
5615
  target_count: report.results.length
5591
5616
  });
5592
5617
  });
5593
- plugins.command("remove").description("Uninstall managed OrgX companion plugins from Claude Code, Codex, or OpenClaw.").argument("[targets...]", "claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
5618
+ plugins.command("remove").description("Uninstall managed Cursor OrgX rules or companion plugins from Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
5594
5619
  const spinner = createOrgxSpinner("Removing OrgX companion plugins");
5595
5620
  spinner.start();
5596
5621
  const report = await uninstallOrgxPlugins({ targets });