@useorgx/wizard 0.1.22 → 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
@@ -3,7 +3,7 @@
3
3
  // src/cli.ts
4
4
  import * as clack from "@clack/prompts";
5
5
  import { spawnSync as spawnSync3 } from "child_process";
6
- import { readFileSync as readFileSync3 } from "fs";
6
+ import { readFileSync as readFileSync4 } from "fs";
7
7
  import { hostname } from "os";
8
8
  import { resolve } from "path";
9
9
  import { Command } from "commander";
@@ -81,6 +81,8 @@ var CURSOR_DIR = join(HOME, ".cursor");
81
81
  var CODEX_DIR = join(HOME, ".codex");
82
82
  var OPENCLAW_DIR = join(HOME, ".openclaw");
83
83
  var AGENTS_DIR = join(HOME, ".agents");
84
+ var CLAUDE_PROJECTS_DIR = join(CLAUDE_DIR, "projects");
85
+ var CODEX_SESSIONS_DIR = join(CODEX_DIR, "sessions");
84
86
  var CLAUDE_SKILLS_DIR = join(CLAUDE_DIR, "skills");
85
87
  var CLAUDE_ORGX_SKILL_DIR = join(CLAUDE_SKILLS_DIR, "orgx");
86
88
  var CLAUDE_ORGX_SKILL_PATH = join(CLAUDE_ORGX_SKILL_DIR, "SKILL.md");
@@ -1335,6 +1337,44 @@ function parsePeopleFirstCapture(value) {
1335
1337
  entries
1336
1338
  };
1337
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
+ }
1338
1378
  function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
1339
1379
  return {
1340
1380
  installationId: `wizard-${randomUUID()}`,
@@ -1350,6 +1390,7 @@ function sanitizeWizardStateRecord(record) {
1350
1390
  const onboardingTask = parseOnboardingTask(record.onboardingTask);
1351
1391
  const skillFiles = parseSkillFiles(record.skillFiles);
1352
1392
  const peopleFirstCapture = parsePeopleFirstCapture(record.peopleFirstCapture);
1393
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(record.dailyBriefOnboarding);
1353
1394
  return {
1354
1395
  installationId: record.installationId.trim(),
1355
1396
  createdAt: record.createdAt.trim(),
@@ -1360,7 +1401,8 @@ function sanitizeWizardStateRecord(record) {
1360
1401
  ...firstValueInitiative ? { firstValueInitiative } : {},
1361
1402
  ...onboardingTask ? { onboardingTask } : {},
1362
1403
  ...skillFiles ? { skillFiles } : {},
1363
- ...peopleFirstCapture ? { peopleFirstCapture } : {}
1404
+ ...peopleFirstCapture ? { peopleFirstCapture } : {},
1405
+ ...dailyBriefOnboarding ? { dailyBriefOnboarding } : {}
1364
1406
  };
1365
1407
  }
1366
1408
  function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
@@ -1389,8 +1431,33 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
1389
1431
  if (skillFiles !== void 0) state.skillFiles = skillFiles;
1390
1432
  const peopleFirstCapture = parsePeopleFirstCapture(parsed.peopleFirstCapture);
1391
1433
  if (peopleFirstCapture !== void 0) state.peopleFirstCapture = peopleFirstCapture;
1434
+ const dailyBriefOnboarding = parseDailyBriefOnboarding(parsed.dailyBriefOnboarding);
1435
+ if (dailyBriefOnboarding !== void 0) {
1436
+ state.dailyBriefOnboarding = dailyBriefOnboarding;
1437
+ }
1392
1438
  return state;
1393
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
+ }
1394
1461
  function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
1395
1462
  const record = sanitizeWizardStateRecord(value);
1396
1463
  writeJsonFile(statePath, record, { mode: 384 });
@@ -4102,8 +4169,8 @@ function encodeRepoPath2(value) {
4102
4169
  return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
4103
4170
  }
4104
4171
  function isLikelyRepoFilePath(path) {
4105
- const basename2 = path.split("/").pop() ?? path;
4106
- return basename2.includes(".") && !/^\.[^./]+$/.test(basename2);
4172
+ const basename3 = path.split("/").pop() ?? path;
4173
+ return basename3.includes(".") && !/^\.[^./]+$/.test(basename3);
4107
4174
  }
4108
4175
  function buildContentsUrl2(spec, path) {
4109
4176
  const encodedPath = encodeRepoPath2(path);
@@ -5102,6 +5169,14 @@ async function runWorkspaceSetup(client, prompts, options) {
5102
5169
  }
5103
5170
  return createAndSelectWorkspace(client, prompts);
5104
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
+ }
5105
5180
  const initialWorkspaceId = currentWorkspace?.id ?? workspaces.find((workspace) => workspace.isDefault)?.id ?? workspaces[0]?.id;
5106
5181
  const selected = await prompts.select({
5107
5182
  message: "Choose the OrgX workspace this machine should use by default.",
@@ -5742,20 +5817,73 @@ var BASELINE_PROMPTS = [
5742
5817
  { task_type: "launch_post", label: "Launch post", placeholder: "60" },
5743
5818
  { task_type: "architecture_doc", label: "Architecture doc", placeholder: "90" }
5744
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
+ }
5745
5860
  async function runDailyBriefOnboarding(options) {
5746
- if (!options.interactive) {
5747
- return {
5748
- status: "skipped_non_interactive",
5749
- message: "Daily Brief onboarding skipped \u2014 not attached to a TTY."
5750
- };
5751
- }
5752
5861
  if (!options.workspace) {
5753
5862
  return {
5754
5863
  status: "skipped_no_workspace",
5755
5864
  message: "Daily Brief onboarding skipped \u2014 no workspace resolved."
5756
5865
  };
5757
5866
  }
5758
- 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);
5759
5887
  if (!auth) {
5760
5888
  return {
5761
5889
  status: "failed",
@@ -5767,6 +5895,15 @@ async function runDailyBriefOnboarding(options) {
5767
5895
  if (state) {
5768
5896
  const row = state.workspaces.find((w) => w.id === options.workspace.id);
5769
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
+ );
5770
5907
  return {
5771
5908
  status: "skipped_already_completed",
5772
5909
  message: "Daily Brief onboarding already completed for this workspace."
@@ -5774,93 +5911,116 @@ async function runDailyBriefOnboarding(options) {
5774
5911
  }
5775
5912
  }
5776
5913
  const { prompts } = options;
5777
- const proceed = await prompts.confirm({
5778
- message: "Set up your Daily Brief? (captures baselines so tomorrow's brief can show real time-saved numbers)",
5779
- 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
+ ]
5780
5934
  });
5781
- if (prompts.isCancel(proceed)) {
5935
+ if (prompts.isCancel(setupChoice)) {
5782
5936
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5783
5937
  }
5784
- if (!proceed) {
5785
- return {
5786
- status: "cancelled",
5787
- message: "Skipped \u2014 run `wizard brief setup` later to configure."
5788
- };
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
+ }
5789
5967
  }
5790
- const baselines = [];
5791
- for (const bp of BASELINE_PROMPTS) {
5792
- const answer = await prompts.text({
5793
- message: `How long does ${bp.label.toLowerCase()} usually take? (minutes, blank to skip)`,
5794
- 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",
5795
5973
  validate(value) {
5796
5974
  if (!value || value.trim() === "") return void 0;
5797
5975
  const n = Number.parseInt(value, 10);
5798
- if (!Number.isFinite(n) || n <= 0 || n > 24 * 60) {
5799
- return "Enter 1 \u2013 1440 or leave blank.";
5976
+ if (!Number.isFinite(n) || n <= 0) {
5977
+ return "Enter a positive number or leave blank.";
5800
5978
  }
5801
5979
  return void 0;
5802
5980
  }
5803
5981
  });
5804
- if (prompts.isCancel(answer)) {
5982
+ if (prompts.isCancel(goalAnswer)) {
5805
5983
  return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5806
5984
  }
5807
- if (typeof answer === "string" && answer.trim() !== "") {
5808
- const minutes = Number.parseInt(answer, 10);
5809
- if (Number.isFinite(minutes) && minutes > 0) {
5810
- 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
+ });
5811
5994
  }
5812
5995
  }
5813
5996
  }
5814
- const goals = [];
5815
- const goalAnswer = await prompts.text({
5816
- message: "Weekly time saved target (minutes, blank to skip)",
5817
- placeholder: "180",
5818
- validate(value) {
5819
- if (!value || value.trim() === "") return void 0;
5820
- const n = Number.parseInt(value, 10);
5821
- if (!Number.isFinite(n) || n <= 0) {
5822
- 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;
5823
6009
  }
5824
- return void 0;
5825
- }
5826
- });
5827
- if (prompts.isCancel(goalAnswer)) {
5828
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5829
- }
5830
- if (typeof goalAnswer === "string" && goalAnswer.trim() !== "") {
5831
- const target = Number.parseInt(goalAnswer, 10);
5832
- if (Number.isFinite(target) && target > 0) {
5833
- goals.push({
5834
- goal_type: "time_saved_weekly",
5835
- target_value: target,
5836
- unit: "minutes",
5837
- period: "weekly"
5838
- });
6010
+ });
6011
+ if (prompts.isCancel(sendTimeAnswer)) {
6012
+ return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5839
6013
  }
5840
- }
5841
- const sendTimeAnswer = await prompts.text({
5842
- message: "When should your daily brief arrive? (HH:MM local, default 07:00)",
5843
- placeholder: "07:00",
5844
- validate(value) {
5845
- if (!value || value.trim() === "") return void 0;
5846
- if (!/^\d{1,2}:\d{2}$/.test(value.trim())) {
5847
- return "Use HH:MM (24h).";
5848
- }
5849
- 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." };
5850
6021
  }
5851
- });
5852
- if (prompts.isCancel(sendTimeAnswer)) {
5853
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
5854
- }
5855
- const sendTimeLocal = typeof sendTimeAnswer === "string" && sendTimeAnswer.trim() ? sendTimeAnswer.trim().length === 4 ? `0${sendTimeAnswer.trim()}` : sendTimeAnswer.trim() : "07:00";
5856
- const onlyOnAttentionAnswer = await prompts.confirm({
5857
- message: "Only email when something needs your attention?",
5858
- initialValue: false
5859
- });
5860
- if (prompts.isCancel(onlyOnAttentionAnswer)) {
5861
- return { status: "cancelled", message: "Daily Brief onboarding cancelled." };
6022
+ onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5862
6023
  }
5863
- const onlyOnAttention = Boolean(onlyOnAttentionAnswer);
5864
6024
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
5865
6025
  const commitPayload = {
5866
6026
  workspace_id: options.workspace.id,
@@ -5902,6 +6062,15 @@ async function runDailyBriefOnboarding(options) {
5902
6062
  }
5903
6063
  const commitBody = await commitResponse.json().catch(() => ({}));
5904
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
+ );
5905
6074
  return {
5906
6075
  status: "completed",
5907
6076
  message: "Your Daily Brief is configured. First brief lands tomorrow.",
@@ -5927,6 +6096,177 @@ async function fetchOnboardingState(auth) {
5927
6096
  }
5928
6097
  }
5929
6098
 
6099
+ // src/lib/ai-session-import.ts
6100
+ import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
6101
+ import { basename as basename2, join as join4, relative as relative2 } from "path";
6102
+ var AI_SESSION_SOURCES = ["codex", "claude"];
6103
+ var DEFAULT_LIMIT_PER_SOURCE = 3;
6104
+ var DEFAULT_SINCE_DAYS = 30;
6105
+ var DEFAULT_MAX_BYTES_PER_FILE = 1e6;
6106
+ var AUDIT_RELEVANT_LINE_PATTERN = /\b(decision|decided|artifact|receipt|proof|commitment|committed|next action|follow[- ]?up|outcome|result|impact|roi|economics|token|cost|saved|open loop|gap|blocker|risk|owner|dri|writeback|rollback|quality score)\b/i;
6107
+ function parseAiSessionSources(value) {
6108
+ if (!value?.trim()) return [];
6109
+ const requested = value.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
6110
+ const expanded = requested.includes("all") ? [...AI_SESSION_SOURCES] : requested;
6111
+ const deduped = [...new Set(expanded)];
6112
+ const invalid = deduped.filter((source) => !AI_SESSION_SOURCES.includes(source));
6113
+ if (invalid.length > 0) {
6114
+ throw new Error(`Unsupported AI-session source: ${invalid.join(", ")}. Use codex, claude, or all.`);
6115
+ }
6116
+ return deduped;
6117
+ }
6118
+ function parseJsonLine(line) {
6119
+ try {
6120
+ return JSON.parse(line);
6121
+ } catch {
6122
+ return null;
6123
+ }
6124
+ }
6125
+ function asText(value) {
6126
+ if (typeof value === "string") return value;
6127
+ if (Array.isArray(value)) {
6128
+ return value.map((item) => {
6129
+ if (typeof item === "string") return item;
6130
+ if (!isRecord(item)) return "";
6131
+ if (typeof item.text === "string") return item.text;
6132
+ if (typeof item.content === "string") return item.content;
6133
+ return "";
6134
+ }).filter(Boolean).join("\n");
6135
+ }
6136
+ if (isRecord(value) && typeof value.text === "string") return value.text;
6137
+ return "";
6138
+ }
6139
+ function extractCodexMessageText(record) {
6140
+ if (!isRecord(record) || record.type !== "response_item" || !isRecord(record.payload)) {
6141
+ return "";
6142
+ }
6143
+ const payload = record.payload;
6144
+ if (payload.type !== "message" || payload.role !== "user" && payload.role !== "assistant") {
6145
+ return "";
6146
+ }
6147
+ return asText(payload.content);
6148
+ }
6149
+ function extractClaudeMessageText(record) {
6150
+ if (!isRecord(record) || record.isMeta === true || !isRecord(record.message)) {
6151
+ return "";
6152
+ }
6153
+ const message = record.message;
6154
+ if (message.role !== "user" && message.role !== "assistant") {
6155
+ return "";
6156
+ }
6157
+ const text2 = asText(message.content);
6158
+ if (/^<local-command-caveat>/i.test(text2.trim())) return "";
6159
+ return text2;
6160
+ }
6161
+ function keepAuditRelevantLines(text2) {
6162
+ return text2.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && AUDIT_RELEVANT_LINE_PATTERN.test(line));
6163
+ }
6164
+ function collectJsonlFiles(root, source) {
6165
+ if (!existsSync5(root)) return [];
6166
+ const files = [];
6167
+ const stack = [root];
6168
+ while (stack.length > 0) {
6169
+ const current = stack.pop();
6170
+ if (!current) continue;
6171
+ let entries;
6172
+ try {
6173
+ entries = readdirSync3(current);
6174
+ } catch {
6175
+ continue;
6176
+ }
6177
+ for (const entry of entries) {
6178
+ const path = join4(current, entry);
6179
+ let stats;
6180
+ try {
6181
+ stats = statSync3(path);
6182
+ } catch {
6183
+ continue;
6184
+ }
6185
+ if (stats.isDirectory()) {
6186
+ stack.push(path);
6187
+ continue;
6188
+ }
6189
+ if (stats.isFile() && path.endsWith(".jsonl")) {
6190
+ files.push({ mtimeMs: stats.mtimeMs, path, source });
6191
+ }
6192
+ }
6193
+ }
6194
+ return files;
6195
+ }
6196
+ function readSessionImport(candidate, root, options) {
6197
+ let stats;
6198
+ try {
6199
+ stats = statSync3(candidate.path);
6200
+ } catch {
6201
+ return null;
6202
+ }
6203
+ if (stats.size > options.maxBytesPerFile) return null;
6204
+ const extractor = candidate.source === "codex" ? extractCodexMessageText : extractClaudeMessageText;
6205
+ const lines = readFileSync3(candidate.path, "utf8").split(/\r?\n/);
6206
+ const relevantLines = [];
6207
+ for (const line of lines) {
6208
+ const record = parseJsonLine(line);
6209
+ const text2 = extractor(record);
6210
+ if (!text2) continue;
6211
+ relevantLines.push(...keepAuditRelevantLines(text2));
6212
+ }
6213
+ const deduped = [...new Set(relevantLines)].slice(0, 80);
6214
+ if (deduped.length === 0) return null;
6215
+ const relativePath = relative2(root, candidate.path);
6216
+ return {
6217
+ sourceId: `${candidate.source}:${basename2(candidate.path, ".jsonl")}`,
6218
+ sourceLabel: `${candidate.source === "codex" ? "Codex" : "Claude"} session ${relativePath}`,
6219
+ text: deduped.join("\n")
6220
+ };
6221
+ }
6222
+ function loadAiSessionImports(options) {
6223
+ const now = options.now ?? /* @__PURE__ */ new Date();
6224
+ const sinceMs = now.getTime() - (options.sinceDays ?? DEFAULT_SINCE_DAYS) * 24 * 60 * 60 * 1e3;
6225
+ const limitPerSource = Math.max(1, options.limitPerSource ?? DEFAULT_LIMIT_PER_SOURCE);
6226
+ const maxBytesPerFile = Math.max(1, options.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE);
6227
+ const roots = {
6228
+ claude: options.claudeProjectsDir ?? CLAUDE_PROJECTS_DIR,
6229
+ codex: options.codexSessionsDir ?? CODEX_SESSIONS_DIR
6230
+ };
6231
+ const imports = [];
6232
+ const connectedSources = [];
6233
+ const missingSources = [];
6234
+ let scannedFiles = 0;
6235
+ let skippedFiles = 0;
6236
+ for (const source of options.sources) {
6237
+ const root = roots[source];
6238
+ const candidates = collectJsonlFiles(root, source).filter((file) => file.mtimeMs >= sinceMs).sort((a, b) => b.mtimeMs - a.mtimeMs);
6239
+ if (candidates.length === 0) {
6240
+ missingSources.push(`${source} session store`);
6241
+ continue;
6242
+ }
6243
+ let importedForSource = 0;
6244
+ for (const candidate of candidates) {
6245
+ if (importedForSource >= limitPerSource) break;
6246
+ scannedFiles += 1;
6247
+ const imported = readSessionImport(candidate, root, { maxBytesPerFile });
6248
+ if (!imported) {
6249
+ skippedFiles += 1;
6250
+ continue;
6251
+ }
6252
+ imports.push(imported);
6253
+ importedForSource += 1;
6254
+ }
6255
+ if (importedForSource > 0) {
6256
+ connectedSources.push(`${source === "codex" ? "Codex" : "Claude"} local sessions`);
6257
+ } else {
6258
+ missingSources.push(`${source} audit-relevant session lines`);
6259
+ }
6260
+ }
6261
+ return {
6262
+ connectedSources,
6263
+ imports,
6264
+ missingSources,
6265
+ scannedFiles,
6266
+ skippedFiles
6267
+ };
6268
+ }
6269
+
5930
6270
  // src/lib/self-audit.ts
5931
6271
  import { createHash as createHash3 } from "crypto";
5932
6272
  var SELF_AUDIT_SCHEMA_VERSION = "2026-04-27";
@@ -6529,10 +6869,10 @@ function formatScoreLine(scores) {
6529
6869
  }
6530
6870
  function readAuditInput(options, interactive) {
6531
6871
  if (options.input?.trim()) {
6532
- return readFileSync3(resolve(options.input.trim()), "utf8");
6872
+ return readFileSync4(resolve(options.input.trim()), "utf8");
6533
6873
  }
6534
6874
  if (!process.stdin.isTTY) {
6535
- return readFileSync3(0, "utf8");
6875
+ return readFileSync4(0, "utf8");
6536
6876
  }
6537
6877
  if (!interactive) {
6538
6878
  throw new Error("Audit input is required. Pass --input <file> or pipe text into wizard audit.");
@@ -6549,6 +6889,53 @@ function readAuditInput(options, interactive) {
6549
6889
  return value;
6550
6890
  });
6551
6891
  }
6892
+ function parsePositiveInteger(value, fallback, label) {
6893
+ if (!value?.trim()) return fallback;
6894
+ const parsed = Number.parseInt(value.trim(), 10);
6895
+ if (!Number.isFinite(parsed) || parsed <= 0) {
6896
+ throw new Error(`${label} must be a positive integer.`);
6897
+ }
6898
+ return parsed;
6899
+ }
6900
+ async function readAuditImports(options, interactive) {
6901
+ const sources = parseAiSessionSources(options.from);
6902
+ const imports = [];
6903
+ const connectedSources = [];
6904
+ const missingSources = [];
6905
+ if (sources.length > 0) {
6906
+ const imported = loadAiSessionImports({
6907
+ ...options.claudeProjectsDir?.trim() ? { claudeProjectsDir: resolve(options.claudeProjectsDir.trim()) } : {},
6908
+ ...options.codexSessionsDir?.trim() ? { codexSessionsDir: resolve(options.codexSessionsDir.trim()) } : {},
6909
+ limitPerSource: parsePositiveInteger(options.sessionLimit, 3, "--session-limit"),
6910
+ sinceDays: parsePositiveInteger(options.sessionDays, 30, "--session-days"),
6911
+ sources
6912
+ });
6913
+ imports.push(...imported.imports);
6914
+ connectedSources.push(...imported.connectedSources);
6915
+ missingSources.push(...imported.missingSources);
6916
+ }
6917
+ const shouldReadManualInput = Boolean(options.input?.trim()) || sources.length === 0 || !process.stdin.isTTY;
6918
+ if (shouldReadManualInput) {
6919
+ const text2 = (await readAuditInput(options, interactive)).trim();
6920
+ if (text2) {
6921
+ imports.push({
6922
+ sourceId: "wizard-audit-input",
6923
+ sourceLabel: options.sourceLabel?.trim() || "Wizard audit input",
6924
+ text: text2
6925
+ });
6926
+ connectedSources.push(options.sourceLabel?.trim() || "Manual AI-session import");
6927
+ }
6928
+ }
6929
+ if (imports.length === 0) {
6930
+ const sourceHint = sources.length > 0 ? ` No audit-relevant lines were found in ${sources.join(", ")} sessions.` : "";
6931
+ throw new Error(`Audit input is required.${sourceHint} Pass --input <file>, pipe text, or use --from codex|claude|all.`);
6932
+ }
6933
+ return {
6934
+ connectedSources,
6935
+ imports,
6936
+ missingSources
6937
+ };
6938
+ }
6552
6939
  function requireWriteApproval(options, interactive) {
6553
6940
  const wantsWrite = Boolean(options.createInitiative || options.attachToInitiative || options.writeFollowUp);
6554
6941
  if (!wantsWrite || options.yes || options.dryRun) return true;
@@ -6591,23 +6978,19 @@ async function resolveAuditWorkspace(options) {
6591
6978
  }
6592
6979
  async function runAuditCommand(options) {
6593
6980
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
6594
- const text2 = (await readAuditInput(options, interactive)).trim();
6595
- if (!text2) return;
6981
+ const auditImports = await readAuditImports(options, interactive);
6596
6982
  const workspace = await resolveAuditWorkspace(options);
6597
6983
  const plan = buildSelfAuditPlan({
6598
6984
  connectedSources: [
6599
- options.sourceLabel?.trim() || "Manual AI-session import",
6985
+ ...auditImports.connectedSources,
6600
6986
  ...workspace.id === "local-workspace" ? [] : ["OrgX workspace"]
6601
6987
  ],
6602
6988
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
6603
- imports: [
6604
- {
6605
- sourceId: "wizard-audit-input",
6606
- sourceLabel: options.sourceLabel?.trim() || "Wizard audit input",
6607
- text: text2
6608
- }
6989
+ imports: auditImports.imports,
6990
+ missingSources: [
6991
+ ...workspace.id === "local-workspace" ? ["OrgX workspace auth"] : [],
6992
+ ...auditImports.missingSources
6609
6993
  ],
6610
- missingSources: workspace.id === "local-workspace" ? ["OrgX workspace auth", "automatic AI-session import"] : ["automatic AI-session import"],
6611
6994
  workspace
6612
6995
  });
6613
6996
  const markdown = renderSelfAuditMarkdown(plan);
@@ -7580,13 +7963,16 @@ function printDoctorReport(report, assessment) {
7580
7963
  async function main() {
7581
7964
  const program = new Command();
7582
7965
  program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
7583
- const pkgVersion = true ? "0.1.22" : void 0;
7966
+ const pkgVersion = true ? "0.1.24" : void 0;
7584
7967
  program.version(pkgVersion ?? "unknown", "-V, --version");
7585
7968
  program.hook("preAction", () => {
7586
7969
  console.log(renderBanner(pkgVersion));
7587
7970
  });
7588
- 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) => {
7589
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
+ }
7590
7976
  await safeTrackWizardTelemetry("wizard_started", {
7591
7977
  command: "setup",
7592
7978
  interactive,
@@ -7752,7 +8138,8 @@ async function main() {
7752
8138
  text: textPrompt
7753
8139
  },
7754
8140
  {
7755
- interactive
8141
+ interactive,
8142
+ skipIfConfigured: !options.workspace
7756
8143
  }
7757
8144
  );
7758
8145
  if (workspaceSetup.status === "cancelled") {
@@ -7790,7 +8177,9 @@ async function main() {
7790
8177
  console.log(` ${ICON.ok} ${pc3.green("workspace ")} ${pc3.bold(workspaceSetup.workspace.name)}`);
7791
8178
  }
7792
8179
  const briefResult = await runDailyBriefOnboarding({
8180
+ force: Boolean(options.dailyBrief),
7793
8181
  interactive,
8182
+ skip: Boolean(options.skipDailyBrief),
7794
8183
  workspace: resolvedWorkspace,
7795
8184
  prompts: {
7796
8185
  cancel: clack.cancel,
@@ -7802,6 +8191,8 @@ async function main() {
7802
8191
  });
7803
8192
  if (briefResult.status === "cancelled") {
7804
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)}`);
7805
8196
  } else if (briefResult.status === "completed") {
7806
8197
  console.log(` ${ICON.ok} ${pc3.green("daily brief")} ${pc3.dim(briefResult.message)}`);
7807
8198
  } else if (briefResult.status === "failed") {
@@ -8242,7 +8633,7 @@ async function main() {
8242
8633
  jsonOutput: Boolean(options.json)
8243
8634
  });
8244
8635
  });
8245
- program.command("audit").description("Run the AI-native Founder Loop self-audit from pasted or file-based AI-session context.").option("--input <path>", "AI-session transcript or summary file; stdin is used when piped").option("--source-label <label>", "label for the imported AI-session source").option("--workspace-id <id>", "workspace id override; defaults to the current OrgX workspace when authenticated").option("--workspace-name <name>", "workspace name override for local-only audits").option("--output-dir <path>", "directory for generated audit JSON and Markdown", ".orgx/audits").option("--attach-to-initiative <id>", "attach the generated audit artifact to an existing OrgX initiative").option("--create-initiative", "create an OrgX initiative from the generated audit plan").option("--write-follow-up", "create one approval-gated OrgX follow-up task from the audit recommendation").option("--workstream-id <id>", "optional workstream id for the generated follow-up task").option("--milestone-id <id>", "optional milestone id for the generated follow-up task").option("--dry-run", "exercise OrgX write paths without sending writes").option("--yes", "approve OrgX write flags in non-interactive mode").option("--json", "emit a JSON command summary").action(async (options) => {
8636
+ program.command("audit").description("Run the AI-native Founder Loop self-audit from pasted or file-based AI-session context.").option("--input <path>", "AI-session transcript or summary file; stdin is used when piped").option("--from <sources>", "auto-import recent local AI sessions: codex, claude, or all").option("--session-limit <count>", "max recent sessions to import per selected source", "3").option("--session-days <days>", "lookback window for local AI-session imports", "30").option("--codex-sessions-dir <path>", "override Codex sessions directory for audit import").option("--claude-projects-dir <path>", "override Claude projects directory for audit import").option("--source-label <label>", "label for the imported AI-session source").option("--workspace-id <id>", "workspace id override; defaults to the current OrgX workspace when authenticated").option("--workspace-name <name>", "workspace name override for local-only audits").option("--output-dir <path>", "directory for generated audit JSON and Markdown", ".orgx/audits").option("--attach-to-initiative <id>", "attach the generated audit artifact to an existing OrgX initiative").option("--create-initiative", "create an OrgX initiative from the generated audit plan").option("--write-follow-up", "create one approval-gated OrgX follow-up task from the audit recommendation").option("--workstream-id <id>", "optional workstream id for the generated follow-up task").option("--milestone-id <id>", "optional milestone id for the generated follow-up task").option("--dry-run", "exercise OrgX write paths without sending writes").option("--yes", "approve OrgX write flags in non-interactive mode").option("--json", "emit a JSON command summary").action(async (options) => {
8246
8637
  await safeTrackWizardTelemetry("audit_started", {
8247
8638
  attach_to_initiative: Boolean(options.attachToInitiative),
8248
8639
  command: "audit",