@useorgx/wizard 0.1.23 → 0.1.25

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
@@ -1337,6 +1337,80 @@ function parsePeopleFirstCapture(value) {
1337
1337
  entries
1338
1338
  };
1339
1339
  }
1340
+ function parseDailyBriefOnboardingEntry(value) {
1341
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1342
+ return void 0;
1343
+ }
1344
+ const record = value;
1345
+ const status = record.status;
1346
+ if (!isNonEmptyString2(record.workspaceId) || status !== "completed" && status !== "skipped") {
1347
+ return void 0;
1348
+ }
1349
+ const completedAt = isNonEmptyString2(record.completedAt) ? record.completedAt.trim() : void 0;
1350
+ const skippedAt = isNonEmptyString2(record.skippedAt) ? record.skippedAt.trim() : void 0;
1351
+ if (status === "completed" && !completedAt) return void 0;
1352
+ if (status === "skipped" && !skippedAt) return void 0;
1353
+ return {
1354
+ workspaceId: record.workspaceId.trim(),
1355
+ status,
1356
+ ...completedAt ? { completedAt } : {},
1357
+ ...skippedAt ? { skippedAt } : {},
1358
+ ...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
1359
+ };
1360
+ }
1361
+ function parseDailyBriefOnboarding(value) {
1362
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1363
+ return void 0;
1364
+ }
1365
+ const record = value;
1366
+ if (!isNonEmptyString2(record.updatedAt) || !Array.isArray(record.entries)) {
1367
+ return void 0;
1368
+ }
1369
+ const entries = record.entries.map((entry) => parseDailyBriefOnboardingEntry(entry)).filter(
1370
+ (entry) => Boolean(entry)
1371
+ );
1372
+ if (entries.length === 0) return void 0;
1373
+ return {
1374
+ updatedAt: record.updatedAt.trim(),
1375
+ entries
1376
+ };
1377
+ }
1378
+ function isSetupPromptKey(value) {
1379
+ return value === "first_initiative" || value === "onboarding_task" || value === "agent_roster" || value === "setup_intent";
1380
+ }
1381
+ function parseSetupPromptDecisionEntry(value) {
1382
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1383
+ return void 0;
1384
+ }
1385
+ const record = value;
1386
+ if (!isNonEmptyString2(record.workspaceId) || !isSetupPromptKey(record.promptKey) || record.status !== "skipped" || !isNonEmptyString2(record.skippedAt)) {
1387
+ return void 0;
1388
+ }
1389
+ return {
1390
+ promptKey: record.promptKey,
1391
+ skippedAt: record.skippedAt.trim(),
1392
+ status: "skipped",
1393
+ workspaceId: record.workspaceId.trim(),
1394
+ ...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
1395
+ };
1396
+ }
1397
+ function parseSetupPromptDecisions(value) {
1398
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1399
+ return void 0;
1400
+ }
1401
+ const record = value;
1402
+ if (!isNonEmptyString2(record.updatedAt) || !Array.isArray(record.entries)) {
1403
+ return void 0;
1404
+ }
1405
+ const entries = record.entries.map((entry) => parseSetupPromptDecisionEntry(entry)).filter(
1406
+ (entry) => Boolean(entry)
1407
+ );
1408
+ if (entries.length === 0) return void 0;
1409
+ return {
1410
+ updatedAt: record.updatedAt.trim(),
1411
+ entries
1412
+ };
1413
+ }
1340
1414
  function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
1341
1415
  return {
1342
1416
  installationId: `wizard-${randomUUID()}`,
@@ -1352,6 +1426,8 @@ function sanitizeWizardStateRecord(record) {
1352
1426
  const onboardingTask = parseOnboardingTask(record.onboardingTask);
1353
1427
  const skillFiles = parseSkillFiles(record.skillFiles);
1354
1428
  const peopleFirstCapture = parsePeopleFirstCapture(record.peopleFirstCapture);
1429
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(record.dailyBriefOnboarding);
1430
+ const setupPromptDecisions = parseSetupPromptDecisions(record.setupPromptDecisions);
1355
1431
  return {
1356
1432
  installationId: record.installationId.trim(),
1357
1433
  createdAt: record.createdAt.trim(),
@@ -1362,7 +1438,9 @@ function sanitizeWizardStateRecord(record) {
1362
1438
  ...firstValueInitiative ? { firstValueInitiative } : {},
1363
1439
  ...onboardingTask ? { onboardingTask } : {},
1364
1440
  ...skillFiles ? { skillFiles } : {},
1365
- ...peopleFirstCapture ? { peopleFirstCapture } : {}
1441
+ ...peopleFirstCapture ? { peopleFirstCapture } : {},
1442
+ ...dailyBriefOnboarding ? { dailyBriefOnboarding } : {},
1443
+ ...setupPromptDecisions ? { setupPromptDecisions } : {}
1366
1444
  };
1367
1445
  }
1368
1446
  function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
@@ -1391,8 +1469,70 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1391
1469
  if (skillFiles !== void 0) state.skillFiles = skillFiles;
1392
1470
  const peopleFirstCapture = parsePeopleFirstCapture(parsed.peopleFirstCapture);
1393
1471
  if (peopleFirstCapture !== void 0) state.peopleFirstCapture = peopleFirstCapture;
1472
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(parsed.dailyBriefOnboarding);
1473
+ if (dailyBriefOnboarding !== void 0) {
1474
+ state.dailyBriefOnboarding = dailyBriefOnboarding;
1475
+ }
1476
+ const setupPromptDecisions = parseSetupPromptDecisions(parsed.setupPromptDecisions);
1477
+ if (setupPromptDecisions !== void 0) {
1478
+ state.setupPromptDecisions = setupPromptDecisions;
1479
+ }
1394
1480
  return state;
1395
1481
  }
1482
+ function getDailyBriefOnboardingDecision(workspaceId, statePath = ORGX_WIZARD_STATE_PATH) {
1483
+ const state = readWizardState(statePath);
1484
+ return state?.dailyBriefOnboarding?.entries.find(
1485
+ (entry) => entry.workspaceId === workspaceId
1486
+ ) ?? null;
1487
+ }
1488
+ function recordDailyBriefOnboardingDecision(entry, statePath = ORGX_WIZARD_STATE_PATH) {
1489
+ return updateWizardState((current) => {
1490
+ const existingEntries = current.dailyBriefOnboarding?.entries ?? [];
1491
+ const withoutExisting = existingEntries.filter(
1492
+ (e) => e.workspaceId !== entry.workspaceId
1493
+ );
1494
+ return {
1495
+ ...current,
1496
+ dailyBriefOnboarding: {
1497
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1498
+ entries: [...withoutExisting, entry]
1499
+ }
1500
+ };
1501
+ }, statePath);
1502
+ }
1503
+ function getSetupPromptDecision(workspaceId, promptKey, statePath = ORGX_WIZARD_STATE_PATH) {
1504
+ const state = readWizardState(statePath);
1505
+ return state?.setupPromptDecisions?.entries.find(
1506
+ (entry) => entry.workspaceId === workspaceId && entry.promptKey === promptKey
1507
+ ) ?? null;
1508
+ }
1509
+ function hasSetupPromptSkip(workspaceId, promptKey, statePath = ORGX_WIZARD_STATE_PATH) {
1510
+ return getSetupPromptDecision(workspaceId, promptKey, statePath) !== null;
1511
+ }
1512
+ function recordSetupPromptSkip(entry, statePath = ORGX_WIZARD_STATE_PATH) {
1513
+ return updateWizardState((current) => {
1514
+ const existingEntries = current.setupPromptDecisions?.entries ?? [];
1515
+ const withoutExisting = existingEntries.filter(
1516
+ (existing) => !(existing.workspaceId === entry.workspaceId && existing.promptKey === entry.promptKey)
1517
+ );
1518
+ return {
1519
+ ...current,
1520
+ setupPromptDecisions: {
1521
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1522
+ entries: [
1523
+ ...withoutExisting,
1524
+ {
1525
+ promptKey: entry.promptKey,
1526
+ skippedAt: entry.skippedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1527
+ status: "skipped",
1528
+ workspaceId: entry.workspaceId,
1529
+ ...entry.workspaceName ? { workspaceName: entry.workspaceName } : {}
1530
+ }
1531
+ ]
1532
+ }
1533
+ };
1534
+ }, statePath);
1535
+ }
1396
1536
  function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
1397
1537
  const record = sanitizeWizardStateRecord(value);
1398
1538
  writeJsonFile(statePath, record, { mode: 384 });
@@ -5104,6 +5244,14 @@ async function runWorkspaceSetup(client, prompts, options) {
5104
5244
  }
5105
5245
  return createAndSelectWorkspace(client, prompts);
5106
5246
  }
5247
+ if (options.skipIfConfigured && currentWorkspace) {
5248
+ return {
5249
+ defaultChanged: false,
5250
+ message: `Using "${currentWorkspace.name}" as the default OrgX workspace.`,
5251
+ status: "unchanged",
5252
+ workspace: currentWorkspace
5253
+ };
5254
+ }
5107
5255
  const initialWorkspaceId = currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id ?? workspaces[0]?.id;
5108
5256
  const selected = await prompts.select({
5109
5257
  message: "Choose the OrgX workspace this machine should use by default.",
@@ -5744,20 +5892,73 @@ var BASELINE_PROMPTS = [
5744
5892
  { task_type: "launch_post", label: "Launch post", placeholder: "60" },
5745
5893
  { task_type: "architecture_doc", label: "Architecture doc", placeholder: "90" }
5746
5894
  ];
5895
+ var DAILY_BRIEF_SETUP_CHOICES = {
5896
+ defaults: "defaults",
5897
+ customize: "customize",
5898
+ skip: "skip"
5899
+ };
5900
+ function buildDefaultBaselines() {
5901
+ return BASELINE_PROMPTS.map((bp) => ({
5902
+ task_type: bp.task_type,
5903
+ minutes: Number.parseInt(bp.placeholder, 10),
5904
+ confidence: 0.4
5905
+ }));
5906
+ }
5907
+ function buildDefaultGoals() {
5908
+ return [
5909
+ {
5910
+ goal_type: "time_saved_weekly",
5911
+ target_value: 180,
5912
+ unit: "minutes",
5913
+ period: "weekly"
5914
+ }
5915
+ ];
5916
+ }
5917
+ function normalizeSendTime(value) {
5918
+ return value.trim().length === 4 ? `0${value.trim()}` : value.trim();
5919
+ }
5920
+ function recordSkipped(workspace, statePath) {
5921
+ recordDailyBriefOnboardingDecision(
5922
+ {
5923
+ workspaceId: workspace.id,
5924
+ workspaceName: workspace.name,
5925
+ status: "skipped",
5926
+ skippedAt: (/* @__PURE__ */ new Date()).toISOString()
5927
+ },
5928
+ statePath
5929
+ );
5930
+ return {
5931
+ status: "skipped_user",
5932
+ message: "Daily Brief setup skipped. Run `wizard setup --daily-brief` when ready."
5933
+ };
5934
+ }
5747
5935
  async function runDailyBriefOnboarding(options) {
5748
- if (!options.interactive) {
5749
- return {
5750
- status: "skipped_non_interactive",
5751
- message: "Daily Brief onboarding skipped \u2014 not attached to a TTY."
5752
- };
5753
- }
5754
5936
  if (!options.workspace) {
5755
5937
  return {
5756
5938
  status: "skipped_no_workspace",
5757
5939
  message: "Daily Brief onboarding skipped \u2014 no workspace resolved."
5758
5940
  };
5759
5941
  }
5760
- const auth = await resolveOrgxAuth();
5942
+ if (options.skip) {
5943
+ return recordSkipped(options.workspace, options.statePath);
5944
+ }
5945
+ const localDecision = getDailyBriefOnboardingDecision(
5946
+ options.workspace.id,
5947
+ options.statePath
5948
+ );
5949
+ if (!options.force && localDecision) {
5950
+ return {
5951
+ status: "skipped_already_completed",
5952
+ message: localDecision.status === "completed" ? "Daily Brief onboarding already completed for this workspace." : "Daily Brief setup was skipped for this workspace. Run `wizard setup --daily-brief` to configure."
5953
+ };
5954
+ }
5955
+ if (!options.interactive) {
5956
+ return {
5957
+ status: "skipped_non_interactive",
5958
+ message: "Daily Brief onboarding skipped \u2014 not attached to a TTY."
5959
+ };
5960
+ }
5961
+ const auth = await resolveOrgxAuth(options.authOptions);
5761
5962
  if (!auth) {
5762
5963
  return {
5763
5964
  status: "failed",
@@ -5769,6 +5970,15 @@ async function runDailyBriefOnboarding(options) {
5769
5970
  if (state) {
5770
5971
  const row = state.workspaces.find((w) => w.id === options.workspace.id);
5771
5972
  if (row?.onboardingCompletedAt) {
5973
+ recordDailyBriefOnboardingDecision(
5974
+ {
5975
+ workspaceId: options.workspace.id,
5976
+ workspaceName: options.workspace.name,
5977
+ status: "completed",
5978
+ completedAt: row.onboardingCompletedAt
5979
+ },
5980
+ options.statePath
5981
+ );
5772
5982
  return {
5773
5983
  status: "skipped_already_completed",
5774
5984
  message: "Daily Brief onboarding already completed for this workspace."
@@ -5776,93 +5986,116 @@ async function runDailyBriefOnboarding(options) {
5776
5986
  }
5777
5987
  }
5778
5988
  const { prompts } = options;
5779
- const proceed = await prompts.confirm({
5780
- message: "Set up your Daily Brief? (captures baselines so tomorrow's brief can show real time-saved numbers)",
5781
- initialValue: true
5989
+ const setupChoice = await prompts.select({
5990
+ message: "Set up Daily Brief now?",
5991
+ initialValue: DAILY_BRIEF_SETUP_CHOICES.defaults,
5992
+ options: [
5993
+ {
5994
+ value: DAILY_BRIEF_SETUP_CHOICES.defaults,
5995
+ label: "Use defaults",
5996
+ hint: "20m code review, 45m PRD, 07:00 daily."
5997
+ },
5998
+ {
5999
+ value: DAILY_BRIEF_SETUP_CHOICES.customize,
6000
+ label: "Customize baselines",
6001
+ hint: "Answer baseline and delivery questions."
6002
+ },
6003
+ {
6004
+ value: DAILY_BRIEF_SETUP_CHOICES.skip,
6005
+ label: "Skip and remember",
6006
+ hint: "Do not ask again unless you pass --daily-brief."
6007
+ }
6008
+ ]
5782
6009
  });
5783
- if (prompts.isCancel(proceed)) {
6010
+ if (prompts.isCancel(setupChoice)) {
5784
6011
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5785
6012
  }
5786
- if (!proceed) {
5787
- return {
5788
- status: "cancelled",
5789
- message: "Skipped \u2014 run `wizard brief setup` later to configure."
5790
- };
6013
+ if (setupChoice === DAILY_BRIEF_SETUP_CHOICES.skip) {
6014
+ return recordSkipped(options.workspace, options.statePath);
6015
+ }
6016
+ const shouldCustomize = setupChoice === DAILY_BRIEF_SETUP_CHOICES.customize;
6017
+ const baselines = shouldCustomize ? [] : buildDefaultBaselines();
6018
+ if (shouldCustomize) {
6019
+ for (const bp of BASELINE_PROMPTS) {
6020
+ const answer = await prompts.text({
6021
+ message: `${bp.label} minutes`,
6022
+ placeholder: bp.placeholder,
6023
+ validate(value) {
6024
+ if (!value || value.trim() === "") return void 0;
6025
+ const n = Number.parseInt(value, 10);
6026
+ if (!Number.isFinite(n) || n <= 0 || n > 24 * 60) {
6027
+ return "Enter 1-1440 or leave blank.";
6028
+ }
6029
+ return void 0;
6030
+ }
6031
+ });
6032
+ if (prompts.isCancel(answer)) {
6033
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
6034
+ }
6035
+ if (typeof answer === "string" && answer.trim() !== "") {
6036
+ const minutes = Number.parseInt(answer, 10);
6037
+ if (Number.isFinite(minutes) && minutes > 0) {
6038
+ baselines.push({ task_type: bp.task_type, minutes, confidence: 0.5 });
6039
+ }
6040
+ }
6041
+ }
5791
6042
  }
5792
- const baselines = [];
5793
- for (const bp of BASELINE_PROMPTS) {
5794
- const answer = await prompts.text({
5795
- message: `How long does ${bp.label.toLowerCase()} usually take? (minutes, blank to skip)`,
5796
- placeholder: bp.placeholder,
6043
+ const goals = shouldCustomize ? [] : buildDefaultGoals();
6044
+ if (shouldCustomize) {
6045
+ const goalAnswer = await prompts.text({
6046
+ message: "Weekly time-saved target minutes",
6047
+ placeholder: "180",
5797
6048
  validate(value) {
5798
6049
  if (!value || value.trim() === "") return void 0;
5799
6050
  const n = Number.parseInt(value, 10);
5800
- if (!Number.isFinite(n) || n <= 0 || n > 24 * 60) {
5801
- return "Enter 1 \u2013 1440 or leave blank.";
6051
+ if (!Number.isFinite(n) || n <= 0) {
6052
+ return "Enter a positive number or leave blank.";
5802
6053
  }
5803
6054
  return void 0;
5804
6055
  }
5805
6056
  });
5806
- if (prompts.isCancel(answer)) {
6057
+ if (prompts.isCancel(goalAnswer)) {
5807
6058
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5808
6059
  }
5809
- if (typeof answer === "string" && answer.trim() !== "") {
5810
- const minutes = Number.parseInt(answer, 10);
5811
- if (Number.isFinite(minutes) && minutes > 0) {
5812
- baselines.push({ task_type: bp.task_type, minutes, confidence: 0.5 });
6060
+ if (typeof goalAnswer === "string" && goalAnswer.trim() !== "") {
6061
+ const target = Number.parseInt(goalAnswer, 10);
6062
+ if (Number.isFinite(target) && target > 0) {
6063
+ goals.push({
6064
+ goal_type: "time_saved_weekly",
6065
+ target_value: target,
6066
+ unit: "minutes",
6067
+ period: "weekly"
6068
+ });
5813
6069
  }
5814
6070
  }
5815
6071
  }
5816
- const goals = [];
5817
- const goalAnswer = await prompts.text({
5818
- message: "Weekly time saved target (minutes, blank to skip)",
5819
- placeholder: "180",
5820
- validate(value) {
5821
- if (!value || value.trim() === "") return void 0;
5822
- const n = Number.parseInt(value, 10);
5823
- if (!Number.isFinite(n) || n <= 0) {
5824
- return "Enter a positive number or leave blank.";
6072
+ let sendTimeLocal = "07:00";
6073
+ let onlyOnAttention = false;
6074
+ if (shouldCustomize) {
6075
+ const sendTimeAnswer = await prompts.text({
6076
+ message: "Daily brief time (HH:MM)",
6077
+ placeholder: "07:00",
6078
+ validate(value) {
6079
+ if (!value || value.trim() === "") return void 0;
6080
+ if (!/^\d{1,2}:\d{2}$/.test(value.trim())) {
6081
+ return "Use HH:MM (24h).";
6082
+ }
6083
+ return void 0;
5825
6084
  }
5826
- return void 0;
5827
- }
5828
- });
5829
- if (prompts.isCancel(goalAnswer)) {
5830
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5831
- }
5832
- if (typeof goalAnswer === "string" && goalAnswer.trim() !== "") {
5833
- const target = Number.parseInt(goalAnswer, 10);
5834
- if (Number.isFinite(target) && target > 0) {
5835
- goals.push({
5836
- goal_type: "time_saved_weekly",
5837
- target_value: target,
5838
- unit: "minutes",
5839
- period: "weekly"
5840
- });
6085
+ });
6086
+ if (prompts.isCancel(sendTimeAnswer)) {
6087
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5841
6088
  }
5842
- }
5843
- const sendTimeAnswer = await prompts.text({
5844
- message: "When should your daily brief arrive? (HH:MM local, default 07:00)",
5845
- placeholder: "07:00",
5846
- validate(value) {
5847
- if (!value || value.trim() === "") return void 0;
5848
- if (!/^\d{1,2}:\d{2}$/.test(value.trim())) {
5849
- return "Use HH:MM (24h).";
5850
- }
5851
- return void 0;
6089
+ sendTimeLocal = typeof sendTimeAnswer === "string" && sendTimeAnswer.trim() ? normalizeSendTime(sendTimeAnswer) : "07:00";
6090
+ const onlyOnAttentionAnswer = await prompts.confirm({
6091
+ message: "Email only when attention is needed?",
6092
+ initialValue: false
6093
+ });
6094
+ if (prompts.isCancel(onlyOnAttentionAnswer)) {
6095
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5852
6096
  }
5853
- });
5854
- if (prompts.isCancel(sendTimeAnswer)) {
5855
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5856
- }
5857
- const sendTimeLocal = typeof sendTimeAnswer === "string" && sendTimeAnswer.trim() ? sendTimeAnswer.trim().length === 4 ? `0${sendTimeAnswer.trim()}` : sendTimeAnswer.trim() : "07:00";
5858
- const onlyOnAttentionAnswer = await prompts.confirm({
5859
- message: "Only email when something needs your attention?",
5860
- initialValue: false
5861
- });
5862
- if (prompts.isCancel(onlyOnAttentionAnswer)) {
5863
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
6097
+ onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5864
6098
  }
5865
- const onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5866
6099
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
5867
6100
  const commitPayload = {
5868
6101
  workspace_id: options.workspace.id,
@@ -5904,6 +6137,15 @@ async function runDailyBriefOnboarding(options) {
5904
6137
  }
5905
6138
  const commitBody = await commitResponse.json().catch(() => ({}));
5906
6139
  const previewUrl = typeof commitBody.daily_brief_preview_url === "string" ? commitBody.daily_brief_preview_url : "/today?mode=preview";
6140
+ recordDailyBriefOnboardingDecision(
6141
+ {
6142
+ workspaceId: options.workspace.id,
6143
+ workspaceName: options.workspace.name,
6144
+ status: "completed",
6145
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
6146
+ },
6147
+ options.statePath
6148
+ );
5907
6149
  return {
5908
6150
  status: "completed",
5909
6151
  message: "Your Daily Brief is configured. First brief lands tomorrow.",
@@ -7224,6 +7466,9 @@ async function maybeCaptureSetupIntent(input) {
7224
7466
  if (!input.interactive || !input.workspace) {
7225
7467
  return "skipped";
7226
7468
  }
7469
+ if (hasSetupPromptSkip(input.workspace.id, "setup_intent")) {
7470
+ return "skipped";
7471
+ }
7227
7472
  const prompt = await textPrompt({
7228
7473
  message: "In one line, what do you want OrgX to move first? (blank to skip \u2014 you can start from the dashboard)",
7229
7474
  placeholder: "e.g. open a warm-intro loop to 50 design-led SaaS founders",
@@ -7239,6 +7484,11 @@ async function maybeCaptureSetupIntent(input) {
7239
7484
  }
7240
7485
  const intentText = typeof prompt === "string" ? prompt.trim() : "";
7241
7486
  if (!intentText) {
7487
+ recordSetupPromptSkip({
7488
+ promptKey: "setup_intent",
7489
+ workspaceId: input.workspace.id,
7490
+ workspaceName: input.workspace.name
7491
+ });
7242
7492
  return "skipped";
7243
7493
  }
7244
7494
  const spinner = createOrgxSpinner("Routing");
@@ -7473,7 +7723,11 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7473
7723
  const storedFirstValueInitiative = existingState?.firstValueInitiative?.workspaceId === input.workspace.id ? existingState.firstValueInitiative : void 0;
7474
7724
  let effectiveInitiativeId = providedInitiativeId || storedDemoInitiative?.id || storedFirstValueInitiative?.id;
7475
7725
  let firstValueInitiative = providedInitiativeId || storedDemoInitiative ? null : firstValueRecordToResult(storedFirstValueInitiative);
7476
- if (!effectiveInitiativeId) {
7726
+ const firstInitiativeSkipped = hasSetupPromptSkip(
7727
+ input.workspace.id,
7728
+ "first_initiative"
7729
+ );
7730
+ if (!effectiveInitiativeId && !firstInitiativeSkipped) {
7477
7731
  const firstInitiativeChoice = await selectPrompt({
7478
7732
  initialValue: "yes",
7479
7733
  message: `Create your first OrgX initiative in ${input.workspace.name}?`,
@@ -7530,10 +7784,20 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7530
7784
  const message = error instanceof Error ? error.message : String(error);
7531
7785
  console.log(` ${ICON.warn} ${pc3.yellow("initiative")} ${pc3.dim(message)}`);
7532
7786
  }
7787
+ } else if (firstInitiativeChoice === "no") {
7788
+ recordSetupPromptSkip({
7789
+ promptKey: "first_initiative",
7790
+ workspaceId: input.workspace.id,
7791
+ workspaceName: input.workspace.name
7792
+ });
7533
7793
  }
7534
7794
  }
7535
7795
  const hasOnboardingTask = existingState?.onboardingTask?.workspaceId === input.workspace.id;
7536
- if (!hasOnboardingTask && effectiveInitiativeId) {
7796
+ const onboardingTaskSkipped = hasSetupPromptSkip(
7797
+ input.workspace.id,
7798
+ "onboarding_task"
7799
+ );
7800
+ if (!hasOnboardingTask && effectiveInitiativeId && !onboardingTaskSkipped) {
7537
7801
  let shouldCreateOnboardingTask = firstValueInitiative !== null;
7538
7802
  if (!shouldCreateOnboardingTask) {
7539
7803
  const onboardingChoice = await selectPrompt({
@@ -7549,6 +7813,13 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7549
7813
  return "cancelled";
7550
7814
  }
7551
7815
  shouldCreateOnboardingTask = onboardingChoice === "yes";
7816
+ if (onboardingChoice === "no") {
7817
+ recordSetupPromptSkip({
7818
+ promptKey: "onboarding_task",
7819
+ workspaceId: input.workspace.id,
7820
+ workspaceName: input.workspace.name
7821
+ });
7822
+ }
7552
7823
  }
7553
7824
  if (shouldCreateOnboardingTask) {
7554
7825
  const spinner = createOrgxSpinner("Creating onboarding workstream and starter task");
@@ -7588,7 +7859,8 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7588
7859
  }
7589
7860
  const refreshedState = readWizardState();
7590
7861
  const hasAgentRoster = refreshedState?.agentRoster?.workspaceId === input.workspace.id;
7591
- if (!hasAgentRoster) {
7862
+ const agentRosterSkipped = hasSetupPromptSkip(input.workspace.id, "agent_roster");
7863
+ if (!hasAgentRoster && !agentRosterSkipped) {
7592
7864
  const rosterChoice = await selectPrompt({
7593
7865
  initialValue: "default",
7594
7866
  message: `Set up an OrgX agent roster for ${input.workspace.name}?`,
@@ -7624,6 +7896,11 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7624
7896
  );
7625
7897
  } else {
7626
7898
  console.log(` ${ICON.skip} ${pc3.dim("agent roster skipped")} ${pc3.dim("(no agents selected)")}`);
7899
+ recordSetupPromptSkip({
7900
+ promptKey: "agent_roster",
7901
+ workspaceId: input.workspace.id,
7902
+ workspaceName: input.workspace.name
7903
+ });
7627
7904
  }
7628
7905
  } else if (rosterChoice === "default") {
7629
7906
  const roster = ensureDefaultAgentRoster(input.workspace);
@@ -7641,6 +7918,12 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
7641
7918
  }
7642
7919
  )
7643
7920
  );
7921
+ } else if (rosterChoice === "no") {
7922
+ recordSetupPromptSkip({
7923
+ promptKey: "agent_roster",
7924
+ workspaceId: input.workspace.id,
7925
+ workspaceName: input.workspace.name
7926
+ });
7644
7927
  }
7645
7928
  }
7646
7929
  return "configured";
@@ -7720,11 +8003,11 @@ async function maybeInstallOptionalCompanionPlugins(input) {
7720
8003
  }
7721
8004
  function printAuthStatus(status) {
7722
8005
  if (!status.configured) {
7723
- console.log(` ${ICON.warn} ${pc3.yellow("no account")} run ${pc3.cyan(`${getCmd()} auth login`)} to connect`);
8006
+ console.log(` ${ICON.warn} ${pc3.yellow("not paired")} run ${pc3.cyan(`${getCmd()} auth login`)} to pair this terminal`);
7724
8007
  return;
7725
8008
  }
7726
8009
  const icon = status.ok ? ICON.ok : ICON.err;
7727
- const state = status.ok ? pc3.green("verified ") : status.skipped ? pc3.yellow("skipped ") : pc3.red("invalid ");
8010
+ const state = status.ok ? pc3.green("paired ") : status.skipped ? pc3.yellow("skipped ") : pc3.red("invalid ");
7728
8011
  const via = pc3.dim(formatAuthSource(status.source));
7729
8012
  console.log(` ${icon} ${state} ${pc3.bold(status.keyPrefix ?? "unknown")} ${via}`);
7730
8013
  if (!status.ok && status.error) {
@@ -7796,13 +8079,16 @@ function printDoctorReport(report, assessment) {
7796
8079
  async function main() {
7797
8080
  const program = new Command();
7798
8081
  program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
7799
- const pkgVersion = true ? "0.1.23" : void 0;
8082
+ const pkgVersion = true ? "0.1.25" : void 0;
7800
8083
  program.version(pkgVersion ?? "unknown", "-V, --version");
7801
8084
  program.hook("preAction", () => {
7802
8085
  console.log(renderBanner(pkgVersion));
7803
8086
  });
7804
- program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").action(async (options) => {
8087
+ 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) => {
7805
8088
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
8089
+ if (options.dailyBrief && options.skipDailyBrief) {
8090
+ throw new Error("Use either --daily-brief or --skip-daily-brief, not both.");
8091
+ }
7806
8092
  await safeTrackWizardTelemetry("wizard_started", {
7807
8093
  command: "setup",
7808
8094
  interactive,
@@ -7921,9 +8207,9 @@ async function main() {
7921
8207
  console.log("");
7922
8208
  if (interactive) {
7923
8209
  const choice = await selectPrompt({
7924
- message: "Connect your OrgX account to enable workspace and AI tool access",
8210
+ message: "Pair this terminal with your OrgX account to finish setup",
7925
8211
  options: [
7926
- { value: "login", label: "Open browser to connect", hint: "recommended" },
8212
+ { value: "login", label: "Open browser to pair", hint: "recommended" },
7927
8213
  { value: "skip", label: "Skip for now", hint: `run \`${getCmd()} auth login\` later` }
7928
8214
  ]
7929
8215
  });
@@ -7935,19 +8221,19 @@ async function main() {
7935
8221
  const loginOk = await runBrowserLogin({ telemetrySource: "browser_pairing" });
7936
8222
  if (!loginOk) {
7937
8223
  console.log(`
7938
- ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} auth login`)} ${pc3.dim("to try again")}`);
8224
+ ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} auth login`)} ${pc3.dim("to start a fresh browser pairing")}`);
7939
8225
  console.log(` ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} auth login --api-key`)} ${pc3.dim("to paste a key directly")}`);
7940
8226
  return;
7941
8227
  }
7942
8228
  resolvedAuth = await resolveOrgxAuth();
7943
8229
  } else {
7944
8230
  console.log(`
7945
- ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} auth login`)} ${pc3.dim("to connect when ready")}`);
8231
+ ${pc3.dim("\u2192")} ${pc3.cyan(`${getCmd()} auth login`)} ${pc3.dim("to pair when ready")}`);
7946
8232
  return;
7947
8233
  }
7948
8234
  } else {
7949
8235
  console.log(
7950
- ` ${ICON.warn} ${pc3.yellow("No account connected.")} Run ${pc3.cyan(`${getCmd()} auth login`)} to connect.`
8236
+ ` ${ICON.warn} ${pc3.yellow("Terminal not paired.")} Run ${pc3.cyan(`${getCmd()} auth login`)} to pair it.`
7951
8237
  );
7952
8238
  return;
7953
8239
  }
@@ -7968,7 +8254,8 @@ async function main() {
7968
8254
  text: textPrompt
7969
8255
  },
7970
8256
  {
7971
- interactive
8257
+ interactive,
8258
+ skipIfConfigured: !options.workspace
7972
8259
  }
7973
8260
  );
7974
8261
  if (workspaceSetup.status === "cancelled") {
@@ -8006,7 +8293,9 @@ async function main() {
8006
8293
  console.log(` ${ICON.ok} ${pc3.green("workspace ")} ${pc3.bold(workspaceSetup.workspace.name)}`);
8007
8294
  }
8008
8295
  const briefResult = await runDailyBriefOnboarding({
8296
+ force: Boolean(options.dailyBrief),
8009
8297
  interactive,
8298
+ skip: Boolean(options.skipDailyBrief),
8010
8299
  workspace: resolvedWorkspace,
8011
8300
  prompts: {
8012
8301
  cancel: clack.cancel,
@@ -8018,6 +8307,8 @@ async function main() {
8018
8307
  });
8019
8308
  if (briefResult.status === "cancelled") {
8020
8309
  console.log(` ${ICON.skip} ${pc3.dim(briefResult.message)}`);
8310
+ } else if (briefResult.status === "skipped_user") {
8311
+ console.log(` ${ICON.skip} ${pc3.dim(briefResult.message)}`);
8021
8312
  } else if (briefResult.status === "completed") {
8022
8313
  console.log(` ${ICON.ok} ${pc3.green("daily brief")} ${pc3.dim(briefResult.message)}`);
8023
8314
  } else if (briefResult.status === "failed") {
@@ -8122,9 +8413,9 @@ async function main() {
8122
8413
  has_base_url: false
8123
8414
  });
8124
8415
  const openclawResults = detectSurface("openclaw").detected ? await addSurface("openclaw") : [];
8125
- spinner.succeed("OrgX account connected");
8416
+ spinner.succeed("OrgX account paired");
8126
8417
  await syncContinuityAfterAuth();
8127
- console.log(` ${ICON.ok} ${pc3.green("verified ")} ${pc3.bold(stored.keyPrefix)} ${pc3.dim("OAuth / PKCE")}`);
8418
+ console.log(` ${ICON.ok} ${pc3.green("paired ")} ${pc3.bold(stored.keyPrefix)} ${pc3.dim("browser sign-in")}`);
8128
8419
  if (openclawResults.length > 0) {
8129
8420
  console.log("");
8130
8421
  printMutationResults(openclawResults);
@@ -8137,22 +8428,36 @@ async function main() {
8137
8428
  return false;
8138
8429
  }
8139
8430
  }
8431
+ function shortPairingId(pairingId) {
8432
+ return pairingId.length > 13 ? `${pairingId.slice(0, 8)}...${pairingId.slice(-4)}` : pairingId;
8433
+ }
8434
+ function formatPairingExpiry(expiresAt) {
8435
+ const remainingMs = Date.parse(expiresAt) - Date.now();
8436
+ if (!Number.isFinite(remainingMs) || remainingMs <= 0) return "expired";
8437
+ const minutes = Math.ceil(remainingMs / 6e4);
8438
+ return minutes <= 1 ? "<1m" : `${minutes}m`;
8439
+ }
8140
8440
  async function runBrowserLogin(opts = {}) {
8141
8441
  const installationId = getOrCreateWizardInstallationId();
8442
+ const deviceName = opts.deviceName ?? hostname();
8142
8443
  const spinner = createOrgxSpinner("Starting OrgX browser pairing");
8143
8444
  spinner.start();
8144
8445
  try {
8145
8446
  const pairing = await startBrowserPairing({
8146
8447
  installationId,
8147
8448
  baseUrl: opts.baseUrl,
8148
- deviceName: opts.deviceName ?? hostname(),
8449
+ deviceName,
8149
8450
  platform: process.platform
8150
8451
  });
8151
- spinner.succeed("Browser pairing session opened");
8452
+ spinner.succeed("Browser pairing ready");
8152
8453
  console.log(`
8153
- ${pc3.dim("Open this URL to connect:")}`);
8454
+ ${pc3.dim("Open this URL to approve terminal pairing:")}`);
8154
8455
  console.log(` ${pc3.cyan(pairing.connectUrl)}
8155
8456
  `);
8457
+ console.log(
8458
+ ` ${pc3.dim("session ")} ${pc3.bold(shortPairingId(pairing.pairingId))} ${pc3.dim("device")} ${pc3.bold(deviceName)} ${pc3.dim("expires")} ${pc3.bold(formatPairingExpiry(pairing.expiresAt))}
8459
+ `
8460
+ );
8156
8461
  if (opts.open !== false) {
8157
8462
  const openResult = openBrowser(pairing.connectUrl);
8158
8463
  if (!openResult.ok && openResult.error) {
@@ -8168,33 +8473,38 @@ async function main() {
8168
8473
  pollToken: pairing.pollToken,
8169
8474
  timeoutMs: (opts.timeout ?? 600) * 1e3
8170
8475
  });
8171
- spinner.text = "Verifying API key...";
8476
+ spinner.text = "Verifying paired account...";
8172
8477
  const result = await verifyAndPersistAuth(ready.key, {
8173
8478
  ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {},
8174
8479
  ...opts.telemetrySource ? { telemetrySource: opts.telemetrySource } : {}
8175
8480
  });
8176
8481
  if (!("stored" in result)) {
8177
- spinner.fail("Pairing completed but key was rejected");
8482
+ spinner.fail("Pairing completed but OrgX rejected the key");
8178
8483
  console.log(` ${pc3.red(result.verification.error ?? `HTTP ${result.verification.status ?? "error"}`)}`);
8179
8484
  console.log(` ${pc3.dim("The browser flow finished, but OrgX rejected the key. Try again or check your account at useorgx.com.")}`);
8180
8485
  return false;
8181
8486
  }
8182
- await acknowledgeBrowserPairing({
8183
- baseUrl: opts.baseUrl,
8184
- pairingId: pairing.pairingId,
8185
- pollToken: pairing.pollToken
8186
- }).catch((error) => {
8487
+ let ackConfirmed = false;
8488
+ try {
8489
+ await acknowledgeBrowserPairing({
8490
+ baseUrl: opts.baseUrl,
8491
+ pairingId: pairing.pairingId,
8492
+ pollToken: pairing.pollToken
8493
+ });
8494
+ ackConfirmed = true;
8495
+ } catch (error) {
8187
8496
  console.log(pc3.dim(`Pairing ack failed: ${error instanceof Error ? error.message : String(error)}`));
8188
- });
8189
- spinner.succeed("OrgX account connected");
8497
+ }
8498
+ spinner.succeed("OrgX account paired");
8190
8499
  await syncContinuityAfterAuth({
8191
8500
  executionMode: ready.executionMode,
8192
8501
  workspaceName: ready.workspaceName
8193
8502
  });
8194
- console.log(` ${ICON.ok} ${pc3.green("verified ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8503
+ console.log(` ${ICON.ok} ${pc3.green("paired ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8195
8504
  if (ready.workspaceName) {
8196
8505
  console.log(` ${ICON.ok} ${pc3.green("workspace ")} ${pc3.bold(ready.workspaceName)}`);
8197
8506
  }
8507
+ console.log(` ${ackConfirmed ? ICON.ok : ICON.warn} ${ackConfirmed ? pc3.green("ack ") : pc3.yellow("ack ")} ${pc3.bold(ackConfirmed ? "terminal confirmed" : "browser delivery pending")} ${pc3.dim(shortPairingId(pairing.pairingId))}`);
8198
8508
  if (result.openclawResults.length > 0) {
8199
8509
  console.log("");
8200
8510
  printMutationResults(result.openclawResults);
@@ -8207,8 +8517,8 @@ async function main() {
8207
8517
  return false;
8208
8518
  }
8209
8519
  }
8210
- const auth = program.command("auth").description("Manage OrgX API key auth for the wizard.");
8211
- auth.command("status").description("Show the resolved OrgX API key source and verify it against OrgX.").action(async () => {
8520
+ const auth = program.command("auth").description("Pair this terminal with an OrgX account.");
8521
+ auth.command("status").description("Show which OrgX account this terminal is paired with.").action(async () => {
8212
8522
  const spinner = createOrgxSpinner("Checking OrgX auth");
8213
8523
  spinner.start();
8214
8524
  const status = await checkOrgxAuth();
@@ -8216,7 +8526,7 @@ async function main() {
8216
8526
  console.log(pc3.dim(" account"));
8217
8527
  printAuthStatus(status);
8218
8528
  });
8219
- auth.command("login").description("Authenticate with OrgX. Uses OAuth PKCE (no OpenClaw required) by default, with OpenClaw pairing and direct key fallbacks.").option("--api-key <key>", "Bypass browser auth and verify this OrgX API key directly.").option("--base-url <url>", "OrgX base URL (for OpenClaw pairing fallback).").option("--device-name <name>", "Device name shown during OpenClaw pairing.").option("--no-open", "Do not automatically open the browser auth URL.").option("--pairing", "Force OpenClaw pairing flow instead of OAuth PKCE.").option("--timeout <seconds>", "How long to wait for browser auth before giving up.", parseTimeoutSeconds, 600).action(async (options) => {
8529
+ auth.command("login").description("Open the browser pairing flow and store a scoped OrgX key for this terminal.").option("--api-key <key>", "Bypass browser auth and verify this OrgX API key directly.").option("--base-url <url>", "OrgX base URL (for OpenClaw pairing fallback).").option("--device-name <name>", "Device name shown during OpenClaw pairing.").option("--no-open", "Do not automatically open the browser auth URL.").option("--pairing", "Force the terminal pairing fallback instead of browser sign-in.").option("--timeout <seconds>", "How long to wait for browser auth before giving up.", parseTimeoutSeconds, 600).action(async (options) => {
8220
8530
  if (options.apiKey) {
8221
8531
  const spinner = createOrgxSpinner("Verifying OrgX API key");
8222
8532
  spinner.start();
@@ -8229,9 +8539,9 @@ async function main() {
8229
8539
  printAuthStatus(result.verification);
8230
8540
  return;
8231
8541
  }
8232
- spinner.succeed("OrgX account connected");
8542
+ spinner.succeed("OrgX account paired");
8233
8543
  await syncContinuityAfterAuth();
8234
- console.log(` ${ICON.ok} ${pc3.green("verified ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8544
+ console.log(` ${ICON.ok} ${pc3.green("paired ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8235
8545
  if (result.openclawResults.length > 0) {
8236
8546
  console.log("");
8237
8547
  printMutationResults(result.openclawResults);
@@ -8254,7 +8564,7 @@ async function main() {
8254
8564
  timeout: options.timeout
8255
8565
  });
8256
8566
  if (!pkceOk) {
8257
- console.log(pc3.dim("\n Falling back to OpenClaw pairing..."));
8567
+ console.log(pc3.dim("\n Browser sign-in did not finish. Opening the terminal pairing fallback..."));
8258
8568
  await runBrowserLogin({
8259
8569
  ...options.baseUrl !== void 0 ? { baseUrl: options.baseUrl } : {},
8260
8570
  ...options.deviceName !== void 0 ? { deviceName: options.deviceName } : {},
@@ -8276,9 +8586,9 @@ async function main() {
8276
8586
  printAuthStatus(result.verification);
8277
8587
  return;
8278
8588
  }
8279
- spinner.succeed("OrgX account connected");
8589
+ spinner.succeed("OrgX account paired");
8280
8590
  await syncContinuityAfterAuth();
8281
- console.log(` ${ICON.ok} ${pc3.green("verified ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8591
+ console.log(` ${ICON.ok} ${pc3.green("paired ")} ${pc3.bold(result.stored.keyPrefix ?? result.verification.keyPrefix ?? "unknown")} ${pc3.dim("wizard auth store")}`);
8282
8592
  if (result.openclawResults.length > 0) {
8283
8593
  console.log("");
8284
8594
  printMutationResults(result.openclawResults);