@useorgx/wizard 0.1.12 → 0.1.14

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/README.md CHANGED
@@ -22,7 +22,7 @@ The wizard modifies local tool configuration only. Depending on the command, it
22
22
 
23
23
  ## Commands
24
24
 
25
- - `setup` adds OrgX MCP configs, standalone skills/rules, and companion plugins to detected AI tools. When OrgX auth is available in an interactive shell, it also guides workspace selection or creation, optional onboarding extras, and optional companion plugin installs for detected Cursor, Claude Code, Codex, and OpenClaw hosts. The founder preset preplans plugin installs before it writes standalone skills so plugin-backed hosts do not get duplicate standalone assets in the same run.
25
+ - `setup` adds OrgX MCP configs, standalone skills/rules, and companion plugins to detected AI tools. When OrgX auth is available in an interactive shell, it guides workspace selection or creation, can create the user's first live OrgX initiative, creates a starter onboarding task under that initiative, and prints a handoff prompt for the configured AI tool of choice. The founder preset preplans plugin installs before it writes standalone skills so plugin-backed hosts do not get duplicate standalone assets in the same run.
26
26
  - `surface list` shows supported surfaces and current status.
27
27
  - `surface add <name>` patches a specific surface.
28
28
  - `surface remove <name>` removes OrgX-managed config from a specific surface.
@@ -60,6 +60,8 @@ The wizard modifies local tool configuration only. Depending on the command, it
60
60
  ## Workspace Bootstrap
61
61
 
62
62
  - `wizard setup` now opens a guided workspace picker in interactive shells, letting you keep the current default workspace, promote another existing workspace, or create a new one and make it active immediately.
63
+ - If the selected workspace has no remembered setup initiative, `wizard setup` offers to create a first initiative, defaulting to `Make OrgX useful on this machine`. It then creates the onboarding workstream and starter task inside that initiative so setup ends with a concrete next action instead of a blank workspace.
64
+ - After the first initiative is ready, setup prints the `/live/<initiative>` URL and a copyable prompt for the user's configured AI tool: continue the initiative, show the next action, and start with the onboarding task.
63
65
  - `wizard workspace current` reads the current OrgX workspace from `GET /api/v1/workspaces/current`, with a fallback to workspace listing if that route is unavailable.
64
66
  - `wizard workspace list` lists all accessible workspaces.
65
67
  - `wizard workspace create "Founders" --description "Initial OrgX workspace"` creates a new workspace through `POST /api/entities`.
package/dist/cli.js CHANGED
@@ -519,9 +519,6 @@ function normalizeOrgxBaseUrl(raw) {
519
519
  }
520
520
  function buildOrgxApiUrl(path, baseUrl) {
521
521
  const parsedBase = new URL(normalizeOrgxBaseUrl(baseUrl));
522
- if (parsedBase.protocol === "https:" && normalizeHost(parsedBase.hostname) === "useorgx.com") {
523
- parsedBase.hostname = "www.useorgx.com";
524
- }
525
522
  const normalizedBase = parsedBase.toString().replace(/\/+$/, "");
526
523
  const apiBase = normalizedBase.endsWith("/api") ? normalizedBase : `${normalizedBase}/api`;
527
524
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
@@ -726,6 +723,21 @@ async function fetchJson({
726
723
  }
727
724
  return payload;
728
725
  }
726
+ var UNROUTABLE_HOSTNAMES = /* @__PURE__ */ new Set(["0.0.0.0", "::", "[::]"]);
727
+ function sanitizeConnectUrl(connectUrl, baseUrl) {
728
+ try {
729
+ const parsed = new URL(connectUrl);
730
+ if (UNROUTABLE_HOSTNAMES.has(parsed.hostname)) {
731
+ const base = new URL(normalizeOrgxBaseUrl(baseUrl));
732
+ parsed.protocol = base.protocol;
733
+ parsed.hostname = base.hostname;
734
+ parsed.port = base.port;
735
+ }
736
+ return parsed.toString();
737
+ } catch {
738
+ return connectUrl;
739
+ }
740
+ }
729
741
  function parsePairingStartResult(value) {
730
742
  if (!isRecord(value)) {
731
743
  throw new Error("OrgX pairing start returned an invalid response.");
@@ -777,7 +789,11 @@ async function startBrowserPairing(options, fetchImpl) {
777
789
  }),
778
790
  fetchImpl
779
791
  });
780
- return parsePairingStartResult(data);
792
+ const result = parsePairingStartResult(data);
793
+ return {
794
+ ...result,
795
+ connectUrl: sanitizeConnectUrl(result.connectUrl, options.baseUrl)
796
+ };
781
797
  }
782
798
  async function pollBrowserPairing(options, fetchImpl) {
783
799
  const baseUrl = normalizeOrgxBaseUrl(options.baseUrl);
@@ -930,6 +946,24 @@ function parseDemoInitiative(value) {
930
946
  ...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
931
947
  };
932
948
  }
949
+ function parseFirstValueInitiative(value) {
950
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
951
+ return void 0;
952
+ }
953
+ const record = value;
954
+ if (!isNonEmptyString2(record.id) || !isNonEmptyString2(record.title) || !isNonEmptyString2(record.liveUrl) || !isNonEmptyString2(record.createdAt)) {
955
+ return void 0;
956
+ }
957
+ return {
958
+ createdAt: record.createdAt.trim(),
959
+ id: record.id.trim(),
960
+ liveUrl: record.liveUrl.trim(),
961
+ ...isNonEmptyString2(record.summary) ? { summary: record.summary.trim() } : {},
962
+ title: record.title.trim(),
963
+ ...isNonEmptyString2(record.workspaceId) ? { workspaceId: record.workspaceId.trim() } : {},
964
+ ...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
965
+ };
966
+ }
933
967
  function parseOnboardingTask(value) {
934
968
  if (!value || typeof value !== "object" || Array.isArray(value)) {
935
969
  return void 0;
@@ -1026,6 +1060,7 @@ function sanitizeWizardStateRecord(record) {
1026
1060
  const continuity = parseContinuityDefaults(record.continuity);
1027
1061
  const agentRoster = parseAgentRoster(record.agentRoster);
1028
1062
  const demoInitiative = parseDemoInitiative(record.demoInitiative);
1063
+ const firstValueInitiative = parseFirstValueInitiative(record.firstValueInitiative);
1029
1064
  const onboardingTask = parseOnboardingTask(record.onboardingTask);
1030
1065
  const skillFiles = parseSkillFiles(record.skillFiles);
1031
1066
  return {
@@ -1035,6 +1070,7 @@ function sanitizeWizardStateRecord(record) {
1035
1070
  ...continuity ? { continuity } : {},
1036
1071
  ...agentRoster ? { agentRoster } : {},
1037
1072
  ...demoInitiative ? { demoInitiative } : {},
1073
+ ...firstValueInitiative ? { firstValueInitiative } : {},
1038
1074
  ...onboardingTask ? { onboardingTask } : {},
1039
1075
  ...skillFiles ? { skillFiles } : {}
1040
1076
  };
@@ -1055,6 +1091,10 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1055
1091
  if (agentRoster !== void 0) state.agentRoster = agentRoster;
1056
1092
  const demoInitiative = parseDemoInitiative(parsed.demoInitiative);
1057
1093
  if (demoInitiative !== void 0) state.demoInitiative = demoInitiative;
1094
+ const firstValueInitiative = parseFirstValueInitiative(parsed.firstValueInitiative);
1095
+ if (firstValueInitiative !== void 0) {
1096
+ state.firstValueInitiative = firstValueInitiative;
1097
+ }
1058
1098
  const onboardingTask = parseOnboardingTask(parsed.onboardingTask);
1059
1099
  if (onboardingTask !== void 0) state.onboardingTask = onboardingTask;
1060
1100
  const skillFiles = parseSkillFiles(parsed.skillFiles);
@@ -2706,6 +2746,8 @@ var ONBOARDING_TASK_TITLE = "Complete OrgX onboarding";
2706
2746
  var ONBOARDING_TASK_SUMMARY = "Starter onboarding task created by @useorgx/wizard so the first workspace has a clear follow-up after setup.";
2707
2747
  var ONBOARDING_WORKSTREAM_TITLE = "OrgX onboarding";
2708
2748
  var ONBOARDING_WORKSTREAM_SUMMARY = "Starter onboarding workstream created by @useorgx/wizard so the first workspace has a home for setup follow-up tasks.";
2749
+ var FIRST_VALUE_INITIATIVE_TITLE = "Make OrgX useful on this machine";
2750
+ var FIRST_VALUE_INITIATIVE_SUMMARY = "First initiative created by @useorgx/wizard so setup ends with a live workspace, an onboarding workstream, and a clean handoff into the user's configured AI tools.";
2709
2751
  function parseResponseBody3(text2) {
2710
2752
  if (!text2) {
2711
2753
  return null;
@@ -2827,6 +2869,17 @@ function toOnboardingTaskRecord(task, workspace, options = {}) {
2827
2869
  workspaceName: workspace.name
2828
2870
  };
2829
2871
  }
2872
+ function toFirstValueInitiativeRecord(initiative, liveUrl, workspace) {
2873
+ return {
2874
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2875
+ id: initiative.id,
2876
+ liveUrl,
2877
+ ...initiative.summary ? { summary: initiative.summary } : {},
2878
+ title: initiative.title,
2879
+ workspaceId: workspace.id,
2880
+ workspaceName: workspace.name
2881
+ };
2882
+ }
2830
2883
  async function requireOrgxAuth2(options = {}) {
2831
2884
  const auth = await resolveOrgxAuth(options);
2832
2885
  if (!auth) {
@@ -2879,9 +2932,6 @@ async function updateEntity(type, id, body, parse2, options = {}) {
2879
2932
  }
2880
2933
  function buildLiveUrl(baseUrl, initiativeId) {
2881
2934
  const parsed = new URL(normalizeOrgxBaseUrl(baseUrl));
2882
- if (parsed.protocol === "https:" && parsed.hostname === "useorgx.com") {
2883
- parsed.hostname = "www.useorgx.com";
2884
- }
2885
2935
  parsed.pathname = `/live/${initiativeId}`;
2886
2936
  parsed.search = "";
2887
2937
  parsed.hash = "";
@@ -2992,6 +3042,43 @@ async function ensureFounderDemoInitiative(workspace, options = {}) {
2992
3042
  liveUrl
2993
3043
  };
2994
3044
  }
3045
+ async function ensureFirstValueInitiative(workspace, options = {}) {
3046
+ const existingRecord = readWizardState(options.statePath)?.firstValueInitiative;
3047
+ const matchingRecord = existingRecord?.workspaceId === workspace.id ? existingRecord : void 0;
3048
+ const auth = await requireOrgxAuth2(options);
3049
+ if (matchingRecord) {
3050
+ return {
3051
+ created: false,
3052
+ initiative: {
3053
+ id: matchingRecord.id,
3054
+ title: matchingRecord.title,
3055
+ ...matchingRecord.summary ? { summary: matchingRecord.summary } : {}
3056
+ },
3057
+ liveUrl: matchingRecord.liveUrl || buildLiveUrl(auth.baseUrl, matchingRecord.id)
3058
+ };
3059
+ }
3060
+ const initiative = await createInitiative(
3061
+ {
3062
+ title: options.title?.trim() || FIRST_VALUE_INITIATIVE_TITLE,
3063
+ summary: options.summary?.trim() || FIRST_VALUE_INITIATIVE_SUMMARY,
3064
+ workspaceId: workspace.id
3065
+ },
3066
+ options
3067
+ );
3068
+ const liveUrl = buildLiveUrl(auth.baseUrl, initiative.id);
3069
+ updateWizardState(
3070
+ (current) => ({
3071
+ ...current,
3072
+ firstValueInitiative: toFirstValueInitiativeRecord(initiative, liveUrl, workspace)
3073
+ }),
3074
+ options.statePath
3075
+ );
3076
+ return {
3077
+ created: true,
3078
+ initiative,
3079
+ liveUrl
3080
+ };
3081
+ }
2995
3082
  async function ensureOnboardingTask(workspace, options = {}) {
2996
3083
  const existingRecord = readWizardState(options.statePath)?.onboardingTask;
2997
3084
  if (existingRecord?.workspaceId === workspace.id) {
@@ -4889,6 +4976,15 @@ function buildFounderDemoTelemetryProperties(result, base = {}) {
4889
4976
  base
4890
4977
  );
4891
4978
  }
4979
+ function buildFirstValueInitiativeTelemetryProperties(result, base = {}) {
4980
+ return withBaseProperties(
4981
+ {
4982
+ created: result.created,
4983
+ has_live_url: Boolean(result.liveUrl)
4984
+ },
4985
+ base
4986
+ );
4987
+ }
4892
4988
  function buildDoctorTelemetryProperties(report, assessment, verification, base = {}) {
4893
4989
  const errorCount = assessment.issues.filter((issue) => issue.level === "error").length;
4894
4990
  const warningCount = assessment.issues.filter((issue) => issue.level === "warning").length;
@@ -5181,6 +5277,41 @@ function printWorkspaceSetupResult(result) {
5181
5277
  console.log(` ${ICON.skip} ${pc3.dim(result.message)}`);
5182
5278
  }
5183
5279
  }
5280
+ function printSetupScopeNote() {
5281
+ console.log(pc3.dim(" setup updates your AI tools with:"));
5282
+ console.log(` ${ICON.skip} ${pc3.dim("MCP configs for local and cloud OrgX access")}`);
5283
+ console.log(` ${ICON.skip} ${pc3.dim("OrgX agent skills, rules, prompts, commands, and hooks")}`);
5284
+ console.log(` ${ICON.skip} ${pc3.dim("companion plugins where your editor supports them")}`);
5285
+ }
5286
+ function printFirstValueHandoff(input) {
5287
+ const cmd = getCmd();
5288
+ console.log("");
5289
+ console.log(pc3.bold("first OrgX handoff"));
5290
+ console.log(
5291
+ ` ${input.initiative.created ? pc3.green("created") : pc3.yellow("ready")} ${pc3.bold(input.initiative.initiative.title)}`
5292
+ );
5293
+ console.log(` live: ${input.initiative.liveUrl}`);
5294
+ console.log(
5295
+ ` ${pc3.dim("ask your AI tool:")} ${pc3.cyan(
5296
+ `Use OrgX to continue "${input.initiative.initiative.title}" in ${input.workspace.name}. Show the next action, then start with the onboarding task.`
5297
+ )}`
5298
+ );
5299
+ console.log(` ${pc3.dim("later:")} ${pc3.cyan(`${cmd} doctor`)} ${pc3.dim("checks tool wiring")}`);
5300
+ }
5301
+ function firstValueRecordToResult(record) {
5302
+ if (!record) {
5303
+ return null;
5304
+ }
5305
+ return {
5306
+ created: false,
5307
+ initiative: {
5308
+ id: record.id,
5309
+ title: record.title,
5310
+ ...record.summary ? { summary: record.summary } : {}
5311
+ },
5312
+ liveUrl: record.liveUrl
5313
+ };
5314
+ }
5184
5315
  function printFounderPresetResult(result) {
5185
5316
  printMutationResults(result.surfaceResults);
5186
5317
  console.log("");
@@ -5221,7 +5352,7 @@ async function textPrompt(input) {
5221
5352
  }
5222
5353
  async function multiselectPrompt(input) {
5223
5354
  const promptInput = {
5224
- message: `${input.message} ${pc3.dim("Space selects items; Enter continues.")}`,
5355
+ message: `${input.message} ${pc3.dim("Space to select, Enter to continue. Defaults are preselected.")}`,
5225
5356
  options: input.options,
5226
5357
  ...input.initialValues ? { initialValues: input.initialValues } : {},
5227
5358
  ...input.required !== void 0 ? { required: input.required } : {}
@@ -5328,25 +5459,96 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
5328
5459
  return "skipped";
5329
5460
  }
5330
5461
  const existingState = readWizardState();
5331
- const effectiveInitiativeId = input.initiativeId?.trim() || (existingState?.demoInitiative?.workspaceId === input.workspace.id ? existingState.demoInitiative.id : void 0);
5332
- const hasOnboardingTask = existingState?.onboardingTask?.workspaceId === input.workspace.id;
5333
- if (!hasOnboardingTask && effectiveInitiativeId) {
5334
- const onboardingChoice = await selectPrompt({
5335
- message: `Create a starter onboarding task for ${input.workspace.name}?`,
5462
+ const providedInitiativeId = input.initiativeId?.trim();
5463
+ const storedDemoInitiative = existingState?.demoInitiative?.workspaceId === input.workspace.id ? existingState.demoInitiative : void 0;
5464
+ const storedFirstValueInitiative = existingState?.firstValueInitiative?.workspaceId === input.workspace.id ? existingState.firstValueInitiative : void 0;
5465
+ let effectiveInitiativeId = providedInitiativeId || storedDemoInitiative?.id || storedFirstValueInitiative?.id;
5466
+ let firstValueInitiative = providedInitiativeId || storedDemoInitiative ? null : firstValueRecordToResult(storedFirstValueInitiative);
5467
+ if (!effectiveInitiativeId) {
5468
+ const firstInitiativeChoice = await selectPrompt({
5469
+ initialValue: "yes",
5470
+ message: `Create your first OrgX initiative in ${input.workspace.name}?`,
5336
5471
  options: [
5337
- { value: "yes", label: "Create onboarding task", hint: "recommended" },
5338
- { value: "no", label: "Skip task creation" }
5472
+ {
5473
+ value: "yes",
5474
+ label: "Create first initiative",
5475
+ hint: "recommended; gives setup a live next step"
5476
+ },
5477
+ { value: "no", label: "Skip initiative creation" }
5339
5478
  ]
5340
5479
  });
5341
- if (clack.isCancel(onboardingChoice)) {
5480
+ if (clack.isCancel(firstInitiativeChoice)) {
5342
5481
  clack.cancel("Setup cancelled.");
5343
5482
  return "cancelled";
5344
5483
  }
5345
- if (onboardingChoice === "yes") {
5484
+ if (firstInitiativeChoice === "yes") {
5485
+ const title = await textPrompt({
5486
+ initialValue: FIRST_VALUE_INITIATIVE_TITLE,
5487
+ message: "What should OrgX help you move forward first?",
5488
+ validate: (value) => {
5489
+ if (!value || value.trim().length === 0) {
5490
+ return "Enter an initiative title.";
5491
+ }
5492
+ return void 0;
5493
+ }
5494
+ });
5495
+ if (clack.isCancel(title)) {
5496
+ clack.cancel("Setup cancelled.");
5497
+ return "cancelled";
5498
+ }
5499
+ const spinner = createOrgxSpinner("Creating your first OrgX initiative and live handoff");
5500
+ spinner.start();
5501
+ try {
5502
+ firstValueInitiative = await ensureFirstValueInitiative(input.workspace, {
5503
+ title: String(title)
5504
+ });
5505
+ spinner.succeed(
5506
+ firstValueInitiative.created ? "First OrgX initiative created" : "First OrgX initiative ready"
5507
+ );
5508
+ effectiveInitiativeId = firstValueInitiative.initiative.id;
5509
+ await safeTrackWizardTelemetry(
5510
+ "first_value_initiative_ready",
5511
+ buildFirstValueInitiativeTelemetryProperties(
5512
+ firstValueInitiative,
5513
+ {
5514
+ command: input.telemetry?.command ?? "setup",
5515
+ ...input.telemetry?.preset ? { preset: input.telemetry.preset } : {}
5516
+ }
5517
+ )
5518
+ );
5519
+ } catch (error) {
5520
+ spinner.fail("First OrgX initiative was not created");
5521
+ const message = error instanceof Error ? error.message : String(error);
5522
+ console.log(` ${ICON.warn} ${pc3.yellow("initiative")} ${pc3.dim(message)}`);
5523
+ }
5524
+ }
5525
+ }
5526
+ const hasOnboardingTask = existingState?.onboardingTask?.workspaceId === input.workspace.id;
5527
+ if (!hasOnboardingTask && effectiveInitiativeId) {
5528
+ let shouldCreateOnboardingTask = firstValueInitiative !== null;
5529
+ if (!shouldCreateOnboardingTask) {
5530
+ const onboardingChoice = await selectPrompt({
5531
+ initialValue: "yes",
5532
+ message: `Create a starter onboarding task for ${input.workspace.name}?`,
5533
+ options: [
5534
+ { value: "yes", label: "Create onboarding task", hint: "recommended" },
5535
+ { value: "no", label: "Skip task creation" }
5536
+ ]
5537
+ });
5538
+ if (clack.isCancel(onboardingChoice)) {
5539
+ clack.cancel("Setup cancelled.");
5540
+ return "cancelled";
5541
+ }
5542
+ shouldCreateOnboardingTask = onboardingChoice === "yes";
5543
+ }
5544
+ if (shouldCreateOnboardingTask) {
5545
+ const spinner = createOrgxSpinner("Creating onboarding workstream and starter task");
5546
+ spinner.start();
5346
5547
  try {
5347
5548
  const task = await ensureOnboardingTask(input.workspace, {
5348
5549
  initiativeId: effectiveInitiativeId
5349
5550
  });
5551
+ spinner.succeed("Onboarding workstream and starter task ready");
5350
5552
  console.log(` ${ICON.ok} ${pc3.green("onboarding")} ${pc3.bold(task.title)}`);
5351
5553
  await safeTrackWizardTelemetry(
5352
5554
  "onboarding_task_created",
@@ -5363,11 +5565,18 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
5363
5565
  )
5364
5566
  );
5365
5567
  } catch (error) {
5568
+ spinner.fail("Onboarding task was not created");
5366
5569
  const message = error instanceof Error ? error.message : String(error);
5367
5570
  console.log(` ${ICON.warn} ${pc3.yellow("onboarding")} ${pc3.dim(message)}`);
5368
5571
  }
5369
5572
  }
5370
5573
  }
5574
+ if (firstValueInitiative) {
5575
+ printFirstValueHandoff({
5576
+ initiative: firstValueInitiative,
5577
+ workspace: input.workspace
5578
+ });
5579
+ }
5371
5580
  const refreshedState = readWizardState();
5372
5581
  const hasAgentRoster = refreshedState?.agentRoster?.workspaceId === input.workspace.id;
5373
5582
  if (!hasAgentRoster) {
@@ -5578,7 +5787,7 @@ function printDoctorReport(report, assessment) {
5578
5787
  async function main() {
5579
5788
  const program = new Command();
5580
5789
  program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
5581
- const pkgVersion = true ? "0.1.12" : void 0;
5790
+ const pkgVersion = true ? "0.1.14" : void 0;
5582
5791
  program.version(pkgVersion ?? "unknown", "-V, --version");
5583
5792
  program.hook("preAction", () => {
5584
5793
  console.log(renderBanner(pkgVersion));
@@ -5590,6 +5799,8 @@ async function main() {
5590
5799
  interactive,
5591
5800
  preset: options.preset ?? "standard"
5592
5801
  });
5802
+ printSetupScopeNote();
5803
+ console.log("");
5593
5804
  if (options.preset) {
5594
5805
  if (options.preset !== "founder") {
5595
5806
  throw new Error(`Unknown setup preset '${options.preset}'. Supported presets: founder.`);