@useorgx/wizard 0.1.32 → 0.1.37
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 +1746 -104
- 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 readFileSync6 } from "fs";
|
|
7
7
|
import { hostname } from "os";
|
|
8
8
|
import { resolve } from "path";
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -6235,6 +6235,7 @@ var INSTRUCTION_BOILERPLATE_PATTERN = /^(?:#{1,6}\s*)?(?:agents\.md|instructions
|
|
|
6235
6235
|
var IMPERATIVE_BOILERPLATE_PATTERN = /^[-*]\s+(?:if the user|when the user|if mcp|when agents|never|always|do not|don'?t|default to|treat|produce|pick|verify|avoid|match|use exactly|keep system boundaries|quote bracketed|for orgx|when capture tooling|if no meaningful|do \*\*not\*\*)\b/i;
|
|
6236
6236
|
var CODE_OR_DOC_NOISE_PATTERN = /^(?:[-*]\s*)?(?:https?:\/\/|\/|\.{0,2}\/|[A-Za-z]:\/|`{1,3}|"{1,2}[A-Za-z0-9:_-]+":|\d+\s*$|\d+\t|import\s|export\s|const\s|let\s|var\s|function\s|type\s|interface\s|CREATE\s+TABLE|ALTER\s+TABLE|SELECT\s+|INSERT\s+|UPDATE\s+|DELETE\s+)/i;
|
|
6237
6237
|
var EMPTY_AUDIT_LABEL_PATTERN = /^(?:[-*]\s*)?(?:decision|artifact|receipt|proof|commitment|next action|follow[- ]?up|outcome|result|impact|roi|economics|open loop|gap|blocker|risk|owner|dri|rollback|quality score)\s*:\s*[\[{(;,]*$/i;
|
|
6238
|
+
var LABEL_VALUE_NOISE_PATTERN = /^(?:[-*]\s*)?(?:decision|artifact|receipt|proof|commitment|next action|follow[- ]?up|outcome|result|impact|roi|economics|open loop|gap|blocker|risk|owner|dri|rollback|quality score)\s*:\s*(?:["']?[\w-]+["']?\s*\|\s*["']?[\w-]+["']?|[\d\s.,%$]+)[,;)]*$/i;
|
|
6238
6239
|
var TYPE_SIGNATURE_NOISE_PATTERN = /^(?:[-*]\s*)?(?:decision|artifact|receipt|proof|commitment|next action|follow[- ]?up|outcome|result|impact|roi|economics|open loop|gap|blocker|risk|owner|dri|rollback|quality score)\s*:\s*[A-Za-z_$][\w$]*(?:<[^>]+>)?[\s,;)]*$/i;
|
|
6239
6240
|
var TOOL_CATALOG_NOISE_PATTERN = /^(?:[-*]\s*)?(?:[a-z][\w.:-]*\s*\([^)]+\),?\s*){2,}$/i;
|
|
6240
6241
|
var BARE_TOOL_SIGNAL_PATTERN = /^(?:\d+\.\s*|[-*]\s*)?(?:mcp__orgx__[\w-]*|orgx_emit_activity|orgx_apply_changeset|complete_with_proof|scaffold_initiative|get_task_with_context|ship_batch|record_outcome|orgx_free_audit)\s*$/i;
|
|
@@ -6340,6 +6341,7 @@ function normalizeAuditRelevantLine(line) {
|
|
|
6340
6341
|
if (IMPERATIVE_BOILERPLATE_PATTERN.test(trimmed)) return null;
|
|
6341
6342
|
if (CODE_OR_DOC_NOISE_PATTERN.test(trimmed)) return null;
|
|
6342
6343
|
if (EMPTY_AUDIT_LABEL_PATTERN.test(trimmed)) return null;
|
|
6344
|
+
if (LABEL_VALUE_NOISE_PATTERN.test(trimmed)) return null;
|
|
6343
6345
|
if (TYPE_SIGNATURE_NOISE_PATTERN.test(trimmed)) return null;
|
|
6344
6346
|
if (TOOL_CATALOG_NOISE_PATTERN.test(trimmed)) return null;
|
|
6345
6347
|
if ((trimmed.match(/\b[a-z][\w.:-]*\s*\([^)]+\)/g) ?? []).length >= 2) return null;
|
|
@@ -6416,19 +6418,32 @@ function readSessionImport(candidate, root, options) {
|
|
|
6416
6418
|
const extractor = candidate.source === "codex" ? extractCodexMessageText : extractClaudeMessageText;
|
|
6417
6419
|
const lines = readFileSync3(candidate.path, "utf8").split(/\r?\n/);
|
|
6418
6420
|
const relevantLines = [];
|
|
6421
|
+
let messageCount = 0;
|
|
6419
6422
|
for (const line of lines) {
|
|
6420
6423
|
const record = parseJsonLine(line);
|
|
6421
6424
|
const text2 = extractor(record);
|
|
6422
6425
|
if (!text2) continue;
|
|
6426
|
+
messageCount += 1;
|
|
6423
6427
|
relevantLines.push(...keepAuditRelevantLines(text2));
|
|
6424
6428
|
}
|
|
6425
6429
|
const deduped = [...new Set(relevantLines)].slice(0, 80);
|
|
6426
6430
|
if (deduped.length === 0) return null;
|
|
6427
6431
|
const relativePath = relative2(root, candidate.path);
|
|
6428
6432
|
return {
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6433
|
+
import: {
|
|
6434
|
+
sourceId: `${candidate.source}:${basename2(candidate.path, ".jsonl")}`,
|
|
6435
|
+
sourceLabel: `${candidate.source === "codex" ? "Codex" : "Claude"} session ${relativePath}`,
|
|
6436
|
+
metadata: {
|
|
6437
|
+
bytes: stats.size,
|
|
6438
|
+
message_count: messageCount,
|
|
6439
|
+
relative_path: relativePath,
|
|
6440
|
+
retained_line_count: deduped.length,
|
|
6441
|
+
source_client: candidate.source
|
|
6442
|
+
},
|
|
6443
|
+
text: deduped.join("\n")
|
|
6444
|
+
},
|
|
6445
|
+
messageCount,
|
|
6446
|
+
retainedLineCount: deduped.length
|
|
6432
6447
|
};
|
|
6433
6448
|
}
|
|
6434
6449
|
function loadAiSessionImports(options) {
|
|
@@ -6443,7 +6458,9 @@ function loadAiSessionImports(options) {
|
|
|
6443
6458
|
const imports = [];
|
|
6444
6459
|
const connectedSources = [];
|
|
6445
6460
|
const missingSources = [];
|
|
6461
|
+
let retainedLines = 0;
|
|
6446
6462
|
let scannedFiles = 0;
|
|
6463
|
+
let scannedMessages = 0;
|
|
6447
6464
|
let skippedFiles = 0;
|
|
6448
6465
|
for (const source of options.sources) {
|
|
6449
6466
|
const root = roots[source];
|
|
@@ -6456,12 +6473,14 @@ function loadAiSessionImports(options) {
|
|
|
6456
6473
|
for (const candidate of candidates) {
|
|
6457
6474
|
if (importedForSource >= limitPerSource) break;
|
|
6458
6475
|
scannedFiles += 1;
|
|
6459
|
-
const
|
|
6460
|
-
if (!
|
|
6476
|
+
const result = readSessionImport(candidate, root, { maxBytesPerFile });
|
|
6477
|
+
if (!result) {
|
|
6461
6478
|
skippedFiles += 1;
|
|
6462
6479
|
continue;
|
|
6463
6480
|
}
|
|
6464
|
-
imports.push(
|
|
6481
|
+
imports.push(result.import);
|
|
6482
|
+
retainedLines += result.retainedLineCount;
|
|
6483
|
+
scannedMessages += result.messageCount;
|
|
6465
6484
|
importedForSource += 1;
|
|
6466
6485
|
}
|
|
6467
6486
|
if (importedForSource > 0) {
|
|
@@ -6474,7 +6493,9 @@ function loadAiSessionImports(options) {
|
|
|
6474
6493
|
connectedSources,
|
|
6475
6494
|
imports,
|
|
6476
6495
|
missingSources,
|
|
6496
|
+
retainedLines,
|
|
6477
6497
|
scannedFiles,
|
|
6498
|
+
scannedMessages,
|
|
6478
6499
|
skippedFiles
|
|
6479
6500
|
};
|
|
6480
6501
|
}
|
|
@@ -6990,6 +7011,7 @@ var WORK_GRAPH_FINDING_TYPES = [
|
|
|
6990
7011
|
"business",
|
|
6991
7012
|
"product_surface",
|
|
6992
7013
|
"goal",
|
|
7014
|
+
"outcome",
|
|
6993
7015
|
"initiative_candidate",
|
|
6994
7016
|
"missed_orchestration_opportunity"
|
|
6995
7017
|
];
|
|
@@ -7022,6 +7044,10 @@ function sourceClientForImport(source) {
|
|
|
7022
7044
|
if (raw.includes("slack")) return "slack";
|
|
7023
7045
|
if (raw.includes("github")) return "github";
|
|
7024
7046
|
if (raw.includes("linear")) return "linear";
|
|
7047
|
+
if (raw.includes("gmail") || raw.includes("email")) return "gmail";
|
|
7048
|
+
if (raw.includes("calendar") || raw.includes("meeting")) return "calendar";
|
|
7049
|
+
if (raw.includes("notion")) return "notion";
|
|
7050
|
+
if (raw.includes("doc")) return "docs";
|
|
7025
7051
|
if (raw.includes("mcp")) return "mcp";
|
|
7026
7052
|
if (raw.includes("api")) return "api";
|
|
7027
7053
|
if (raw.includes("manual") || raw.includes("wizard-audit-input")) return "manual";
|
|
@@ -7030,7 +7056,7 @@ function sourceClientForImport(source) {
|
|
|
7030
7056
|
function normalizeSourceClient(value) {
|
|
7031
7057
|
if (typeof value !== "string") return "unknown";
|
|
7032
7058
|
const normalized = value.trim().toLowerCase();
|
|
7033
|
-
if (normalized === "codex" || normalized === "claude" || normalized === "claude-code" || normalized === "cursor" || normalized === "openclaw" || normalized === "slack" || normalized === "mcp" || normalized === "github" || normalized === "linear" || normalized === "manual" || normalized === "wizard" || normalized === "api") {
|
|
7059
|
+
if (normalized === "codex" || normalized === "claude" || normalized === "claude-code" || normalized === "cursor" || normalized === "openclaw" || normalized === "slack" || normalized === "mcp" || normalized === "github" || normalized === "linear" || normalized === "gmail" || normalized === "calendar" || normalized === "notion" || normalized === "docs" || normalized === "manual" || normalized === "wizard" || normalized === "api") {
|
|
7034
7060
|
return normalized;
|
|
7035
7061
|
}
|
|
7036
7062
|
if (normalized.includes("claude")) return "claude";
|
|
@@ -7039,9 +7065,46 @@ function normalizeSourceClient(value) {
|
|
|
7039
7065
|
if (normalized.includes("slack")) return "slack";
|
|
7040
7066
|
if (normalized.includes("github")) return "github";
|
|
7041
7067
|
if (normalized.includes("linear")) return "linear";
|
|
7068
|
+
if (normalized.includes("gmail") || normalized.includes("email")) return "gmail";
|
|
7069
|
+
if (normalized.includes("calendar") || normalized.includes("meeting")) return "calendar";
|
|
7070
|
+
if (normalized.includes("notion")) return "notion";
|
|
7071
|
+
if (normalized.includes("doc")) return "docs";
|
|
7042
7072
|
if (normalized.includes("mcp")) return "mcp";
|
|
7043
7073
|
return "unknown";
|
|
7044
7074
|
}
|
|
7075
|
+
function sourceClientFromText(value) {
|
|
7076
|
+
const normalized = value.toLowerCase();
|
|
7077
|
+
if (/\bclaude(?:[- ]code)?\b|\.claude\/projects|claude:/.test(normalized)) return "claude";
|
|
7078
|
+
if (/\bcodex\b|\.codex\/sessions|rollout-/.test(normalized)) return "codex";
|
|
7079
|
+
if (/\bcursor\b/.test(normalized)) return "cursor";
|
|
7080
|
+
if (/\bopenclaw\b/.test(normalized)) return "openclaw";
|
|
7081
|
+
if (/\bslack\b/.test(normalized)) return "slack";
|
|
7082
|
+
if (/\bgithub\b|\bgit:|pull request|commit\b/.test(normalized)) return "github";
|
|
7083
|
+
if (/\blinear\b/.test(normalized)) return "linear";
|
|
7084
|
+
if (/\bgmail\b|\bemail\b/.test(normalized)) return "gmail";
|
|
7085
|
+
if (/\bcalendar\b|\bmeeting\b/.test(normalized)) return "calendar";
|
|
7086
|
+
if (/\bnotion\b/.test(normalized)) return "notion";
|
|
7087
|
+
if (/\bdocs?\b|google drive/.test(normalized)) return "docs";
|
|
7088
|
+
if (/\bmcp\b|mcp__|orgx_emit|scaffold_initiative|ship_batch/.test(normalized)) return "mcp";
|
|
7089
|
+
if (/\borgx api\b|\bapi\b/.test(normalized)) return "api";
|
|
7090
|
+
return "unknown";
|
|
7091
|
+
}
|
|
7092
|
+
function sourceClientForExtractionFinding(extraction, finding) {
|
|
7093
|
+
const explicit = normalizeSourceClient(finding.source_client);
|
|
7094
|
+
if (explicit !== "unknown") return explicit;
|
|
7095
|
+
const inferred = sourceClientFromText([
|
|
7096
|
+
finding.source_id ?? "",
|
|
7097
|
+
finding.source_label ?? "",
|
|
7098
|
+
finding.evidence_ref ?? "",
|
|
7099
|
+
finding.summary ?? ""
|
|
7100
|
+
].join("\n"));
|
|
7101
|
+
if (inferred !== "unknown") return inferred;
|
|
7102
|
+
return normalizeSourceClient(extraction.source_client);
|
|
7103
|
+
}
|
|
7104
|
+
function arrayOfStrings(value) {
|
|
7105
|
+
if (!Array.isArray(value)) return [];
|
|
7106
|
+
return value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
7107
|
+
}
|
|
7045
7108
|
function normalizeFindingType(value) {
|
|
7046
7109
|
if (typeof value !== "string") return null;
|
|
7047
7110
|
const normalized = value.trim().toLowerCase();
|
|
@@ -7052,9 +7115,23 @@ function normalizeConfidence(value, fallback = 0.72) {
|
|
|
7052
7115
|
return Math.max(0.1, Math.min(0.99, Number(value.toFixed(2))));
|
|
7053
7116
|
}
|
|
7054
7117
|
function titleFromText(text2, fallback) {
|
|
7055
|
-
const
|
|
7118
|
+
const lower = text2.toLowerCase();
|
|
7119
|
+
if (lower.includes("mcp__orgx__list_entities") && lower.includes("zod")) {
|
|
7120
|
+
return "OrgX MCP list_entities is failing schema validation";
|
|
7121
|
+
}
|
|
7122
|
+
if (lower.includes("scaffold_initiative") && lower.includes("auto_continue") && lower.includes("dispatch")) {
|
|
7123
|
+
return "scaffold_initiative creates ready streams without dispatching agent runs";
|
|
7124
|
+
}
|
|
7125
|
+
if (lower.includes("operation qa loop") && lower.includes("0/") && lower.includes("entities")) {
|
|
7126
|
+
return "OrgX scaffold fails to create Operation QA Loop entities";
|
|
7127
|
+
}
|
|
7128
|
+
if (lower.includes("production-only redirect") || lower.includes("livedemopageclient")) {
|
|
7129
|
+
return "Production route behavior changed without durable approval";
|
|
7130
|
+
}
|
|
7131
|
+
const normalized = text2.replace(/[`*_>#]/g, "").replace(/^\s*[-*\d.)]+\s*/, "").replace(/^\s*(decision|artifact|commitment|next action|follow[- ]?up|outcome|roi|economics|open loop|gap|blocker|risk|goal|summary)\s*:\s*/i, "").replace(/^\s*(fix|fixing|debug|investigate|continue|todo)\s+(the\s+)?(bug|issue|problem)\s*[:.-]?\s*/i, "").replace(/^\s*one\s+bug\s+surfaced\s*:\s*/i, "").replace(/\s+/g, " ").trim();
|
|
7056
7132
|
const firstSentence = normalized.split(/[.!?]\s/)[0]?.trim() || normalized;
|
|
7057
|
-
|
|
7133
|
+
const firstClause = firstSentence.split(/\s[-:;]\s/)[0]?.trim() || firstSentence;
|
|
7134
|
+
return (firstClause || fallback).slice(0, 110);
|
|
7058
7135
|
}
|
|
7059
7136
|
function normalizeClientExtractionId(extraction, index) {
|
|
7060
7137
|
return extraction.extraction_id?.trim() || `${extraction.source_client || "unknown"}:client-extraction:${index + 1}`;
|
|
@@ -7074,43 +7151,49 @@ function buildWorkGraphExtractionProtocol() {
|
|
|
7074
7151
|
source_search_strategy: [
|
|
7075
7152
|
{
|
|
7076
7153
|
id: "decisions",
|
|
7077
|
-
lens: "Decision
|
|
7154
|
+
lens: "Decision evidence",
|
|
7078
7155
|
query: "Find choices, tradeoffs, approvals, rejected options, contradictions, architecture calls, product calls, and decisions that were restated later.",
|
|
7079
7156
|
return_when: "A choice shaped future work, blocked work, or should become durable organizational memory."
|
|
7080
7157
|
},
|
|
7081
7158
|
{
|
|
7082
7159
|
id: "artifacts",
|
|
7083
|
-
lens: "Artifact
|
|
7160
|
+
lens: "Artifact evidence",
|
|
7084
7161
|
query: "Find created or modified artifacts: PRs, files, docs, designs, prompts, plans, reports, screenshots, deployed routes, tests, and verification receipts.",
|
|
7085
7162
|
return_when: "The artifact has a source event, proof reference, downstream use, owner, or missing verification."
|
|
7086
7163
|
},
|
|
7087
7164
|
{
|
|
7088
7165
|
id: "blockers",
|
|
7089
|
-
lens: "Blocker
|
|
7166
|
+
lens: "Blocker evidence",
|
|
7090
7167
|
query: "Find failed tool calls, timeouts, rejected validators, missing auth, missing source coverage, repeated unresolved questions, stalled owners, and external blockers.",
|
|
7091
7168
|
return_when: "The blocker explains why work did not become durable, verified, assigned, or shipped."
|
|
7092
7169
|
},
|
|
7093
7170
|
{
|
|
7094
7171
|
id: "people_businesses",
|
|
7095
|
-
lens: "People and business
|
|
7096
|
-
query: "Find users, customers, buyers, stakeholders, reviewers, teams, businesses, accounts, and market signals connected to work or decisions.",
|
|
7172
|
+
lens: "People and business context",
|
|
7173
|
+
query: "Find users, customers, buyers, stakeholders, reviewers, teams, businesses, accounts, deal context, support signals, and market signals connected to work or decisions.",
|
|
7097
7174
|
return_when: "A person or business changes priority, ownership, revenue potential, customer pain, or follow-up urgency."
|
|
7098
7175
|
},
|
|
7176
|
+
{
|
|
7177
|
+
id: "coordination_sources",
|
|
7178
|
+
lens: "Coordination and calendar/email context",
|
|
7179
|
+
query: "Find Slack threads, emails, meetings, docs, handoffs, approvals, owner changes, follow-ups, and coordination gaps that explain how work moved or stalled outside the AI client.",
|
|
7180
|
+
return_when: "The coordination source proves ownership, urgency, approval, customer context, or a missing source needed for attribution."
|
|
7181
|
+
},
|
|
7099
7182
|
{
|
|
7100
7183
|
id: "product_surfaces",
|
|
7101
|
-
lens: "Product surface
|
|
7184
|
+
lens: "Product surface coverage",
|
|
7102
7185
|
query: "Find surfaces such as live rooms, command center, widgets, plugins, wizard flows, public pages, APIs, MCP tools, Slack/GitHub/Linear integrations, and signup/claim flows.",
|
|
7103
7186
|
return_when: "A surface was changed, verified, blocked, requested, or connected to a goal or artifact."
|
|
7104
7187
|
},
|
|
7105
7188
|
{
|
|
7106
7189
|
id: "agents_tools_sources",
|
|
7107
|
-
lens: "Agent
|
|
7190
|
+
lens: "Agent, skill, tool, and source usage",
|
|
7108
7191
|
query: "Find agent runs, subagents, MCP calls, hook lifecycle events, tool availability, tool misses, source coverage, and runtime writeback behavior.",
|
|
7109
7192
|
return_when: "The event proves whether OrgX was called, skipped, unavailable, or only mentioned in instructions."
|
|
7110
7193
|
},
|
|
7111
7194
|
{
|
|
7112
7195
|
id: "outcomes_roi",
|
|
7113
|
-
lens: "Outcome and ROI
|
|
7196
|
+
lens: "Outcome and ROI evidence",
|
|
7114
7197
|
query: "Find shipped/completed work, test/browser/deploy verification, outcomes, time saved, cost, revenue, customer impact, attribution, and expected lift.",
|
|
7115
7198
|
return_when: "The outcome can be tied to evidence and a prior decision, artifact, blocker, or source."
|
|
7116
7199
|
},
|
|
@@ -7119,18 +7202,30 @@ function buildWorkGraphExtractionProtocol() {
|
|
|
7119
7202
|
lens: "Recurring patterns",
|
|
7120
7203
|
query: "Find repeated shapes across sessions: trapped decisions, orphaned artifacts, missing owner, repeated work, source gaps, tooling mismatch, unverified outcomes, handoff friction, and unclaimed business signals.",
|
|
7121
7204
|
return_when: "The same pattern appears across multiple sessions, days, tools, actors, or product surfaces."
|
|
7205
|
+
},
|
|
7206
|
+
{
|
|
7207
|
+
id: "domains",
|
|
7208
|
+
lens: "Domain coverage",
|
|
7209
|
+
query: "Find which domains the work spans: product/UX, agents/runtime, MCP/platform, wizard/CLI, plugin distribution, source integrations, quality verification, GTM, sales, operations, and business leverage.",
|
|
7210
|
+
return_when: "A domain has concrete work evidence, not just a generic mention."
|
|
7211
|
+
},
|
|
7212
|
+
{
|
|
7213
|
+
id: "skills_tools",
|
|
7214
|
+
lens: "Commonly invoked skills, agents, and tools",
|
|
7215
|
+
query: "Find named skills, OrgX domain agents, MCP tools, client tools, commands, test tools, and source systems that shaped the work.",
|
|
7216
|
+
return_when: "A skill/tool/source was used, requested, blocked, missed, or repeatedly referenced as part of execution."
|
|
7122
7217
|
}
|
|
7123
7218
|
],
|
|
7124
7219
|
required_output: {
|
|
7125
7220
|
schema_version: WORK_GRAPH_EXTRACTION_SCHEMA_VERSION,
|
|
7126
7221
|
extraction_id: "stable id for this extraction run",
|
|
7127
|
-
source_client: "codex | claude | claude-code | cursor | openclaw | slack | mcp | github | linear | manual | api | unknown",
|
|
7222
|
+
source_client: "codex | claude | claude-code | cursor | openclaw | slack | mcp | github | linear | gmail | calendar | notion | docs | manual | api | unknown",
|
|
7128
7223
|
source_label: "human-readable source label",
|
|
7129
7224
|
searched_sources: ["session/log/source group names searched"],
|
|
7130
7225
|
search_queries: [
|
|
7131
7226
|
{
|
|
7132
7227
|
id: "decisions",
|
|
7133
|
-
lens: "Decision
|
|
7228
|
+
lens: "Decision evidence",
|
|
7134
7229
|
query: "query actually used",
|
|
7135
7230
|
result_count: 0
|
|
7136
7231
|
}
|
|
@@ -7143,9 +7238,10 @@ function buildWorkGraphExtractionProtocol() {
|
|
|
7143
7238
|
},
|
|
7144
7239
|
findings: [
|
|
7145
7240
|
{
|
|
7146
|
-
type: "decision | artifact | blocker | person | business | product_surface | goal | action | initiative_candidate | missed_orchestration_opportunity",
|
|
7241
|
+
type: "decision | artifact | blocker | person | business | product_surface | goal | outcome | action | initiative_candidate | missed_orchestration_opportunity",
|
|
7147
7242
|
title: "short durable title, not a raw line",
|
|
7148
7243
|
summary: "one sentence explaining why this matters",
|
|
7244
|
+
source_client: "optional override when a blended extractor found evidence from another client",
|
|
7149
7245
|
source_id: "session/tool/source id",
|
|
7150
7246
|
source_label: "source label",
|
|
7151
7247
|
evidence_ref: "stable evidence pointer",
|
|
@@ -7164,12 +7260,13 @@ function buildWorkGraphExtractionProtocol() {
|
|
|
7164
7260
|
]
|
|
7165
7261
|
},
|
|
7166
7262
|
quality_bar: [
|
|
7167
|
-
"Search broadly before summarizing; do not stop at the newest session if older sessions contain recurrence.",
|
|
7263
|
+
"Search broadly through message turns before summarizing; do not stop at the newest session if older sessions contain recurrence.",
|
|
7168
7264
|
"Every finding must include a source id or evidence ref.",
|
|
7169
|
-
"A
|
|
7265
|
+
"A durable finding starts only from evidence-bearing work signals, not empty labels, code type signatures, tool catalogs, or guardrail text.",
|
|
7170
7266
|
"Prefer fewer, higher-confidence findings over many shallow lines.",
|
|
7171
7267
|
"Include negative evidence when OrgX/MCP was available but not called.",
|
|
7172
7268
|
"Separate actual tool calls from textual mentions of tool names.",
|
|
7269
|
+
"Extract the range of work domains and common skills/tools so the reader can see what kinds of work the audit actually understood.",
|
|
7173
7270
|
"Mark confidence below 0.6 when the finding is inferred from weak or single-source evidence.",
|
|
7174
7271
|
"Do not emit raw JSON tool payloads; summarize the tool result into a blocker/artifact/outcome finding."
|
|
7175
7272
|
],
|
|
@@ -7184,10 +7281,10 @@ function buildWorkGraphExtractionProtocol() {
|
|
|
7184
7281
|
]
|
|
7185
7282
|
};
|
|
7186
7283
|
const prompt = [
|
|
7187
|
-
"You are
|
|
7188
|
-
"Search across available local
|
|
7284
|
+
"You are running the OrgX AI-client audit skill from your own session/search logs.",
|
|
7285
|
+
"Search across available local message turns, transcripts, tool-call logs, hook events, and source indexes using every lens in the schema.",
|
|
7189
7286
|
"Return JSON only. Match the required_output shape exactly. Do not return raw transcripts.",
|
|
7190
|
-
"The output will
|
|
7287
|
+
"The output will create public-safe OrgX evidence paths, so every finding must be evidence-bearing and useful enough for a human to inspect."
|
|
7191
7288
|
].join(" ");
|
|
7192
7289
|
return {
|
|
7193
7290
|
schema_version: WORK_GRAPH_EXTRACTION_SCHEMA_VERSION,
|
|
@@ -7219,6 +7316,12 @@ function includesAny2(text2, patterns) {
|
|
|
7219
7316
|
return patterns.some((pattern) => pattern.test(text2));
|
|
7220
7317
|
}
|
|
7221
7318
|
function buildCoverage(imports, connectedSources, missingSources, clientExtractions = []) {
|
|
7319
|
+
const findings = buildClientExtractionFindings(clientExtractions);
|
|
7320
|
+
const sourceClients = sortedUnique([
|
|
7321
|
+
...imports.map(sourceClientForImport),
|
|
7322
|
+
...findings.map((finding) => finding.source_client),
|
|
7323
|
+
...clientExtractions.map((extraction) => normalizeSourceClient(extraction.source_client))
|
|
7324
|
+
].filter((source) => source !== "unknown"));
|
|
7222
7325
|
const extractionText = clientExtractions.flatMap((extraction) => [
|
|
7223
7326
|
extraction.source_client,
|
|
7224
7327
|
extraction.source_label ?? "",
|
|
@@ -7235,15 +7338,170 @@ ${extractionText}`.toLowerCase();
|
|
|
7235
7338
|
const mcpObserved = /\bmcp\b|mcp__|tool call|tools\/call|call_tool|orgx_emit_activity/i.test(allText);
|
|
7236
7339
|
const orgxMcpCalled = /mcp__orgx__|orgx_emit_activity|orgx_apply_changeset|complete_with_proof|scaffold_initiative/i.test(allText);
|
|
7237
7340
|
const skillOnlySignal = orgxObserved && !orgxMcpCalled && /\bskill|instructions|agent|workflow\b/i.test(allText);
|
|
7341
|
+
const normalizedConnectedSources = sortedUnique(
|
|
7342
|
+
connectedSources.map((source) => {
|
|
7343
|
+
const client = sourceClientFromText(source);
|
|
7344
|
+
return client === "unknown" ? source : labelForSourceClient(client);
|
|
7345
|
+
})
|
|
7346
|
+
);
|
|
7347
|
+
const inferredConnected = [
|
|
7348
|
+
...normalizedConnectedSources,
|
|
7349
|
+
...sourceClients.includes("codex") ? ["Codex sessions"] : [],
|
|
7350
|
+
...sourceClients.includes("claude") || sourceClients.includes("claude-code") ? ["Claude Code sessions"] : [],
|
|
7351
|
+
...sourceClients.includes("github") ? ["Git/GitHub proof"] : [],
|
|
7352
|
+
...sourceClients.includes("mcp") ? ["MCP tool telemetry"] : [],
|
|
7353
|
+
...sourceClients.includes("slack") ? ["Slack coordination"] : []
|
|
7354
|
+
];
|
|
7355
|
+
const inferredMissing = [
|
|
7356
|
+
...missingSources,
|
|
7357
|
+
...sourceClients.includes("slack") ? [] : ["Slack coordination"],
|
|
7358
|
+
...sourceClients.includes("github") ? [] : ["GitHub PR/commit proof"],
|
|
7359
|
+
...allText.includes("hook") || allText.includes("outbox") ? [] : ["Runtime hook outbox replay"]
|
|
7360
|
+
];
|
|
7361
|
+
const connected = sortedUnique(inferredConnected.filter(Boolean));
|
|
7362
|
+
const missing = sortedUnique(inferredMissing.filter((source) => !connected.includes(source)));
|
|
7363
|
+
const manifests = buildSourceCoverageManifests({
|
|
7364
|
+
clientExtractions,
|
|
7365
|
+
connectedSources: connected,
|
|
7366
|
+
findings,
|
|
7367
|
+
imports,
|
|
7368
|
+
missingSources: missing
|
|
7369
|
+
});
|
|
7370
|
+
const partialCount = manifests.filter((manifest) => manifest.status === "partial").length;
|
|
7371
|
+
const coverageScore = clampScore2(
|
|
7372
|
+
28 + Math.min(34, connected.length * 7) + Math.min(18, findings.length * 2) + (sourceClients.includes("codex") ? 6 : 0) + (sourceClients.includes("claude") || sourceClients.includes("claude-code") ? 6 : 0) - missing.length * 7 - partialCount * 3
|
|
7373
|
+
);
|
|
7238
7374
|
return {
|
|
7239
|
-
connected
|
|
7240
|
-
missing
|
|
7375
|
+
connected,
|
|
7376
|
+
missing,
|
|
7241
7377
|
mcpObserved,
|
|
7242
7378
|
orgxObserved,
|
|
7243
7379
|
orgxMcpCalled,
|
|
7244
|
-
skillOnlySignal
|
|
7380
|
+
skillOnlySignal,
|
|
7381
|
+
coverage_score: coverageScore,
|
|
7382
|
+
manifests,
|
|
7383
|
+
notes: [
|
|
7384
|
+
"OrgX/MCP writeback is one coverage signal; it is not required for the audit to find useful work.",
|
|
7385
|
+
missing.length > 0 ? `Coverage is limited by missing sources: ${missing.join(", ")}.` : "Connected sources are sufficient for a first-pass operating profile, but still require user review."
|
|
7386
|
+
]
|
|
7245
7387
|
};
|
|
7246
7388
|
}
|
|
7389
|
+
function buildSourceCoverageManifests(input) {
|
|
7390
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
7391
|
+
const addManifest = (manifest) => {
|
|
7392
|
+
const sourceLabel2 = canonicalSourceManifestLabel(manifest);
|
|
7393
|
+
const key = `${manifest.source_client}:${sourceLabel2}`;
|
|
7394
|
+
const previous = manifests.get(key);
|
|
7395
|
+
if (!previous) {
|
|
7396
|
+
manifests.set(key, { ...manifest, source_label: sourceLabel2 });
|
|
7397
|
+
return;
|
|
7398
|
+
}
|
|
7399
|
+
manifests.set(key, {
|
|
7400
|
+
...previous,
|
|
7401
|
+
source_label: sourceLabel2,
|
|
7402
|
+
status: previous.status === "connected" || manifest.status === "connected" ? "connected" : previous.status === "partial" || manifest.status === "partial" ? "partial" : "missing",
|
|
7403
|
+
searched_sources: sortedUnique([...previous.searched_sources, ...manifest.searched_sources]),
|
|
7404
|
+
searched_session_count: previous.searched_session_count + manifest.searched_session_count,
|
|
7405
|
+
skipped_session_count: previous.skipped_session_count + manifest.skipped_session_count,
|
|
7406
|
+
query_count: previous.query_count + manifest.query_count,
|
|
7407
|
+
finding_count: previous.finding_count + manifest.finding_count,
|
|
7408
|
+
confidence: Math.max(previous.confidence, manifest.confidence),
|
|
7409
|
+
notes: sortedUnique([...previous.notes, ...manifest.notes])
|
|
7410
|
+
});
|
|
7411
|
+
};
|
|
7412
|
+
for (const extraction of input.clientExtractions) {
|
|
7413
|
+
const extractionFindings = buildClientExtractionFindings([extraction]);
|
|
7414
|
+
const byClient = /* @__PURE__ */ new Map();
|
|
7415
|
+
for (const finding of extractionFindings) {
|
|
7416
|
+
byClient.set(finding.source_client, [...byClient.get(finding.source_client) ?? [], finding]);
|
|
7417
|
+
}
|
|
7418
|
+
for (const [sourceClient, findings] of byClient) {
|
|
7419
|
+
const searchedSources = extraction.searched_sources ?? [];
|
|
7420
|
+
addManifest({
|
|
7421
|
+
source_client: sourceClient,
|
|
7422
|
+
source_label: labelForSourceClient(sourceClient),
|
|
7423
|
+
status: findings.length > 0 ? "connected" : "partial",
|
|
7424
|
+
searched_sources: searchedSources,
|
|
7425
|
+
searched_session_count: extraction.extraction_quality?.searched_session_count ?? 0,
|
|
7426
|
+
skipped_session_count: extraction.extraction_quality?.skipped_session_count ?? 0,
|
|
7427
|
+
query_count: extraction.search_queries?.length ?? 0,
|
|
7428
|
+
finding_count: findings.length,
|
|
7429
|
+
confidence: normalizeConfidence(extraction.extraction_quality?.confidence, 0.74),
|
|
7430
|
+
notes: extraction.extraction_quality?.notes ?? []
|
|
7431
|
+
});
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7434
|
+
for (const source of input.imports) {
|
|
7435
|
+
const sourceClient = sourceClientForImport(source);
|
|
7436
|
+
addManifest({
|
|
7437
|
+
source_client: sourceClient,
|
|
7438
|
+
source_label: source.sourceLabel,
|
|
7439
|
+
status: "connected",
|
|
7440
|
+
searched_sources: [source.sourceId],
|
|
7441
|
+
searched_session_count: 1,
|
|
7442
|
+
skipped_session_count: 0,
|
|
7443
|
+
query_count: 0,
|
|
7444
|
+
finding_count: input.findings.filter((finding) => finding.source_id === source.sourceId).length,
|
|
7445
|
+
confidence: 0.62,
|
|
7446
|
+
notes: ["Fallback line-level import; lower confidence than client-native extraction."]
|
|
7447
|
+
});
|
|
7448
|
+
}
|
|
7449
|
+
for (const source of input.missingSources) {
|
|
7450
|
+
addManifest({
|
|
7451
|
+
source_client: sourceClientFromText(source),
|
|
7452
|
+
source_label: source,
|
|
7453
|
+
status: "missing",
|
|
7454
|
+
searched_sources: [],
|
|
7455
|
+
searched_session_count: 0,
|
|
7456
|
+
skipped_session_count: 0,
|
|
7457
|
+
query_count: 0,
|
|
7458
|
+
finding_count: 0,
|
|
7459
|
+
confidence: 0,
|
|
7460
|
+
notes: ["Not connected or not searched in this audit pass."]
|
|
7461
|
+
});
|
|
7462
|
+
}
|
|
7463
|
+
return [...manifests.values()].sort((left, right) => {
|
|
7464
|
+
const rank = { connected: 0, partial: 1, missing: 2 };
|
|
7465
|
+
return rank[left.status] - rank[right.status] || right.finding_count - left.finding_count;
|
|
7466
|
+
});
|
|
7467
|
+
}
|
|
7468
|
+
function canonicalSourceManifestLabel(manifest) {
|
|
7469
|
+
if (manifest.source_client === "codex" || manifest.source_client === "claude" || manifest.source_client === "claude-code") {
|
|
7470
|
+
return labelForSourceClient(manifest.source_client);
|
|
7471
|
+
}
|
|
7472
|
+
if (manifest.source_client === "github" || manifest.source_client === "slack" || manifest.source_client === "mcp") {
|
|
7473
|
+
return labelForSourceClient(manifest.source_client);
|
|
7474
|
+
}
|
|
7475
|
+
return manifest.source_label;
|
|
7476
|
+
}
|
|
7477
|
+
function labelForSourceClient(sourceClient) {
|
|
7478
|
+
switch (sourceClient) {
|
|
7479
|
+
case "codex":
|
|
7480
|
+
return "Codex sessions";
|
|
7481
|
+
case "claude":
|
|
7482
|
+
case "claude-code":
|
|
7483
|
+
return "Claude Code sessions";
|
|
7484
|
+
case "mcp":
|
|
7485
|
+
return "MCP tool telemetry";
|
|
7486
|
+
case "github":
|
|
7487
|
+
return "Git/GitHub proof";
|
|
7488
|
+
case "slack":
|
|
7489
|
+
return "Slack coordination";
|
|
7490
|
+
case "linear":
|
|
7491
|
+
return "Linear issues";
|
|
7492
|
+
case "gmail":
|
|
7493
|
+
return "Email coordination";
|
|
7494
|
+
case "calendar":
|
|
7495
|
+
return "Calendar/meeting context";
|
|
7496
|
+
case "wizard":
|
|
7497
|
+
return "Wizard audit layer";
|
|
7498
|
+
case "notion":
|
|
7499
|
+
case "docs":
|
|
7500
|
+
return "Docs";
|
|
7501
|
+
default:
|
|
7502
|
+
return sourceClient.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
7503
|
+
}
|
|
7504
|
+
}
|
|
7247
7505
|
function summarizeClientExtractions(clientExtractions) {
|
|
7248
7506
|
return clientExtractions.map((extraction, index) => {
|
|
7249
7507
|
const extractionId = normalizeClientExtractionId(extraction, index);
|
|
@@ -7252,9 +7510,12 @@ function summarizeClientExtractions(clientExtractions) {
|
|
|
7252
7510
|
source_client: normalizeSourceClient(extraction.source_client),
|
|
7253
7511
|
source_label: extraction.source_label?.trim() || `${extraction.source_client || "Unknown"} AI-client extraction`,
|
|
7254
7512
|
searched_source_count: extraction.searched_sources?.length ?? 0,
|
|
7513
|
+
searched_session_count: extraction.extraction_quality?.searched_session_count ?? 0,
|
|
7514
|
+
skipped_session_count: extraction.extraction_quality?.skipped_session_count ?? 0,
|
|
7255
7515
|
query_count: extraction.search_queries?.length ?? 0,
|
|
7256
7516
|
finding_count: extraction.findings.length,
|
|
7257
|
-
confidence: normalizeConfidence(extraction.extraction_quality?.confidence, 0.74)
|
|
7517
|
+
confidence: normalizeConfidence(extraction.extraction_quality?.confidence, 0.74),
|
|
7518
|
+
notes: extraction.extraction_quality?.notes ?? []
|
|
7258
7519
|
};
|
|
7259
7520
|
});
|
|
7260
7521
|
}
|
|
@@ -7275,21 +7536,78 @@ function buildClientExtractionEvents(clientExtractions) {
|
|
|
7275
7536
|
finding_count: summary.finding_count,
|
|
7276
7537
|
query_count: summary.query_count,
|
|
7277
7538
|
searched_source_count: summary.searched_source_count,
|
|
7539
|
+
searched_session_count: summary.searched_session_count,
|
|
7540
|
+
skipped_session_count: summary.skipped_session_count,
|
|
7278
7541
|
raw_transcript_sent: false
|
|
7279
7542
|
}
|
|
7280
7543
|
}));
|
|
7281
7544
|
}
|
|
7545
|
+
function numberFromImportMetadata(source, key) {
|
|
7546
|
+
const value = source.metadata?.[key];
|
|
7547
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
7548
|
+
}
|
|
7549
|
+
function buildAuditMethod(input) {
|
|
7550
|
+
const extractionSummaries = summarizeClientExtractions(input.clientExtractions);
|
|
7551
|
+
const nativePacks = extractionSummaries.filter((summary) => summary.source_client === "codex" || summary.source_client === "claude" || summary.source_client === "claude-code").map((summary) => ({
|
|
7552
|
+
source_client: summary.source_client,
|
|
7553
|
+
source_label: summary.source_label,
|
|
7554
|
+
searched_session_count: summary.searched_session_count,
|
|
7555
|
+
finding_count: summary.finding_count,
|
|
7556
|
+
confidence: summary.confidence
|
|
7557
|
+
}));
|
|
7558
|
+
const searchedMessages = input.imports.reduce(
|
|
7559
|
+
(total, source) => total + numberFromImportMetadata(source, "message_count"),
|
|
7560
|
+
0
|
|
7561
|
+
);
|
|
7562
|
+
const retainedLines = input.imports.reduce((total, source) => {
|
|
7563
|
+
const explicit = numberFromImportMetadata(source, "retained_line_count");
|
|
7564
|
+
return total + (explicit || source.text.split(/\r?\n/).filter(Boolean).length);
|
|
7565
|
+
}, 0);
|
|
7566
|
+
const skippedFiles = input.imports.reduce(
|
|
7567
|
+
(total, source) => total + numberFromImportMetadata(source, "skipped_file_count"),
|
|
7568
|
+
0
|
|
7569
|
+
);
|
|
7570
|
+
const extractionSearchedSessions = extractionSummaries.reduce(
|
|
7571
|
+
(total, summary) => total + summary.searched_session_count,
|
|
7572
|
+
0
|
|
7573
|
+
);
|
|
7574
|
+
const extractionSkippedSessions = extractionSummaries.reduce(
|
|
7575
|
+
(total, summary) => total + summary.skipped_session_count,
|
|
7576
|
+
0
|
|
7577
|
+
);
|
|
7578
|
+
const sourceGroups = sortedUnique([
|
|
7579
|
+
...input.imports.map((source) => source.sourceLabel),
|
|
7580
|
+
...input.clientExtractions.flatMap((extraction) => extraction.searched_sources ?? [])
|
|
7581
|
+
]);
|
|
7582
|
+
return {
|
|
7583
|
+
mode: "ai_client_session_search",
|
|
7584
|
+
searched_session_files: input.imports.length + extractionSearchedSessions,
|
|
7585
|
+
skipped_session_files: skippedFiles + extractionSkippedSessions,
|
|
7586
|
+
searched_message_count: searchedMessages,
|
|
7587
|
+
retained_evidence_lines: retainedLines,
|
|
7588
|
+
searched_source_groups: sourceGroups.length,
|
|
7589
|
+
extraction_lenses: input.extractionProtocol.schema.source_search_strategy.map((lens) => lens.lens),
|
|
7590
|
+
client_native_packs: nativePacks,
|
|
7591
|
+
privacy_contract: input.extractionProtocol.schema.privacy_contract,
|
|
7592
|
+
notes: [
|
|
7593
|
+
"The wizard reads local Codex/Claude message turns, filters out guardrails/code noise, then runs native extraction packs over the retained evidence lines.",
|
|
7594
|
+
"Counts describe local files/message turns inspected before redaction; raw transcripts are not stored in the report.",
|
|
7595
|
+
nativePacks.length > 0 ? "Codex/Claude native packs classified session evidence into decisions, artifacts, blockers, domains, skills/tools, and missed writeback signals." : "No native AI-client pack produced findings; this report is fallback-import only."
|
|
7596
|
+
]
|
|
7597
|
+
};
|
|
7598
|
+
}
|
|
7282
7599
|
function buildClientExtractionFindings(clientExtractions) {
|
|
7283
7600
|
const findings = [];
|
|
7284
7601
|
clientExtractions.forEach((extraction, extractionIndex) => {
|
|
7285
7602
|
const extractionId = normalizeClientExtractionId(extraction, extractionIndex);
|
|
7286
|
-
const
|
|
7287
|
-
const
|
|
7603
|
+
const extractionSourceClient = normalizeSourceClient(extraction.source_client);
|
|
7604
|
+
const sourceLabel2 = extraction.source_label?.trim() || `${extractionSourceClient} AI-client extraction`;
|
|
7288
7605
|
extraction.findings.forEach((finding, findingIndex) => {
|
|
7289
7606
|
const type = normalizeFindingType(finding.type);
|
|
7290
7607
|
const title = finding.title?.trim();
|
|
7291
7608
|
const summary = finding.summary?.trim();
|
|
7292
7609
|
if (!type || !title || !summary) return;
|
|
7610
|
+
const sourceClient = sourceClientForExtractionFinding(extraction, finding);
|
|
7293
7611
|
findings.push({
|
|
7294
7612
|
type,
|
|
7295
7613
|
title: title.slice(0, 180),
|
|
@@ -7299,7 +7617,7 @@ function buildClientExtractionFindings(clientExtractions) {
|
|
|
7299
7617
|
evidence_ref: finding.evidence_ref?.trim() || `${extractionId}:F${findingIndex + 1}`,
|
|
7300
7618
|
confidence: normalizeConfidence(finding.confidence, normalizeConfidence(extraction.extraction_quality?.confidence, 0.76)),
|
|
7301
7619
|
metadata: {
|
|
7302
|
-
source_label: finding.source_label?.trim() ||
|
|
7620
|
+
source_label: finding.source_label?.trim() || sourceLabel2,
|
|
7303
7621
|
extraction_id: extractionId,
|
|
7304
7622
|
schema_version: extraction.schema_version ?? null,
|
|
7305
7623
|
occurred_at: finding.occurred_at ?? null,
|
|
@@ -7313,6 +7631,135 @@ function buildClientExtractionFindings(clientExtractions) {
|
|
|
7313
7631
|
});
|
|
7314
7632
|
return findings;
|
|
7315
7633
|
}
|
|
7634
|
+
function nativeExtractionFindingType(line) {
|
|
7635
|
+
const lower = line.toLowerCase();
|
|
7636
|
+
if (/^\s*(?:decision|decided|choice|approved|rejected)\s*:/i.test(line)) return "decision";
|
|
7637
|
+
if (/^\s*(?:artifact|receipt|proof)\s*:/i.test(line)) return "artifact";
|
|
7638
|
+
if (/^\s*(?:outcome|result|impact)\s*:/i.test(line)) return "outcome";
|
|
7639
|
+
if (/^\s*(?:roi|economics)\s*:/i.test(line)) return "business";
|
|
7640
|
+
if (/^\s*(?:next action|follow[- ]?up|commitment)\s*:/i.test(line)) return "action";
|
|
7641
|
+
if (/^\s*(?:blocker|risk|gap|open loop|rollback)\s*:/i.test(line)) return lower.includes("source") ? "missed_orchestration_opportunity" : "blocker";
|
|
7642
|
+
if (/\b(?:failed|fails|error|invalid|unavailable|timeout|timed out|not called|not dispatched|missing|broken)\b/i.test(line)) {
|
|
7643
|
+
if (/\b(?:tool|mcp|orgx|writeback|source|hook|outbox)\b/i.test(line)) return "missed_orchestration_opportunity";
|
|
7644
|
+
return "blocker";
|
|
7645
|
+
}
|
|
7646
|
+
if (/\b(?:created|generated|implemented|shipped|verified|passed)\b/i.test(line)) return "artifact";
|
|
7647
|
+
if (/\b(?:owner|dri|assigned)\b/i.test(line)) return "person";
|
|
7648
|
+
if (/\b(?:initiative|workstream|milestone|launch|goal)\b/i.test(line)) return "goal";
|
|
7649
|
+
return null;
|
|
7650
|
+
}
|
|
7651
|
+
function nativeEpisodeType(line) {
|
|
7652
|
+
if (/\b(?:plan|decide|decision|choice|tradeoff|approve|reject)\b/i.test(line)) return "planning";
|
|
7653
|
+
if (/\b(?:implemented|created|generated|edited|file|diff|commit|artifact)\b/i.test(line)) return "implementation";
|
|
7654
|
+
if (/\b(?:failed|fails|error|timeout|invalid|debug|retry|blocked|blocker)\b/i.test(line)) return "debugging";
|
|
7655
|
+
if (/\b(?:verified|passed|test|browser|qa|proof|outcome)\b/i.test(line)) return "verification";
|
|
7656
|
+
return "handoff";
|
|
7657
|
+
}
|
|
7658
|
+
function nativeFindingConfidence(type, line) {
|
|
7659
|
+
let confidence = type === "decision" || type === "artifact" || type === "outcome" ? 0.78 : 0.72;
|
|
7660
|
+
if (/^\s*(?:decision|artifact|blocker|outcome|proof|result|next action|open loop|risk|gap)\s*:/i.test(line)) confidence += 0.08;
|
|
7661
|
+
if (/\b(?:mcp__orgx__|scaffold_initiative|orgx_emit_activity|complete_with_proof|github|codex|claude)\b/i.test(line)) confidence += 0.05;
|
|
7662
|
+
if (line.length < 32) confidence -= 0.1;
|
|
7663
|
+
return normalizeConfidence(confidence, 0.72);
|
|
7664
|
+
}
|
|
7665
|
+
function nativeRelatedEntityNames(line) {
|
|
7666
|
+
const candidates = [
|
|
7667
|
+
...Array.from(line.matchAll(/`([^`]{3,80})`/g)).map((match) => match[1] ?? ""),
|
|
7668
|
+
...Array.from(line.matchAll(/\b(?:OrgX|MCP|Codex|Claude|Slack|GitHub|Cursor|ChatGPT|Work Graph|Profile|Scaffold Initiative|Operation QA Loop|Runtime Hook|Eject Bay|Trail Inspector)\b/gi)).map((match) => match[0] ?? "")
|
|
7669
|
+
];
|
|
7670
|
+
return sortedUnique(
|
|
7671
|
+
candidates.map((candidate) => candidate.trim()).filter((candidate) => candidate.length >= 3).slice(0, 8)
|
|
7672
|
+
);
|
|
7673
|
+
}
|
|
7674
|
+
function supportsNativeExtraction(sourceClient) {
|
|
7675
|
+
return sourceClient === "codex" || sourceClient === "claude" || sourceClient === "claude-code";
|
|
7676
|
+
}
|
|
7677
|
+
function buildNativeAiClientExtractions(imports, generatedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
7678
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
7679
|
+
for (const source of imports) {
|
|
7680
|
+
const sourceClient = sourceClientForImport(source);
|
|
7681
|
+
if (!supportsNativeExtraction(sourceClient)) continue;
|
|
7682
|
+
const bucket = grouped.get(sourceClient) ?? {
|
|
7683
|
+
findings: [],
|
|
7684
|
+
searchedSources: [],
|
|
7685
|
+
searchedSessionCount: 0,
|
|
7686
|
+
skippedSessionCount: 0
|
|
7687
|
+
};
|
|
7688
|
+
bucket.searchedSources.push(source.sourceId);
|
|
7689
|
+
bucket.searchedSessionCount += 1;
|
|
7690
|
+
source.text.split(/\r?\n/).forEach((line, lineIndex) => {
|
|
7691
|
+
const trimmed = line.trim();
|
|
7692
|
+
if (!trimmed) return;
|
|
7693
|
+
const type = nativeExtractionFindingType(trimmed);
|
|
7694
|
+
if (!type) {
|
|
7695
|
+
bucket.skippedSessionCount += 1;
|
|
7696
|
+
return;
|
|
7697
|
+
}
|
|
7698
|
+
bucket.findings.push({
|
|
7699
|
+
type,
|
|
7700
|
+
title: titleFromText(trimmed, type.replace(/_/g, " ")),
|
|
7701
|
+
summary: trimmed,
|
|
7702
|
+
source_client: sourceClient,
|
|
7703
|
+
source_id: source.sourceId,
|
|
7704
|
+
source_label: source.sourceLabel,
|
|
7705
|
+
evidence_ref: `${source.sourceId}:native:${lineIndex + 1}`,
|
|
7706
|
+
confidence: nativeFindingConfidence(type, trimmed),
|
|
7707
|
+
occurred_at: generatedAt,
|
|
7708
|
+
redacted_verbatim: trimmed.slice(0, 420),
|
|
7709
|
+
privacy_state: "redacted",
|
|
7710
|
+
metadata: {
|
|
7711
|
+
episode_type: nativeEpisodeType(trimmed),
|
|
7712
|
+
related_entity_names: nativeRelatedEntityNames(trimmed),
|
|
7713
|
+
related_source_ids: [source.sourceId],
|
|
7714
|
+
state: type === "blocker" || type === "missed_orchestration_opportunity" ? "blocked" : type === "outcome" || type === "artifact" ? "verified" : "observed"
|
|
7715
|
+
}
|
|
7716
|
+
});
|
|
7717
|
+
});
|
|
7718
|
+
grouped.set(sourceClient, bucket);
|
|
7719
|
+
}
|
|
7720
|
+
return [...grouped.entries()].filter(([, bucket]) => bucket.findings.length > 0).map(([sourceClient, bucket]) => ({
|
|
7721
|
+
schema_version: WORK_GRAPH_EXTRACTION_SCHEMA_VERSION,
|
|
7722
|
+
extraction_id: `${sourceClient}:native-extraction:${shortHash({
|
|
7723
|
+
sources: bucket.searchedSources,
|
|
7724
|
+
findings: bucket.findings.map((finding) => finding.evidence_ref)
|
|
7725
|
+
}, 12)}`,
|
|
7726
|
+
source_client: sourceClient,
|
|
7727
|
+
source_label: `${labelForSourceClient(sourceClient)} native extraction`,
|
|
7728
|
+
searched_sources: sortedUnique(bucket.searchedSources),
|
|
7729
|
+
search_queries: buildWorkGraphExtractionProtocol().schema.source_search_strategy.map((lens) => ({
|
|
7730
|
+
id: lens.id,
|
|
7731
|
+
lens: lens.lens,
|
|
7732
|
+
query: lens.query,
|
|
7733
|
+
result_count: bucket.findings.filter((finding) => {
|
|
7734
|
+
const text2 = `${finding.title ?? ""}
|
|
7735
|
+
${finding.summary ?? ""}`;
|
|
7736
|
+
if (lens.id === "decisions") return finding.type === "decision";
|
|
7737
|
+
if (lens.id === "artifacts") return finding.type === "artifact";
|
|
7738
|
+
if (lens.id === "blockers") return finding.type === "blocker" || finding.type === "missed_orchestration_opportunity";
|
|
7739
|
+
if (lens.id === "people_businesses") return finding.type === "person" || finding.type === "business";
|
|
7740
|
+
if (lens.id === "product_surfaces") return finding.type === "product_surface" || /\b(surface|profile|wizard|plugin|mcp)\b/i.test(text2);
|
|
7741
|
+
if (lens.id === "agents_tools_sources") return /\b(agent|skill|tool|mcp|codex|claude|github|slack)\b/i.test(text2);
|
|
7742
|
+
if (lens.id === "outcomes_roi") return finding.type === "outcome" || finding.type === "business";
|
|
7743
|
+
if (lens.id === "domains") return nativeRelatedEntityNames(text2).length > 0;
|
|
7744
|
+
if (lens.id === "skills_tools") return /\b(orgx-design|agent|skill|tool|mcp|codex|claude|github|slack)\b/i.test(text2);
|
|
7745
|
+
return bucket.findings.length > 1 ? 1 : 0;
|
|
7746
|
+
}).length
|
|
7747
|
+
})),
|
|
7748
|
+
extraction_quality: {
|
|
7749
|
+
confidence: normalizeConfidence(
|
|
7750
|
+
bucket.findings.reduce((total, finding) => total + (finding.confidence ?? 0.72), 0) / bucket.findings.length,
|
|
7751
|
+
0.74
|
|
7752
|
+
),
|
|
7753
|
+
searched_session_count: bucket.searchedSessionCount,
|
|
7754
|
+
skipped_session_count: bucket.skippedSessionCount,
|
|
7755
|
+
notes: [
|
|
7756
|
+
"Auto-generated by orgx-wizard from local AI-client session imports.",
|
|
7757
|
+
"Raw transcripts are excluded; only redacted evidence snippets and source refs are retained."
|
|
7758
|
+
]
|
|
7759
|
+
},
|
|
7760
|
+
findings: bucket.findings
|
|
7761
|
+
}));
|
|
7762
|
+
}
|
|
7316
7763
|
function buildDerivedFindings(imports) {
|
|
7317
7764
|
const findings = [];
|
|
7318
7765
|
let derivedIndex = 0;
|
|
@@ -7361,6 +7808,101 @@ function buildDerivedFindings(imports) {
|
|
|
7361
7808
|
}
|
|
7362
7809
|
return findings;
|
|
7363
7810
|
}
|
|
7811
|
+
var WORK_GRAPH_DOMAIN_RULES = [
|
|
7812
|
+
{
|
|
7813
|
+
id: "domain:orgx-agents-runtime",
|
|
7814
|
+
label: "OrgX agents and runtime",
|
|
7815
|
+
summary: "Agent orchestration, MCP writeback, hooks, approvals, and runtime governance.",
|
|
7816
|
+
patterns: [/\bagent\b/i, /\bsubagent\b/i, /\bmcp\b/i, /\bhook\b/i, /\bwriteback\b/i, /\borgx_emit\b/i, /\bscaffold_initiative\b/i]
|
|
7817
|
+
},
|
|
7818
|
+
{
|
|
7819
|
+
id: "domain:wizard-cli",
|
|
7820
|
+
label: "Wizard and CLI",
|
|
7821
|
+
summary: "OrgX Wizard setup, audit/profile generation, local release, and onboarding commands.",
|
|
7822
|
+
patterns: [/\bwizard\b/i, /\bcli\b/i, /\bnpm\b/i, /\brelease\b/i, /\bpublish\b/i, /\bwork-graph\b/i, /\bsessions reconcile\b/i]
|
|
7823
|
+
},
|
|
7824
|
+
{
|
|
7825
|
+
id: "domain:public-profile-ux",
|
|
7826
|
+
label: "Public profile and UX",
|
|
7827
|
+
summary: "Shareable readout, claim flow, mobile/desktop layout, evidence inspection, and profile copy.",
|
|
7828
|
+
patterns: [/\bprofile\b/i, /\bpublic readout\b/i, /\bclaim\b/i, /\bmobile\b/i, /\bdesktop\b/i, /\bux\b/i, /\bmirror\b/i, /\btrail inspector\b/i]
|
|
7829
|
+
},
|
|
7830
|
+
{
|
|
7831
|
+
id: "domain:plugins-integrations",
|
|
7832
|
+
label: "Plugins and integrations",
|
|
7833
|
+
summary: "Codex, Claude Code, Cursor/OpenClaw, Slack, GitHub, Linear, and source coverage work.",
|
|
7834
|
+
patterns: [/\bplugin\b/i, /\bcodex\b/i, /\bclaude\b/i, /\bcursor\b/i, /\bopenclaw\b/i, /\bslack\b/i, /\bgithub\b/i, /\blinear\b/i]
|
|
7835
|
+
},
|
|
7836
|
+
{
|
|
7837
|
+
id: "domain:quality-verification",
|
|
7838
|
+
label: "Quality and verification",
|
|
7839
|
+
summary: "Tests, browser QA, type checks, release proof, and stale/fixed verification.",
|
|
7840
|
+
patterns: [/\btest\b/i, /\btypecheck\b/i, /\bqa\b/i, /\bverified\b/i, /\bproof\b/i, /\bplaywright\b/i, /\bbrowser\b/i, /\bci\b/i]
|
|
7841
|
+
},
|
|
7842
|
+
{
|
|
7843
|
+
id: "domain:gtm-business",
|
|
7844
|
+
label: "GTM and business leverage",
|
|
7845
|
+
summary: "ICP framing, pricing/value estimates, outreach, buyers, revenue, and market-facing proof.",
|
|
7846
|
+
patterns: [/\bicp\b/i, /\bbuyer\b/i, /\bpricing\b/i, /\brevenue\b/i, /\bsales\b/i, /\bmarketing\b/i, /\bgtm\b/i, /\boperator leverage\b/i]
|
|
7847
|
+
}
|
|
7848
|
+
];
|
|
7849
|
+
function buildDomainCoverage(findings) {
|
|
7850
|
+
const signals = WORK_GRAPH_DOMAIN_RULES.map((rule) => {
|
|
7851
|
+
const matched = findings.filter((finding) => {
|
|
7852
|
+
const text2 = `${finding.title}
|
|
7853
|
+
${finding.summary}
|
|
7854
|
+
${finding.metadata.redacted_verbatim ?? ""}`;
|
|
7855
|
+
return rule.patterns.some((pattern) => pattern.test(text2));
|
|
7856
|
+
});
|
|
7857
|
+
if (matched.length === 0) return null;
|
|
7858
|
+
return {
|
|
7859
|
+
id: rule.id,
|
|
7860
|
+
label: rule.label,
|
|
7861
|
+
summary: rule.summary,
|
|
7862
|
+
finding_count: matched.length,
|
|
7863
|
+
source_clients: sortedUnique(matched.map((finding) => finding.source_client)),
|
|
7864
|
+
evidence_refs: sortedUnique(matched.map((finding) => finding.evidence_ref)).slice(0, 12),
|
|
7865
|
+
confidence: Number((matched.reduce((total, finding) => total + finding.confidence, 0) / matched.length).toFixed(2))
|
|
7866
|
+
};
|
|
7867
|
+
}).filter((signal) => Boolean(signal));
|
|
7868
|
+
return signals.sort((left, right) => right.finding_count - left.finding_count || right.confidence - left.confidence).slice(0, 8);
|
|
7869
|
+
}
|
|
7870
|
+
var SKILL_TOOL_RULES = [
|
|
7871
|
+
{ id: "skill:orgx-design", kind: "skill", label: "orgx-design", pattern: /\borgx-design\b|\$orgx-design/i },
|
|
7872
|
+
{ id: "skill:runtime-reporting", kind: "skill", label: "orgx-runtime-reporting", pattern: /\borgx-runtime-reporting\b|runtime reporting/i },
|
|
7873
|
+
{ id: "skill:initiative-ops", kind: "skill", label: "orgx-initiative-ops", pattern: /\borgx-initiative-ops\b|initiative ops/i },
|
|
7874
|
+
{ id: "agent:engineering", kind: "agent", label: "engineering-agent", pattern: /\bengineering-agent\b|engineering agent/i },
|
|
7875
|
+
{ id: "agent:design", kind: "agent", label: "design-agent", pattern: /\bdesign-agent\b|design agent/i },
|
|
7876
|
+
{ id: "agent:product", kind: "agent", label: "product-agent", pattern: /\bproduct-agent\b|product agent/i },
|
|
7877
|
+
{ id: "agent:orchestrator", kind: "agent", label: "orchestrator-agent", pattern: /\borchestrator-agent\b|orchestrator agent/i },
|
|
7878
|
+
{ id: "tool:orgx-list-entities", kind: "mcp_tool", label: "mcp__orgx__list_entities", pattern: /\bmcp__orgx__list_entities\b/i },
|
|
7879
|
+
{ id: "tool:scaffold", kind: "mcp_tool", label: "scaffold_initiative", pattern: /\bscaffold_initiative\b/i },
|
|
7880
|
+
{ id: "tool:complete-proof", kind: "mcp_tool", label: "complete_with_proof", pattern: /\bcomplete_with_proof\b/i },
|
|
7881
|
+
{ id: "tool:ship-batch", kind: "mcp_tool", label: "ship_batch", pattern: /\bship_batch\b/i },
|
|
7882
|
+
{ id: "client:codex", kind: "client_tool", label: "Codex", pattern: /\bcodex\b/i },
|
|
7883
|
+
{ id: "client:claude", kind: "client_tool", label: "Claude Code", pattern: /\bclaude(?: code)?\b/i },
|
|
7884
|
+
{ id: "source:github", kind: "source", label: "GitHub", pattern: /\bgithub\b|\bpull request\b|\bcommit\b/i },
|
|
7885
|
+
{ id: "source:slack", kind: "source", label: "Slack", pattern: /\bslack\b/i }
|
|
7886
|
+
];
|
|
7887
|
+
function buildSkillToolSignals(findings) {
|
|
7888
|
+
return SKILL_TOOL_RULES.map((rule) => {
|
|
7889
|
+
const matched = findings.filter(
|
|
7890
|
+
(finding) => rule.pattern.test(`${finding.title}
|
|
7891
|
+
${finding.summary}
|
|
7892
|
+
${finding.metadata.redacted_verbatim ?? ""}`)
|
|
7893
|
+
);
|
|
7894
|
+
if (matched.length === 0) return null;
|
|
7895
|
+
return {
|
|
7896
|
+
id: rule.id,
|
|
7897
|
+
label: rule.label,
|
|
7898
|
+
kind: rule.kind,
|
|
7899
|
+
mention_count: matched.length,
|
|
7900
|
+
source_clients: sortedUnique(matched.map((finding) => finding.source_client)),
|
|
7901
|
+
evidence_refs: sortedUnique(matched.map((finding) => finding.evidence_ref)).slice(0, 12),
|
|
7902
|
+
confidence: Number((matched.reduce((total, finding) => total + finding.confidence, 0) / matched.length).toFixed(2))
|
|
7903
|
+
};
|
|
7904
|
+
}).filter((signal) => Boolean(signal)).sort((left, right) => right.mention_count - left.mention_count || right.confidence - left.confidence).slice(0, 12);
|
|
7905
|
+
}
|
|
7364
7906
|
function buildWorkGraphEvents(imports) {
|
|
7365
7907
|
return imports.map((source, index) => ({
|
|
7366
7908
|
schema_version: WORK_GRAPH_SCHEMA_VERSION,
|
|
@@ -7373,6 +7915,7 @@ function buildWorkGraphEvents(imports) {
|
|
|
7373
7915
|
metadata: {
|
|
7374
7916
|
import_index: index,
|
|
7375
7917
|
line_count: source.text.split(/\r?\n/).filter(Boolean).length,
|
|
7918
|
+
...source.metadata ?? {},
|
|
7376
7919
|
raw_transcript_sent: false
|
|
7377
7920
|
}
|
|
7378
7921
|
}));
|
|
@@ -7466,9 +8009,84 @@ function scoreOpportunity(coverage, findings) {
|
|
|
7466
8009
|
orgx_fit: orgxFit
|
|
7467
8010
|
};
|
|
7468
8011
|
}
|
|
8012
|
+
function estimateImpactProjection(input) {
|
|
8013
|
+
const { coverage, findings, opportunityScore, patterns, trails } = input;
|
|
8014
|
+
const blockerEvents = trails.filter((trail) => trail.subject_entity_type === "blocker").reduce((total, trail) => total + Math.max(1, trail.events.length), 0);
|
|
8015
|
+
const decisionEvents = trails.filter((trail) => trail.subject_entity_type === "decision").reduce((total, trail) => total + Math.max(1, trail.events.length), 0);
|
|
8016
|
+
const artifactEvents = trails.filter((trail) => trail.subject_entity_type === "artifact").reduce((total, trail) => total + Math.max(1, trail.events.length), 0);
|
|
8017
|
+
const missedCount = findings.filter((finding) => finding.type === "missed_orchestration_opportunity").length;
|
|
8018
|
+
const repeatedEvents = trails.filter((trail) => trail.events.length > 1).reduce((total, trail) => total + trail.events.length, 0);
|
|
8019
|
+
const rawHours = blockerEvents * 0.75 + decisionEvents * 0.45 + artifactEvents * 0.25 + missedCount * 0.65 + repeatedEvents * 0.35 + coverage.missing.length * 0.4;
|
|
8020
|
+
const hours = Number(Math.max(0.5, Math.min(40, rawHours)).toFixed(1));
|
|
8021
|
+
const acceleration = clampScore2(
|
|
8022
|
+
6 + Math.round(opportunityScore.automation_potential * 0.22) + patterns.filter((pattern) => pattern.severity === "critical" || pattern.severity === "high").length * 5 + (coverage.manifests?.filter((manifest) => manifest.status === "connected").length ?? 0) * 2
|
|
8023
|
+
);
|
|
8024
|
+
const confidenceInputs = [
|
|
8025
|
+
...findings.map((finding) => finding.confidence),
|
|
8026
|
+
...patterns.map((pattern) => pattern.confidence),
|
|
8027
|
+
coverage.coverage_score ? coverage.coverage_score / 100 : 0.55
|
|
8028
|
+
];
|
|
8029
|
+
const confidence = Number((confidenceInputs.reduce((total, value) => total + value, 0) / Math.max(1, confidenceInputs.length)).toFixed(2));
|
|
8030
|
+
return {
|
|
8031
|
+
time_saved_hours_per_week: hours,
|
|
8032
|
+
acceleration_percent: Math.min(70, acceleration),
|
|
8033
|
+
estimated_monthly_value_usd: Math.round(hours * 4.33 * 200),
|
|
8034
|
+
confidence,
|
|
8035
|
+
basis: [
|
|
8036
|
+
`${blockerEvents} blocker event${blockerEvents === 1 ? "" : "s"} at 45 minutes of reconstruction/coordination each.`,
|
|
8037
|
+
`${decisionEvents} decision event${decisionEvents === 1 ? "" : "s"} at 27 minutes of rediscovery/promotion each.`,
|
|
8038
|
+
`${missedCount} missed orchestration signal${missedCount === 1 ? "" : "s"} at 39 minutes of manual writeback each.`,
|
|
8039
|
+
`${coverage.missing.length} missing source${coverage.missing.length === 1 ? "" : "s"} reducing attribution confidence.`
|
|
8040
|
+
],
|
|
8041
|
+
assumptions: [
|
|
8042
|
+
"Uses a conservative $200/hour blended founder/operator cost for public-safe value estimates.",
|
|
8043
|
+
"Acceleration estimates the execution lift from turning repeated evidence into automated attribution, decisions, and source connections.",
|
|
8044
|
+
"Impact is directional until the user claims the fingerprint and confirms or corrects the evidence."
|
|
8045
|
+
]
|
|
8046
|
+
};
|
|
8047
|
+
}
|
|
8048
|
+
function scoreExecutionQuality(input) {
|
|
8049
|
+
const { coverage, findings, impact, patterns, recommendations, trails } = input;
|
|
8050
|
+
const uniqueClients = sortedUnique(findings.map((finding) => finding.source_client));
|
|
8051
|
+
const unknownCount = findings.filter((finding) => finding.source_client === "unknown").length;
|
|
8052
|
+
const multiEventTrails = trails.filter((trail) => trail.events.length > 1).length;
|
|
8053
|
+
const evidenceCoverage = clampScore2(
|
|
8054
|
+
(coverage.coverage_score ?? 50) + Math.min(18, coverage.connected.length * 3) - coverage.missing.length * 4
|
|
8055
|
+
);
|
|
8056
|
+
const sourceAttribution = clampScore2(
|
|
8057
|
+
34 + uniqueClients.filter((client) => client !== "unknown").length * 10 + (coverage.manifests?.filter((manifest) => manifest.status === "connected").length ?? 0) * 6 - unknownCount * 8
|
|
8058
|
+
);
|
|
8059
|
+
const trailDepth = clampScore2(
|
|
8060
|
+
25 + (trails.length > 0 ? Math.round(multiEventTrails / trails.length * 45) : 0) + Math.min(20, trails.reduce((total, trail) => total + trail.events.length, 0) * 2)
|
|
8061
|
+
);
|
|
8062
|
+
const insightDepth = clampScore2(
|
|
8063
|
+
30 + Math.min(28, patterns.length * 8) + Math.min(18, findings.filter((finding) => ["blocker", "decision", "outcome", "missed_orchestration_opportunity"].includes(finding.type)).length * 3)
|
|
8064
|
+
);
|
|
8065
|
+
const actionability = clampScore2(
|
|
8066
|
+
30 + Math.min(35, recommendations.length * 10) + Math.min(20, recommendations.filter((recommendation) => recommendation.priority === "p0").length * 10)
|
|
8067
|
+
);
|
|
8068
|
+
const impactConfidence = clampScore2(impact.confidence * 100);
|
|
8069
|
+
const overall = clampScore2(
|
|
8070
|
+
evidenceCoverage * 0.22 + sourceAttribution * 0.18 + trailDepth * 0.18 + insightDepth * 0.18 + actionability * 0.14 + impactConfidence * 0.1
|
|
8071
|
+
);
|
|
8072
|
+
return {
|
|
8073
|
+
overall,
|
|
8074
|
+
evidence_coverage: evidenceCoverage,
|
|
8075
|
+
source_attribution: sourceAttribution,
|
|
8076
|
+
trail_depth: trailDepth,
|
|
8077
|
+
insight_depth: insightDepth,
|
|
8078
|
+
actionability,
|
|
8079
|
+
impact_confidence: impactConfidence,
|
|
8080
|
+
notes: [
|
|
8081
|
+
"10/10 requires client-native extraction per source, multi-event chronology, source-specific evidence, and action recommendations tied to impact.",
|
|
8082
|
+
multiEventTrails === trails.length ? "Every evidence path has multiple events." : `${trails.length - multiEventTrails} finding${trails.length - multiEventTrails === 1 ? "" : "s"} still need more chronology before they should be called recurring.`,
|
|
8083
|
+
coverage.missing.length > 0 ? `Missing source coverage: ${coverage.missing.join(", ")}.` : "No required source gaps were declared for this run."
|
|
8084
|
+
]
|
|
8085
|
+
};
|
|
8086
|
+
}
|
|
7469
8087
|
function inferFinalState(findings) {
|
|
7470
8088
|
if (findings.some((finding) => finding.type === "blocker")) return "blocked";
|
|
7471
|
-
if (findings.some((finding) => finding.type === "artifact" || /\b(shipped|completed|done|verified)\b/i.test(finding.summary))) {
|
|
8089
|
+
if (findings.some((finding) => finding.type === "artifact" || finding.type === "outcome" || /\b(shipped|completed|done|verified)\b/i.test(finding.summary))) {
|
|
7472
8090
|
return "completed";
|
|
7473
8091
|
}
|
|
7474
8092
|
if (findings.some((finding) => finding.type === "action" || finding.type === "decision")) return "in_progress";
|
|
@@ -7534,6 +8152,8 @@ function entityTypeForFinding(finding) {
|
|
|
7534
8152
|
case "goal":
|
|
7535
8153
|
case "initiative_candidate":
|
|
7536
8154
|
return "initiative";
|
|
8155
|
+
case "outcome":
|
|
8156
|
+
return "outcome";
|
|
7537
8157
|
case "action":
|
|
7538
8158
|
return /\b(outcome|shipped|completed|verified)\b/i.test(finding.summary) ? "outcome" : "task";
|
|
7539
8159
|
case "missed_orchestration_opportunity":
|
|
@@ -7586,6 +8206,8 @@ function eventTypeForFinding(finding) {
|
|
|
7586
8206
|
case "goal":
|
|
7587
8207
|
case "initiative_candidate":
|
|
7588
8208
|
return "initiative_created";
|
|
8209
|
+
case "outcome":
|
|
8210
|
+
return "outcome_recorded";
|
|
7589
8211
|
case "action":
|
|
7590
8212
|
return /\b(outcome|result|impact|roi)\b/i.test(finding.summary) ? "outcome_recorded" : "recommendation_generated";
|
|
7591
8213
|
case "missed_orchestration_opportunity":
|
|
@@ -7596,7 +8218,7 @@ function trailStateForFindings(findings) {
|
|
|
7596
8218
|
if (findings.some((finding) => finding.type === "blocker")) return "blocked";
|
|
7597
8219
|
if (findings.some((finding) => finding.type === "missed_orchestration_opportunity")) return "missing_evidence";
|
|
7598
8220
|
if (findings.some((finding) => /\b(contradict|conflict)\b/i.test(finding.summary))) return "contradicted";
|
|
7599
|
-
if (findings.some((finding) => /\b(verified|proof|passed|complete_with_proof)\b/i.test(finding.summary))) return "verified";
|
|
8221
|
+
if (findings.some((finding) => finding.type === "outcome" || /\b(verified|proof|passed|complete_with_proof)\b/i.test(finding.summary))) return "verified";
|
|
7600
8222
|
if (findings.some((finding) => finding.type === "decision")) return "inferred";
|
|
7601
8223
|
return "observed";
|
|
7602
8224
|
}
|
|
@@ -7604,6 +8226,7 @@ function trailValenceForFindings(findings, recurrence) {
|
|
|
7604
8226
|
if (findings.some((finding) => finding.type === "blocker")) return recurrence > 1 ? "escalating" : "risk";
|
|
7605
8227
|
if (findings.some((finding) => finding.type === "missed_orchestration_opportunity")) return "leak";
|
|
7606
8228
|
if (findings.some((finding) => finding.type === "decision") && recurrence > 1) return "wasteful_recurrence";
|
|
8229
|
+
if (findings.some((finding) => finding.type === "outcome")) return "healthy";
|
|
7607
8230
|
if (findings.some((finding) => finding.type === "business")) return "opportunity";
|
|
7608
8231
|
if (findings.some((finding) => finding.type === "artifact")) return "healthy";
|
|
7609
8232
|
return recurrence > 1 ? "useful_recurrence" : "opportunity";
|
|
@@ -7611,35 +8234,93 @@ function trailValenceForFindings(findings, recurrence) {
|
|
|
7611
8234
|
function trailShapeForFindings(findings, recurrence) {
|
|
7612
8235
|
const decisions = findings.filter((finding) => finding.type === "decision").length;
|
|
7613
8236
|
const artifacts = findings.filter((finding) => finding.type === "artifact").length;
|
|
8237
|
+
if (recurrence <= 1) return "single_signal";
|
|
7614
8238
|
if (decisions > artifacts && decisions > 0) return "decision_heavy_artifact_light";
|
|
7615
8239
|
if (artifacts > decisions && artifacts > 0 && decisions === 0) return "artifact_heavy_decision_light";
|
|
7616
|
-
if (findings.some((finding) => finding.type === "blocker")) return "accelerating_issue";
|
|
8240
|
+
if (findings.some((finding) => finding.type === "blocker")) return recurrence >= 3 ? "accelerating_issue" : "dense_recent_cluster";
|
|
7617
8241
|
if (recurrence >= 3) return "chronic_recurrence";
|
|
7618
8242
|
if (findings.some((finding) => /\b(resurface|again|back|revived|reappeared)\b/i.test(finding.summary))) return "zombie_revival";
|
|
7619
|
-
if (findings.some((finding) => /\b(verified|passed|shipped|completed)\b/i.test(finding.summary))) return "healthy_execution";
|
|
8243
|
+
if (findings.some((finding) => finding.type === "outcome" || /\b(verified|passed|shipped|completed)\b/i.test(finding.summary))) return "healthy_execution";
|
|
7620
8244
|
return "dense_recent_cluster";
|
|
7621
8245
|
}
|
|
8246
|
+
function findingTimestamp(finding, fallback) {
|
|
8247
|
+
const occurredAt = finding.metadata.occurred_at;
|
|
8248
|
+
return isIsoTimestamp(occurredAt) ? occurredAt : fallback;
|
|
8249
|
+
}
|
|
8250
|
+
function canonicalRelatedToken(finding) {
|
|
8251
|
+
const candidates = [
|
|
8252
|
+
...arrayOfStrings(finding.metadata.related_source_ids),
|
|
8253
|
+
...arrayOfStrings(finding.metadata.related_entity_names),
|
|
8254
|
+
finding.source_id,
|
|
8255
|
+
finding.title
|
|
8256
|
+
];
|
|
8257
|
+
const scored = candidates.map((candidate) => candidate.trim()).filter(Boolean).map((candidate) => {
|
|
8258
|
+
const normalized = candidate.toLowerCase();
|
|
8259
|
+
let score = 0;
|
|
8260
|
+
if (/_/.test(candidate)) score += 6;
|
|
8261
|
+
if (/orgx|mcp|wizard|plugin|runtime|hook|work graph|profile|trace|scaffold|ship|spawn|record|submit|list/i.test(candidate)) score += 5;
|
|
8262
|
+
if (/session|jsonl|rollout|line|current-release/i.test(normalized)) score -= 4;
|
|
8263
|
+
if (candidate.length > 80) score -= 2;
|
|
8264
|
+
return { candidate, score };
|
|
8265
|
+
}).filter((item) => item.score > 0).sort((left, right) => right.score - left.score);
|
|
8266
|
+
return scored[0]?.candidate ?? null;
|
|
8267
|
+
}
|
|
8268
|
+
function groupingKeyForFinding(finding) {
|
|
8269
|
+
const entityType = entityTypeForFinding(finding);
|
|
8270
|
+
const token = canonicalRelatedToken(finding);
|
|
8271
|
+
if (token && ["blocker", "source", "surface", "initiative", "outcome", "task"].includes(entityType)) {
|
|
8272
|
+
return `${entityType}:${slugPart(token)}`;
|
|
8273
|
+
}
|
|
8274
|
+
return `${entityType}:${slugPart(finding.title)}`;
|
|
8275
|
+
}
|
|
8276
|
+
function trailTitleForGroup(entityType, group) {
|
|
8277
|
+
const token = canonicalRelatedToken(group[0]);
|
|
8278
|
+
if (group.length > 1 && token) {
|
|
8279
|
+
const label = token.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
8280
|
+
if (entityType === "blocker") return `${label} is recurring as an execution blocker`;
|
|
8281
|
+
if (entityType === "source") return `${label} is an attribution coverage gap`;
|
|
8282
|
+
if (entityType === "surface") return `${label} is becoming a product surface evidence path`;
|
|
8283
|
+
if (entityType === "outcome") return `${label} is becoming outcome evidence`;
|
|
8284
|
+
return `${label} is becoming durable work`;
|
|
8285
|
+
}
|
|
8286
|
+
return group[0].title;
|
|
8287
|
+
}
|
|
8288
|
+
function trailSummaryForGroup(group) {
|
|
8289
|
+
if (group.length === 1) return group[0].summary;
|
|
8290
|
+
const sources = sortedUnique(group.map((finding) => labelForSourceClient(finding.source_client)));
|
|
8291
|
+
const states = sortedUnique(
|
|
8292
|
+
group.map((finding) => typeof finding.metadata.state === "string" ? finding.metadata.state : "").filter(Boolean)
|
|
8293
|
+
);
|
|
8294
|
+
return [
|
|
8295
|
+
`${group.length} evidence events connect this finding across ${sources.join(", ")}.`,
|
|
8296
|
+
states.length > 0 ? `Observed states: ${states.join(", ")}.` : "",
|
|
8297
|
+
group[0]?.summary ?? ""
|
|
8298
|
+
].filter(Boolean).join(" ");
|
|
8299
|
+
}
|
|
7622
8300
|
function buildWorkGraphTrails(findings, generatedAt) {
|
|
7623
8301
|
const grouped = /* @__PURE__ */ new Map();
|
|
7624
8302
|
for (const finding of findings) {
|
|
7625
|
-
const
|
|
7626
|
-
const key = `${entityType}:${slugPart(finding.title)}`;
|
|
8303
|
+
const key = groupingKeyForFinding(finding);
|
|
7627
8304
|
grouped.set(key, [...grouped.get(key) ?? [], finding]);
|
|
7628
8305
|
}
|
|
7629
8306
|
return [...grouped.entries()].map(([key, group], index) => {
|
|
7630
|
-
const
|
|
8307
|
+
const sortedGroup = [...group].sort(
|
|
8308
|
+
(left, right) => findingTimestamp(left, generatedAt).localeCompare(findingTimestamp(right, generatedAt))
|
|
8309
|
+
);
|
|
8310
|
+
const first = sortedGroup[0];
|
|
7631
8311
|
const entityType = entityTypeForFinding(first);
|
|
7632
8312
|
const entityId = `${entityType}:${shortHash(key, 12)}`;
|
|
7633
|
-
const trailId = `trail:${shortHash({ key, evidence:
|
|
7634
|
-
const recurrence =
|
|
7635
|
-
const evidenceRefs = sortedUnique(
|
|
7636
|
-
const events =
|
|
8313
|
+
const trailId = `trail:${shortHash({ key, evidence: sortedGroup.map((finding) => finding.evidence_ref) }, 14)}`;
|
|
8314
|
+
const recurrence = sortedGroup.length;
|
|
8315
|
+
const evidenceRefs = sortedUnique(sortedGroup.map((finding) => finding.evidence_ref));
|
|
8316
|
+
const events = sortedGroup.map((finding, eventIndex) => ({
|
|
7637
8317
|
id: `${trailId}:event:${eventIndex + 1}`,
|
|
7638
8318
|
trail_id: trailId,
|
|
7639
8319
|
event_type: eventTypeForFinding(finding),
|
|
7640
8320
|
entity_id: entityId,
|
|
7641
8321
|
entity_type: entityType,
|
|
7642
|
-
timestamp: generatedAt,
|
|
8322
|
+
timestamp: findingTimestamp(finding, generatedAt),
|
|
8323
|
+
...typeof finding.metadata.actor_id === "string" ? { actor_id: finding.metadata.actor_id } : {},
|
|
7643
8324
|
source_id: finding.source_id,
|
|
7644
8325
|
source_type: finding.source_client,
|
|
7645
8326
|
redacted_verbatim: finding.summary.slice(0, 320),
|
|
@@ -7656,28 +8337,30 @@ function buildWorkGraphTrails(findings, generatedAt) {
|
|
|
7656
8337
|
confidence: Math.min(0.92, Math.max(0.58, event.confidence - 0.04)),
|
|
7657
8338
|
evidence_refs: event.evidence_refs
|
|
7658
8339
|
}));
|
|
7659
|
-
const confidence =
|
|
8340
|
+
const confidence = sortedGroup.reduce((total, finding) => total + finding.confidence, 0) / sortedGroup.length;
|
|
8341
|
+
const createdAt = events[0]?.timestamp ?? generatedAt;
|
|
8342
|
+
const updatedAt = events[events.length - 1]?.timestamp ?? generatedAt;
|
|
7660
8343
|
return {
|
|
7661
8344
|
id: trailId,
|
|
7662
8345
|
kind: trailKindForEntity(entityType),
|
|
7663
|
-
title:
|
|
7664
|
-
summary:
|
|
8346
|
+
title: trailTitleForGroup(entityType, sortedGroup),
|
|
8347
|
+
summary: trailSummaryForGroup(sortedGroup),
|
|
7665
8348
|
subject_entity_id: entityId,
|
|
7666
8349
|
subject_entity_type: entityType,
|
|
7667
|
-
state: trailStateForFindings(
|
|
7668
|
-
valence: trailValenceForFindings(
|
|
8350
|
+
state: trailStateForFindings(sortedGroup),
|
|
8351
|
+
valence: trailValenceForFindings(sortedGroup, recurrence),
|
|
7669
8352
|
confidence: Number(confidence.toFixed(2)),
|
|
7670
|
-
recurrence_score: Math.min(100, recurrence *
|
|
8353
|
+
recurrence_score: recurrence <= 1 ? Math.min(24, evidenceRefs.length * 8 + 10) : Math.min(100, recurrence * 24 + evidenceRefs.length * 7),
|
|
7671
8354
|
impact_score: Math.min(100, Math.round(first.confidence * 70) + recurrence * 8 + (index < 4 ? 10 : 0)),
|
|
7672
8355
|
privacy_state: "redacted",
|
|
7673
8356
|
events,
|
|
7674
8357
|
edges,
|
|
7675
8358
|
evidence_refs: evidenceRefs,
|
|
7676
|
-
blocker_ids:
|
|
8359
|
+
blocker_ids: sortedGroup.filter((finding) => finding.type === "blocker").map((finding) => finding.evidence_ref),
|
|
7677
8360
|
recommendation_ids: [],
|
|
7678
|
-
created_at:
|
|
7679
|
-
updated_at:
|
|
7680
|
-
shape: trailShapeForFindings(
|
|
8361
|
+
created_at: createdAt,
|
|
8362
|
+
updated_at: updatedAt,
|
|
8363
|
+
shape: trailShapeForFindings(sortedGroup, recurrence)
|
|
7681
8364
|
};
|
|
7682
8365
|
});
|
|
7683
8366
|
}
|
|
@@ -7702,7 +8385,7 @@ function buildRecurringPatterns(coverage, findings, trails) {
|
|
|
7702
8385
|
patterns.push({
|
|
7703
8386
|
id: "pattern:trapped-decision",
|
|
7704
8387
|
title: "Decisions are being made without durable OrgX writeback",
|
|
7705
|
-
description: `${decisionTrails.length} decision
|
|
8388
|
+
description: `${decisionTrails.length} decision finding${decisionTrails.length === 1 ? "" : "s"} appeared while no OrgX MCP write was detected.`,
|
|
7706
8389
|
pattern_type: "trapped_decision",
|
|
7707
8390
|
affected_trail_ids: decisionTrails.map((trail) => trail.id),
|
|
7708
8391
|
affected_entity_ids: decisionTrails.map((trail) => trail.subject_entity_id),
|
|
@@ -7718,7 +8401,7 @@ function buildRecurringPatterns(coverage, findings, trails) {
|
|
|
7718
8401
|
patterns.push({
|
|
7719
8402
|
id: "pattern:orphaned-artifact",
|
|
7720
8403
|
title: "Artifacts do not have visible ownership",
|
|
7721
|
-
description: `${artifactTrails.length} artifact
|
|
8404
|
+
description: `${artifactTrails.length} artifact finding${artifactTrails.length === 1 ? "" : "s"} appeared without a clear owner-visible record.`,
|
|
7722
8405
|
pattern_type: "orphaned_artifact",
|
|
7723
8406
|
affected_trail_ids: artifactTrails.map((trail) => trail.id),
|
|
7724
8407
|
affected_entity_ids: artifactTrails.map((trail) => trail.subject_entity_id),
|
|
@@ -7767,7 +8450,7 @@ function buildRecurringPatterns(coverage, findings, trails) {
|
|
|
7767
8450
|
patterns.push({
|
|
7768
8451
|
id: "pattern:repeated-work",
|
|
7769
8452
|
title: "The same work shape is recurring",
|
|
7770
|
-
description: `${highRecurrence.length}
|
|
8453
|
+
description: `${highRecurrence.length} finding${highRecurrence.length === 1 ? "" : "s"} repeat strongly enough to deserve durable operating memory.`,
|
|
7771
8454
|
pattern_type: "repeated_work",
|
|
7772
8455
|
affected_trail_ids: highRecurrence.map((trail) => trail.id),
|
|
7773
8456
|
affected_entity_ids: highRecurrence.map((trail) => trail.subject_entity_id),
|
|
@@ -7783,7 +8466,7 @@ function buildRecurringPatterns(coverage, findings, trails) {
|
|
|
7783
8466
|
patterns.push({
|
|
7784
8467
|
id: "pattern:business-signal-unclaimed",
|
|
7785
8468
|
title: "Business signal has not become a launchable initiative",
|
|
7786
|
-
description: `${businessTrails.length} business
|
|
8469
|
+
description: `${businessTrails.length} business finding${businessTrails.length === 1 ? "" : "s"} appeared without a matching initiative candidate.`,
|
|
7787
8470
|
pattern_type: "business_signal_unclaimed",
|
|
7788
8471
|
affected_trail_ids: businessTrails.map((trail) => trail.id),
|
|
7789
8472
|
affected_entity_ids: businessTrails.map((trail) => trail.subject_entity_id),
|
|
@@ -7796,10 +8479,13 @@ function buildRecurringPatterns(coverage, findings, trails) {
|
|
|
7796
8479
|
});
|
|
7797
8480
|
}
|
|
7798
8481
|
if (blockerTrails.length > 0) {
|
|
8482
|
+
const topBlockerTrail = [...blockerTrails].sort(
|
|
8483
|
+
(left, right) => right.events.length - left.events.length || right.impact_score - left.impact_score
|
|
8484
|
+
)[0];
|
|
7799
8485
|
patterns.push({
|
|
7800
8486
|
id: "pattern:handoff-friction",
|
|
7801
|
-
title: "Blockers are becoming handoff friction",
|
|
7802
|
-
description: `${blockerTrails.length} blocker
|
|
8487
|
+
title: topBlockerTrail && topBlockerTrail.events.length > 1 ? `${topBlockerTrail.title} and needs owner-visible resolution` : "Blockers are becoming handoff friction",
|
|
8488
|
+
description: `${blockerTrails.length} blocker finding${blockerTrails.length === 1 ? "" : "s"} need owner-visible resolution.`,
|
|
7803
8489
|
pattern_type: "handoff_friction",
|
|
7804
8490
|
affected_trail_ids: blockerTrails.map((trail) => trail.id),
|
|
7805
8491
|
affected_entity_ids: blockerTrails.map((trail) => trail.subject_entity_id),
|
|
@@ -7852,7 +8538,7 @@ function buildTrailRecommendations(patterns, trails) {
|
|
|
7852
8538
|
add({
|
|
7853
8539
|
id: "recommendation:connect-source",
|
|
7854
8540
|
title: "Connect missing source coverage",
|
|
7855
|
-
summary: "Close the evidence gap by connecting the coordination or proof sources where
|
|
8541
|
+
summary: "Close the evidence gap by connecting the coordination or proof sources where findings lose ownership or verification context.",
|
|
7856
8542
|
action_type: "connect_source",
|
|
7857
8543
|
trail_ids: pattern.affected_trail_ids,
|
|
7858
8544
|
evidence_refs: evidenceRefs,
|
|
@@ -7872,10 +8558,22 @@ function buildTrailRecommendations(patterns, trails) {
|
|
|
7872
8558
|
expected_lift: "+continuous attribution",
|
|
7873
8559
|
confidence: pattern.confidence
|
|
7874
8560
|
});
|
|
8561
|
+
} else if (pattern.pattern_type === "handoff_friction") {
|
|
8562
|
+
add({
|
|
8563
|
+
id: "recommendation:resolve-blocker-handoff",
|
|
8564
|
+
title: "Resolve the blocker handoff",
|
|
8565
|
+
summary: "Promote the recurring blocker path into assigned work with proof requirements and a clear owner.",
|
|
8566
|
+
action_type: "assign_owner",
|
|
8567
|
+
trail_ids: pattern.affected_trail_ids,
|
|
8568
|
+
evidence_refs: evidenceRefs,
|
|
8569
|
+
priority: pattern.severity === "critical" || pattern.severity === "high" ? "p0" : "p1",
|
|
8570
|
+
expected_lift: "+execution continuity",
|
|
8571
|
+
confidence: pattern.confidence
|
|
8572
|
+
});
|
|
7875
8573
|
} else if (pattern.pattern_type === "business_signal_unclaimed" || pattern.pattern_type === "repeated_work") {
|
|
7876
8574
|
add({
|
|
7877
8575
|
id: "recommendation:launch-initiative",
|
|
7878
|
-
title: "Launch from this
|
|
8576
|
+
title: "Launch from this evidence",
|
|
7879
8577
|
summary: "Convert the highest-recurring evidence path into an OrgX initiative with proof requirements.",
|
|
7880
8578
|
action_type: "launch_initiative",
|
|
7881
8579
|
trail_ids: pattern.affected_trail_ids,
|
|
@@ -7890,7 +8588,7 @@ function buildTrailRecommendations(patterns, trails) {
|
|
|
7890
8588
|
const topTrail = [...trails].sort((a, b) => b.impact_score - a.impact_score)[0];
|
|
7891
8589
|
add({
|
|
7892
8590
|
id: "recommendation:inspect-top-trail",
|
|
7893
|
-
title: "Inspect the strongest
|
|
8591
|
+
title: "Inspect the strongest finding",
|
|
7894
8592
|
summary: "Review the highest-confidence evidence path and decide whether it should become durable OrgX memory.",
|
|
7895
8593
|
action_type: "launch_initiative",
|
|
7896
8594
|
trail_ids: [topTrail.id],
|
|
@@ -7900,44 +8598,64 @@ function buildTrailRecommendations(patterns, trails) {
|
|
|
7900
8598
|
confidence: topTrail.confidence
|
|
7901
8599
|
});
|
|
7902
8600
|
}
|
|
7903
|
-
|
|
8601
|
+
const priorityRank = { p0: 0, p1: 1, p2: 2 };
|
|
8602
|
+
return recommendations.sort(
|
|
8603
|
+
(left, right) => priorityRank[left.priority] - priorityRank[right.priority] || right.confidence - left.confidence
|
|
8604
|
+
).slice(0, 5);
|
|
7904
8605
|
}
|
|
7905
8606
|
function buildWorkGraphMirror(input) {
|
|
7906
|
-
const { coverage, generatedAt, patterns, recommendations, trails } = input;
|
|
7907
|
-
const topTrail =
|
|
8607
|
+
const { auditMethod, coverage, domains = [], generatedAt, impact, patterns, recommendations, skillToolSignals = [], trails } = input;
|
|
8608
|
+
const topTrail = selectPublicTopTrail(trails);
|
|
7908
8609
|
const topPattern = [...patterns].sort((a, b) => b.recurrence_count - a.recurrence_count)[0];
|
|
7909
8610
|
const decisionCount = trailsForType(trails, "decision").length;
|
|
7910
8611
|
const artifactCount = trailsForType(trails, "artifact").length;
|
|
7911
8612
|
const blockerCount = trailsForType(trails, "blocker").length;
|
|
7912
8613
|
const sourceGapCount = coverage.missing.length;
|
|
7913
|
-
const
|
|
8614
|
+
const sourceClients = sortedUnique(
|
|
8615
|
+
trails.flatMap((trail) => trail.events.map((event) => event.source_type))
|
|
8616
|
+
);
|
|
8617
|
+
const sourcePhrase = sourceClients.length > 0 ? sourceClients.map(labelForSourceClient).join(", ") : coverage.connected.join(", ") || "local sources";
|
|
8618
|
+
const headline = blockerCount > 0 ? "Your AI work is shipping, but the execution record is incomplete" : sourceGapCount > 0 ? "Your AI work is visible, but the proof chain is incomplete" : topPattern ? "Your work has a recurring operating pattern worth preserving" : topTrail ? "Your work is becoming an operating profile" : "Your work is leaving evidence OrgX can organize";
|
|
8619
|
+
const domainPhrase = domains.length > 0 ? domains.slice(0, 4).map((domain) => domain.label).join(", ") : "the connected work surface";
|
|
8620
|
+
const toolPhrase = skillToolSignals.length > 0 ? skillToolSignals.slice(0, 4).map((signal) => signal.label).join(", ") : "client sessions and available tools";
|
|
7914
8621
|
const primaryClaimRefs = topTrail?.evidence_refs ?? [];
|
|
7915
8622
|
const claims = [
|
|
7916
8623
|
{
|
|
7917
8624
|
id: "mirror:trail-count",
|
|
7918
|
-
text: `${trails.length} trails were detected across ${coverage.connected.length} connected source${coverage.connected.length === 1 ? "" : "s"}.`,
|
|
8625
|
+
text: `${trails.length} evidence-backed finding${trails.length === 1 ? "" : "s"} were detected across ${coverage.connected.length} connected source${coverage.connected.length === 1 ? "" : "s"}.`,
|
|
7919
8626
|
evidence_refs: trails.flatMap((trail) => trail.evidence_refs).slice(0, 6),
|
|
7920
8627
|
confidence: trails.length > 0 ? 0.82 : 0.55
|
|
7921
8628
|
},
|
|
7922
8629
|
{
|
|
7923
8630
|
id: "mirror:decision-artifact-balance",
|
|
7924
|
-
text: `${decisionCount} decision
|
|
8631
|
+
text: `${decisionCount} decision finding${decisionCount === 1 ? "" : "s"} and ${artifactCount} artifact finding${artifactCount === 1 ? "" : "s"} were found.`,
|
|
7925
8632
|
evidence_refs: trails.filter((trail) => trail.subject_entity_type === "decision" || trail.subject_entity_type === "artifact").flatMap((trail) => trail.evidence_refs).slice(0, 6),
|
|
7926
8633
|
confidence: 0.78
|
|
7927
8634
|
},
|
|
7928
8635
|
{
|
|
7929
8636
|
id: "mirror:missing-sources",
|
|
7930
|
-
text: sourceGapCount > 0 ? `${sourceGapCount} source gap${sourceGapCount === 1 ? "" : "s"} still limit attribution depth.` : "The connected sources are enough for a first operating profile.",
|
|
8637
|
+
text: sourceGapCount > 0 ? `${sourceGapCount} source gap${sourceGapCount === 1 ? "" : "s"} still limit attribution depth.` : "The connected sources are enough for a first operating profile, pending human review.",
|
|
7931
8638
|
evidence_refs: trailsForType(trails, "source").flatMap((trail) => trail.evidence_refs).slice(0, 4),
|
|
7932
8639
|
confidence: sourceGapCount > 0 ? 0.76 : 0.66
|
|
7933
|
-
}
|
|
8640
|
+
},
|
|
8641
|
+
...impact ? [{
|
|
8642
|
+
id: "mirror:impact",
|
|
8643
|
+
text: `${impact.time_saved_hours_per_week} hours/week and +${impact.acceleration_percent}% execution acceleration are recoverable if the top findings get owner, proof, and writeback.`,
|
|
8644
|
+
evidence_refs: trails.flatMap((trail) => trail.evidence_refs).slice(0, 6),
|
|
8645
|
+
confidence: impact.confidence
|
|
8646
|
+
}] : []
|
|
7934
8647
|
];
|
|
8648
|
+
const searchClaim = auditMethod ? `OrgX searched ${auditMethod.searched_session_files} AI-client session files and ${auditMethod.searched_message_count} message turns across ${sourcePhrase}; it retained ${auditMethod.retained_evidence_lines} evidence lines and excluded raw transcripts.` : `OrgX searched your AI-client session evidence across ${sourcePhrase} without requiring OrgX tool calls to be present.`;
|
|
8649
|
+
const topIssue = topTrail ? `The highest-risk issue is ${topTrail.title.toLowerCase()}.` : topPattern ? `The highest-risk pattern is ${topPattern.title.toLowerCase()}.` : "The first profile is forming from sparse evidence and should be reviewed before promotion.";
|
|
7935
8650
|
const body = [
|
|
7936
|
-
|
|
7937
|
-
`
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
8651
|
+
searchClaim,
|
|
8652
|
+
`It found ${trails.length} evidence-backed finding${trails.length === 1 ? "" : "s"} across ${domainPhrase}, with ${toolPhrase} showing up as the strongest skills, tools, or sources.`,
|
|
8653
|
+
topIssue,
|
|
8654
|
+
blockerCount > 0 ? `${blockerCount} blocker finding${blockerCount === 1 ? "" : "s"} show work returning as new work instead of becoming owner-visible resolution.` : `${decisionCount} decision finding${decisionCount === 1 ? "" : "s"} and ${artifactCount} artifact finding${artifactCount === 1 ? "" : "s"} show where work can become durable.`,
|
|
8655
|
+
sourceGapCount > 0 ? `${sourceGapCount} source gap${sourceGapCount === 1 ? "" : "s"} still limit trust: ownership, handoffs, GitHub proof, Slack coordination, or later verification.` : "The connected sources are enough for a first public-safe profile, pending human review.",
|
|
8656
|
+
impact ? `Left unresolved, the profile estimates ${impact.time_saved_hours_per_week} recoverable hours/week and about $${impact.estimated_monthly_value_usd.toLocaleString("en-US")}/month in operator leverage.` : "",
|
|
8657
|
+
recommendations[0] ? `The next repair is concrete: ${recommendations[0].title}.` : "The next move is to inspect the highest-confidence finding before publishing it."
|
|
8658
|
+
].filter(Boolean).join(" ");
|
|
7941
8659
|
return {
|
|
7942
8660
|
headline,
|
|
7943
8661
|
body,
|
|
@@ -7947,14 +8665,58 @@ function buildWorkGraphMirror(input) {
|
|
|
7947
8665
|
generated_at: generatedAt
|
|
7948
8666
|
};
|
|
7949
8667
|
}
|
|
8668
|
+
function selectPublicTopTrail(trails) {
|
|
8669
|
+
const ranked = [...trails].sort((left, right) => publicTrailRank(right) - publicTrailRank(left));
|
|
8670
|
+
return ranked[0];
|
|
8671
|
+
}
|
|
8672
|
+
function publicTrailRank(trail) {
|
|
8673
|
+
const title = trail.title.trim();
|
|
8674
|
+
let score = trail.impact_score;
|
|
8675
|
+
if (trail.events.length > 1) score += 10;
|
|
8676
|
+
if (trail.subject_entity_type === "blocker") score += 6;
|
|
8677
|
+
if (/\b(?:scaffold|ship_batch|mcp__orgx__list_entities|list entities|schema validation|route behavior|dispatching agent runs|operation qa loop)\b/i.test(title)) {
|
|
8678
|
+
score += 14;
|
|
8679
|
+
}
|
|
8680
|
+
if (/^(?:[-*✓{`'"]|\d+[,.]?$)/.test(title)) score -= 32;
|
|
8681
|
+
if (/[{}|;]/.test(title)) score -= 28;
|
|
8682
|
+
if (title.length < 22) score -= 26;
|
|
8683
|
+
if (/^(?:result|summary)\s*:/i.test(title)) score -= 18;
|
|
8684
|
+
return score;
|
|
8685
|
+
}
|
|
7950
8686
|
function buildTensionMetrics(input) {
|
|
7951
|
-
const { coverage, patterns, trails } = input;
|
|
8687
|
+
const { coverage, impact, patterns, quality, trails } = input;
|
|
7952
8688
|
const decisionTrails = trailsForType(trails, "decision");
|
|
7953
8689
|
const blockerTrails = trailsForType(trails, "blocker");
|
|
7954
8690
|
const artifactTrails = trailsForType(trails, "artifact");
|
|
7955
8691
|
const missingSourceTrails = trailsForType(trails, "source");
|
|
7956
8692
|
const topReady = trails.filter((trail) => trail.impact_score >= 70 && trail.confidence >= 0.75);
|
|
7957
8693
|
return [
|
|
8694
|
+
...quality ? [{
|
|
8695
|
+
id: "tension:quality-score",
|
|
8696
|
+
label: "quality score",
|
|
8697
|
+
value: `${quality.overall}/100`,
|
|
8698
|
+
tone: quality.overall >= 82 ? "good" : quality.overall >= 65 ? "warning" : "danger",
|
|
8699
|
+
trail_ids: trails.slice(0, 8).map((trail) => trail.id),
|
|
8700
|
+
evidence_refs: trails.flatMap((trail) => trail.evidence_refs).slice(0, 8),
|
|
8701
|
+
explanation: "Weighted audit quality across evidence coverage, attribution, chronology depth, insight depth, actionability, and impact confidence."
|
|
8702
|
+
}] : [],
|
|
8703
|
+
...impact ? [{
|
|
8704
|
+
id: "tension:time-saved",
|
|
8705
|
+
label: "hours recoverable",
|
|
8706
|
+
value: `${impact.time_saved_hours_per_week}h/wk`,
|
|
8707
|
+
tone: impact.time_saved_hours_per_week >= 4 ? "warning" : "muted",
|
|
8708
|
+
trail_ids: patterns.flatMap((pattern) => pattern.affected_trail_ids).slice(0, 8),
|
|
8709
|
+
evidence_refs: trails.flatMap((trail) => trail.evidence_refs).slice(0, 8),
|
|
8710
|
+
explanation: "Estimated time recovered by promoting repeated decisions, blockers, artifacts, and writeback gaps into durable operating memory."
|
|
8711
|
+
}, {
|
|
8712
|
+
id: "tension:acceleration",
|
|
8713
|
+
label: "acceleration",
|
|
8714
|
+
value: `+${impact.acceleration_percent}%`,
|
|
8715
|
+
tone: impact.acceleration_percent >= 30 ? "good" : "muted",
|
|
8716
|
+
trail_ids: patterns.flatMap((pattern) => pattern.affected_trail_ids).slice(0, 8),
|
|
8717
|
+
evidence_refs: trails.flatMap((trail) => trail.evidence_refs).slice(0, 8),
|
|
8718
|
+
explanation: "Directional execution lift from connecting source evidence, writeback, owners, and action recommendations."
|
|
8719
|
+
}] : [],
|
|
7958
8720
|
{
|
|
7959
8721
|
id: "tension:work-leaks",
|
|
7960
8722
|
label: "work leaks",
|
|
@@ -7971,7 +8733,7 @@ function buildTensionMetrics(input) {
|
|
|
7971
8733
|
tone: decisionTrails.length > 0 && !coverage.orgxMcpCalled ? "danger" : "muted",
|
|
7972
8734
|
trail_ids: decisionTrails.map((trail) => trail.id),
|
|
7973
8735
|
evidence_refs: decisionTrails.flatMap((trail) => trail.evidence_refs).slice(0, 8),
|
|
7974
|
-
explanation: "Decision
|
|
8736
|
+
explanation: "Decision evidence that has not been promoted into durable OrgX records."
|
|
7975
8737
|
},
|
|
7976
8738
|
{
|
|
7977
8739
|
id: "tension:artifacts-orphaned",
|
|
@@ -7998,7 +8760,7 @@ function buildTensionMetrics(input) {
|
|
|
7998
8760
|
tone: topReady.length > 0 && blockerTrails.length === 0 ? "good" : "muted",
|
|
7999
8761
|
trail_ids: topReady.map((trail) => trail.id).slice(0, 6),
|
|
8000
8762
|
evidence_refs: topReady.flatMap((trail) => trail.evidence_refs).slice(0, 8),
|
|
8001
|
-
explanation: "High-confidence
|
|
8763
|
+
explanation: "High-confidence findings that can become initiatives, decisions, artifacts, or owner-visible follow-ups."
|
|
8002
8764
|
}
|
|
8003
8765
|
];
|
|
8004
8766
|
}
|
|
@@ -8011,6 +8773,317 @@ function countFindingsByType(findings) {
|
|
|
8011
8773
|
Object.entries(counts).sort(([left], [right]) => left.localeCompare(right))
|
|
8012
8774
|
);
|
|
8013
8775
|
}
|
|
8776
|
+
function isIsoTimestamp(value) {
|
|
8777
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
8778
|
+
}
|
|
8779
|
+
function redactionStateForFinding(finding) {
|
|
8780
|
+
const privacy = typeof finding.metadata.privacy_state === "string" ? finding.metadata.privacy_state : "";
|
|
8781
|
+
if (privacy === "private") return "private";
|
|
8782
|
+
if (privacy === "redacted") return "redacted";
|
|
8783
|
+
return "public_summary";
|
|
8784
|
+
}
|
|
8785
|
+
function attributionKindForFinding(type) {
|
|
8786
|
+
switch (type) {
|
|
8787
|
+
case "action":
|
|
8788
|
+
case "blocker":
|
|
8789
|
+
case "outcome":
|
|
8790
|
+
return "action";
|
|
8791
|
+
case "decision":
|
|
8792
|
+
case "artifact":
|
|
8793
|
+
case "person":
|
|
8794
|
+
case "business":
|
|
8795
|
+
case "product_surface":
|
|
8796
|
+
case "goal":
|
|
8797
|
+
return type;
|
|
8798
|
+
case "initiative_candidate":
|
|
8799
|
+
return "goal";
|
|
8800
|
+
case "missed_orchestration_opportunity":
|
|
8801
|
+
return "source";
|
|
8802
|
+
default:
|
|
8803
|
+
return null;
|
|
8804
|
+
}
|
|
8805
|
+
}
|
|
8806
|
+
function attributionEventTypeForFinding(finding) {
|
|
8807
|
+
if (finding.source_client === "slack") return "slack_message";
|
|
8808
|
+
if (finding.source_client === "github") return "github_event";
|
|
8809
|
+
if (finding.source_client === "linear") return "linear_event";
|
|
8810
|
+
if (finding.source_client === "gmail") return "gmail_message";
|
|
8811
|
+
if (finding.source_client === "calendar") return "calendar_event";
|
|
8812
|
+
if (finding.source_client === "notion" || finding.source_client === "docs") return "doc_signal";
|
|
8813
|
+
if (finding.source_client === "mcp") return "mcp_call";
|
|
8814
|
+
if (finding.type === "artifact") return "repo_artifact";
|
|
8815
|
+
if (finding.type === "missed_orchestration_opportunity") return "source_coverage";
|
|
8816
|
+
if (/\b(mcp|tool|hook|runtime)\b/i.test(`${finding.title} ${finding.summary}`)) return "tool_signal";
|
|
8817
|
+
return "client_extraction";
|
|
8818
|
+
}
|
|
8819
|
+
function nodeBucketForKind(kind) {
|
|
8820
|
+
switch (kind) {
|
|
8821
|
+
case "decision":
|
|
8822
|
+
return "decisions";
|
|
8823
|
+
case "artifact":
|
|
8824
|
+
return "artifacts";
|
|
8825
|
+
case "person":
|
|
8826
|
+
return "people";
|
|
8827
|
+
case "agent":
|
|
8828
|
+
return "agents";
|
|
8829
|
+
case "tool":
|
|
8830
|
+
return "tools";
|
|
8831
|
+
case "business":
|
|
8832
|
+
return "businesses";
|
|
8833
|
+
case "product_surface":
|
|
8834
|
+
return "product_surfaces";
|
|
8835
|
+
case "goal":
|
|
8836
|
+
return "goals";
|
|
8837
|
+
case "source":
|
|
8838
|
+
return "sources";
|
|
8839
|
+
case "action":
|
|
8840
|
+
default:
|
|
8841
|
+
return "actions";
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
function nodeIdForFinding(kind, finding) {
|
|
8845
|
+
const dedupeSource = finding.metadata.dedupe_key ?? finding.evidence_ref ?? finding.title;
|
|
8846
|
+
return `${kind}:${slugPart(finding.title)}:${shortHash(dedupeSource, 8)}`;
|
|
8847
|
+
}
|
|
8848
|
+
function buildFindingNode(finding, kind) {
|
|
8849
|
+
const id = nodeIdForFinding(kind, finding);
|
|
8850
|
+
return {
|
|
8851
|
+
id,
|
|
8852
|
+
kind,
|
|
8853
|
+
label: finding.title,
|
|
8854
|
+
summary: finding.summary,
|
|
8855
|
+
source_client: finding.source_client,
|
|
8856
|
+
evidence_refs: [finding.evidence_ref],
|
|
8857
|
+
linked_node_ids: [],
|
|
8858
|
+
confidence: finding.confidence,
|
|
8859
|
+
weight: clampScore2(finding.confidence * 100),
|
|
8860
|
+
review_state: "unreviewed",
|
|
8861
|
+
dedupe_key: `${kind}:${slugPart(finding.title)}`,
|
|
8862
|
+
metadata: {
|
|
8863
|
+
source_id: finding.source_id,
|
|
8864
|
+
finding_type: finding.type,
|
|
8865
|
+
...finding.metadata
|
|
8866
|
+
}
|
|
8867
|
+
};
|
|
8868
|
+
}
|
|
8869
|
+
function mergeNodes(nodes) {
|
|
8870
|
+
const merged = /* @__PURE__ */ new Map();
|
|
8871
|
+
for (const node of nodes) {
|
|
8872
|
+
const key = node.dedupe_key ?? node.id;
|
|
8873
|
+
const previous = merged.get(key);
|
|
8874
|
+
if (!previous) {
|
|
8875
|
+
merged.set(key, node);
|
|
8876
|
+
continue;
|
|
8877
|
+
}
|
|
8878
|
+
merged.set(key, {
|
|
8879
|
+
...previous,
|
|
8880
|
+
confidence: Math.max(previous.confidence, node.confidence),
|
|
8881
|
+
evidence_refs: sortedUnique([...previous.evidence_refs, ...node.evidence_refs]),
|
|
8882
|
+
linked_node_ids: sortedUnique([...previous.linked_node_ids, ...node.linked_node_ids]),
|
|
8883
|
+
weight: Math.max(previous.weight, node.weight)
|
|
8884
|
+
});
|
|
8885
|
+
}
|
|
8886
|
+
return [...merged.values()].sort((left, right) => right.weight - left.weight);
|
|
8887
|
+
}
|
|
8888
|
+
function sourceNode(source, connected) {
|
|
8889
|
+
const label = source.trim() || "Unknown source";
|
|
8890
|
+
return {
|
|
8891
|
+
id: `source:${slugPart(label)}:${connected ? "connected" : "missing"}`,
|
|
8892
|
+
kind: "source",
|
|
8893
|
+
label,
|
|
8894
|
+
summary: connected ? `${label} contributed evidence to this Work Graph.` : `${label} was not connected, so related attribution remains incomplete.`,
|
|
8895
|
+
evidence_refs: [],
|
|
8896
|
+
linked_node_ids: [],
|
|
8897
|
+
confidence: connected ? 0.8 : 0.52,
|
|
8898
|
+
weight: connected ? 70 : 62,
|
|
8899
|
+
review_state: connected ? "unreviewed" : "important",
|
|
8900
|
+
dedupe_key: `source:${slugPart(label)}`,
|
|
8901
|
+
metadata: { connected }
|
|
8902
|
+
};
|
|
8903
|
+
}
|
|
8904
|
+
function buildToolNodes(coverage, findings) {
|
|
8905
|
+
const mentionsOrgxTool = coverage.mcpObserved || findings.some((finding) => /\b(orgx[_-]?mcp|orgx_emit|mcp__orgx|tool call)\b/i.test(`${finding.title} ${finding.summary}`));
|
|
8906
|
+
if (!mentionsOrgxTool) return [];
|
|
8907
|
+
return [
|
|
8908
|
+
{
|
|
8909
|
+
id: "tool:orgx-mcp",
|
|
8910
|
+
kind: "tool",
|
|
8911
|
+
label: "OrgX MCP",
|
|
8912
|
+
summary: coverage.orgxMcpCalled ? "OrgX MCP was observed as a durable writeback surface in the audited work." : "OrgX MCP was available or mentioned, but the audit found incomplete durable writeback.",
|
|
8913
|
+
source_client: "mcp",
|
|
8914
|
+
evidence_refs: findings.filter((finding) => /\b(orgx|mcp|tool)\b/i.test(`${finding.title} ${finding.summary}`)).map((finding) => finding.evidence_ref).slice(0, 12),
|
|
8915
|
+
linked_node_ids: [],
|
|
8916
|
+
confidence: coverage.orgxMcpCalled ? 0.86 : 0.72,
|
|
8917
|
+
weight: coverage.orgxMcpCalled ? 88 : 76,
|
|
8918
|
+
review_state: "unreviewed",
|
|
8919
|
+
dedupe_key: "tool:orgx-mcp",
|
|
8920
|
+
metadata: {
|
|
8921
|
+
mcp_observed: coverage.mcpObserved,
|
|
8922
|
+
orgx_observed: coverage.orgxObserved,
|
|
8923
|
+
orgx_mcp_called: coverage.orgxMcpCalled,
|
|
8924
|
+
skill_only_signal: coverage.skillOnlySignal
|
|
8925
|
+
}
|
|
8926
|
+
}
|
|
8927
|
+
];
|
|
8928
|
+
}
|
|
8929
|
+
function buildAgentNodes(findings) {
|
|
8930
|
+
const actorIds = sortedUnique(
|
|
8931
|
+
findings.map((finding) => typeof finding.metadata.actor_id === "string" ? finding.metadata.actor_id.trim() : "").filter(Boolean)
|
|
8932
|
+
);
|
|
8933
|
+
const sourceAgents = sortedUnique(
|
|
8934
|
+
findings.map(
|
|
8935
|
+
(finding) => ["codex", "claude", "claude-code", "cursor", "openclaw"].includes(finding.source_client) ? finding.source_client : ""
|
|
8936
|
+
).filter(Boolean)
|
|
8937
|
+
);
|
|
8938
|
+
return [...actorIds, ...sourceAgents].slice(0, 20).map((agent) => ({
|
|
8939
|
+
id: `agent:${slugPart(agent)}`,
|
|
8940
|
+
kind: "agent",
|
|
8941
|
+
label: agent,
|
|
8942
|
+
summary: `${agent} contributed evidence to the Work Graph audit.`,
|
|
8943
|
+
source_client: sourceAgents.includes(agent) ? agent : "manual",
|
|
8944
|
+
evidence_refs: findings.filter((finding) => finding.metadata.actor_id === agent || finding.source_client === agent).map((finding) => finding.evidence_ref).slice(0, 12),
|
|
8945
|
+
linked_node_ids: [],
|
|
8946
|
+
confidence: 0.72,
|
|
8947
|
+
weight: 64,
|
|
8948
|
+
review_state: "unreviewed",
|
|
8949
|
+
dedupe_key: `agent:${slugPart(agent)}`,
|
|
8950
|
+
metadata: {}
|
|
8951
|
+
}));
|
|
8952
|
+
}
|
|
8953
|
+
function buildWorkGraphAttributionSpine(input) {
|
|
8954
|
+
const evidence_refs = input.findings.map((finding) => ({
|
|
8955
|
+
id: finding.evidence_ref,
|
|
8956
|
+
source_client: finding.source_client,
|
|
8957
|
+
source_id: finding.source_id,
|
|
8958
|
+
label: finding.title,
|
|
8959
|
+
summary: finding.summary.slice(0, 1200),
|
|
8960
|
+
...isIsoTimestamp(finding.metadata.occurred_at) ? { occurred_at: finding.metadata.occurred_at } : {},
|
|
8961
|
+
confidence: finding.confidence,
|
|
8962
|
+
redaction_state: redactionStateForFinding(finding),
|
|
8963
|
+
metadata: {
|
|
8964
|
+
raw_transcript_sent: false,
|
|
8965
|
+
source_label: finding.metadata.source_label ?? null
|
|
8966
|
+
}
|
|
8967
|
+
}));
|
|
8968
|
+
const source_events = [
|
|
8969
|
+
...input.events.map((event) => ({
|
|
8970
|
+
source_client: event.source_client,
|
|
8971
|
+
source_id: event.source_id,
|
|
8972
|
+
source_label: event.source_label,
|
|
8973
|
+
event_type: event.event_type === "client_extraction" ? "client_extraction" : event.event_type,
|
|
8974
|
+
evidence_ref: event.evidence_ref,
|
|
8975
|
+
confidence: 0.7,
|
|
8976
|
+
metadata: {
|
|
8977
|
+
...event.metadata,
|
|
8978
|
+
raw_transcript_sent: false
|
|
8979
|
+
}
|
|
8980
|
+
})),
|
|
8981
|
+
...input.findings.map((finding) => ({
|
|
8982
|
+
source_client: finding.source_client,
|
|
8983
|
+
source_id: finding.source_id,
|
|
8984
|
+
source_label: typeof finding.metadata.source_label === "string" ? finding.metadata.source_label : finding.source_id,
|
|
8985
|
+
event_type: attributionEventTypeForFinding(finding),
|
|
8986
|
+
...isIsoTimestamp(finding.metadata.occurred_at) ? { occurred_at: finding.metadata.occurred_at } : {},
|
|
8987
|
+
evidence_ref: finding.evidence_ref,
|
|
8988
|
+
...typeof finding.metadata.actor_id === "string" ? { actor_ref: finding.metadata.actor_id } : {},
|
|
8989
|
+
confidence: finding.confidence,
|
|
8990
|
+
metadata: {
|
|
8991
|
+
finding_type: finding.type,
|
|
8992
|
+
raw_transcript_sent: false
|
|
8993
|
+
}
|
|
8994
|
+
}))
|
|
8995
|
+
];
|
|
8996
|
+
const buckets = {
|
|
8997
|
+
actions: [],
|
|
8998
|
+
decisions: [],
|
|
8999
|
+
artifacts: [],
|
|
9000
|
+
people: [],
|
|
9001
|
+
agents: buildAgentNodes(input.findings),
|
|
9002
|
+
tools: buildToolNodes(input.coverage, input.findings),
|
|
9003
|
+
businesses: [],
|
|
9004
|
+
product_surfaces: [],
|
|
9005
|
+
goals: [],
|
|
9006
|
+
sources: [
|
|
9007
|
+
...input.coverage.connected.map((source) => sourceNode(source, true)),
|
|
9008
|
+
...input.coverage.missing.map((source) => sourceNode(source, false))
|
|
9009
|
+
],
|
|
9010
|
+
initiative_candidates: []
|
|
9011
|
+
};
|
|
9012
|
+
for (const finding of input.findings) {
|
|
9013
|
+
const kind = attributionKindForFinding(finding.type);
|
|
9014
|
+
if (!kind) continue;
|
|
9015
|
+
const node = buildFindingNode(finding, kind);
|
|
9016
|
+
const bucket = finding.type === "initiative_candidate" ? "initiative_candidates" : nodeBucketForKind(kind);
|
|
9017
|
+
buckets[bucket].push(node);
|
|
9018
|
+
}
|
|
9019
|
+
const normalized = {
|
|
9020
|
+
source_events: source_events.filter(
|
|
9021
|
+
(event, index, all) => all.findIndex(
|
|
9022
|
+
(candidate) => [
|
|
9023
|
+
candidate.source_client,
|
|
9024
|
+
candidate.source_id,
|
|
9025
|
+
candidate.event_type,
|
|
9026
|
+
candidate.evidence_ref
|
|
9027
|
+
].join(":") === [
|
|
9028
|
+
event.source_client,
|
|
9029
|
+
event.source_id,
|
|
9030
|
+
event.event_type,
|
|
9031
|
+
event.evidence_ref
|
|
9032
|
+
].join(":")
|
|
9033
|
+
) === index
|
|
9034
|
+
).slice(0, 1e3),
|
|
9035
|
+
actions: mergeNodes(buckets.actions).slice(0, 500),
|
|
9036
|
+
decisions: mergeNodes(buckets.decisions).slice(0, 500),
|
|
9037
|
+
artifacts: mergeNodes(buckets.artifacts).slice(0, 500),
|
|
9038
|
+
people: mergeNodes(buckets.people).slice(0, 500),
|
|
9039
|
+
agents: mergeNodes(buckets.agents).slice(0, 200),
|
|
9040
|
+
tools: mergeNodes(buckets.tools).slice(0, 300),
|
|
9041
|
+
businesses: mergeNodes(buckets.businesses).slice(0, 200),
|
|
9042
|
+
product_surfaces: mergeNodes(buckets.product_surfaces).slice(0, 500),
|
|
9043
|
+
goals: mergeNodes(buckets.goals).slice(0, 500),
|
|
9044
|
+
sources: mergeNodes(buckets.sources).slice(0, 300),
|
|
9045
|
+
initiative_candidates: mergeNodes(buckets.initiative_candidates).slice(0, 50),
|
|
9046
|
+
evidence_refs: mergeByEvidenceId(evidence_refs).slice(0, 1e3)
|
|
9047
|
+
};
|
|
9048
|
+
const nodeCount = normalized.actions.length + normalized.decisions.length + normalized.artifacts.length + normalized.people.length + normalized.agents.length + normalized.tools.length + normalized.businesses.length + normalized.product_surfaces.length + normalized.goals.length + normalized.sources.length + normalized.initiative_candidates.length;
|
|
9049
|
+
const confidenceInputs = [
|
|
9050
|
+
...normalized.evidence_refs.map((evidence) => evidence.confidence),
|
|
9051
|
+
...normalized.source_events.map((event) => event.confidence)
|
|
9052
|
+
];
|
|
9053
|
+
const confidence = confidenceInputs.length ? Number((confidenceInputs.reduce((total, value) => total + value, 0) / confidenceInputs.length).toFixed(2)) : 0;
|
|
9054
|
+
return {
|
|
9055
|
+
...normalized,
|
|
9056
|
+
confidence,
|
|
9057
|
+
dedupe_keys: sortedUnique([
|
|
9058
|
+
...Object.values(normalized).flat().map((item) => typeof item === "object" && item && "dedupe_key" in item ? String(item.dedupe_key ?? "") : "").filter(Boolean)
|
|
9059
|
+
]).slice(0, 1e3),
|
|
9060
|
+
privacy: {
|
|
9061
|
+
redaction_state: "public_summary",
|
|
9062
|
+
raw_transcripts_included: false,
|
|
9063
|
+
public_summary_only: true
|
|
9064
|
+
},
|
|
9065
|
+
review: {
|
|
9066
|
+
pending_count: nodeCount,
|
|
9067
|
+
correction_affordances: [
|
|
9068
|
+
"confirm",
|
|
9069
|
+
"merge",
|
|
9070
|
+
"hide",
|
|
9071
|
+
"mark_important",
|
|
9072
|
+
"launch_or_dismiss"
|
|
9073
|
+
]
|
|
9074
|
+
}
|
|
9075
|
+
};
|
|
9076
|
+
}
|
|
9077
|
+
function mergeByEvidenceId(evidenceRefs) {
|
|
9078
|
+
const merged = /* @__PURE__ */ new Map();
|
|
9079
|
+
for (const evidence of evidenceRefs) {
|
|
9080
|
+
const previous = merged.get(evidence.id);
|
|
9081
|
+
if (!previous || evidence.confidence > previous.confidence) {
|
|
9082
|
+
merged.set(evidence.id, evidence);
|
|
9083
|
+
}
|
|
9084
|
+
}
|
|
9085
|
+
return [...merged.values()].sort((left, right) => right.confidence - left.confidence);
|
|
9086
|
+
}
|
|
8014
9087
|
function buildWorkGraphFingerprint(input) {
|
|
8015
9088
|
const sourceClients = sortedUnique(input.findings.map((finding) => finding.source_client));
|
|
8016
9089
|
const patternHashes = input.findings.map(
|
|
@@ -8088,6 +9161,7 @@ function buildSessionReconciliationReport(input) {
|
|
|
8088
9161
|
throw new Error("At least one source import or AI-client extraction is required to build a Work Graph report.");
|
|
8089
9162
|
}
|
|
8090
9163
|
const generatedAt = input.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
9164
|
+
const extractionProtocol = buildWorkGraphExtractionProtocol();
|
|
8091
9165
|
const clientExtractionSummaries = summarizeClientExtractions(clientExtractions);
|
|
8092
9166
|
const connectedSources = sortedUnique([
|
|
8093
9167
|
...input.connectedSources ?? input.imports.map((source) => source.sourceLabel),
|
|
@@ -8103,23 +9177,56 @@ function buildSessionReconciliationReport(input) {
|
|
|
8103
9177
|
(finding, index, all) => all.findIndex((candidate) => candidate.evidence_ref === finding.evidence_ref) === index
|
|
8104
9178
|
);
|
|
8105
9179
|
const allFindings = [...findings, ...autoMissed];
|
|
9180
|
+
const auditMethod = buildAuditMethod({
|
|
9181
|
+
clientExtractions,
|
|
9182
|
+
extractionProtocol,
|
|
9183
|
+
imports: input.imports
|
|
9184
|
+
});
|
|
9185
|
+
const domainCoverage = buildDomainCoverage(allFindings);
|
|
9186
|
+
const skillToolSignals = buildSkillToolSignals(allFindings);
|
|
8106
9187
|
const trails = buildWorkGraphTrails(allFindings, generatedAt);
|
|
8107
9188
|
const recurringPatterns = buildRecurringPatterns(coverage, allFindings, trails);
|
|
8108
9189
|
const opportunityScore = scoreOpportunity(coverage, allFindings);
|
|
8109
9190
|
const initiativeKickoffs = buildKickoffs(allFindings, missed, opportunityScore);
|
|
8110
9191
|
const recommendations = buildTrailRecommendations(recurringPatterns, trails);
|
|
9192
|
+
const impactProjection = estimateImpactProjection({
|
|
9193
|
+
coverage,
|
|
9194
|
+
findings: allFindings,
|
|
9195
|
+
opportunityScore,
|
|
9196
|
+
patterns: recurringPatterns,
|
|
9197
|
+
trails
|
|
9198
|
+
});
|
|
9199
|
+
const executionQuality = scoreExecutionQuality({
|
|
9200
|
+
coverage,
|
|
9201
|
+
findings: allFindings,
|
|
9202
|
+
impact: impactProjection,
|
|
9203
|
+
patterns: recurringPatterns,
|
|
9204
|
+
recommendations,
|
|
9205
|
+
trails
|
|
9206
|
+
});
|
|
8111
9207
|
const mirror = buildWorkGraphMirror({
|
|
9208
|
+
auditMethod,
|
|
8112
9209
|
coverage,
|
|
9210
|
+
domains: domainCoverage,
|
|
8113
9211
|
generatedAt,
|
|
9212
|
+
impact: impactProjection,
|
|
8114
9213
|
patterns: recurringPatterns,
|
|
8115
9214
|
recommendations,
|
|
9215
|
+
skillToolSignals,
|
|
8116
9216
|
trails
|
|
8117
9217
|
});
|
|
8118
9218
|
const tensionMetrics = buildTensionMetrics({
|
|
8119
9219
|
coverage,
|
|
9220
|
+
impact: impactProjection,
|
|
8120
9221
|
patterns: recurringPatterns,
|
|
9222
|
+
quality: executionQuality,
|
|
8121
9223
|
trails
|
|
8122
9224
|
});
|
|
9225
|
+
const attributionSpine = buildWorkGraphAttributionSpine({
|
|
9226
|
+
coverage,
|
|
9227
|
+
events,
|
|
9228
|
+
findings: allFindings
|
|
9229
|
+
});
|
|
8123
9230
|
const fingerprint = buildWorkGraphFingerprint({
|
|
8124
9231
|
connectedSources,
|
|
8125
9232
|
findings: allFindings,
|
|
@@ -8155,8 +9262,11 @@ function buildSessionReconciliationReport(input) {
|
|
|
8155
9262
|
source_client: "wizard",
|
|
8156
9263
|
session_id: sessionId,
|
|
8157
9264
|
workspace: input.workspace,
|
|
8158
|
-
extraction_protocol:
|
|
9265
|
+
extraction_protocol: extractionProtocol,
|
|
9266
|
+
audit_method: auditMethod,
|
|
8159
9267
|
client_extractions: clientExtractionSummaries,
|
|
9268
|
+
domain_coverage: domainCoverage,
|
|
9269
|
+
skill_tool_signals: skillToolSignals,
|
|
8160
9270
|
source_coverage: coverage,
|
|
8161
9271
|
final_state: inferFinalState(allFindings),
|
|
8162
9272
|
events,
|
|
@@ -8167,7 +9277,10 @@ function buildSessionReconciliationReport(input) {
|
|
|
8167
9277
|
recommendations,
|
|
8168
9278
|
mirror,
|
|
8169
9279
|
tension_metrics: tensionMetrics,
|
|
9280
|
+
attribution_spine: attributionSpine,
|
|
8170
9281
|
opportunity_score: opportunityScore,
|
|
9282
|
+
execution_quality: executionQuality,
|
|
9283
|
+
impact_projection: impactProjection,
|
|
8171
9284
|
initiative_kickoffs: initiativeKickoffs,
|
|
8172
9285
|
redaction_level: "summary_only",
|
|
8173
9286
|
raw_transcripts_sent: false
|
|
@@ -8234,6 +9347,18 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8234
9347
|
lines.push(`- ${lens.lens}: ${lens.return_when}`);
|
|
8235
9348
|
}
|
|
8236
9349
|
lines.push("");
|
|
9350
|
+
lines.push("## Audit Method");
|
|
9351
|
+
lines.push("");
|
|
9352
|
+
lines.push(`Mode: ${report.audit_method.mode}`);
|
|
9353
|
+
lines.push(`Session files searched: ${report.audit_method.searched_session_files}`);
|
|
9354
|
+
lines.push(`Message turns searched: ${report.audit_method.searched_message_count}`);
|
|
9355
|
+
lines.push(`Evidence lines retained: ${report.audit_method.retained_evidence_lines}`);
|
|
9356
|
+
lines.push(`Source groups searched: ${report.audit_method.searched_source_groups}`);
|
|
9357
|
+
lines.push(`Extraction lenses: ${report.audit_method.extraction_lenses.join(", ")}`);
|
|
9358
|
+
for (const note of report.audit_method.notes) {
|
|
9359
|
+
lines.push(`- ${note}`);
|
|
9360
|
+
}
|
|
9361
|
+
lines.push("");
|
|
8237
9362
|
lines.push("## Client Extractions");
|
|
8238
9363
|
lines.push("");
|
|
8239
9364
|
if (report.client_extractions.length === 0) {
|
|
@@ -8244,6 +9369,26 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8244
9369
|
}
|
|
8245
9370
|
}
|
|
8246
9371
|
lines.push("");
|
|
9372
|
+
lines.push("## Domain Coverage");
|
|
9373
|
+
lines.push("");
|
|
9374
|
+
if (report.domain_coverage.length === 0) {
|
|
9375
|
+
lines.push("- No domain clusters reached the public-summary threshold.");
|
|
9376
|
+
} else {
|
|
9377
|
+
for (const domain of report.domain_coverage) {
|
|
9378
|
+
lines.push(`- ${domain.label}: ${domain.finding_count} findings across ${domain.source_clients.join(", ")}. ${domain.summary}`);
|
|
9379
|
+
}
|
|
9380
|
+
}
|
|
9381
|
+
lines.push("");
|
|
9382
|
+
lines.push("## Skills, Agents, Tools, and Sources");
|
|
9383
|
+
lines.push("");
|
|
9384
|
+
if (report.skill_tool_signals.length === 0) {
|
|
9385
|
+
lines.push("- No repeated skill/tool signals reached the public-summary threshold.");
|
|
9386
|
+
} else {
|
|
9387
|
+
for (const signal of report.skill_tool_signals) {
|
|
9388
|
+
lines.push(`- [${signal.kind}] ${signal.label}: ${signal.mention_count} mention${signal.mention_count === 1 ? "" : "s"} across ${signal.source_clients.join(", ")}.`);
|
|
9389
|
+
}
|
|
9390
|
+
}
|
|
9391
|
+
lines.push("");
|
|
8247
9392
|
lines.push("## Opportunity Score");
|
|
8248
9393
|
lines.push("");
|
|
8249
9394
|
lines.push(`Overall: ${report.opportunity_score.overall}/100`);
|
|
@@ -8254,15 +9399,46 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8254
9399
|
lines.push(`Automation potential: ${report.opportunity_score.automation_potential}/100`);
|
|
8255
9400
|
lines.push(`OrgX fit: ${report.opportunity_score.orgx_fit}/100`);
|
|
8256
9401
|
lines.push("");
|
|
9402
|
+
lines.push("## Execution Quality");
|
|
9403
|
+
lines.push("");
|
|
9404
|
+
lines.push(`Overall: ${report.execution_quality.overall}/100`);
|
|
9405
|
+
lines.push(`Evidence coverage: ${report.execution_quality.evidence_coverage}/100`);
|
|
9406
|
+
lines.push(`Source attribution: ${report.execution_quality.source_attribution}/100`);
|
|
9407
|
+
lines.push(`Chronology depth: ${report.execution_quality.trail_depth}/100`);
|
|
9408
|
+
lines.push(`Insight depth: ${report.execution_quality.insight_depth}/100`);
|
|
9409
|
+
lines.push(`Actionability: ${report.execution_quality.actionability}/100`);
|
|
9410
|
+
lines.push(`Impact confidence: ${report.execution_quality.impact_confidence}/100`);
|
|
9411
|
+
for (const note of report.execution_quality.notes) {
|
|
9412
|
+
lines.push(`- ${note}`);
|
|
9413
|
+
}
|
|
9414
|
+
lines.push("");
|
|
9415
|
+
lines.push("## Impact Projection");
|
|
9416
|
+
lines.push("");
|
|
9417
|
+
lines.push(`Time saved: ${report.impact_projection.time_saved_hours_per_week}h/week`);
|
|
9418
|
+
lines.push(`Acceleration: +${report.impact_projection.acceleration_percent}%`);
|
|
9419
|
+
lines.push(`Estimated monthly value: $${report.impact_projection.estimated_monthly_value_usd.toLocaleString("en-US")}`);
|
|
9420
|
+
lines.push(`Confidence: ${report.impact_projection.confidence}`);
|
|
9421
|
+
for (const item of report.impact_projection.basis) {
|
|
9422
|
+
lines.push(`- ${item}`);
|
|
9423
|
+
}
|
|
9424
|
+
lines.push("");
|
|
8257
9425
|
lines.push("## Source Coverage");
|
|
8258
9426
|
lines.push("");
|
|
8259
9427
|
lines.push(`Connected: ${report.source_coverage.connected.join(", ") || "none"}`);
|
|
8260
9428
|
lines.push(`Missing: ${report.source_coverage.missing.join(", ") || "none"}`);
|
|
9429
|
+
lines.push(`Coverage score: ${report.source_coverage.coverage_score ?? 0}/100`);
|
|
8261
9430
|
lines.push(`MCP observed: ${report.source_coverage.mcpObserved ? "yes" : "no"}`);
|
|
8262
9431
|
lines.push(`OrgX observed: ${report.source_coverage.orgxObserved ? "yes" : "no"}`);
|
|
8263
9432
|
lines.push(`OrgX MCP called: ${report.source_coverage.orgxMcpCalled ? "yes" : "no"}`);
|
|
9433
|
+
if (report.source_coverage.manifests?.length) {
|
|
9434
|
+
lines.push("");
|
|
9435
|
+
lines.push("Source manifests:");
|
|
9436
|
+
for (const manifest of report.source_coverage.manifests) {
|
|
9437
|
+
lines.push(`- [${manifest.status}] ${manifest.source_label}: ${manifest.finding_count} findings, ${manifest.searched_session_count} searched / ${manifest.skipped_session_count} skipped sessions, confidence ${manifest.confidence}`);
|
|
9438
|
+
}
|
|
9439
|
+
}
|
|
8264
9440
|
lines.push("");
|
|
8265
|
-
lines.push("##
|
|
9441
|
+
lines.push("## Operating Readout");
|
|
8266
9442
|
lines.push("");
|
|
8267
9443
|
lines.push(`### ${report.mirror.headline}`);
|
|
8268
9444
|
lines.push("");
|
|
@@ -8272,13 +9448,13 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8272
9448
|
lines.push(`- ${claim.text} (${claim.evidence_refs.join(", ") || "no evidence refs"})`);
|
|
8273
9449
|
}
|
|
8274
9450
|
lines.push("");
|
|
8275
|
-
lines.push("##
|
|
9451
|
+
lines.push("## Operating Leakage");
|
|
8276
9452
|
lines.push("");
|
|
8277
9453
|
for (const metric of report.tension_metrics) {
|
|
8278
9454
|
lines.push(`- ${metric.value} ${metric.label}: ${metric.explanation}`);
|
|
8279
9455
|
}
|
|
8280
9456
|
lines.push("");
|
|
8281
|
-
lines.push("##
|
|
9457
|
+
lines.push("## Evidence Paths");
|
|
8282
9458
|
lines.push("");
|
|
8283
9459
|
for (const trail of report.trails.slice(0, 12)) {
|
|
8284
9460
|
lines.push(`- [${trail.kind}] ${trail.title} \u2014 ${trail.state}, ${trail.valence}, ${trail.shape} (${trail.evidence_refs.join(", ")})`);
|
|
@@ -8316,12 +9492,36 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8316
9492
|
lines.push(`- [${kickoff.priority}] ${kickoff.title}: ${kickoff.summary}`);
|
|
8317
9493
|
}
|
|
8318
9494
|
lines.push("");
|
|
8319
|
-
lines.push("##
|
|
9495
|
+
lines.push("## Repair Recommendations");
|
|
8320
9496
|
lines.push("");
|
|
8321
9497
|
for (const recommendation of report.recommendations) {
|
|
8322
9498
|
lines.push(`- [${recommendation.priority}] ${recommendation.title}: ${recommendation.summary}`);
|
|
8323
9499
|
}
|
|
8324
9500
|
lines.push("");
|
|
9501
|
+
lines.push("## Attribution Spine");
|
|
9502
|
+
lines.push("");
|
|
9503
|
+
lines.push(`Source events: ${report.attribution_spine.source_events.length}`);
|
|
9504
|
+
lines.push(`Evidence refs: ${report.attribution_spine.evidence_refs.length}`);
|
|
9505
|
+
lines.push(`Review nodes: ${report.attribution_spine.review.pending_count}`);
|
|
9506
|
+
lines.push(`Confidence: ${report.attribution_spine.confidence}`);
|
|
9507
|
+
lines.push("");
|
|
9508
|
+
const attributionGroups = [
|
|
9509
|
+
["Actions", report.attribution_spine.actions],
|
|
9510
|
+
["Decisions", report.attribution_spine.decisions],
|
|
9511
|
+
["Artifacts", report.attribution_spine.artifacts],
|
|
9512
|
+
["People", report.attribution_spine.people],
|
|
9513
|
+
["Businesses", report.attribution_spine.businesses],
|
|
9514
|
+
["Surfaces", report.attribution_spine.product_surfaces],
|
|
9515
|
+
["Sources", report.attribution_spine.sources]
|
|
9516
|
+
];
|
|
9517
|
+
for (const [label, nodes] of attributionGroups) {
|
|
9518
|
+
if (nodes.length === 0) continue;
|
|
9519
|
+
lines.push(`${label}:`);
|
|
9520
|
+
for (const node of nodes.slice(0, 5)) {
|
|
9521
|
+
lines.push(`- ${node.label} (${node.evidence_refs.join(", ") || "source coverage"})`);
|
|
9522
|
+
}
|
|
9523
|
+
lines.push("");
|
|
9524
|
+
}
|
|
8325
9525
|
lines.push("## Signup Hydration");
|
|
8326
9526
|
lines.push("");
|
|
8327
9527
|
lines.push(`- Strategy: ${report.signup_hydration.strategy}`);
|
|
@@ -8337,8 +9537,314 @@ function renderWorkGraphMarkdown(report) {
|
|
|
8337
9537
|
return lines.join("\n");
|
|
8338
9538
|
}
|
|
8339
9539
|
|
|
9540
|
+
// src/lib/work-graph-publish.ts
|
|
9541
|
+
async function parseResponse(response) {
|
|
9542
|
+
const text2 = await response.text();
|
|
9543
|
+
if (!text2) return null;
|
|
9544
|
+
try {
|
|
9545
|
+
return JSON.parse(text2);
|
|
9546
|
+
} catch {
|
|
9547
|
+
return text2;
|
|
9548
|
+
}
|
|
9549
|
+
}
|
|
9550
|
+
async function publishWorkGraphReport(report, options = {}) {
|
|
9551
|
+
const auth = await resolveOrgxAuth();
|
|
9552
|
+
if (!auth) {
|
|
9553
|
+
throw new Error("OrgX auth is required to publish a Work Graph. Run `orgx-wizard auth login` or set ORGX_API_KEY.");
|
|
9554
|
+
}
|
|
9555
|
+
const url = buildOrgxApiUrl("/client/work-graph/reports", auth.baseUrl);
|
|
9556
|
+
const response = await fetch(url, {
|
|
9557
|
+
method: "POST",
|
|
9558
|
+
headers: {
|
|
9559
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
9560
|
+
"Content-Type": "application/json"
|
|
9561
|
+
},
|
|
9562
|
+
body: JSON.stringify({
|
|
9563
|
+
report,
|
|
9564
|
+
...options.workspaceId ? { workspace_id: options.workspaceId } : {},
|
|
9565
|
+
...options.initiativeId ? { initiative_id: options.initiativeId } : {},
|
|
9566
|
+
...options.entityType ? { entity_type: options.entityType } : {},
|
|
9567
|
+
...options.entityId ? { entity_id: options.entityId } : {},
|
|
9568
|
+
...options.artifactUrl ? { artifact_url: options.artifactUrl } : {},
|
|
9569
|
+
attach_artifact: Boolean(options.attachArtifact),
|
|
9570
|
+
public_share: Boolean(options.publicShare)
|
|
9571
|
+
}),
|
|
9572
|
+
signal: options.signal ?? AbortSignal.timeout(15e3)
|
|
9573
|
+
});
|
|
9574
|
+
return {
|
|
9575
|
+
ok: response.ok,
|
|
9576
|
+
status: response.status,
|
|
9577
|
+
url,
|
|
9578
|
+
data: await parseResponse(response)
|
|
9579
|
+
};
|
|
9580
|
+
}
|
|
9581
|
+
async function publishWorkGraphEvents(fingerprint, patch, options = {}) {
|
|
9582
|
+
const auth = await resolveOrgxAuth();
|
|
9583
|
+
if (!auth) {
|
|
9584
|
+
throw new Error("OrgX auth is required to replay Work Graph hook events. Run `orgx-wizard auth login` or set ORGX_API_KEY.");
|
|
9585
|
+
}
|
|
9586
|
+
const url = buildOrgxApiUrl("/client/work-graph/events", auth.baseUrl);
|
|
9587
|
+
const response = await fetch(url, {
|
|
9588
|
+
method: "POST",
|
|
9589
|
+
headers: {
|
|
9590
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
9591
|
+
"Content-Type": "application/json"
|
|
9592
|
+
},
|
|
9593
|
+
body: JSON.stringify({
|
|
9594
|
+
work_graph_fingerprint: fingerprint,
|
|
9595
|
+
patch
|
|
9596
|
+
}),
|
|
9597
|
+
signal: options.signal ?? AbortSignal.timeout(15e3)
|
|
9598
|
+
});
|
|
9599
|
+
return {
|
|
9600
|
+
ok: response.ok,
|
|
9601
|
+
status: response.status,
|
|
9602
|
+
url,
|
|
9603
|
+
data: await parseResponse(response)
|
|
9604
|
+
};
|
|
9605
|
+
}
|
|
9606
|
+
|
|
9607
|
+
// src/lib/work-graph-hook-events.ts
|
|
9608
|
+
import { createHash as createHash5 } from "crypto";
|
|
9609
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
9610
|
+
var SOURCE_CLIENTS = [
|
|
9611
|
+
"codex",
|
|
9612
|
+
"claude",
|
|
9613
|
+
"claude-code",
|
|
9614
|
+
"cursor",
|
|
9615
|
+
"openclaw",
|
|
9616
|
+
"slack",
|
|
9617
|
+
"mcp",
|
|
9618
|
+
"github",
|
|
9619
|
+
"linear",
|
|
9620
|
+
"gmail",
|
|
9621
|
+
"calendar",
|
|
9622
|
+
"notion",
|
|
9623
|
+
"docs",
|
|
9624
|
+
"manual",
|
|
9625
|
+
"wizard",
|
|
9626
|
+
"api",
|
|
9627
|
+
"unknown"
|
|
9628
|
+
];
|
|
9629
|
+
function isRecord2(value) {
|
|
9630
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
9631
|
+
}
|
|
9632
|
+
function asString2(value) {
|
|
9633
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
9634
|
+
}
|
|
9635
|
+
function asNumber(value) {
|
|
9636
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
9637
|
+
}
|
|
9638
|
+
function asStringArray(value) {
|
|
9639
|
+
if (!Array.isArray(value)) return void 0;
|
|
9640
|
+
return value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
9641
|
+
}
|
|
9642
|
+
function stableHash(value) {
|
|
9643
|
+
return createHash5("sha256").update(value).digest("hex").slice(0, 20);
|
|
9644
|
+
}
|
|
9645
|
+
function normalizeSourceClient2(value) {
|
|
9646
|
+
const raw = asString2(value)?.toLowerCase();
|
|
9647
|
+
if (!raw) return "unknown";
|
|
9648
|
+
if (SOURCE_CLIENTS.includes(raw)) return raw;
|
|
9649
|
+
if (raw === "claude_code") return "claude-code";
|
|
9650
|
+
return "unknown";
|
|
9651
|
+
}
|
|
9652
|
+
function safeTimestamp(value) {
|
|
9653
|
+
const raw = asString2(value);
|
|
9654
|
+
if (raw && !Number.isNaN(Date.parse(raw))) return new Date(raw).toISOString();
|
|
9655
|
+
return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
9656
|
+
}
|
|
9657
|
+
function sourceLabel(sourceClient) {
|
|
9658
|
+
switch (sourceClient) {
|
|
9659
|
+
case "claude-code":
|
|
9660
|
+
return "Claude Code";
|
|
9661
|
+
case "codex":
|
|
9662
|
+
return "Codex";
|
|
9663
|
+
case "openclaw":
|
|
9664
|
+
return "OpenClaw";
|
|
9665
|
+
case "cursor":
|
|
9666
|
+
return "Cursor";
|
|
9667
|
+
default:
|
|
9668
|
+
return sourceClient.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9671
|
+
function readHookRecord(line) {
|
|
9672
|
+
try {
|
|
9673
|
+
const parsed = JSON.parse(line);
|
|
9674
|
+
if (!isRecord2(parsed)) return null;
|
|
9675
|
+
const record = {};
|
|
9676
|
+
const schemaVersion = asString2(parsed.schema_version);
|
|
9677
|
+
const source = asString2(parsed.source);
|
|
9678
|
+
const sourceClient = asString2(parsed.source_client);
|
|
9679
|
+
const event = asString2(parsed.event);
|
|
9680
|
+
const sessionId = asString2(parsed.session_id);
|
|
9681
|
+
const turnId = asString2(parsed.turn_id);
|
|
9682
|
+
const cwd = asString2(parsed.cwd);
|
|
9683
|
+
const transcriptPath = asString2(parsed.transcript_path);
|
|
9684
|
+
const timestamp = asString2(parsed.timestamp);
|
|
9685
|
+
if (schemaVersion) record.schema_version = schemaVersion;
|
|
9686
|
+
if (source) record.source = source;
|
|
9687
|
+
if (sourceClient) record.source_client = sourceClient;
|
|
9688
|
+
if (event) record.event = event;
|
|
9689
|
+
if (sessionId) record.session_id = sessionId;
|
|
9690
|
+
if (turnId) record.turn_id = turnId;
|
|
9691
|
+
if (cwd) record.cwd = cwd;
|
|
9692
|
+
if (transcriptPath) record.transcript_path = transcriptPath;
|
|
9693
|
+
if (timestamp) record.timestamp = timestamp;
|
|
9694
|
+
if (isRecord2(parsed.summary)) {
|
|
9695
|
+
const summary = {};
|
|
9696
|
+
const toolName = asString2(parsed.summary.tool_name);
|
|
9697
|
+
const promptChars = asNumber(parsed.summary.prompt_chars);
|
|
9698
|
+
const payloadKeys = asStringArray(parsed.summary.payload_keys);
|
|
9699
|
+
if (toolName) summary.tool_name = toolName;
|
|
9700
|
+
if (promptChars !== void 0) summary.prompt_chars = promptChars;
|
|
9701
|
+
if (payloadKeys) summary.payload_keys = payloadKeys;
|
|
9702
|
+
record.summary = summary;
|
|
9703
|
+
}
|
|
9704
|
+
return record;
|
|
9705
|
+
} catch {
|
|
9706
|
+
return null;
|
|
9707
|
+
}
|
|
9708
|
+
}
|
|
9709
|
+
function readRuntimeHookOutbox(path, limit = 200) {
|
|
9710
|
+
if (!existsSync6(path)) return { path, records: [], skipped: 0 };
|
|
9711
|
+
const lines = readFileSync4(path, "utf8").split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
9712
|
+
const selected = lines.slice(Math.max(0, lines.length - Math.max(1, limit)));
|
|
9713
|
+
const records = [];
|
|
9714
|
+
let skipped = Math.max(0, lines.length - selected.length);
|
|
9715
|
+
for (const line of selected) {
|
|
9716
|
+
const record = readHookRecord(line);
|
|
9717
|
+
if (record) {
|
|
9718
|
+
records.push(record);
|
|
9719
|
+
} else {
|
|
9720
|
+
skipped += 1;
|
|
9721
|
+
}
|
|
9722
|
+
}
|
|
9723
|
+
return { path, records, skipped };
|
|
9724
|
+
}
|
|
9725
|
+
function buildWorkGraphHookReplayPatch(readResult) {
|
|
9726
|
+
const sourceEvents = [];
|
|
9727
|
+
const evidenceRefs = [];
|
|
9728
|
+
const sources = /* @__PURE__ */ new Map();
|
|
9729
|
+
const agents = /* @__PURE__ */ new Map();
|
|
9730
|
+
const tools = /* @__PURE__ */ new Map();
|
|
9731
|
+
const dedupeKeys = /* @__PURE__ */ new Set();
|
|
9732
|
+
readResult.records.forEach((record, index) => {
|
|
9733
|
+
const sourceClient = normalizeSourceClient2(record.source_client);
|
|
9734
|
+
const event = record.event ?? "runtime_hook";
|
|
9735
|
+
const timestamp = safeTimestamp(record.timestamp);
|
|
9736
|
+
const sourceId = record.session_id ?? record.transcript_path ?? record.cwd ?? `${sourceClient}:hook:${index}`;
|
|
9737
|
+
const evidenceId = `hook:${stableHash(`${sourceClient}:${sourceId}:${event}:${timestamp}:${index}`)}`;
|
|
9738
|
+
const toolName = record.summary?.tool_name;
|
|
9739
|
+
const hasMcpTool = Boolean(toolName && /(mcp|orgx)/i.test(toolName));
|
|
9740
|
+
const label = `${sourceLabel(sourceClient)} ${event}`;
|
|
9741
|
+
const summary = hasMcpTool ? `${sourceLabel(sourceClient)} hook observed tool activity through ${toolName}.` : `${sourceLabel(sourceClient)} hook observed ${event} in the local runtime.`;
|
|
9742
|
+
evidenceRefs.push({
|
|
9743
|
+
id: evidenceId,
|
|
9744
|
+
source_client: sourceClient,
|
|
9745
|
+
source_id: sourceId,
|
|
9746
|
+
label,
|
|
9747
|
+
summary,
|
|
9748
|
+
occurred_at: timestamp,
|
|
9749
|
+
confidence: hasMcpTool ? 0.82 : 0.68,
|
|
9750
|
+
redaction_state: "public_summary",
|
|
9751
|
+
metadata: {
|
|
9752
|
+
raw_transcript_sent: false,
|
|
9753
|
+
hook_source: record.source ?? "runtime_hook",
|
|
9754
|
+
cwd: record.cwd ?? null,
|
|
9755
|
+
transcript_path: record.transcript_path ?? null
|
|
9756
|
+
}
|
|
9757
|
+
});
|
|
9758
|
+
sourceEvents.push({
|
|
9759
|
+
source_client: sourceClient,
|
|
9760
|
+
source_id: sourceId,
|
|
9761
|
+
source_label: sourceLabel(sourceClient),
|
|
9762
|
+
event_type: hasMcpTool ? "mcp_call" : "runtime_hook",
|
|
9763
|
+
occurred_at: timestamp,
|
|
9764
|
+
evidence_ref: evidenceId,
|
|
9765
|
+
confidence: hasMcpTool ? 0.82 : 0.68,
|
|
9766
|
+
metadata: {
|
|
9767
|
+
hook_event: event,
|
|
9768
|
+
raw_transcript_sent: false,
|
|
9769
|
+
prompt_chars: record.summary?.prompt_chars ?? null,
|
|
9770
|
+
payload_keys: record.summary?.payload_keys ?? []
|
|
9771
|
+
}
|
|
9772
|
+
});
|
|
9773
|
+
const sourceEvidence = sources.get(sourceClient) ?? [];
|
|
9774
|
+
sourceEvidence.push(evidenceId);
|
|
9775
|
+
sources.set(sourceClient, sourceEvidence.slice(0, 30));
|
|
9776
|
+
dedupeKeys.add(`hook:${sourceClient}:${sourceId}:${event}`);
|
|
9777
|
+
if (sourceClient !== "unknown") {
|
|
9778
|
+
const agentId = `agent:${sourceClient}`;
|
|
9779
|
+
agents.set(agentId, {
|
|
9780
|
+
id: agentId,
|
|
9781
|
+
kind: "agent",
|
|
9782
|
+
label: sourceLabel(sourceClient),
|
|
9783
|
+
summary: `${sourceLabel(sourceClient)} is emitting passive runtime hook evidence into this Work Graph.`,
|
|
9784
|
+
source_client: sourceClient,
|
|
9785
|
+
evidence_refs: sourceEvidence.slice(0, 30),
|
|
9786
|
+
linked_node_ids: [`source:${sourceClient}`],
|
|
9787
|
+
confidence: 0.7,
|
|
9788
|
+
weight: 62,
|
|
9789
|
+
review_state: "unreviewed",
|
|
9790
|
+
dedupe_key: agentId,
|
|
9791
|
+
metadata: { runtime_hook_replay: true }
|
|
9792
|
+
});
|
|
9793
|
+
}
|
|
9794
|
+
if (toolName) {
|
|
9795
|
+
const toolId = `tool:${stableHash(toolName.toLowerCase())}`;
|
|
9796
|
+
const previous = tools.get(toolId);
|
|
9797
|
+
const previousEvidence = Array.isArray(previous?.evidence_refs) ? previous.evidence_refs.filter((item) => typeof item === "string") : [];
|
|
9798
|
+
tools.set(toolId, {
|
|
9799
|
+
id: toolId,
|
|
9800
|
+
kind: "tool",
|
|
9801
|
+
label: toolName,
|
|
9802
|
+
summary: hasMcpTool ? `Runtime hook evidence shows ${toolName} participating in OrgX/MCP work.` : `Runtime hook evidence shows ${toolName} participating in local work.`,
|
|
9803
|
+
source_client: sourceClient,
|
|
9804
|
+
evidence_refs: [...previousEvidence, evidenceId].slice(0, 30),
|
|
9805
|
+
linked_node_ids: [`source:${sourceClient}`],
|
|
9806
|
+
confidence: hasMcpTool ? 0.82 : 0.66,
|
|
9807
|
+
weight: hasMcpTool ? 78 : 54,
|
|
9808
|
+
review_state: "unreviewed",
|
|
9809
|
+
dedupe_key: toolId,
|
|
9810
|
+
metadata: { runtime_hook_replay: true }
|
|
9811
|
+
});
|
|
9812
|
+
}
|
|
9813
|
+
});
|
|
9814
|
+
const sourceNodes = [...sources.entries()].map(([sourceClient, refs]) => ({
|
|
9815
|
+
id: `source:${sourceClient}`,
|
|
9816
|
+
kind: "source",
|
|
9817
|
+
label: sourceLabel(sourceClient),
|
|
9818
|
+
summary: `${sourceLabel(sourceClient)} hook events have been replayed into this Work Graph profile.`,
|
|
9819
|
+
source_client: sourceClient,
|
|
9820
|
+
evidence_refs: refs.slice(0, 30),
|
|
9821
|
+
linked_node_ids: [],
|
|
9822
|
+
confidence: 0.7,
|
|
9823
|
+
weight: 65,
|
|
9824
|
+
review_state: "unreviewed",
|
|
9825
|
+
dedupe_key: `source:${sourceClient}`,
|
|
9826
|
+
metadata: { runtime_hook_replay: true }
|
|
9827
|
+
}));
|
|
9828
|
+
const patch = {
|
|
9829
|
+
source_events: sourceEvents,
|
|
9830
|
+
evidence_refs: evidenceRefs,
|
|
9831
|
+
sources: sourceNodes,
|
|
9832
|
+
agents: [...agents.values()],
|
|
9833
|
+
tools: [...tools.values()],
|
|
9834
|
+
dedupe_keys: [...dedupeKeys].slice(0, 200),
|
|
9835
|
+
confidence: evidenceRefs.length > 0 ? 0.7 : 0
|
|
9836
|
+
};
|
|
9837
|
+
return {
|
|
9838
|
+
patch,
|
|
9839
|
+
records: readResult.records.length,
|
|
9840
|
+
skipped: readResult.skipped,
|
|
9841
|
+
sources: [...sources.keys()],
|
|
9842
|
+
evidenceRefs: evidenceRefs.length
|
|
9843
|
+
};
|
|
9844
|
+
}
|
|
9845
|
+
|
|
8340
9846
|
// src/lib/runtime-hooks.ts
|
|
8341
|
-
import { copyFileSync, existsSync as
|
|
9847
|
+
import { copyFileSync, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
8342
9848
|
import { homedir as homedir2 } from "os";
|
|
8343
9849
|
import { dirname as dirname4, join as join5 } from "path";
|
|
8344
9850
|
var HOOK_MARKER = "orgx-session-hook.mjs";
|
|
@@ -8364,7 +9870,7 @@ function backupPath(path, now) {
|
|
|
8364
9870
|
return `${path}.bak.${timestamp}`;
|
|
8365
9871
|
}
|
|
8366
9872
|
function backupExisting(path, now) {
|
|
8367
|
-
if (!
|
|
9873
|
+
if (!existsSync7(path)) return null;
|
|
8368
9874
|
const backup = backupPath(path, now);
|
|
8369
9875
|
copyFileSync(path, backup);
|
|
8370
9876
|
return backup;
|
|
@@ -8562,7 +10068,7 @@ function inspectRuntimeHooks(options = {}) {
|
|
|
8562
10068
|
installed: {
|
|
8563
10069
|
claudeCode: hasOrgxHook(claudeSettingsRaw),
|
|
8564
10070
|
codex: hasOrgxHook(codexHooksRaw),
|
|
8565
|
-
hookScript:
|
|
10071
|
+
hookScript: existsSync7(paths.hookScriptPath)
|
|
8566
10072
|
},
|
|
8567
10073
|
codex: {
|
|
8568
10074
|
configExists: Boolean(codexConfigRaw),
|
|
@@ -8762,12 +10268,72 @@ function printRuntimeHookInspection(report) {
|
|
|
8762
10268
|
console.log(` ${report.installed.claudeCode ? ICON.ok : ICON.warn} ${pc3.bold("Claude Code ")} ${report.installed.claudeCode ? pc3.green("installed") : pc3.yellow("missing")} ${pc3.dim(report.paths.claudeSettingsPath)}`);
|
|
8763
10269
|
console.log(` ${ICON.skip} ${pc3.bold("outbox ")} ${pc3.dim(`${report.outboxEvents} event${report.outboxEvents === 1 ? "" : "s"} at ${report.paths.outboxPath}`)}`);
|
|
8764
10270
|
}
|
|
10271
|
+
function requireHookReplayApproval(options, interactive) {
|
|
10272
|
+
if (options.yes) return true;
|
|
10273
|
+
if (!interactive) {
|
|
10274
|
+
throw new Error("Replaying Work Graph hook events requires --yes in non-interactive mode.");
|
|
10275
|
+
}
|
|
10276
|
+
return clack.confirm({
|
|
10277
|
+
message: "Replay passive hook events into this claimed Work Graph profile?"
|
|
10278
|
+
}).then((value) => {
|
|
10279
|
+
if (clack.isCancel(value) || value !== true) {
|
|
10280
|
+
clack.cancel("Hook replay cancelled.");
|
|
10281
|
+
return false;
|
|
10282
|
+
}
|
|
10283
|
+
return true;
|
|
10284
|
+
});
|
|
10285
|
+
}
|
|
10286
|
+
function parsePositiveInt(value, fallback) {
|
|
10287
|
+
if (!value?.trim()) return fallback;
|
|
10288
|
+
const parsed = Number.parseInt(value.trim(), 10);
|
|
10289
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
10290
|
+
throw new Error(`Expected a positive integer, got ${value}`);
|
|
10291
|
+
}
|
|
10292
|
+
return parsed;
|
|
10293
|
+
}
|
|
10294
|
+
async function runHookReplayCommand(options) {
|
|
10295
|
+
const fingerprint = options.fingerprint?.trim();
|
|
10296
|
+
if (!fingerprint) {
|
|
10297
|
+
throw new Error("Missing --fingerprint <wgf_...> for hook event replay.");
|
|
10298
|
+
}
|
|
10299
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
10300
|
+
const paths = inspectRuntimeHooks().paths;
|
|
10301
|
+
const outboxPath = resolve(options.outbox?.trim() || paths.outboxPath);
|
|
10302
|
+
const readResult = readRuntimeHookOutbox(outboxPath, parsePositiveInt(options.limit, 200));
|
|
10303
|
+
const replay = buildWorkGraphHookReplayPatch(readResult);
|
|
10304
|
+
if (replay.records === 0) {
|
|
10305
|
+
if (options.json) {
|
|
10306
|
+
console.log(JSON.stringify({ ok: true, published: false, reason: "empty_outbox", ...replay }, null, 2));
|
|
10307
|
+
return;
|
|
10308
|
+
}
|
|
10309
|
+
console.log(` ${ICON.skip} ${pc3.bold("outbox ")} ${pc3.dim(`no hook events found at ${outboxPath}`)}`);
|
|
10310
|
+
return;
|
|
10311
|
+
}
|
|
10312
|
+
const approved = await requireHookReplayApproval(options, interactive);
|
|
10313
|
+
if (!approved) return;
|
|
10314
|
+
const result = await publishWorkGraphEvents(fingerprint, replay.patch);
|
|
10315
|
+
if (!result.ok) process.exitCode = 1;
|
|
10316
|
+
await safeTrackWizardTelemetry("hooks_replay_ran", {
|
|
10317
|
+
command: "hooks replay",
|
|
10318
|
+
fingerprint,
|
|
10319
|
+
records: String(replay.records),
|
|
10320
|
+
sources: replay.sources.join(","),
|
|
10321
|
+
status: String(result.status)
|
|
10322
|
+
});
|
|
10323
|
+
if (options.json) {
|
|
10324
|
+
console.log(JSON.stringify({ ...replay, published: result }, null, 2));
|
|
10325
|
+
return;
|
|
10326
|
+
}
|
|
10327
|
+
console.log(` ${result.ok ? ICON.ok : ICON.warn} ${pc3.bold("replayed ")} ${replay.records} hook event${replay.records === 1 ? "" : "s"} ${pc3.dim(`status ${result.status}`)}`);
|
|
10328
|
+
console.log(` ${ICON.skip} ${pc3.bold("sources ")} ${pc3.dim(replay.sources.join(", ") || "none")}`);
|
|
10329
|
+
console.log(` ${ICON.skip} ${pc3.bold("evidence ")} ${pc3.dim(`${replay.evidenceRefs} public-summary ref${replay.evidenceRefs === 1 ? "" : "s"}`)}`);
|
|
10330
|
+
}
|
|
8765
10331
|
function readAuditInput(options, interactive) {
|
|
8766
10332
|
if (options.input?.trim()) {
|
|
8767
|
-
return
|
|
10333
|
+
return readFileSync6(resolve(options.input.trim()), "utf8");
|
|
8768
10334
|
}
|
|
8769
10335
|
if (!process.stdin.isTTY) {
|
|
8770
|
-
return
|
|
10336
|
+
return readFileSync6(0, "utf8");
|
|
8771
10337
|
}
|
|
8772
10338
|
if (!interactive) {
|
|
8773
10339
|
throw new Error("Audit input is required. Pass --input <file> or pipe text into wizard audit.");
|
|
@@ -8800,7 +10366,7 @@ function collectPathOption(value, previous = []) {
|
|
|
8800
10366
|
}
|
|
8801
10367
|
function parseClientExtractionFile(path) {
|
|
8802
10368
|
const resolvedPath = resolve(path);
|
|
8803
|
-
const parsed = JSON.parse(
|
|
10369
|
+
const parsed = JSON.parse(readFileSync6(resolvedPath, "utf8"));
|
|
8804
10370
|
if (!isRecord(parsed)) {
|
|
8805
10371
|
throw new Error(`AI-client extraction must be a JSON object: ${resolvedPath}`);
|
|
8806
10372
|
}
|
|
@@ -8839,6 +10405,11 @@ async function readAuditImports(options, interactive) {
|
|
|
8839
10405
|
imports.push({
|
|
8840
10406
|
sourceId: "wizard-audit-input",
|
|
8841
10407
|
sourceLabel: options.sourceLabel?.trim() || "Wizard audit input",
|
|
10408
|
+
metadata: {
|
|
10409
|
+
message_count: 1,
|
|
10410
|
+
retained_line_count: text2.split(/\r?\n/).filter(Boolean).length,
|
|
10411
|
+
source_client: "manual"
|
|
10412
|
+
},
|
|
8842
10413
|
text: text2
|
|
8843
10414
|
});
|
|
8844
10415
|
connectedSources.push(options.sourceLabel?.trim() || "Manual AI-session import");
|
|
@@ -8902,6 +10473,22 @@ function requireWriteApproval(options, interactive) {
|
|
|
8902
10473
|
return true;
|
|
8903
10474
|
});
|
|
8904
10475
|
}
|
|
10476
|
+
function requireWorkGraphPublishApproval(options, interactive) {
|
|
10477
|
+
const wantsPublish = Boolean(options.publish || options.publicShare);
|
|
10478
|
+
if (!wantsPublish || options.yes || options.dryRun) return true;
|
|
10479
|
+
if (!interactive) {
|
|
10480
|
+
throw new Error("Publishing a Work Graph requires --yes in non-interactive mode.");
|
|
10481
|
+
}
|
|
10482
|
+
return clack.confirm({
|
|
10483
|
+
message: "Publish this Work Graph to OrgX and create a shareable profile?"
|
|
10484
|
+
}).then((value) => {
|
|
10485
|
+
if (clack.isCancel(value) || value !== true) {
|
|
10486
|
+
clack.cancel("Work Graph publish cancelled.");
|
|
10487
|
+
return false;
|
|
10488
|
+
}
|
|
10489
|
+
return true;
|
|
10490
|
+
});
|
|
10491
|
+
}
|
|
8905
10492
|
async function resolveAuditWorkspace(options) {
|
|
8906
10493
|
const explicitId = options.workspaceId?.trim();
|
|
8907
10494
|
const explicitName = options.workspaceName?.trim();
|
|
@@ -9021,18 +10608,27 @@ async function runWorkGraphCommand(options, defaults = {}) {
|
|
|
9021
10608
|
};
|
|
9022
10609
|
const auditInputs = await readWorkGraphInputs(commandOptions, interactive);
|
|
9023
10610
|
const workspace = await resolveAuditWorkspace(commandOptions);
|
|
10611
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10612
|
+
const nativeClientExtractions = buildNativeAiClientExtractions(
|
|
10613
|
+
auditInputs.imports,
|
|
10614
|
+
generatedAt
|
|
10615
|
+
);
|
|
10616
|
+
const clientExtractions = [
|
|
10617
|
+
...auditInputs.clientExtractions,
|
|
10618
|
+
...nativeClientExtractions
|
|
10619
|
+
];
|
|
9024
10620
|
const report = buildSessionReconciliationReport({
|
|
9025
|
-
clientExtractions
|
|
10621
|
+
clientExtractions,
|
|
9026
10622
|
connectedSources: [
|
|
9027
10623
|
...auditInputs.connectedSources,
|
|
9028
10624
|
...workspace.id === "local-workspace" ? [] : ["OrgX workspace"]
|
|
9029
10625
|
],
|
|
9030
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9031
10626
|
imports: auditInputs.imports,
|
|
9032
10627
|
missingSources: [
|
|
9033
10628
|
...workspace.id === "local-workspace" ? ["OrgX workspace auth"] : [],
|
|
9034
10629
|
...auditInputs.missingSources
|
|
9035
10630
|
],
|
|
10631
|
+
generatedAt,
|
|
9036
10632
|
workspace
|
|
9037
10633
|
});
|
|
9038
10634
|
const markdown = renderWorkGraphMarkdown(report);
|
|
@@ -9042,6 +10638,39 @@ async function runWorkGraphCommand(options, defaults = {}) {
|
|
|
9042
10638
|
const markdownPath = resolve(outputDir, `work-graph-report-${timestamp}.md`);
|
|
9043
10639
|
writeJsonFile(jsonPath, report);
|
|
9044
10640
|
writeTextFile(markdownPath, markdown);
|
|
10641
|
+
let published = null;
|
|
10642
|
+
const shouldPublish = Boolean(commandOptions.publish || commandOptions.publicShare);
|
|
10643
|
+
if (shouldPublish) {
|
|
10644
|
+
const approved = await requireWorkGraphPublishApproval(commandOptions, interactive);
|
|
10645
|
+
if (approved) {
|
|
10646
|
+
if (commandOptions.dryRun) {
|
|
10647
|
+
published = { ok: true, status: 0 };
|
|
10648
|
+
} else {
|
|
10649
|
+
const publishResult = await publishWorkGraphReport(report, {
|
|
10650
|
+
...commandOptions.artifactUrl?.trim() ? { artifactUrl: commandOptions.artifactUrl.trim() } : {},
|
|
10651
|
+
attachArtifact: Boolean(commandOptions.attachArtifact || commandOptions.attachToInitiative),
|
|
10652
|
+
...commandOptions.entityId?.trim() ? { entityId: commandOptions.entityId.trim() } : {},
|
|
10653
|
+
...commandOptions.entityType ? { entityType: commandOptions.entityType } : {},
|
|
10654
|
+
...commandOptions.attachToInitiative?.trim() ? { initiativeId: commandOptions.attachToInitiative.trim() } : {},
|
|
10655
|
+
publicShare: Boolean(commandOptions.publicShare || commandOptions.publish),
|
|
10656
|
+
...workspace.id !== "local-workspace" ? { workspaceId: workspace.id } : {}
|
|
10657
|
+
});
|
|
10658
|
+
if (!publishResult.ok) {
|
|
10659
|
+
throw new Error(`Work Graph publish failed with HTTP ${publishResult.status}: ${JSON.stringify(publishResult.data)}`);
|
|
10660
|
+
}
|
|
10661
|
+
const body = isRecord(publishResult.data) ? publishResult.data : {};
|
|
10662
|
+
const publicShare = isRecord(body.public_share) ? body.public_share : null;
|
|
10663
|
+
const publicUrl = typeof publicShare?.url === "string" ? `${normalizeOrgxBaseUrl(process.env.ORGX_BASE_URL || DEFAULT_ORGX_BASE_URL)}${publicShare.url}` : void 0;
|
|
10664
|
+
const readout = isRecord(body.public_readout) ? body.public_readout : null;
|
|
10665
|
+
published = {
|
|
10666
|
+
ok: true,
|
|
10667
|
+
status: publishResult.status,
|
|
10668
|
+
...publicUrl ? { publicUrl } : {},
|
|
10669
|
+
...typeof readout?.review_url === "string" ? { reviewUrl: readout.review_url } : {}
|
|
10670
|
+
};
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
}
|
|
9045
10674
|
if (commandOptions.json) {
|
|
9046
10675
|
console.log(JSON.stringify({
|
|
9047
10676
|
jsonPath,
|
|
@@ -9051,13 +10680,17 @@ async function runWorkGraphCommand(options, defaults = {}) {
|
|
|
9051
10680
|
hydrationKey: report.signup_hydration.hydration_key,
|
|
9052
10681
|
finalState: report.final_state,
|
|
9053
10682
|
opportunityScore: report.opportunity_score,
|
|
10683
|
+
executionQuality: report.execution_quality,
|
|
10684
|
+
impactProjection: report.impact_projection,
|
|
9054
10685
|
missedOrchestration: report.missed_orchestration_opportunities.length,
|
|
9055
10686
|
clientExtractionCount: report.client_extractions.length,
|
|
9056
10687
|
kickoffCount: report.initiative_kickoffs.length,
|
|
9057
|
-
|
|
10688
|
+
findingCount: report.trails.length,
|
|
9058
10689
|
recurringPatternCount: report.recurring_patterns.length,
|
|
9059
|
-
|
|
9060
|
-
|
|
10690
|
+
attributionCount: report.attribution_spine.review.pending_count,
|
|
10691
|
+
topFinding: report.mirror.primary_trail_id ?? null,
|
|
10692
|
+
readoutHeadline: report.mirror.headline,
|
|
10693
|
+
published
|
|
9061
10694
|
}, null, 2));
|
|
9062
10695
|
return;
|
|
9063
10696
|
}
|
|
@@ -9067,11 +10700,13 @@ async function runWorkGraphCommand(options, defaults = {}) {
|
|
|
9067
10700
|
console.log(` ${ICON.ok} ${pc3.green("state ")} ${pc3.dim(report.final_state)}`);
|
|
9068
10701
|
console.log(` ${ICON.ok} ${pc3.green("extractions ")} ${pc3.dim(String(report.client_extractions.length))}`);
|
|
9069
10702
|
console.log(` ${ICON.ok} ${pc3.green("score ")} ${pc3.dim(formatWorkGraphScoreLine(report.opportunity_score))}`);
|
|
10703
|
+
console.log(` ${ICON.ok} ${pc3.green("quality ")} ${pc3.dim(`${report.execution_quality.overall}/100 \xB7 coverage ${report.source_coverage.coverage_score ?? 0}/100`)}`);
|
|
10704
|
+
console.log(` ${ICON.ok} ${pc3.green("impact ")} ${pc3.dim(`${report.impact_projection.time_saved_hours_per_week}h/week \xB7 +${report.impact_projection.acceleration_percent}% acceleration \xB7 ~$${report.impact_projection.estimated_monthly_value_usd.toLocaleString("en-US")}/month`)}`);
|
|
9070
10705
|
const missed = report.missed_orchestration_opportunities.length;
|
|
9071
10706
|
const missedColor = missed > 0 ? pc3.yellow : pc3.green;
|
|
9072
10707
|
console.log(` ${missed > 0 ? ICON.warn : ICON.ok} ${missedColor("missed ")} ${pc3.dim(`${missed} orchestration opportunit${missed === 1 ? "y" : "ies"}`)}`);
|
|
9073
|
-
console.log(` ${ICON.ok} ${pc3.green("
|
|
9074
|
-
console.log(` ${ICON.skip} ${pc3.bold("
|
|
10708
|
+
console.log(` ${ICON.ok} ${pc3.green("findings ")} ${pc3.dim(`${report.trails.length} finding${report.trails.length === 1 ? "" : "s"} \xB7 ${report.recurring_patterns.length} recurring pattern${report.recurring_patterns.length === 1 ? "" : "s"}`)}`);
|
|
10709
|
+
console.log(` ${ICON.skip} ${pc3.bold("readout ")} ${report.mirror.headline}`);
|
|
9075
10710
|
for (const metric of report.tension_metrics.slice(0, 4)) {
|
|
9076
10711
|
const tone = metric.tone === "danger" ? pc3.red : metric.tone === "warning" ? pc3.yellow : metric.tone === "good" ? pc3.green : pc3.dim;
|
|
9077
10712
|
console.log(` ${ICON.skip} ${tone(`${metric.value} ${metric.label}`)} ${pc3.dim(metric.explanation)}`);
|
|
@@ -9079,6 +10714,10 @@ async function runWorkGraphCommand(options, defaults = {}) {
|
|
|
9079
10714
|
for (const kickoff of report.initiative_kickoffs) {
|
|
9080
10715
|
console.log(` ${ICON.skip} ${pc3.bold(kickoff.priority.padEnd(3))} ${kickoff.title}`);
|
|
9081
10716
|
}
|
|
10717
|
+
console.log(` ${ICON.ok} ${pc3.green("attribution ")} ${pc3.dim(`${report.attribution_spine.review.pending_count} nodes \xB7 ${report.attribution_spine.source_events.length} source events`)}`);
|
|
10718
|
+
if (published?.publicUrl) {
|
|
10719
|
+
console.log(` ${ICON.ok} ${pc3.green("profile ")} ${pc3.bold(published.publicUrl)}`);
|
|
10720
|
+
}
|
|
9082
10721
|
}
|
|
9083
10722
|
async function checkPluginStatusesCompact() {
|
|
9084
10723
|
const spinner = createOrgxSpinner("Checking OrgX companion plugin status");
|
|
@@ -10038,7 +11677,7 @@ function printDoctorReport(report, assessment) {
|
|
|
10038
11677
|
async function main() {
|
|
10039
11678
|
const program = new Command();
|
|
10040
11679
|
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
10041
|
-
const pkgVersion = true ? "0.1.
|
|
11680
|
+
const pkgVersion = true ? "0.1.37" : void 0;
|
|
10042
11681
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
10043
11682
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
10044
11683
|
if (Boolean(actionCommand.optsWithGlobals().json)) return;
|
|
@@ -10738,22 +12377,22 @@ async function main() {
|
|
|
10738
12377
|
});
|
|
10739
12378
|
await runAuditCommand(options);
|
|
10740
12379
|
});
|
|
10741
|
-
const workGraph = program.command("work-graph").description("Build a redacted OrgX
|
|
10742
|
-
workGraph.command("extraction-schema").description("Print the AI-client
|
|
12380
|
+
const workGraph = program.command("work-graph").description("Build a redacted OrgX Profile from AI-client session search, Slack, MCP, or manual context.");
|
|
12381
|
+
workGraph.command("extraction-schema").description("Print the packaged AI-client audit skill used to search sessions, messages, tools, domains, and logs.").option("--output <path>", "write the schema prompt to a file").option("--json", "emit the protocol as JSON instead of Markdown").action(async (options) => {
|
|
10743
12382
|
await safeTrackWizardTelemetry("work_graph_extraction_schema_started", {
|
|
10744
12383
|
command: "work-graph extraction-schema",
|
|
10745
12384
|
json: Boolean(options.json)
|
|
10746
12385
|
});
|
|
10747
12386
|
runWorkGraphExtractionSchemaCommand(options);
|
|
10748
12387
|
});
|
|
10749
|
-
workGraph.command("preview").description("Preview the
|
|
12388
|
+
workGraph.command("preview").description("Preview the OrgX Profile evidence findings without writing to OrgX.").option("--input <path>", "source transcript or summary file; stdin is used when piped").option("--extraction <path>", "structured AI-client extraction JSON; repeat or comma-separate for multiple clients", collectPathOption, []).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", "15").option("--session-days <days>", "lookback window for local AI-session imports", "60").option("--codex-sessions-dir <path>", "override Codex sessions directory for import").option("--claude-projects-dir <path>", "override Claude projects directory for import").option("--source-label <label>", "label for the imported manual 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 previews").option("--output-dir <path>", "directory for generated Work Graph JSON and Markdown", ".orgx/work-graph").option("--json", "emit a JSON command summary").action(async (options) => {
|
|
10750
12389
|
await safeTrackWizardTelemetry("work_graph_preview_started", {
|
|
10751
12390
|
command: "work-graph preview",
|
|
10752
12391
|
from: options.from ?? "manual"
|
|
10753
12392
|
});
|
|
10754
12393
|
await runWorkGraphCommand(options);
|
|
10755
12394
|
});
|
|
10756
|
-
workGraph.command("profile").description("Build a local OrgX Profile with
|
|
12395
|
+
workGraph.command("profile").description("Build a local OrgX Profile with evidence findings, domain coverage, source confidence, and repair recommendations.").option("--input <path>", "source transcript or summary file; stdin is used when piped").option("--extraction <path>", "structured AI-client extraction JSON; repeat or comma-separate for multiple clients", collectPathOption, []).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", "25").option("--session-days <days>", "lookback window for local AI-session imports", "60").option("--codex-sessions-dir <path>", "override Codex sessions directory for import").option("--claude-projects-dir <path>", "override Claude projects directory for import").option("--source-label <label>", "label for the imported manual 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 profiles").option("--output-dir <path>", "directory for generated Work Graph JSON and Markdown", ".orgx/work-graph").option("--publish", "publish the generated OrgX Profile to OrgX and return a shareable URL").option("--public-share", "create a public redacted /work-graph/<token> share when publishing").option("--attach-artifact", "attach the report as an OrgX artifact when an initiative/entity is provided").option("--attach-to-initiative <id>", "attach the report to an existing OrgX initiative").option("--entity-type <type>", "entity type for artifact attachment: project, initiative, milestone, task, decision").option("--entity-id <id>", "entity id for artifact attachment").option("--artifact-url <url>", "override the artifact URL stored in OrgX").option("--yes", "approve publish/write prompts in non-interactive mode").option("--json", "emit a JSON command summary").action(async (options) => {
|
|
10757
12396
|
await safeTrackWizardTelemetry("work_graph_profile_started", {
|
|
10758
12397
|
command: "work-graph profile",
|
|
10759
12398
|
from: options.from ?? "manual"
|
|
@@ -10761,7 +12400,7 @@ async function main() {
|
|
|
10761
12400
|
await runWorkGraphCommand(options);
|
|
10762
12401
|
});
|
|
10763
12402
|
const sessions = program.command("sessions").description("Inspect and reconcile local AI sessions into OrgX-ready Work Graph reports.");
|
|
10764
|
-
sessions.command("reconcile").description("Backfill recent Codex and Claude sessions into a redacted
|
|
12403
|
+
sessions.command("reconcile").description("Backfill recent Codex and Claude sessions into a redacted OrgX Profile report.").option("--extraction <path>", "structured AI-client extraction JSON; repeat or comma-separate for multiple clients", collectPathOption, []).option("--from <sources>", "auto-import recent local AI sessions: codex, claude, or all", "all").option("--session-limit <count>", "max recent sessions to import per selected source", "25").option("--session-days <days>", "lookback window for local AI-session imports", "30").option("--codex-sessions-dir <path>", "override Codex sessions directory for import").option("--claude-projects-dir <path>", "override Claude projects directory for import").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 reconciliation").option("--output-dir <path>", "directory for generated Work Graph JSON and Markdown", ".orgx/work-graph").option("--publish", "publish the generated OrgX Profile to OrgX and return a shareable URL").option("--public-share", "create a public redacted /work-graph/<token> share when publishing").option("--attach-artifact", "attach the report as an OrgX artifact when an initiative/entity is provided").option("--attach-to-initiative <id>", "attach the report to an existing OrgX initiative").option("--entity-type <type>", "entity type for artifact attachment: project, initiative, milestone, task, decision").option("--entity-id <id>", "entity id for artifact attachment").option("--artifact-url <url>", "override the artifact URL stored in OrgX").option("--yes", "approve publish/write prompts in non-interactive mode").option("--json", "emit a JSON command summary").action(async (options) => {
|
|
10765
12404
|
await safeTrackWizardTelemetry("sessions_reconcile_started", {
|
|
10766
12405
|
command: "sessions reconcile",
|
|
10767
12406
|
from: options.from ?? "all"
|
|
@@ -10805,6 +12444,9 @@ async function main() {
|
|
|
10805
12444
|
}
|
|
10806
12445
|
}
|
|
10807
12446
|
});
|
|
12447
|
+
hooks.command("replay").description("Replay passive hook outbox events into a claimed Work Graph profile.").requiredOption("--fingerprint <fingerprint>", "target Work Graph fingerprint, for example wgf_0123...").option("--outbox <path>", "runtime hook JSONL outbox path").option("--limit <count>", "maximum recent hook events to replay", "200").option("--yes", "approve publishing hook evidence without prompting").option("--json", "emit a JSON command summary").action(async (options) => {
|
|
12448
|
+
await runHookReplayCommand(options);
|
|
12449
|
+
});
|
|
10808
12450
|
program.command("doctor").description("Verify local OrgX surface config and optional remote setup status.").action(async () => {
|
|
10809
12451
|
const spinner = createOrgxSpinner("Running OrgX health check");
|
|
10810
12452
|
spinner.start();
|