@useorgx/wizard 0.1.23 → 0.1.24

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,44 @@ 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
+ }
1340
1378
  function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
1341
1379
  return {
1342
1380
  installationId: `wizard-${randomUUID()}`,
@@ -1352,6 +1390,7 @@ function sanitizeWizardStateRecord(record) {
1352
1390
  const onboardingTask = parseOnboardingTask(record.onboardingTask);
1353
1391
  const skillFiles = parseSkillFiles(record.skillFiles);
1354
1392
  const peopleFirstCapture = parsePeopleFirstCapture(record.peopleFirstCapture);
1393
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(record.dailyBriefOnboarding);
1355
1394
  return {
1356
1395
  installationId: record.installationId.trim(),
1357
1396
  createdAt: record.createdAt.trim(),
@@ -1362,7 +1401,8 @@ function sanitizeWizardStateRecord(record) {
1362
1401
  ...firstValueInitiative ? { firstValueInitiative } : {},
1363
1402
  ...onboardingTask ? { onboardingTask } : {},
1364
1403
  ...skillFiles ? { skillFiles } : {},
1365
- ...peopleFirstCapture ? { peopleFirstCapture } : {}
1404
+ ...peopleFirstCapture ? { peopleFirstCapture } : {},
1405
+ ...dailyBriefOnboarding ? { dailyBriefOnboarding } : {}
1366
1406
  };
1367
1407
  }
1368
1408
  function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
@@ -1391,8 +1431,33 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1391
1431
  if (skillFiles !== void 0) state.skillFiles = skillFiles;
1392
1432
  const peopleFirstCapture = parsePeopleFirstCapture(parsed.peopleFirstCapture);
1393
1433
  if (peopleFirstCapture !== void 0) state.peopleFirstCapture = peopleFirstCapture;
1434
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(parsed.dailyBriefOnboarding);
1435
+ if (dailyBriefOnboarding !== void 0) {
1436
+ state.dailyBriefOnboarding = dailyBriefOnboarding;
1437
+ }
1394
1438
  return state;
1395
1439
  }
1440
+ function getDailyBriefOnboardingDecision(workspaceId, statePath = ORGX_WIZARD_STATE_PATH) {
1441
+ const state = readWizardState(statePath);
1442
+ return state?.dailyBriefOnboarding?.entries.find(
1443
+ (entry) => entry.workspaceId === workspaceId
1444
+ ) ?? null;
1445
+ }
1446
+ function recordDailyBriefOnboardingDecision(entry, statePath = ORGX_WIZARD_STATE_PATH) {
1447
+ return updateWizardState((current) => {
1448
+ const existingEntries = current.dailyBriefOnboarding?.entries ?? [];
1449
+ const withoutExisting = existingEntries.filter(
1450
+ (e) => e.workspaceId !== entry.workspaceId
1451
+ );
1452
+ return {
1453
+ ...current,
1454
+ dailyBriefOnboarding: {
1455
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1456
+ entries: [...withoutExisting, entry]
1457
+ }
1458
+ };
1459
+ }, statePath);
1460
+ }
1396
1461
  function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
1397
1462
  const record = sanitizeWizardStateRecord(value);
1398
1463
  writeJsonFile(statePath, record, { mode: 384 });
@@ -5104,6 +5169,14 @@ async function runWorkspaceSetup(client, prompts, options) {
5104
5169
  }
5105
5170
  return createAndSelectWorkspace(client, prompts);
5106
5171
  }
5172
+ if (options.skipIfConfigured && currentWorkspace) {
5173
+ return {
5174
+ defaultChanged: false,
5175
+ message: `Using "${currentWorkspace.name}" as the default OrgX workspace.`,
5176
+ status: "unchanged",
5177
+ workspace: currentWorkspace
5178
+ };
5179
+ }
5107
5180
  const initialWorkspaceId = currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id ?? workspaces[0]?.id;
5108
5181
  const selected = await prompts.select({
5109
5182
  message: "Choose the OrgX workspace this machine should use by default.",
@@ -5744,20 +5817,73 @@ var BASELINE_PROMPTS = [
5744
5817
  { task_type: "launch_post", label: "Launch post", placeholder: "60" },
5745
5818
  { task_type: "architecture_doc", label: "Architecture doc", placeholder: "90" }
5746
5819
  ];
5820
+ var DAILY_BRIEF_SETUP_CHOICES = {
5821
+ defaults: "defaults",
5822
+ customize: "customize",
5823
+ skip: "skip"
5824
+ };
5825
+ function buildDefaultBaselines() {
5826
+ return BASELINE_PROMPTS.map((bp) => ({
5827
+ task_type: bp.task_type,
5828
+ minutes: Number.parseInt(bp.placeholder, 10),
5829
+ confidence: 0.4
5830
+ }));
5831
+ }
5832
+ function buildDefaultGoals() {
5833
+ return [
5834
+ {
5835
+ goal_type: "time_saved_weekly",
5836
+ target_value: 180,
5837
+ unit: "minutes",
5838
+ period: "weekly"
5839
+ }
5840
+ ];
5841
+ }
5842
+ function normalizeSendTime(value) {
5843
+ return value.trim().length === 4 ? `0${value.trim()}` : value.trim();
5844
+ }
5845
+ function recordSkipped(workspace, statePath) {
5846
+ recordDailyBriefOnboardingDecision(
5847
+ {
5848
+ workspaceId: workspace.id,
5849
+ workspaceName: workspace.name,
5850
+ status: "skipped",
5851
+ skippedAt: (/* @__PURE__ */ new Date()).toISOString()
5852
+ },
5853
+ statePath
5854
+ );
5855
+ return {
5856
+ status: "skipped_user",
5857
+ message: "Daily Brief setup skipped. Run `wizard setup --daily-brief` when ready."
5858
+ };
5859
+ }
5747
5860
  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
5861
  if (!options.workspace) {
5755
5862
  return {
5756
5863
  status: "skipped_no_workspace",
5757
5864
  message: "Daily Brief onboarding skipped \u2014 no workspace resolved."
5758
5865
  };
5759
5866
  }
5760
- const auth = await resolveOrgxAuth();
5867
+ if (options.skip) {
5868
+ return recordSkipped(options.workspace, options.statePath);
5869
+ }
5870
+ const localDecision = getDailyBriefOnboardingDecision(
5871
+ options.workspace.id,
5872
+ options.statePath
5873
+ );
5874
+ if (!options.force && localDecision) {
5875
+ return {
5876
+ status: "skipped_already_completed",
5877
+ 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."
5878
+ };
5879
+ }
5880
+ if (!options.interactive) {
5881
+ return {
5882
+ status: "skipped_non_interactive",
5883
+ message: "Daily Brief onboarding skipped \u2014 not attached to a TTY."
5884
+ };
5885
+ }
5886
+ const auth = await resolveOrgxAuth(options.authOptions);
5761
5887
  if (!auth) {
5762
5888
  return {
5763
5889
  status: "failed",
@@ -5769,6 +5895,15 @@ async function runDailyBriefOnboarding(options) {
5769
5895
  if (state) {
5770
5896
  const row = state.workspaces.find((w) => w.id === options.workspace.id);
5771
5897
  if (row?.onboardingCompletedAt) {
5898
+ recordDailyBriefOnboardingDecision(
5899
+ {
5900
+ workspaceId: options.workspace.id,
5901
+ workspaceName: options.workspace.name,
5902
+ status: "completed",
5903
+ completedAt: row.onboardingCompletedAt
5904
+ },
5905
+ options.statePath
5906
+ );
5772
5907
  return {
5773
5908
  status: "skipped_already_completed",
5774
5909
  message: "Daily Brief onboarding already completed for this workspace."
@@ -5776,93 +5911,116 @@ async function runDailyBriefOnboarding(options) {
5776
5911
  }
5777
5912
  }
5778
5913
  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
5914
+ const setupChoice = await prompts.select({
5915
+ message: "Daily Brief setup",
5916
+ initialValue: DAILY_BRIEF_SETUP_CHOICES.defaults,
5917
+ options: [
5918
+ {
5919
+ value: DAILY_BRIEF_SETUP_CHOICES.defaults,
5920
+ label: "Use defaults",
5921
+ hint: "20m code review, 45m PRD, 07:00 daily."
5922
+ },
5923
+ {
5924
+ value: DAILY_BRIEF_SETUP_CHOICES.customize,
5925
+ label: "Customize",
5926
+ hint: "Answer baseline and delivery questions."
5927
+ },
5928
+ {
5929
+ value: DAILY_BRIEF_SETUP_CHOICES.skip,
5930
+ label: "Skip",
5931
+ hint: "Do not ask again unless you pass --daily-brief."
5932
+ }
5933
+ ]
5782
5934
  });
5783
- if (prompts.isCancel(proceed)) {
5935
+ if (prompts.isCancel(setupChoice)) {
5784
5936
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5785
5937
  }
5786
- if (!proceed) {
5787
- return {
5788
- status: "cancelled",
5789
- message: "Skipped \u2014 run `wizard brief setup` later to configure."
5790
- };
5938
+ if (setupChoice === DAILY_BRIEF_SETUP_CHOICES.skip) {
5939
+ return recordSkipped(options.workspace, options.statePath);
5940
+ }
5941
+ const shouldCustomize = setupChoice === DAILY_BRIEF_SETUP_CHOICES.customize;
5942
+ const baselines = shouldCustomize ? [] : buildDefaultBaselines();
5943
+ if (shouldCustomize) {
5944
+ for (const bp of BASELINE_PROMPTS) {
5945
+ const answer = await prompts.text({
5946
+ message: `${bp.label} minutes`,
5947
+ placeholder: bp.placeholder,
5948
+ validate(value) {
5949
+ if (!value || value.trim() === "") return void 0;
5950
+ const n = Number.parseInt(value, 10);
5951
+ if (!Number.isFinite(n) || n <= 0 || n > 24 * 60) {
5952
+ return "Enter 1-1440 or leave blank.";
5953
+ }
5954
+ return void 0;
5955
+ }
5956
+ });
5957
+ if (prompts.isCancel(answer)) {
5958
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5959
+ }
5960
+ if (typeof answer === "string" && answer.trim() !== "") {
5961
+ const minutes = Number.parseInt(answer, 10);
5962
+ if (Number.isFinite(minutes) && minutes > 0) {
5963
+ baselines.push({ task_type: bp.task_type, minutes, confidence: 0.5 });
5964
+ }
5965
+ }
5966
+ }
5791
5967
  }
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,
5968
+ const goals = shouldCustomize ? [] : buildDefaultGoals();
5969
+ if (shouldCustomize) {
5970
+ const goalAnswer = await prompts.text({
5971
+ message: "Weekly time-saved target minutes",
5972
+ placeholder: "180",
5797
5973
  validate(value) {
5798
5974
  if (!value || value.trim() === "") return void 0;
5799
5975
  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.";
5976
+ if (!Number.isFinite(n) || n <= 0) {
5977
+ return "Enter a positive number or leave blank.";
5802
5978
  }
5803
5979
  return void 0;
5804
5980
  }
5805
5981
  });
5806
- if (prompts.isCancel(answer)) {
5982
+ if (prompts.isCancel(goalAnswer)) {
5807
5983
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5808
5984
  }
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 });
5985
+ if (typeof goalAnswer === "string" && goalAnswer.trim() !== "") {
5986
+ const target = Number.parseInt(goalAnswer, 10);
5987
+ if (Number.isFinite(target) && target > 0) {
5988
+ goals.push({
5989
+ goal_type: "time_saved_weekly",
5990
+ target_value: target,
5991
+ unit: "minutes",
5992
+ period: "weekly"
5993
+ });
5813
5994
  }
5814
5995
  }
5815
5996
  }
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.";
5997
+ let sendTimeLocal = "07:00";
5998
+ let onlyOnAttention = false;
5999
+ if (shouldCustomize) {
6000
+ const sendTimeAnswer = await prompts.text({
6001
+ message: "Daily brief time (HH:MM)",
6002
+ placeholder: "07:00",
6003
+ validate(value) {
6004
+ if (!value || value.trim() === "") return void 0;
6005
+ if (!/^\d{1,2}:\d{2}$/.test(value.trim())) {
6006
+ return "Use HH:MM (24h).";
6007
+ }
6008
+ return void 0;
5825
6009
  }
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
- });
6010
+ });
6011
+ if (prompts.isCancel(sendTimeAnswer)) {
6012
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5841
6013
  }
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;
6014
+ sendTimeLocal = typeof sendTimeAnswer === "string" && sendTimeAnswer.trim() ? normalizeSendTime(sendTimeAnswer) : "07:00";
6015
+ const onlyOnAttentionAnswer = await prompts.confirm({
6016
+ message: "Email only when attention is needed?",
6017
+ initialValue: false
6018
+ });
6019
+ if (prompts.isCancel(onlyOnAttentionAnswer)) {
6020
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5852
6021
  }
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." };
6022
+ onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5864
6023
  }
5865
- const onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5866
6024
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
5867
6025
  const commitPayload = {
5868
6026
  workspace_id: options.workspace.id,
@@ -5904,6 +6062,15 @@ async function runDailyBriefOnboarding(options) {
5904
6062
  }
5905
6063
  const commitBody = await commitResponse.json().catch(() => ({}));
5906
6064
  const previewUrl = typeof commitBody.daily_brief_preview_url === "string" ? commitBody.daily_brief_preview_url : "/today?mode=preview";
6065
+ recordDailyBriefOnboardingDecision(
6066
+ {
6067
+ workspaceId: options.workspace.id,
6068
+ workspaceName: options.workspace.name,
6069
+ status: "completed",
6070
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
6071
+ },
6072
+ options.statePath
6073
+ );
5907
6074
  return {
5908
6075
  status: "completed",
5909
6076
  message: "Your Daily Brief is configured. First brief lands tomorrow.",
@@ -7796,13 +7963,16 @@ function printDoctorReport(report, assessment) {
7796
7963
  async function main() {
7797
7964
  const program = new Command();
7798
7965
  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;
7966
+ const pkgVersion = true ? "0.1.24" : void 0;
7800
7967
  program.version(pkgVersion ?? "unknown", "-V, --version");
7801
7968
  program.hook("preAction", () => {
7802
7969
  console.log(renderBanner(pkgVersion));
7803
7970
  });
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) => {
7971
+ 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
7972
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
7973
+ if (options.dailyBrief && options.skipDailyBrief) {
7974
+ throw new Error("Use either --daily-brief or --skip-daily-brief, not both.");
7975
+ }
7806
7976
  await safeTrackWizardTelemetry("wizard_started", {
7807
7977
  command: "setup",
7808
7978
  interactive,
@@ -7968,7 +8138,8 @@ async function main() {
7968
8138
  text: textPrompt
7969
8139
  },
7970
8140
  {
7971
- interactive
8141
+ interactive,
8142
+ skipIfConfigured: !options.workspace
7972
8143
  }
7973
8144
  );
7974
8145
  if (workspaceSetup.status === "cancelled") {
@@ -8006,7 +8177,9 @@ async function main() {
8006
8177
  console.log(` ${ICON.ok} ${pc3.green("workspace ")} ${pc3.bold(workspaceSetup.workspace.name)}`);
8007
8178
  }
8008
8179
  const briefResult = await runDailyBriefOnboarding({
8180
+ force: Boolean(options.dailyBrief),
8009
8181
  interactive,
8182
+ skip: Boolean(options.skipDailyBrief),
8010
8183
  workspace: resolvedWorkspace,
8011
8184
  prompts: {
8012
8185
  cancel: clack.cancel,
@@ -8018,6 +8191,8 @@ async function main() {
8018
8191
  });
8019
8192
  if (briefResult.status === "cancelled") {
8020
8193
  console.log(` ${ICON.skip} ${pc3.dim(briefResult.message)}`);
8194
+ } else if (briefResult.status === "skipped_user") {
8195
+ console.log(` ${ICON.skip} ${pc3.dim(briefResult.message)}`);
8021
8196
  } else if (briefResult.status === "completed") {
8022
8197
  console.log(` ${ICON.ok} ${pc3.green("daily brief")} ${pc3.dim(briefResult.message)}`);
8023
8198
  } else if (briefResult.status === "failed") {