@useorgx/wizard 0.1.44 → 0.1.46
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 +531 -83
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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
|
|
6
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
7
7
|
import { hostname } from "os";
|
|
8
8
|
import { resolve as resolve2 } from "path";
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -1376,7 +1376,7 @@ function parseDailyBriefOnboarding(value) {
|
|
|
1376
1376
|
};
|
|
1377
1377
|
}
|
|
1378
1378
|
function isSetupPromptKey(value) {
|
|
1379
|
-
return value === "first_initiative" || value === "onboarding_task" || value === "agent_roster" || value === "setup_intent";
|
|
1379
|
+
return value === "first_initiative" || value === "onboarding_task" || value === "agent_roster" || value === "local_skill_discovery" || value === "setup_intent";
|
|
1380
1380
|
}
|
|
1381
1381
|
function parseSetupPromptDecisionEntry(value) {
|
|
1382
1382
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -3215,8 +3215,8 @@ function encodeRepoPath2(value) {
|
|
|
3215
3215
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3216
3216
|
}
|
|
3217
3217
|
function isLikelyRepoFilePath(path) {
|
|
3218
|
-
const
|
|
3219
|
-
return
|
|
3218
|
+
const basename5 = path.split("/").pop() ?? path;
|
|
3219
|
+
return basename5.includes(".") && !/^\.[^./]+$/.test(basename5);
|
|
3220
3220
|
}
|
|
3221
3221
|
function buildContentsUrl2(spec, path) {
|
|
3222
3222
|
const encodedPath = encodeRepoPath2(path);
|
|
@@ -5392,6 +5392,207 @@ async function runFounderPreset(prompts, options) {
|
|
|
5392
5392
|
};
|
|
5393
5393
|
}
|
|
5394
5394
|
|
|
5395
|
+
// src/lib/local-skill-discovery.ts
|
|
5396
|
+
import { createHash as createHash3 } from "crypto";
|
|
5397
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
5398
|
+
import { basename as basename2, join as join4, relative as relative2 } from "path";
|
|
5399
|
+
var DEFAULT_MAX_BYTES = 48e3;
|
|
5400
|
+
var DEFAULT_LIMIT = 12;
|
|
5401
|
+
var IGNORED_DIRS = /* @__PURE__ */ new Set([".git", ".next", ".turbo", "build", "dist", "node_modules"]);
|
|
5402
|
+
var LOCAL_SKILL_SOURCES = ["opencode", "claude", "codex", "agents", "workspace"];
|
|
5403
|
+
var DOMAIN_KEYWORDS = [
|
|
5404
|
+
{ domain: "engineering", pattern: /\b(eval|benchmark|test|ci|code|github|repo|runtime|api|llm|model)\b/i },
|
|
5405
|
+
{ domain: "product", pattern: /\b(customer|workflow|roadmap|prd|user|adoption|value|requirements?)\b/i },
|
|
5406
|
+
{ domain: "operations", pattern: /\b(runbook|incident|sla|dashboard|superset|metric|monitor|ops)\b/i },
|
|
5407
|
+
{ domain: "design", pattern: /\b(ui|ux|design|accessibility|component|visual)\b/i },
|
|
5408
|
+
{ domain: "marketing", pattern: /\b(launch|campaign|positioning|gtm|content|story)\b/i },
|
|
5409
|
+
{ domain: "sales", pattern: /\b(deal|pipeline|prospect|meddic|outreach|buyer)\b/i }
|
|
5410
|
+
];
|
|
5411
|
+
function hash(value, length = 10) {
|
|
5412
|
+
return createHash3("sha256").update(value).digest("hex").slice(0, length);
|
|
5413
|
+
}
|
|
5414
|
+
function safeStat(path) {
|
|
5415
|
+
try {
|
|
5416
|
+
return statSync3(path);
|
|
5417
|
+
} catch {
|
|
5418
|
+
return null;
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
function defaultRoots(input) {
|
|
5422
|
+
return {
|
|
5423
|
+
agents: [join4(input.home, ".agents", "skills")],
|
|
5424
|
+
claude: [join4(input.home, ".claude", "skills"), join4(input.cwd, ".claude", "skills")],
|
|
5425
|
+
codex: [join4(input.home, ".codex", "skills"), join4(input.cwd, ".codex", "skills")],
|
|
5426
|
+
opencode: [
|
|
5427
|
+
join4(input.home, ".opencode", "skills"),
|
|
5428
|
+
join4(input.home, ".config", "opencode", "skills"),
|
|
5429
|
+
join4(input.home, "Library", "Application Support", "opencode", "skills"),
|
|
5430
|
+
join4(input.cwd, ".opencode", "skills")
|
|
5431
|
+
],
|
|
5432
|
+
workspace: [
|
|
5433
|
+
join4(input.cwd, "skills"),
|
|
5434
|
+
join4(input.cwd, ".agents", "skills"),
|
|
5435
|
+
join4(input.cwd, ".orgx", "skills")
|
|
5436
|
+
]
|
|
5437
|
+
};
|
|
5438
|
+
}
|
|
5439
|
+
function walkSkillFiles(root, maxFiles = 200) {
|
|
5440
|
+
const rootStats = safeStat(root);
|
|
5441
|
+
if (!rootStats) return [];
|
|
5442
|
+
if (rootStats.isFile()) return [root];
|
|
5443
|
+
if (!rootStats.isDirectory()) return [];
|
|
5444
|
+
const files = [];
|
|
5445
|
+
const stack = [root];
|
|
5446
|
+
while (stack.length > 0 && files.length < maxFiles) {
|
|
5447
|
+
const current = stack.pop();
|
|
5448
|
+
if (!current) continue;
|
|
5449
|
+
let entries;
|
|
5450
|
+
try {
|
|
5451
|
+
entries = readdirSync3(current, { withFileTypes: true });
|
|
5452
|
+
} catch {
|
|
5453
|
+
continue;
|
|
5454
|
+
}
|
|
5455
|
+
for (const entry of entries) {
|
|
5456
|
+
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5457
|
+
const path = join4(current, entry.name);
|
|
5458
|
+
if (entry.isDirectory()) {
|
|
5459
|
+
stack.push(path);
|
|
5460
|
+
} else if (entry.isFile() && /\.(md|mdc|txt)$/i.test(entry.name)) {
|
|
5461
|
+
files.push(path);
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
return files;
|
|
5466
|
+
}
|
|
5467
|
+
function readWindow(path, maxBytes) {
|
|
5468
|
+
const stats = safeStat(path);
|
|
5469
|
+
if (!stats?.isFile() || stats.size === 0) return null;
|
|
5470
|
+
try {
|
|
5471
|
+
const text2 = readFileSync3(path, "utf8");
|
|
5472
|
+
return text2.slice(0, maxBytes);
|
|
5473
|
+
} catch {
|
|
5474
|
+
return null;
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
function titleFrom(path, text2) {
|
|
5478
|
+
const heading = text2.match(/^#\s+(.+)$/m)?.[1]?.trim();
|
|
5479
|
+
if (heading) return heading.slice(0, 120);
|
|
5480
|
+
return basename2(path).replace(/\.(md|mdc|txt)$/i, "").replace(/[-_]+/g, " ");
|
|
5481
|
+
}
|
|
5482
|
+
function snippetFrom(text2) {
|
|
5483
|
+
const lines = text2.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("---") && !/^#+\s/.test(line));
|
|
5484
|
+
return lines.slice(0, 4).join(" ").replace(/\s+/g, " ").slice(0, 420);
|
|
5485
|
+
}
|
|
5486
|
+
function tokenize(value) {
|
|
5487
|
+
return value.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length >= 3);
|
|
5488
|
+
}
|
|
5489
|
+
function scoreCandidate(text2, context, source) {
|
|
5490
|
+
const haystack = text2.toLowerCase();
|
|
5491
|
+
const contextTokens = [...new Set(tokenize(context))];
|
|
5492
|
+
const contextHits = contextTokens.filter((token) => haystack.includes(token)).length;
|
|
5493
|
+
const explicitSkillSignal = /\b(skill|agent|workflow|instruction|rule|prompt|playbook)\b/i.test(text2) ? 2 : 0;
|
|
5494
|
+
const sourceBoost = source === "opencode" ? 2 : source === "workspace" ? 1 : 0;
|
|
5495
|
+
const score = contextHits * 3 + explicitSkillSignal + sourceBoost;
|
|
5496
|
+
const reasonParts = [
|
|
5497
|
+
contextHits > 0 ? `${contextHits} context match${contextHits === 1 ? "" : "es"}` : "local skill file",
|
|
5498
|
+
sourceBoost > 0 ? `${source} source` : ""
|
|
5499
|
+
].filter(Boolean);
|
|
5500
|
+
return { reason: reasonParts.join("; "), score };
|
|
5501
|
+
}
|
|
5502
|
+
function inferDomains(text2, context) {
|
|
5503
|
+
const joined = `${text2}
|
|
5504
|
+
${context}`;
|
|
5505
|
+
const domains = DOMAIN_KEYWORDS.filter((entry) => entry.pattern.test(joined)).map((entry) => entry.domain);
|
|
5506
|
+
return domains.length > 0 ? [...new Set(domains)] : ["orchestrator"];
|
|
5507
|
+
}
|
|
5508
|
+
function parseLocalSkillSources(value) {
|
|
5509
|
+
if (!value?.trim() || value.trim().toLowerCase() === "all") {
|
|
5510
|
+
return [...LOCAL_SKILL_SOURCES];
|
|
5511
|
+
}
|
|
5512
|
+
const requested = value.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
|
|
5513
|
+
const invalid = requested.filter((source) => !LOCAL_SKILL_SOURCES.includes(source));
|
|
5514
|
+
if (invalid.length > 0) {
|
|
5515
|
+
throw new Error(`Unsupported local skill source: ${invalid.join(", ")}. Use ${LOCAL_SKILL_SOURCES.join(", ")}, or all.`);
|
|
5516
|
+
}
|
|
5517
|
+
return [...new Set(requested)];
|
|
5518
|
+
}
|
|
5519
|
+
function discoverLocalSkills(options = {}) {
|
|
5520
|
+
const cwd = options.cwd ?? process.cwd();
|
|
5521
|
+
const home = options.home ?? process.env.HOME ?? "";
|
|
5522
|
+
const sources = options.sources ?? [...LOCAL_SKILL_SOURCES];
|
|
5523
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
5524
|
+
const context = options.context?.trim() ?? "";
|
|
5525
|
+
const roots = defaultRoots({ cwd, home });
|
|
5526
|
+
for (const [source, overrides] of Object.entries(options.roots ?? {})) {
|
|
5527
|
+
roots[source] = overrides;
|
|
5528
|
+
}
|
|
5529
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5530
|
+
const candidates = [];
|
|
5531
|
+
for (const source of sources) {
|
|
5532
|
+
for (const root of roots[source] ?? []) {
|
|
5533
|
+
for (const path of walkSkillFiles(root)) {
|
|
5534
|
+
if (seen.has(path)) continue;
|
|
5535
|
+
seen.add(path);
|
|
5536
|
+
const text2 = readWindow(path, maxBytes);
|
|
5537
|
+
if (!text2 || /ORGX SKILL COMPOSED v1/.test(text2)) continue;
|
|
5538
|
+
const title = titleFrom(path, text2);
|
|
5539
|
+
const snippet = snippetFrom(text2);
|
|
5540
|
+
const scored = scoreCandidate(`${title}
|
|
5541
|
+
${snippet}
|
|
5542
|
+
${text2}`, context, source);
|
|
5543
|
+
candidates.push({
|
|
5544
|
+
agentDomains: inferDomains(`${title}
|
|
5545
|
+
${snippet}`, context),
|
|
5546
|
+
id: `${source}-${hash(path)}`,
|
|
5547
|
+
path,
|
|
5548
|
+
reason: scored.reason,
|
|
5549
|
+
score: scored.score,
|
|
5550
|
+
snippet,
|
|
5551
|
+
source,
|
|
5552
|
+
title
|
|
5553
|
+
});
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
return candidates.sort((left, right) => right.score - left.score || left.title.localeCompare(right.title)).slice(0, Math.max(1, options.limit ?? DEFAULT_LIMIT));
|
|
5558
|
+
}
|
|
5559
|
+
function selectLocalSkillCandidates(candidates, selection) {
|
|
5560
|
+
const wanted = selection.split(",").map((item) => item.trim()).filter(Boolean);
|
|
5561
|
+
const selected = [];
|
|
5562
|
+
for (const item of wanted) {
|
|
5563
|
+
const byIndex = /^\d+$/.test(item) ? candidates[Number(item) - 1] : void 0;
|
|
5564
|
+
const byId = candidates.find((candidate) => candidate.id === item);
|
|
5565
|
+
const match = byIndex ?? byId;
|
|
5566
|
+
if (!match) {
|
|
5567
|
+
throw new Error(`No local skill candidate matched '${item}'.`);
|
|
5568
|
+
}
|
|
5569
|
+
selected.push(match);
|
|
5570
|
+
}
|
|
5571
|
+
return [...new Map(selected.map((candidate) => [candidate.id, candidate])).values()];
|
|
5572
|
+
}
|
|
5573
|
+
function buildLocalSkillExtensionContent(candidates, context) {
|
|
5574
|
+
const lines = [
|
|
5575
|
+
"# Local Skill Preferences",
|
|
5576
|
+
"",
|
|
5577
|
+
"Use these opt-in local preferences when they are relevant to the current OrgX initiative. Do not override explicit user instructions or repo guardrails."
|
|
5578
|
+
];
|
|
5579
|
+
const trimmedContext = context?.trim();
|
|
5580
|
+
if (trimmedContext) {
|
|
5581
|
+
lines.push("", `Context: ${trimmedContext}`);
|
|
5582
|
+
}
|
|
5583
|
+
for (const candidate of candidates) {
|
|
5584
|
+
lines.push(
|
|
5585
|
+
"",
|
|
5586
|
+
`## ${candidate.title}`,
|
|
5587
|
+
"",
|
|
5588
|
+
`- Source: ${candidate.source} (${relative2(process.cwd(), candidate.path)})`,
|
|
5589
|
+
`- Suggested agents: ${candidate.agentDomains.join(", ")}`,
|
|
5590
|
+
`- Preserve: ${candidate.snippet || "local workflow preference from this skill file."}`
|
|
5591
|
+
);
|
|
5592
|
+
}
|
|
5593
|
+
return lines.join("\n");
|
|
5594
|
+
}
|
|
5595
|
+
|
|
5395
5596
|
// src/lib/mutation-output.ts
|
|
5396
5597
|
function summarizeMutationResults(results) {
|
|
5397
5598
|
return results.map((result) => ({
|
|
@@ -5913,6 +6114,40 @@ function normalizeHotkey(input) {
|
|
|
5913
6114
|
}
|
|
5914
6115
|
}
|
|
5915
6116
|
|
|
6117
|
+
// src/lib/setup-profiles.ts
|
|
6118
|
+
var SETUP_PROFILES = {
|
|
6119
|
+
"local-ai-workflow": {
|
|
6120
|
+
id: "local-ai-workflow",
|
|
6121
|
+
label: "Local AI workflow",
|
|
6122
|
+
firstInitiativeTitle: "Make local AI work visible and shippable",
|
|
6123
|
+
firstInitiativeSummary: [
|
|
6124
|
+
"First OrgX initiative tailored for a local AI-assisted workflow.",
|
|
6125
|
+
"Use local AI-session evidence, Git/GitHub proof, and existing project context to create a live work graph, a concrete onboarding task, and a path to cloud execution once GitHub is connected."
|
|
6126
|
+
].join(" "),
|
|
6127
|
+
handoffPrompt: "Use OrgX to continue this local AI-workflow initiative. Start with the onboarding task, inspect local AI-client and GitHub proof, preserve selected local skills, and show the next action plus the cloud handoff once GitHub is connected.",
|
|
6128
|
+
localProofCommand: "orgx-wizard sessions reconcile --from opencode,github --public-share --yes",
|
|
6129
|
+
skillDiscoveryCommand: `orgx-wizard skills discover-local --from opencode,claude,codex,workspace --context "Describe this person's domain, tools, and workflow"`
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
function resolveSetupProfile(id) {
|
|
6133
|
+
const normalized = id?.trim().toLowerCase();
|
|
6134
|
+
if (!normalized) return null;
|
|
6135
|
+
return SETUP_PROFILES[normalized] ?? null;
|
|
6136
|
+
}
|
|
6137
|
+
function supportedSetupProfileIds() {
|
|
6138
|
+
return Object.keys(SETUP_PROFILES).sort();
|
|
6139
|
+
}
|
|
6140
|
+
function buildProfileSummary(profile, context) {
|
|
6141
|
+
const trimmedContext = context?.trim();
|
|
6142
|
+
if (!trimmedContext) return profile.firstInitiativeSummary;
|
|
6143
|
+
return `${profile.firstInitiativeSummary} Context: ${trimmedContext}`;
|
|
6144
|
+
}
|
|
6145
|
+
function buildProfileHandoffPrompt(profile, fallbackPrompt, context) {
|
|
6146
|
+
if (!profile) return fallbackPrompt;
|
|
6147
|
+
const trimmedContext = context?.trim();
|
|
6148
|
+
return trimmedContext ? `${profile.handoffPrompt} Context: ${trimmedContext}` : profile.handoffPrompt;
|
|
6149
|
+
}
|
|
6150
|
+
|
|
5916
6151
|
// src/lib/daily-brief-onboarding.ts
|
|
5917
6152
|
function extractErrorHint(body) {
|
|
5918
6153
|
if (!body) return null;
|
|
@@ -6222,8 +6457,8 @@ async function fetchOnboardingState(auth) {
|
|
|
6222
6457
|
}
|
|
6223
6458
|
|
|
6224
6459
|
// src/lib/ai-session-import.ts
|
|
6225
|
-
import { existsSync as
|
|
6226
|
-
import { basename as
|
|
6460
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
6461
|
+
import { basename as basename3, join as join5, relative as relative3 } from "path";
|
|
6227
6462
|
var AI_SESSION_SOURCES = ["codex", "claude"];
|
|
6228
6463
|
var DEFAULT_LIMIT_PER_SOURCE = 3;
|
|
6229
6464
|
var DEFAULT_SINCE_DAYS = 30;
|
|
@@ -6376,7 +6611,7 @@ function keepAuditRelevantLines(text2) {
|
|
|
6376
6611
|
return text2.split(/\r?\n/).map((line) => normalizeAuditRelevantLine(line)).filter((line) => Boolean(line));
|
|
6377
6612
|
}
|
|
6378
6613
|
function collectJsonlFiles(root, source) {
|
|
6379
|
-
if (!
|
|
6614
|
+
if (!existsSync6(root)) return [];
|
|
6380
6615
|
const files = [];
|
|
6381
6616
|
const stack = [root];
|
|
6382
6617
|
while (stack.length > 0) {
|
|
@@ -6384,15 +6619,15 @@ function collectJsonlFiles(root, source) {
|
|
|
6384
6619
|
if (!current) continue;
|
|
6385
6620
|
let entries;
|
|
6386
6621
|
try {
|
|
6387
|
-
entries =
|
|
6622
|
+
entries = readdirSync4(current);
|
|
6388
6623
|
} catch {
|
|
6389
6624
|
continue;
|
|
6390
6625
|
}
|
|
6391
6626
|
for (const entry of entries) {
|
|
6392
|
-
const path =
|
|
6627
|
+
const path = join5(current, entry);
|
|
6393
6628
|
let stats;
|
|
6394
6629
|
try {
|
|
6395
|
-
stats =
|
|
6630
|
+
stats = statSync4(path);
|
|
6396
6631
|
} catch {
|
|
6397
6632
|
continue;
|
|
6398
6633
|
}
|
|
@@ -6410,13 +6645,13 @@ function collectJsonlFiles(root, source) {
|
|
|
6410
6645
|
function readSessionImport(candidate, root, options) {
|
|
6411
6646
|
let stats;
|
|
6412
6647
|
try {
|
|
6413
|
-
stats =
|
|
6648
|
+
stats = statSync4(candidate.path);
|
|
6414
6649
|
} catch {
|
|
6415
6650
|
return null;
|
|
6416
6651
|
}
|
|
6417
6652
|
if (stats.size > options.maxBytesPerFile) return null;
|
|
6418
6653
|
const extractor = candidate.source === "codex" ? extractCodexMessageText : extractClaudeMessageText;
|
|
6419
|
-
const lines =
|
|
6654
|
+
const lines = readFileSync4(candidate.path, "utf8").split(/\r?\n/);
|
|
6420
6655
|
const relevantLines = [];
|
|
6421
6656
|
let messageCount = 0;
|
|
6422
6657
|
for (const line of lines) {
|
|
@@ -6428,10 +6663,10 @@ function readSessionImport(candidate, root, options) {
|
|
|
6428
6663
|
}
|
|
6429
6664
|
const deduped = [...new Set(relevantLines)].slice(0, 80);
|
|
6430
6665
|
if (deduped.length === 0) return null;
|
|
6431
|
-
const relativePath =
|
|
6666
|
+
const relativePath = relative3(root, candidate.path);
|
|
6432
6667
|
return {
|
|
6433
6668
|
import: {
|
|
6434
|
-
sourceId: `${candidate.source}:${
|
|
6669
|
+
sourceId: `${candidate.source}:${basename3(candidate.path, ".jsonl")}`,
|
|
6435
6670
|
sourceLabel: `${candidate.source === "codex" ? "Codex" : "Claude"} session ${relativePath}`,
|
|
6436
6671
|
metadata: {
|
|
6437
6672
|
bytes: stats.size,
|
|
@@ -6501,11 +6736,11 @@ function loadAiSessionImports(options) {
|
|
|
6501
6736
|
}
|
|
6502
6737
|
|
|
6503
6738
|
// src/lib/work-graph-source-adapters.ts
|
|
6504
|
-
import { createHash as
|
|
6739
|
+
import { createHash as createHash4 } from "crypto";
|
|
6505
6740
|
import { execFileSync } from "child_process";
|
|
6506
|
-
import { closeSync, existsSync as
|
|
6741
|
+
import { closeSync, existsSync as existsSync7, openSync, readFileSync as readFileSync5, readdirSync as readdirSync5, readSync, statSync as statSync5 } from "fs";
|
|
6507
6742
|
import { homedir as homedir2 } from "os";
|
|
6508
|
-
import { basename as
|
|
6743
|
+
import { basename as basename4, join as join6, resolve } from "path";
|
|
6509
6744
|
var CLIENT_SOURCES = ["claude_code", "codex", "opencode", "goose", "cursor", "github", "slack"];
|
|
6510
6745
|
var DEFAULT_LIMIT_PER_SOURCE2 = 8;
|
|
6511
6746
|
var DEFAULT_SINCE_DAYS2 = 45;
|
|
@@ -6524,21 +6759,21 @@ function parseInvestigationSourceList(value) {
|
|
|
6524
6759
|
}
|
|
6525
6760
|
return deduped;
|
|
6526
6761
|
}
|
|
6527
|
-
function
|
|
6528
|
-
return
|
|
6762
|
+
function hash2(value, length = 24) {
|
|
6763
|
+
return createHash4("sha256").update(JSON.stringify(value)).digest("hex").slice(0, length);
|
|
6529
6764
|
}
|
|
6530
6765
|
function expandPath(path, env) {
|
|
6531
6766
|
return path.replace(/^~(?=\/|$)/, env.home).replace(/\$CWD/g, env.cwd).replace(/\$HOME/g, env.home);
|
|
6532
6767
|
}
|
|
6533
|
-
function
|
|
6768
|
+
function safeStat2(path) {
|
|
6534
6769
|
try {
|
|
6535
|
-
return
|
|
6770
|
+
return statSync5(path);
|
|
6536
6771
|
} catch {
|
|
6537
6772
|
return null;
|
|
6538
6773
|
}
|
|
6539
6774
|
}
|
|
6540
6775
|
function walkFiles(root, predicate, maxFiles = 500) {
|
|
6541
|
-
if (!
|
|
6776
|
+
if (!existsSync7(root)) return [];
|
|
6542
6777
|
const files = [];
|
|
6543
6778
|
const stack = [root];
|
|
6544
6779
|
const ignored = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist", "build", ".turbo"]);
|
|
@@ -6547,14 +6782,14 @@ function walkFiles(root, predicate, maxFiles = 500) {
|
|
|
6547
6782
|
if (!current) continue;
|
|
6548
6783
|
let entries;
|
|
6549
6784
|
try {
|
|
6550
|
-
entries =
|
|
6785
|
+
entries = readdirSync5(current);
|
|
6551
6786
|
} catch {
|
|
6552
6787
|
continue;
|
|
6553
6788
|
}
|
|
6554
6789
|
for (const entry of entries) {
|
|
6555
6790
|
if (ignored.has(entry)) continue;
|
|
6556
|
-
const path =
|
|
6557
|
-
const stats =
|
|
6791
|
+
const path = join6(current, entry);
|
|
6792
|
+
const stats = safeStat2(path);
|
|
6558
6793
|
if (!stats) continue;
|
|
6559
6794
|
if (stats.isDirectory()) {
|
|
6560
6795
|
stack.push(path);
|
|
@@ -6606,10 +6841,10 @@ function nowWindow(timestamp, now) {
|
|
|
6606
6841
|
return "older";
|
|
6607
6842
|
}
|
|
6608
6843
|
function makeRawEvent(input) {
|
|
6609
|
-
const contentHash =
|
|
6844
|
+
const contentHash = hash2(input.payload, 64);
|
|
6610
6845
|
const uri = `${input.client}:${input.sessionId}:${input.uriSuffix}`;
|
|
6611
6846
|
return {
|
|
6612
|
-
event_id: `evt_${
|
|
6847
|
+
event_id: `evt_${hash2([uri, contentHash], 24)}`,
|
|
6613
6848
|
source_ref: {
|
|
6614
6849
|
source_id: input.client,
|
|
6615
6850
|
uri,
|
|
@@ -6652,7 +6887,7 @@ function parseJsonLine2(line) {
|
|
|
6652
6887
|
}
|
|
6653
6888
|
function readTextWindow(path, stats, maxBytes) {
|
|
6654
6889
|
if (stats.size <= maxBytes) {
|
|
6655
|
-
return { text:
|
|
6890
|
+
return { text: readFileSync5(path, "utf8"), truncated: false };
|
|
6656
6891
|
}
|
|
6657
6892
|
const bytesToRead = Math.min(stats.size, maxBytes);
|
|
6658
6893
|
const buffer = Buffer.alloc(bytesToRead);
|
|
@@ -6796,7 +7031,7 @@ function mapClaudeRecord(record, fallbackTimestamp) {
|
|
|
6796
7031
|
return out;
|
|
6797
7032
|
}
|
|
6798
7033
|
function readJsonlCandidate(candidate, options) {
|
|
6799
|
-
const stats =
|
|
7034
|
+
const stats = safeStat2(candidate.path);
|
|
6800
7035
|
if (!stats) {
|
|
6801
7036
|
return {
|
|
6802
7037
|
collectionMethods: [],
|
|
@@ -6810,7 +7045,7 @@ function readJsonlCandidate(candidate, options) {
|
|
|
6810
7045
|
const window = readTextWindow(candidate.path, stats, options.maxBytesPerFile);
|
|
6811
7046
|
const lines = window.text.split(/\r?\n/);
|
|
6812
7047
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
6813
|
-
const sessionId =
|
|
7048
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6814
7049
|
const events = [];
|
|
6815
7050
|
for (const [index, line] of lines.entries()) {
|
|
6816
7051
|
if (!line.trim()) continue;
|
|
@@ -6873,7 +7108,7 @@ function mapGenericJsonRecord(record, fallbackTimestamp) {
|
|
|
6873
7108
|
}];
|
|
6874
7109
|
}
|
|
6875
7110
|
function readJsonCandidate(candidate, options) {
|
|
6876
|
-
const stats =
|
|
7111
|
+
const stats = safeStat2(candidate.path);
|
|
6877
7112
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6878
7113
|
return {
|
|
6879
7114
|
collectionMethods: [],
|
|
@@ -6886,7 +7121,7 @@ function readJsonCandidate(candidate, options) {
|
|
|
6886
7121
|
}
|
|
6887
7122
|
let parsed;
|
|
6888
7123
|
try {
|
|
6889
|
-
parsed = JSON.parse(
|
|
7124
|
+
parsed = JSON.parse(readFileSync5(candidate.path, "utf8"));
|
|
6890
7125
|
} catch {
|
|
6891
7126
|
return {
|
|
6892
7127
|
collectionMethods: [],
|
|
@@ -6899,7 +7134,7 @@ function readJsonCandidate(candidate, options) {
|
|
|
6899
7134
|
}
|
|
6900
7135
|
const records = flattenPotentialMessages(parsed).slice(0, 800);
|
|
6901
7136
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
6902
|
-
const sessionId =
|
|
7137
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6903
7138
|
const events = records.flatMap(
|
|
6904
7139
|
(record, index) => mapGenericJsonRecord(record, fallbackTimestamp).map(
|
|
6905
7140
|
(item, partIndex) => makeRawEvent({
|
|
@@ -6952,7 +7187,7 @@ function flattenPotentialMessages(value) {
|
|
|
6952
7187
|
return out;
|
|
6953
7188
|
}
|
|
6954
7189
|
function readMarkdownCandidate(candidate, options) {
|
|
6955
|
-
const stats =
|
|
7190
|
+
const stats = safeStat2(candidate.path);
|
|
6956
7191
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6957
7192
|
return {
|
|
6958
7193
|
collectionMethods: [],
|
|
@@ -6963,8 +7198,8 @@ function readMarkdownCandidate(candidate, options) {
|
|
|
6963
7198
|
searchedSessions: 0
|
|
6964
7199
|
};
|
|
6965
7200
|
}
|
|
6966
|
-
const text2 =
|
|
6967
|
-
const sessionId =
|
|
7201
|
+
const text2 = readFileSync5(candidate.path, "utf8");
|
|
7202
|
+
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
6968
7203
|
const timestamp = new Date(stats.mtimeMs).toISOString();
|
|
6969
7204
|
const event = makeRawEvent({
|
|
6970
7205
|
client: candidate.source,
|
|
@@ -6993,7 +7228,7 @@ function readMarkdownCandidate(candidate, options) {
|
|
|
6993
7228
|
};
|
|
6994
7229
|
}
|
|
6995
7230
|
function readGitReflogCandidate(candidate, options) {
|
|
6996
|
-
const stats =
|
|
7231
|
+
const stats = safeStat2(candidate.path);
|
|
6997
7232
|
if (!stats || stats.size > options.maxBytesPerFile) {
|
|
6998
7233
|
return {
|
|
6999
7234
|
collectionMethods: [],
|
|
@@ -7004,7 +7239,7 @@ function readGitReflogCandidate(candidate, options) {
|
|
|
7004
7239
|
searchedSessions: 0
|
|
7005
7240
|
};
|
|
7006
7241
|
}
|
|
7007
|
-
const lines =
|
|
7242
|
+
const lines = readFileSync5(candidate.path, "utf8").split(/\r?\n/).filter(Boolean).slice(-250);
|
|
7008
7243
|
const events = [];
|
|
7009
7244
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
7010
7245
|
for (const [index, line] of lines.entries()) {
|
|
@@ -7150,10 +7385,10 @@ function discoverCandidates(source, env, sinceMs) {
|
|
|
7150
7385
|
for (const rootPattern of paths) {
|
|
7151
7386
|
const expanded = expandPath(rootPattern, env);
|
|
7152
7387
|
const root = expanded.includes("*") ? expanded.slice(0, expanded.indexOf("*")).replace(/\/$/, "") : expanded;
|
|
7153
|
-
const exactStats =
|
|
7388
|
+
const exactStats = safeStat2(expanded);
|
|
7154
7389
|
const found = exactStats?.isFile() ? [expanded] : walkFiles(root, predicate);
|
|
7155
7390
|
for (const path of found) {
|
|
7156
|
-
const stats =
|
|
7391
|
+
const stats = safeStat2(path);
|
|
7157
7392
|
if (!stats || stats.mtimeMs < sinceMs) continue;
|
|
7158
7393
|
candidates.push({ extractionMode, mtimeMs: stats.mtimeMs, path, source });
|
|
7159
7394
|
}
|
|
@@ -7221,7 +7456,7 @@ function discoverOverrideCandidates(source, root, sinceMs) {
|
|
|
7221
7456
|
const files = walkFiles(root, (path) => path.endsWith(".jsonl") || path.endsWith(".json"));
|
|
7222
7457
|
const candidates = [];
|
|
7223
7458
|
for (const path of files) {
|
|
7224
|
-
const stats =
|
|
7459
|
+
const stats = safeStat2(path);
|
|
7225
7460
|
if (!stats || stats.mtimeMs < sinceMs) continue;
|
|
7226
7461
|
candidates.push({ extractionMode, mtimeMs: stats.mtimeMs, path, source });
|
|
7227
7462
|
}
|
|
@@ -7296,7 +7531,7 @@ function extractionFromEvents(input) {
|
|
|
7296
7531
|
}
|
|
7297
7532
|
return {
|
|
7298
7533
|
schema_version: "2.0.0.investigation",
|
|
7299
|
-
extraction_id: `${input.client}:investigation:${
|
|
7534
|
+
extraction_id: `${input.client}:investigation:${hash2([input.client, input.events.map((event) => event.event_id)], 12)}`,
|
|
7300
7535
|
source_client: workGraphSourceClient(input.client),
|
|
7301
7536
|
source_label: clientLabel(input.client),
|
|
7302
7537
|
collection_methods: [...new Set(input.collectionMethods)].sort(),
|
|
@@ -7389,7 +7624,7 @@ function loadWorkGraphInvestigationSourceData(options) {
|
|
|
7389
7624
|
}
|
|
7390
7625
|
|
|
7391
7626
|
// src/lib/self-audit.ts
|
|
7392
|
-
import { createHash as
|
|
7627
|
+
import { createHash as createHash5 } from "crypto";
|
|
7393
7628
|
var SELF_AUDIT_SCHEMA_VERSION = "2026-04-27";
|
|
7394
7629
|
var AUDIT_DIMENSIONS = [
|
|
7395
7630
|
"queryability",
|
|
@@ -7556,7 +7791,7 @@ function buildSelfCritique(scores) {
|
|
|
7556
7791
|
});
|
|
7557
7792
|
}
|
|
7558
7793
|
function hashPlanPayload(payload) {
|
|
7559
|
-
return
|
|
7794
|
+
return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
7560
7795
|
}
|
|
7561
7796
|
function buildSelfAuditPlan(input) {
|
|
7562
7797
|
if (input.imports.length === 0) {
|
|
@@ -7886,10 +8121,10 @@ Rollback: ${plan.recommended_follow_up.rollback}`,
|
|
|
7886
8121
|
}
|
|
7887
8122
|
|
|
7888
8123
|
// src/lib/work-graph.ts
|
|
7889
|
-
import { createHash as
|
|
8124
|
+
import { createHash as createHash7 } from "crypto";
|
|
7890
8125
|
|
|
7891
8126
|
// src/lib/work-graph-investigation.ts
|
|
7892
|
-
import { createHash as
|
|
8127
|
+
import { createHash as createHash6 } from "crypto";
|
|
7893
8128
|
var WORK_GRAPH_INVESTIGATION_SCHEMA_VERSION = "2.0.0";
|
|
7894
8129
|
var WORK_GRAPH_INVESTIGATION_CLIENTS = [
|
|
7895
8130
|
"claude_code",
|
|
@@ -8021,8 +8256,8 @@ var CAPABILITY_CEILINGS = {
|
|
|
8021
8256
|
decision_lineage: "high"
|
|
8022
8257
|
}
|
|
8023
8258
|
};
|
|
8024
|
-
function
|
|
8025
|
-
return
|
|
8259
|
+
function hash3(value, length = 16) {
|
|
8260
|
+
return createHash6("sha256").update(JSON.stringify(value)).digest("hex").slice(0, length);
|
|
8026
8261
|
}
|
|
8027
8262
|
function clamp(value, min = 0, max = 1) {
|
|
8028
8263
|
return Math.max(min, Math.min(max, value));
|
|
@@ -8075,8 +8310,8 @@ function loopTopicKey(loop) {
|
|
|
8075
8310
|
for (const [pattern, topic] of topicRules) {
|
|
8076
8311
|
if (pattern.test(text2)) return topic;
|
|
8077
8312
|
}
|
|
8078
|
-
if (!intent) return `unclassified:${
|
|
8079
|
-
return `topic:${
|
|
8313
|
+
if (!intent) return `unclassified:${hash3(loop.loop_id, 10)}`;
|
|
8314
|
+
return `topic:${hash3(intent.toLowerCase(), 10)}`;
|
|
8080
8315
|
}
|
|
8081
8316
|
function bestFamilyCentroid(group) {
|
|
8082
8317
|
const candidates = group.map((loop) => cleanLoopIntent(loop.origin.intent, "")).filter(Boolean).map((intent) => {
|
|
@@ -8140,7 +8375,7 @@ function windowFor(timestamp, now) {
|
|
|
8140
8375
|
function rawEventFromFinding(finding, index, generatedAt) {
|
|
8141
8376
|
const sourceClient = normalizeClient(finding.source_client);
|
|
8142
8377
|
const timestamp = typeof finding.metadata.occurred_at === "string" ? finding.metadata.occurred_at : generatedAt;
|
|
8143
|
-
const eventId = `evt_${
|
|
8378
|
+
const eventId = `evt_${hash3([finding.evidence_ref, finding.title, index], 24)}`;
|
|
8144
8379
|
const payload = {
|
|
8145
8380
|
title: finding.title,
|
|
8146
8381
|
summary: finding.summary,
|
|
@@ -8172,7 +8407,7 @@ function rawEventFromFinding(finding, index, generatedAt) {
|
|
|
8172
8407
|
payload,
|
|
8173
8408
|
raw_byte_offset: null,
|
|
8174
8409
|
raw_row_id: null,
|
|
8175
|
-
content_hash:
|
|
8410
|
+
content_hash: hash3(payload, 64),
|
|
8176
8411
|
redaction_applied: true
|
|
8177
8412
|
};
|
|
8178
8413
|
}
|
|
@@ -8184,7 +8419,7 @@ function rawEventFromSourceEvent(event, index, generatedAt) {
|
|
|
8184
8419
|
text_summary: event.text.slice(0, 420)
|
|
8185
8420
|
};
|
|
8186
8421
|
return {
|
|
8187
|
-
event_id: `evt_${
|
|
8422
|
+
event_id: `evt_${hash3([event.evidence_ref, index], 24)}`,
|
|
8188
8423
|
source_ref: {
|
|
8189
8424
|
source_id: sourceClient,
|
|
8190
8425
|
uri: event.evidence_ref,
|
|
@@ -8202,7 +8437,7 @@ function rawEventFromSourceEvent(event, index, generatedAt) {
|
|
|
8202
8437
|
payload,
|
|
8203
8438
|
raw_byte_offset: null,
|
|
8204
8439
|
raw_row_id: null,
|
|
8205
|
-
content_hash:
|
|
8440
|
+
content_hash: hash3(payload, 64),
|
|
8206
8441
|
redaction_applied: true
|
|
8207
8442
|
};
|
|
8208
8443
|
}
|
|
@@ -8333,7 +8568,7 @@ function buildWorkLoops(input) {
|
|
|
8333
8568
|
trail.confidence || matchedFindings.reduce((total, finding) => total + finding.confidence, 0) / Math.max(1, matchedFindings.length)
|
|
8334
8569
|
);
|
|
8335
8570
|
return {
|
|
8336
|
-
loop_id: `loop_${
|
|
8571
|
+
loop_id: `loop_${hash3([trail.id, index], 18)}`,
|
|
8337
8572
|
cites: eventIds,
|
|
8338
8573
|
origin: {
|
|
8339
8574
|
event_id: eventIds[0] ?? `evt_missing_${index}`,
|
|
@@ -8419,7 +8654,7 @@ function buildLoopFamilies(loops, events, impact) {
|
|
|
8419
8654
|
(loop) => loop.cites.map((cite) => events.find((event) => event.event_id === cite)?.source_id).filter(Boolean)
|
|
8420
8655
|
)
|
|
8421
8656
|
);
|
|
8422
|
-
const familyId = `family_${
|
|
8657
|
+
const familyId = `family_${hash3(key, 16)}`;
|
|
8423
8658
|
const timestamps = group.map((loop) => Date.parse(loop.origin.timestamp)).filter(Number.isFinite);
|
|
8424
8659
|
const spanDays = timestamps.length > 1 ? Math.max(1, Math.ceil((Math.max(...timestamps) - Math.min(...timestamps)) / 864e5)) : 0;
|
|
8425
8660
|
const publicLoopCount = group.filter((loop) => loop.public_surface).length;
|
|
@@ -8772,7 +9007,7 @@ function counterfactualForLoop(loop, family) {
|
|
|
8772
9007
|
orgx_outcome: repair.expected_outcome,
|
|
8773
9008
|
resulting_entity: {
|
|
8774
9009
|
kind: entityKind,
|
|
8775
|
-
inferred_id: `orgx_${entityKind}_${
|
|
9010
|
+
inferred_id: `orgx_${entityKind}_${hash3(loop.loop_id, 12)}`,
|
|
8776
9011
|
would_link_to: loop.cites
|
|
8777
9012
|
},
|
|
8778
9013
|
realism_score: Number(realism.toFixed(2)),
|
|
@@ -8983,7 +9218,7 @@ function buildMirror(input) {
|
|
|
8983
9218
|
};
|
|
8984
9219
|
}
|
|
8985
9220
|
function buildWorkGraphInvestigation(input) {
|
|
8986
|
-
const auditId = `wgi_${
|
|
9221
|
+
const auditId = `wgi_${hash3([input.fingerprint, input.generatedAt], 24)}`;
|
|
8987
9222
|
const rawEvents = buildRawEvents(input);
|
|
8988
9223
|
const corpus = buildCorpusManifest({
|
|
8989
9224
|
auditId,
|
|
@@ -9124,7 +9359,7 @@ function clampScore2(value) {
|
|
|
9124
9359
|
return Math.max(0, Math.min(100, Math.round(value)));
|
|
9125
9360
|
}
|
|
9126
9361
|
function hashJson(value) {
|
|
9127
|
-
return
|
|
9362
|
+
return createHash7("sha256").update(JSON.stringify(value)).digest("hex");
|
|
9128
9363
|
}
|
|
9129
9364
|
function normalizeFingerprintText(value) {
|
|
9130
9365
|
return value.toLowerCase().replace(/https?:\/\/\S+/g, "url").replace(/[0-9a-f]{12,}/g, "hash").replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/g, "uuid").replace(/\s+/g, " ").trim().slice(0, 600);
|
|
@@ -10353,6 +10588,7 @@ ${finding.summary}`)
|
|
|
10353
10588
|
coverage,
|
|
10354
10589
|
findings
|
|
10355
10590
|
});
|
|
10591
|
+
const tiers = computeTiers({ stackScore, durabilityScore });
|
|
10356
10592
|
return {
|
|
10357
10593
|
aq,
|
|
10358
10594
|
stack_score: stackScore,
|
|
@@ -10362,6 +10598,7 @@ ${finding.summary}`)
|
|
|
10362
10598
|
source_bonus: sourceBonus,
|
|
10363
10599
|
context_leak_score: contextLeakScore,
|
|
10364
10600
|
archetype,
|
|
10601
|
+
tiers,
|
|
10365
10602
|
repair_quests: repairQuests,
|
|
10366
10603
|
notes: [
|
|
10367
10604
|
"AQ is source-positive: connected sources, proof, and runtime writeback raise the current score; missing sources raise the ceiling and repair quests instead of lowering the current score.",
|
|
@@ -10444,6 +10681,56 @@ function buildAgenticRepairQuests(input) {
|
|
|
10444
10681
|
}
|
|
10445
10682
|
return quests.sort((left, right) => right.expected_aq_lift - left.expected_aq_lift).slice(0, 6);
|
|
10446
10683
|
}
|
|
10684
|
+
var STACK_TIER_LABELS = {
|
|
10685
|
+
1: "Prompt Tourist",
|
|
10686
|
+
2: "Assisted",
|
|
10687
|
+
3: "Operator",
|
|
10688
|
+
4: "AI-Forward",
|
|
10689
|
+
5: "AI-Maxed",
|
|
10690
|
+
6: "Distributed Agent"
|
|
10691
|
+
};
|
|
10692
|
+
var DURABLE_TIER_LABELS = {
|
|
10693
|
+
1: "Transcript Graveyard",
|
|
10694
|
+
2: "Context Leaking",
|
|
10695
|
+
3: "Partial Memory",
|
|
10696
|
+
4: "Durable",
|
|
10697
|
+
5: "Compounding",
|
|
10698
|
+
6: "Compounding Org"
|
|
10699
|
+
};
|
|
10700
|
+
function stackTier(score) {
|
|
10701
|
+
if (score < 25) return 1;
|
|
10702
|
+
if (score < 45) return 2;
|
|
10703
|
+
if (score < 55) return 3;
|
|
10704
|
+
if (score < 70) return 4;
|
|
10705
|
+
if (score < 85) return 5;
|
|
10706
|
+
return 6;
|
|
10707
|
+
}
|
|
10708
|
+
function durableTier(score) {
|
|
10709
|
+
if (score < 25) return 1;
|
|
10710
|
+
if (score < 45) return 2;
|
|
10711
|
+
if (score < 60) return 3;
|
|
10712
|
+
if (score < 75) return 4;
|
|
10713
|
+
if (score < 90) return 5;
|
|
10714
|
+
return 6;
|
|
10715
|
+
}
|
|
10716
|
+
function computeTiers(input) {
|
|
10717
|
+
const sTier = stackTier(input.stackScore);
|
|
10718
|
+
const dTier = durableTier(input.durabilityScore);
|
|
10719
|
+
return {
|
|
10720
|
+
stack: { tier: sTier, label: STACK_TIER_LABELS[sTier] },
|
|
10721
|
+
durable: { tier: dTier, label: DURABLE_TIER_LABELS[dTier] }
|
|
10722
|
+
};
|
|
10723
|
+
}
|
|
10724
|
+
var ARCHETYPE_PRIMARIES = {
|
|
10725
|
+
mcp_necromancer: "Tool-Rich, Memory-Poor",
|
|
10726
|
+
ai_native_operator: "Connected & Durable",
|
|
10727
|
+
proof_maximalist: "Heavy on Receipts",
|
|
10728
|
+
context_leaker: "Tools In, Proof Out",
|
|
10729
|
+
agent_wrangler: "Agents Without Ops",
|
|
10730
|
+
decision_ghost: "Decisions Without Records",
|
|
10731
|
+
careful_operator: "Small Stack, Tight Loop",
|
|
10732
|
+
prompt_tourist: "Early Days"
|
|
10733
|
+
};
|
|
10447
10734
|
function assignAgenticArchetype(input) {
|
|
10448
10735
|
const { stackScore, durabilityScore, contextLeakScore, agenticGap, criticPassRatio } = input;
|
|
10449
10736
|
const toolFailureCount = input.findings.filter(
|
|
@@ -10460,6 +10747,7 @@ ${finding.summary}`)
|
|
|
10460
10747
|
return {
|
|
10461
10748
|
id: "ai_native_operator",
|
|
10462
10749
|
label: "AI-Native Operator",
|
|
10750
|
+
primary: ARCHETYPE_PRIMARIES.ai_native_operator,
|
|
10463
10751
|
roast: "The agents are working and the receipts mostly survive contact with reality.",
|
|
10464
10752
|
truth: "Your work is both agent-rich and increasingly durable.",
|
|
10465
10753
|
repair: "Scale the loop into weekly deltas and team-level source coverage."
|
|
@@ -10469,6 +10757,7 @@ ${finding.summary}`)
|
|
|
10469
10757
|
return {
|
|
10470
10758
|
id: "proof_maximalist",
|
|
10471
10759
|
label: "Proof Maximalist",
|
|
10760
|
+
primary: ARCHETYPE_PRIMARIES.proof_maximalist,
|
|
10472
10761
|
roast: "Annoyingly competent. Receipts attached.",
|
|
10473
10762
|
truth: "Verification and ownership are the strong parts of your system.",
|
|
10474
10763
|
repair: "Use the proof base to widen the agent stack."
|
|
@@ -10478,6 +10767,7 @@ ${finding.summary}`)
|
|
|
10478
10767
|
return {
|
|
10479
10768
|
id: "mcp_necromancer",
|
|
10480
10769
|
label: "MCP Necromancer",
|
|
10770
|
+
primary: ARCHETYPE_PRIMARIES.mcp_necromancer,
|
|
10481
10771
|
roast: "You summoned the tools; a few still need contracts.",
|
|
10482
10772
|
truth: "Your stack is rich, but repeated tool failures are leaking context.",
|
|
10483
10773
|
repair: "Add runtime hook replay and tool-contract proof before expanding the stack."
|
|
@@ -10487,6 +10777,7 @@ ${finding.summary}`)
|
|
|
10487
10777
|
return {
|
|
10488
10778
|
id: "context_leaker",
|
|
10489
10779
|
label: "Context Leaker",
|
|
10780
|
+
primary: ARCHETYPE_PRIMARIES.context_leaker,
|
|
10490
10781
|
roast: "Your stack is cooking. Your operating memory is evaporating.",
|
|
10491
10782
|
truth: "A lot is happening, but too much of it dies in sessions.",
|
|
10492
10783
|
repair: "Enable runtime hooks, connect proof sources, and promote trapped decisions."
|
|
@@ -10496,6 +10787,7 @@ ${finding.summary}`)
|
|
|
10496
10787
|
return {
|
|
10497
10788
|
id: "agent_wrangler",
|
|
10498
10789
|
label: "Agent Wrangler",
|
|
10790
|
+
primary: ARCHETYPE_PRIMARIES.agent_wrangler,
|
|
10499
10791
|
roast: "You have agents. They do not yet have an operating system.",
|
|
10500
10792
|
truth: "Delegation is happening, but coordination proof is thin.",
|
|
10501
10793
|
repair: "Promote owner-visible workstreams and attach proof to agent handoffs."
|
|
@@ -10505,6 +10797,7 @@ ${finding.summary}`)
|
|
|
10505
10797
|
return {
|
|
10506
10798
|
id: "decision_ghost",
|
|
10507
10799
|
label: "Decision Ghost",
|
|
10800
|
+
primary: ARCHETYPE_PRIMARIES.decision_ghost,
|
|
10508
10801
|
roast: "Your best calls are haunting transcripts instead of steering work.",
|
|
10509
10802
|
truth: "Decision evidence exists, but durable decision records are weak.",
|
|
10510
10803
|
repair: "Promote decisions with commit, owner, and outcome refs."
|
|
@@ -10514,6 +10807,7 @@ ${finding.summary}`)
|
|
|
10514
10807
|
return {
|
|
10515
10808
|
id: "careful_operator",
|
|
10516
10809
|
label: "Careful Operator",
|
|
10810
|
+
primary: ARCHETYPE_PRIMARIES.careful_operator,
|
|
10517
10811
|
roast: "Small stack, strong receipts.",
|
|
10518
10812
|
truth: "You use fewer agents, but the work you do run tends to compound.",
|
|
10519
10813
|
repair: "Add one new client or proof source without weakening durability."
|
|
@@ -10522,6 +10816,7 @@ ${finding.summary}`)
|
|
|
10522
10816
|
return {
|
|
10523
10817
|
id: "prompt_tourist",
|
|
10524
10818
|
label: "Prompt Tourist",
|
|
10819
|
+
primary: ARCHETYPE_PRIMARIES.prompt_tourist,
|
|
10525
10820
|
roast: "You are early enough that the score is still honest, not embarrassing.",
|
|
10526
10821
|
truth: "There is not enough durable agent work yet to call this a compounding system.",
|
|
10527
10822
|
repair: "Pick one client, run real work through it, then connect proof."
|
|
@@ -12155,14 +12450,14 @@ function renderWorkGraphMarkdown(report, options = {}) {
|
|
|
12155
12450
|
}
|
|
12156
12451
|
|
|
12157
12452
|
// src/lib/work-graph-publish.ts
|
|
12158
|
-
import { createHash as
|
|
12453
|
+
import { createHash as createHash8, randomUUID as randomUUID2 } from "crypto";
|
|
12159
12454
|
import { gzipSync } from "zlib";
|
|
12160
12455
|
var WORK_GRAPH_REPORT_GZIP_THRESHOLD_BYTES = 4e6;
|
|
12161
12456
|
var WORK_GRAPH_REPORT_CHUNK_UPLOAD_THRESHOLD_BYTES = 5e5;
|
|
12162
12457
|
var WORK_GRAPH_REPORT_CHUNK_CHARS = 3e4;
|
|
12163
12458
|
var WORK_GRAPH_REPORT_CHUNK_UPLOAD_TIMEOUT_MS = 3e5;
|
|
12164
12459
|
function hashText(value) {
|
|
12165
|
-
return
|
|
12460
|
+
return createHash8("sha256").update(value).digest("hex");
|
|
12166
12461
|
}
|
|
12167
12462
|
function buildWorkGraphReportPostPayload(report, options = {}) {
|
|
12168
12463
|
return {
|
|
@@ -12369,8 +12664,8 @@ async function publishWorkGraphEvents(fingerprint, patch, options = {}) {
|
|
|
12369
12664
|
}
|
|
12370
12665
|
|
|
12371
12666
|
// src/lib/work-graph-hook-events.ts
|
|
12372
|
-
import { createHash as
|
|
12373
|
-
import { existsSync as
|
|
12667
|
+
import { createHash as createHash9 } from "crypto";
|
|
12668
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
12374
12669
|
var SOURCE_CLIENTS = [
|
|
12375
12670
|
"codex",
|
|
12376
12671
|
"claude",
|
|
@@ -12404,7 +12699,7 @@ function asStringArray(value) {
|
|
|
12404
12699
|
return value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
12405
12700
|
}
|
|
12406
12701
|
function stableHash(value) {
|
|
12407
|
-
return
|
|
12702
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, 20);
|
|
12408
12703
|
}
|
|
12409
12704
|
function normalizeSourceClient2(value) {
|
|
12410
12705
|
const raw = asString2(value)?.toLowerCase();
|
|
@@ -12471,8 +12766,8 @@ function readHookRecord(line) {
|
|
|
12471
12766
|
}
|
|
12472
12767
|
}
|
|
12473
12768
|
function readRuntimeHookOutbox(path, limit = 200) {
|
|
12474
|
-
if (!
|
|
12475
|
-
const lines =
|
|
12769
|
+
if (!existsSync8(path)) return { path, records: [], skipped: 0 };
|
|
12770
|
+
const lines = readFileSync6(path, "utf8").split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
12476
12771
|
const selected = lines.slice(Math.max(0, lines.length - Math.max(1, limit)));
|
|
12477
12772
|
const records = [];
|
|
12478
12773
|
let skipped = Math.max(0, lines.length - selected.length);
|
|
@@ -12608,20 +12903,20 @@ function buildWorkGraphHookReplayPatch(readResult) {
|
|
|
12608
12903
|
}
|
|
12609
12904
|
|
|
12610
12905
|
// src/lib/runtime-hooks.ts
|
|
12611
|
-
import { copyFileSync, existsSync as
|
|
12906
|
+
import { copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "fs";
|
|
12612
12907
|
import { homedir as homedir3 } from "os";
|
|
12613
|
-
import { dirname as dirname4, join as
|
|
12908
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
12614
12909
|
var HOOK_MARKER = "orgx-session-hook.mjs";
|
|
12615
12910
|
var HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PermissionRequest", "Stop"];
|
|
12616
12911
|
var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "SubagentStop", "Stop", "SessionEnd"];
|
|
12617
12912
|
function defaultPaths(options = {}) {
|
|
12618
|
-
const hookDir =
|
|
12913
|
+
const hookDir = join7(ORGX_WIZARD_CONFIG_HOME, "hooks");
|
|
12619
12914
|
return {
|
|
12620
|
-
claudeSettingsPath: options.claudeSettingsPath ??
|
|
12621
|
-
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ??
|
|
12622
|
-
codexHooksPath: options.codexHooksPath ??
|
|
12623
|
-
hookScriptPath: options.hookScriptPath ??
|
|
12624
|
-
outboxPath: options.outboxPath ??
|
|
12915
|
+
claudeSettingsPath: options.claudeSettingsPath ?? join7(CLAUDE_DIR, "settings.json"),
|
|
12916
|
+
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ?? join7(CODEX_DIR, "config.toml"),
|
|
12917
|
+
codexHooksPath: options.codexHooksPath ?? join7(CODEX_DIR, "hooks.json"),
|
|
12918
|
+
hookScriptPath: options.hookScriptPath ?? join7(hookDir, HOOK_MARKER),
|
|
12919
|
+
outboxPath: options.outboxPath ?? join7(hookDir, "events.jsonl")
|
|
12625
12920
|
};
|
|
12626
12921
|
}
|
|
12627
12922
|
function countJsonlLines(path) {
|
|
@@ -12634,7 +12929,7 @@ function backupPath(path, now) {
|
|
|
12634
12929
|
return `${path}.bak.${timestamp}`;
|
|
12635
12930
|
}
|
|
12636
12931
|
function backupExisting(path, now) {
|
|
12637
|
-
if (!
|
|
12932
|
+
if (!existsSync9(path)) return null;
|
|
12638
12933
|
const backup = backupPath(path, now);
|
|
12639
12934
|
copyFileSync(path, backup);
|
|
12640
12935
|
return backup;
|
|
@@ -12832,7 +13127,7 @@ function inspectRuntimeHooks(options = {}) {
|
|
|
12832
13127
|
installed: {
|
|
12833
13128
|
claudeCode: hasOrgxHook(claudeSettingsRaw),
|
|
12834
13129
|
codex: hasOrgxHook(codexHooksRaw),
|
|
12835
|
-
hookScript:
|
|
13130
|
+
hookScript: existsSync9(paths.hookScriptPath)
|
|
12836
13131
|
},
|
|
12837
13132
|
codex: {
|
|
12838
13133
|
configExists: Boolean(codexConfigRaw),
|
|
@@ -13094,10 +13389,10 @@ async function runHookReplayCommand(options) {
|
|
|
13094
13389
|
}
|
|
13095
13390
|
function readAuditInput(options, interactive) {
|
|
13096
13391
|
if (options.input?.trim()) {
|
|
13097
|
-
return
|
|
13392
|
+
return readFileSync8(resolve2(options.input.trim()), "utf8");
|
|
13098
13393
|
}
|
|
13099
13394
|
if (!process.stdin.isTTY) {
|
|
13100
|
-
return
|
|
13395
|
+
return readFileSync8(0, "utf8");
|
|
13101
13396
|
}
|
|
13102
13397
|
if (!interactive) {
|
|
13103
13398
|
throw new Error("Audit input is required. Pass --input <file> or pipe text into wizard audit.");
|
|
@@ -13130,7 +13425,7 @@ function collectPathOption(value, previous = []) {
|
|
|
13130
13425
|
}
|
|
13131
13426
|
function parseClientExtractionFile(path) {
|
|
13132
13427
|
const resolvedPath = resolve2(path);
|
|
13133
|
-
const parsed = JSON.parse(
|
|
13428
|
+
const parsed = JSON.parse(readFileSync8(resolvedPath, "utf8"));
|
|
13134
13429
|
if (!isRecord(parsed)) {
|
|
13135
13430
|
throw new Error(`AI-client extraction must be a JSON object: ${resolvedPath}`);
|
|
13136
13431
|
}
|
|
@@ -13615,6 +13910,40 @@ function printSkillExtensions(extensions) {
|
|
|
13615
13910
|
);
|
|
13616
13911
|
}
|
|
13617
13912
|
}
|
|
13913
|
+
function printLocalSkillCandidates(candidates) {
|
|
13914
|
+
if (candidates.length === 0) {
|
|
13915
|
+
console.log(` ${ICON.skip} ${pc3.dim("no local skill files found")}`);
|
|
13916
|
+
return;
|
|
13917
|
+
}
|
|
13918
|
+
candidates.forEach((candidate, index) => {
|
|
13919
|
+
const domains = candidate.agentDomains.join(", ");
|
|
13920
|
+
console.log(
|
|
13921
|
+
` ${ICON.ok} ${pc3.bold(String(index + 1).padStart(2, " "))} ${pc3.bold(candidate.title)} ${pc3.dim(candidate.id)}`
|
|
13922
|
+
);
|
|
13923
|
+
console.log(` ${pc3.dim(`${candidate.source} \xB7 ${domains} \xB7 ${candidate.reason}`)}`);
|
|
13924
|
+
console.log(` ${pc3.dim(candidate.path)}`);
|
|
13925
|
+
if (candidate.snippet) {
|
|
13926
|
+
console.log(` ${pc3.dim(candidate.snippet)}`);
|
|
13927
|
+
}
|
|
13928
|
+
});
|
|
13929
|
+
}
|
|
13930
|
+
function writeLocalSkillSelection(input) {
|
|
13931
|
+
const scope = input.scope ?? "user";
|
|
13932
|
+
const nextContent = buildLocalSkillExtensionContent(input.candidates, input.context);
|
|
13933
|
+
const existing = listSkillExtensions().find(
|
|
13934
|
+
(extension) => extension.skillId === "orgx" && extension.scope === scope
|
|
13935
|
+
);
|
|
13936
|
+
const content = existing?.content.trim() ? `${existing.content.trimEnd()}
|
|
13937
|
+
|
|
13938
|
+
${nextContent}` : nextContent;
|
|
13939
|
+
return addSkillExtension({
|
|
13940
|
+
content,
|
|
13941
|
+
overwrite: true,
|
|
13942
|
+
scope,
|
|
13943
|
+
skillId: "orgx",
|
|
13944
|
+
title: "Local skill preferences"
|
|
13945
|
+
});
|
|
13946
|
+
}
|
|
13618
13947
|
function printSkillExtensionWrite(result) {
|
|
13619
13948
|
const action = result.created ? "created" : result.changed ? "updated" : "unchanged";
|
|
13620
13949
|
const color = result.created || result.changed ? pc3.green : pc3.dim;
|
|
@@ -13680,6 +14009,8 @@ function printSetupScopeNote() {
|
|
|
13680
14009
|
}
|
|
13681
14010
|
function printFirstValueHandoff(input) {
|
|
13682
14011
|
const cmd = getCmd();
|
|
14012
|
+
const fallbackPrompt = `Use OrgX to continue "${input.initiative.initiative.title}" in ${input.workspace.name}. Show the next action, then start with the onboarding task.`;
|
|
14013
|
+
const handoffPrompt = buildProfileHandoffPrompt(input.profile, fallbackPrompt, input.context);
|
|
13683
14014
|
console.log("");
|
|
13684
14015
|
console.log(pc3.bold("first OrgX handoff"));
|
|
13685
14016
|
console.log(
|
|
@@ -13688,9 +14019,13 @@ function printFirstValueHandoff(input) {
|
|
|
13688
14019
|
console.log(` live: ${input.initiative.liveUrl}`);
|
|
13689
14020
|
console.log(
|
|
13690
14021
|
` ${pc3.dim("ask your AI tool:")} ${pc3.cyan(
|
|
13691
|
-
|
|
14022
|
+
handoffPrompt
|
|
13692
14023
|
)}`
|
|
13693
14024
|
);
|
|
14025
|
+
if (input.profile) {
|
|
14026
|
+
console.log(` ${pc3.dim("local proof:")} ${pc3.cyan(input.profile.localProofCommand)}`);
|
|
14027
|
+
console.log(` ${pc3.dim("skills:")} ${pc3.cyan(input.profile.skillDiscoveryCommand)}`);
|
|
14028
|
+
}
|
|
13694
14029
|
console.log(` ${pc3.dim("later:")} ${pc3.cyan(`${cmd} doctor`)} ${pc3.dim("checks tool wiring")}`);
|
|
13695
14030
|
}
|
|
13696
14031
|
function firstValueRecordToResult(record) {
|
|
@@ -14180,7 +14515,7 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14180
14515
|
}
|
|
14181
14516
|
if (firstInitiativeChoice === "yes") {
|
|
14182
14517
|
const title = await textPrompt({
|
|
14183
|
-
initialValue: FIRST_VALUE_INITIATIVE_TITLE,
|
|
14518
|
+
initialValue: input.profile?.firstInitiativeTitle ?? FIRST_VALUE_INITIATIVE_TITLE,
|
|
14184
14519
|
message: "What should OrgX help you move forward first?",
|
|
14185
14520
|
validate: (value) => {
|
|
14186
14521
|
if (!value || value.trim().length === 0) {
|
|
@@ -14197,6 +14532,7 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14197
14532
|
spinner.start();
|
|
14198
14533
|
try {
|
|
14199
14534
|
firstValueInitiative = await ensureFirstValueInitiative(input.workspace, {
|
|
14535
|
+
...input.context || input.profile ? { summary: input.profile ? buildProfileSummary(input.profile, input.context) : input.context } : {},
|
|
14200
14536
|
title: String(title)
|
|
14201
14537
|
});
|
|
14202
14538
|
spinner.succeed(
|
|
@@ -14287,7 +14623,9 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14287
14623
|
}
|
|
14288
14624
|
if (firstValueInitiative) {
|
|
14289
14625
|
printFirstValueHandoff({
|
|
14626
|
+
...input.context ? { context: input.context } : {},
|
|
14290
14627
|
initiative: firstValueInitiative,
|
|
14628
|
+
...input.profile !== void 0 ? { profile: input.profile } : {},
|
|
14291
14629
|
workspace: input.workspace
|
|
14292
14630
|
});
|
|
14293
14631
|
}
|
|
@@ -14360,6 +14698,64 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
14360
14698
|
});
|
|
14361
14699
|
}
|
|
14362
14700
|
}
|
|
14701
|
+
const localSkillDiscoverySkipped = hasSetupPromptSkip(
|
|
14702
|
+
input.workspace.id,
|
|
14703
|
+
"local_skill_discovery"
|
|
14704
|
+
);
|
|
14705
|
+
if (!localSkillDiscoverySkipped) {
|
|
14706
|
+
const context = input.context?.trim();
|
|
14707
|
+
const candidates = discoverLocalSkills({
|
|
14708
|
+
...context ? { context } : {},
|
|
14709
|
+
limit: 8
|
|
14710
|
+
});
|
|
14711
|
+
if (candidates.length > 0) {
|
|
14712
|
+
const selectedSkillIds = await multiselectPrompt({
|
|
14713
|
+
message: "Bring existing local skills into your OrgX agents?",
|
|
14714
|
+
options: [
|
|
14715
|
+
...candidates.map((candidate, index) => ({
|
|
14716
|
+
value: candidate.id,
|
|
14717
|
+
label: `${index + 1}. ${candidate.title}`,
|
|
14718
|
+
hint: `${candidate.source} \xB7 ${candidate.agentDomains.join(", ")} \xB7 ${candidate.reason}`
|
|
14719
|
+
})),
|
|
14720
|
+
{
|
|
14721
|
+
value: "__skip__",
|
|
14722
|
+
label: "Skip local skill import",
|
|
14723
|
+
hint: "You can run `orgx-wizard skills discover-local` later."
|
|
14724
|
+
}
|
|
14725
|
+
],
|
|
14726
|
+
required: false
|
|
14727
|
+
});
|
|
14728
|
+
if (clack.isCancel(selectedSkillIds)) {
|
|
14729
|
+
clack.cancel("Setup cancelled.");
|
|
14730
|
+
return "cancelled";
|
|
14731
|
+
}
|
|
14732
|
+
const selected = candidates.filter((candidate) => selectedSkillIds.includes(candidate.id));
|
|
14733
|
+
if (selectedSkillIds.includes("__skip__") || selected.length === 0) {
|
|
14734
|
+
recordSetupPromptSkip({
|
|
14735
|
+
promptKey: "local_skill_discovery",
|
|
14736
|
+
workspaceId: input.workspace.id,
|
|
14737
|
+
workspaceName: input.workspace.name
|
|
14738
|
+
});
|
|
14739
|
+
console.log(` ${ICON.skip} ${pc3.dim("local skills skipped")}`);
|
|
14740
|
+
} else {
|
|
14741
|
+
const result = writeLocalSkillSelection({
|
|
14742
|
+
candidates: selected,
|
|
14743
|
+
...context ? { context } : {}
|
|
14744
|
+
});
|
|
14745
|
+
printSkillExtensionWrite(result);
|
|
14746
|
+
console.log(
|
|
14747
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply selected local preferences to configured tools.`)}`
|
|
14748
|
+
);
|
|
14749
|
+
await safeTrackWizardTelemetry("local_skills_configured", {
|
|
14750
|
+
candidate_count: candidates.length,
|
|
14751
|
+
command: input.telemetry?.command ?? "setup",
|
|
14752
|
+
selected_count: selected.length,
|
|
14753
|
+
...input.telemetry?.preset ? { preset: input.telemetry.preset } : {},
|
|
14754
|
+
profile: input.profile?.id ?? "none"
|
|
14755
|
+
});
|
|
14756
|
+
}
|
|
14757
|
+
}
|
|
14758
|
+
}
|
|
14363
14759
|
return "configured";
|
|
14364
14760
|
}
|
|
14365
14761
|
async function promptOptionalCompanionPluginTargets(input) {
|
|
@@ -14513,20 +14909,26 @@ function printDoctorReport(report, assessment) {
|
|
|
14513
14909
|
async function main() {
|
|
14514
14910
|
const program = new Command();
|
|
14515
14911
|
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
14516
|
-
const pkgVersion = true ? "0.1.
|
|
14912
|
+
const pkgVersion = true ? "0.1.46" : void 0;
|
|
14517
14913
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
14518
14914
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
14519
14915
|
if (Boolean(actionCommand.optsWithGlobals().json)) return;
|
|
14520
14916
|
console.log(renderBanner(pkgVersion));
|
|
14521
14917
|
});
|
|
14522
|
-
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) => {
|
|
14918
|
+
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("--profile <name>", `tailor setup for a workflow profile (${supportedSetupProfileIds().join(", ")})`).option("--context <text>", "extra workflow context to include in the first initiative and handoff").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) => {
|
|
14523
14919
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
14524
14920
|
if (options.dailyBrief && options.skipDailyBrief) {
|
|
14525
14921
|
throw new Error("Use either --daily-brief or --skip-daily-brief, not both.");
|
|
14526
14922
|
}
|
|
14923
|
+
const setupProfile = resolveSetupProfile(options.profile);
|
|
14924
|
+
if (options.profile && !setupProfile) {
|
|
14925
|
+
throw new Error(`Unknown setup profile '${options.profile}'. Supported profiles: ${supportedSetupProfileIds().join(", ")}.`);
|
|
14926
|
+
}
|
|
14927
|
+
const setupContext = options.context?.trim() || void 0;
|
|
14527
14928
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
14528
14929
|
command: "setup",
|
|
14529
14930
|
interactive,
|
|
14931
|
+
profile: setupProfile?.id ?? "none",
|
|
14530
14932
|
preset: options.preset ?? "standard"
|
|
14531
14933
|
});
|
|
14532
14934
|
printSetupScopeNote();
|
|
@@ -14596,7 +14998,9 @@ async function main() {
|
|
|
14596
14998
|
);
|
|
14597
14999
|
}
|
|
14598
15000
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
15001
|
+
...setupContext ? { context: setupContext } : {},
|
|
14599
15002
|
interactive,
|
|
15003
|
+
profile: setupProfile,
|
|
14600
15004
|
telemetry: { command: "setup", preset: "founder" },
|
|
14601
15005
|
workspace: presetResult.workspace,
|
|
14602
15006
|
...presetResult.demoInitiative ? { initiativeId: presetResult.demoInitiative.initiative.id } : {}
|
|
@@ -14757,7 +15161,9 @@ async function main() {
|
|
|
14757
15161
|
return;
|
|
14758
15162
|
}
|
|
14759
15163
|
const addOnResult = await maybeConfigureOptionalWorkspaceAddOns({
|
|
15164
|
+
...setupContext ? { context: setupContext } : {},
|
|
14760
15165
|
interactive,
|
|
15166
|
+
profile: setupProfile,
|
|
14761
15167
|
telemetry: { command: "setup", preset: "standard" },
|
|
14762
15168
|
workspace: resolvedWorkspace
|
|
14763
15169
|
});
|
|
@@ -15361,6 +15767,48 @@ async function main() {
|
|
|
15361
15767
|
}
|
|
15362
15768
|
}
|
|
15363
15769
|
});
|
|
15770
|
+
skills.command("discover-local").description("Inventory local skill files and optionally fold selected ones into the OrgX base skill extension.").option("--from <sources>", "local sources to scan: opencode, claude, codex, agents, workspace, or all", "all").option("--context <text>", "workflow context used to rank and annotate discovered skills").option("--limit <count>", "max candidates to show", "12").option("--apply <selection>", "comma-separated candidate numbers or ids to opt into the OrgX base skill extension").option("--scope <scope>", "extension scope: user, workspace, or project", "user").option("--json", "emit a JSON summary").action(async (options) => {
|
|
15771
|
+
const sources = parseLocalSkillSources(options.from);
|
|
15772
|
+
const limit = parsePositiveInteger(options.limit, 12, "--limit");
|
|
15773
|
+
const candidates = discoverLocalSkills({
|
|
15774
|
+
...options.context?.trim() ? { context: options.context.trim() } : {},
|
|
15775
|
+
limit,
|
|
15776
|
+
sources
|
|
15777
|
+
});
|
|
15778
|
+
let extensionWrite = null;
|
|
15779
|
+
if (options.apply?.trim()) {
|
|
15780
|
+
const selected = selectLocalSkillCandidates(candidates, options.apply);
|
|
15781
|
+
extensionWrite = writeLocalSkillSelection({
|
|
15782
|
+
candidates: selected,
|
|
15783
|
+
...options.context?.trim() ? { context: options.context.trim() } : {},
|
|
15784
|
+
scope: options.scope ?? "user"
|
|
15785
|
+
});
|
|
15786
|
+
}
|
|
15787
|
+
if (options.json) {
|
|
15788
|
+
console.log(JSON.stringify({
|
|
15789
|
+
applied: extensionWrite ? {
|
|
15790
|
+
changed: extensionWrite.changed,
|
|
15791
|
+
created: extensionWrite.created,
|
|
15792
|
+
path: extensionWrite.path
|
|
15793
|
+
} : null,
|
|
15794
|
+
candidates
|
|
15795
|
+
}, null, 2));
|
|
15796
|
+
return;
|
|
15797
|
+
}
|
|
15798
|
+
printLocalSkillCandidates(candidates);
|
|
15799
|
+
if (extensionWrite) {
|
|
15800
|
+
console.log("");
|
|
15801
|
+
printSkillExtensionWrite(extensionWrite);
|
|
15802
|
+
console.log(
|
|
15803
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply selected local preferences to configured tools.`)}`
|
|
15804
|
+
);
|
|
15805
|
+
} else if (candidates.length > 0) {
|
|
15806
|
+
console.log("");
|
|
15807
|
+
console.log(
|
|
15808
|
+
` ${ICON.skip} ${pc3.dim(`Opt in with ${getCmd()} skills discover-local --apply 1,2, then run ${getCmd()} skills sync.`)}`
|
|
15809
|
+
);
|
|
15810
|
+
}
|
|
15811
|
+
});
|
|
15364
15812
|
const skillExtensions = skills.command("extensions").description("Create, edit, and sync user extensions appended after OrgX core skills.");
|
|
15365
15813
|
skillExtensions.command("list").description("List local OrgX skill extensions.").action(() => {
|
|
15366
15814
|
printSkillExtensions(listSkillExtensions());
|