avorelo 0.1.0 → 0.3.0
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/LICENSE +23 -16
- package/README.md +90 -51
- package/bin/avorelo.mjs +7 -0
- package/dist/avorelo.mjs +19741 -0
- package/package.json +135 -120
- package/bin/avorelo +0 -9
- package/scripts/README.md +0 -40
- package/scripts/cco-dashboard.js +0 -252
- package/scripts/cco-status.js +0 -430
- package/scripts/lib/activation/account-state.js +0 -37
- package/scripts/lib/activation/activation-runner.js +0 -546
- package/scripts/lib/activation/activation-self-healing.js +0 -480
- package/scripts/lib/activation/activation-state.js +0 -83
- package/scripts/lib/activation/activation-summary.js +0 -191
- package/scripts/lib/activation/adapters/claude-code.js +0 -77
- package/scripts/lib/activation/adapters/codex-cli.js +0 -52
- package/scripts/lib/activation/adapters/cursor.js +0 -37
- package/scripts/lib/activation/adapters/github-agent.js +0 -39
- package/scripts/lib/activation/adapters/terminal.js +0 -42
- package/scripts/lib/activation/adapters/vscode.js +0 -39
- package/scripts/lib/activation/adapters/windsurf.js +0 -37
- package/scripts/lib/activation/ai-surface-detector.js +0 -151
- package/scripts/lib/activation/connect-account.js +0 -145
- package/scripts/lib/activation/detect-environment.js +0 -75
- package/scripts/lib/activation/detect-hosts.js +0 -62
- package/scripts/lib/activation/format-activation-output.js +0 -109
- package/scripts/lib/activation/next-action.js +0 -43
- package/scripts/lib/activation/repair-engine.js +0 -219
- package/scripts/lib/activation-distribution-readiness.js +0 -507
- package/scripts/lib/adapter-conformance.js +0 -176
- package/scripts/lib/adapter-readiness.js +0 -417
- package/scripts/lib/adapter-safety-boundaries.js +0 -335
- package/scripts/lib/adapter-technical-readiness-gate.js +0 -205
- package/scripts/lib/agent-access-governance.js +0 -455
- package/scripts/lib/agent-enforcement.js +0 -765
- package/scripts/lib/agent-policy-profile.js +0 -210
- package/scripts/lib/agent-security/action-evaluator.js +0 -507
- package/scripts/lib/agent-security/adapter-registry.js +0 -98
- package/scripts/lib/agent-security/auto-policy.js +0 -139
- package/scripts/lib/agent-security/bounded-scan.js +0 -93
- package/scripts/lib/agent-security/enforcement-adapter.js +0 -174
- package/scripts/lib/agent-security/enforcement-engine.js +0 -1129
- package/scripts/lib/agent-security/file-write-adapter.js +0 -183
- package/scripts/lib/agent-security/file-write-rules.js +0 -178
- package/scripts/lib/agent-security/index.js +0 -3342
- package/scripts/lib/agent-security/instruction-risk.js +0 -181
- package/scripts/lib/agent-security/mcp-action-adapter.js +0 -185
- package/scripts/lib/agent-security/mcp-action-rules.js +0 -184
- package/scripts/lib/agent-security/package-action-adapter.js +0 -175
- package/scripts/lib/agent-security/package-action-rules.js +0 -233
- package/scripts/lib/agent-security/performance.js +0 -148
- package/scripts/lib/agent-security/permission-minimizer.js +0 -403
- package/scripts/lib/agent-security/scan-cache.js +0 -74
- package/scripts/lib/agent-security/source-trust.js +0 -146
- package/scripts/lib/ai-install-prompt.js +0 -288
- package/scripts/lib/ai-workspace-hygiene.js +0 -1499
- package/scripts/lib/alpha-activation.js +0 -520
- package/scripts/lib/alpha-feedback.js +0 -263
- package/scripts/lib/alpha-readiness-gate.js +0 -332
- package/scripts/lib/anti-gaming.js +0 -169
- package/scripts/lib/artifact-health.js +0 -431
- package/scripts/lib/attribution.js +0 -180
- package/scripts/lib/audit.js +0 -289
- package/scripts/lib/avorelo-skill-registry.js +0 -810
- package/scripts/lib/batch-jobs.js +0 -71
- package/scripts/lib/brain-pack.js +0 -578
- package/scripts/lib/brand-boundary.js +0 -424
- package/scripts/lib/brand.js +0 -74
- package/scripts/lib/browser-capability.js +0 -1048
- package/scripts/lib/browser-proof-preflight.js +0 -321
- package/scripts/lib/cache-readiness.js +0 -187
- package/scripts/lib/canonical-reentry.js +0 -162
- package/scripts/lib/capability-packs.js +0 -314
- package/scripts/lib/capability-recommender.js +0 -512
- package/scripts/lib/capability-registry.js +0 -1059
- package/scripts/lib/carry-forward-surfacing.js +0 -194
- package/scripts/lib/ccusage-adapter.js +0 -188
- package/scripts/lib/company-loop.js +0 -1149
- package/scripts/lib/config.js +0 -637
- package/scripts/lib/context-acquisition-plan.js +0 -287
- package/scripts/lib/context-budget-guard.js +0 -170
- package/scripts/lib/context-budget-scanner.js +0 -257
- package/scripts/lib/context-optimizer.js +0 -715
- package/scripts/lib/context-reduction-plan.js +0 -178
- package/scripts/lib/context-safety.js +0 -88
- package/scripts/lib/context-savings-engine.js +0 -158
- package/scripts/lib/cost-evidence.js +0 -254
- package/scripts/lib/cross-host-install-plan.js +0 -308
- package/scripts/lib/cross-host-install-readiness.js +0 -237
- package/scripts/lib/cross-host-value-flow.js +0 -268
- package/scripts/lib/dashboard.js +0 -900
- package/scripts/lib/design-partner-feedback.js +0 -346
- package/scripts/lib/entitlements.js +0 -100
- package/scripts/lib/execution-packet.js +0 -559
- package/scripts/lib/experimentation-events.js +0 -547
- package/scripts/lib/external-capability-compliance.js +0 -107
- package/scripts/lib/external-user-simulation.js +0 -166
- package/scripts/lib/failure-recovery-readiness.js +0 -81
- package/scripts/lib/failure-recovery.js +0 -419
- package/scripts/lib/feedback-intelligence.js +0 -537
- package/scripts/lib/feedback-signals.js +0 -205
- package/scripts/lib/file-integrity.js +0 -68
- package/scripts/lib/fsx.js +0 -127
- package/scripts/lib/full-readiness-gate.js +0 -451
- package/scripts/lib/guidance-builder.js +0 -174
- package/scripts/lib/hook-apply.js +0 -1019
- package/scripts/lib/hook-baseline.js +0 -310
- package/scripts/lib/hook-config-preview.js +0 -275
- package/scripts/lib/hook-contracts.js +0 -290
- package/scripts/lib/hook-safety-boundary-readiness.js +0 -80
- package/scripts/lib/host-capability-matrix.js +0 -351
- package/scripts/lib/host-support-context.js +0 -254
- package/scripts/lib/http-hook-action.js +0 -538
- package/scripts/lib/install-ai-readiness.js +0 -84
- package/scripts/lib/install-intake-risk.js +0 -1037
- package/scripts/lib/install-journey-intelligence.js +0 -329
- package/scripts/lib/intervention-guidance.js +0 -57
- package/scripts/lib/known-limitations.js +0 -115
- package/scripts/lib/l8-path-truth.js +0 -146
- package/scripts/lib/launch-hardening-gate.js +0 -436
- package/scripts/lib/launch-readiness.js +0 -628
- package/scripts/lib/learning-memory.js +0 -686
- package/scripts/lib/lifecycle-hooks.js +0 -802
- package/scripts/lib/local-package-smoke.js +0 -423
- package/scripts/lib/local-pricing.js +0 -299
- package/scripts/lib/mcp-enforcement.js +0 -311
- package/scripts/lib/mcp-least-privilege-policy.js +0 -303
- package/scripts/lib/mcp-tool-inventory.js +0 -388
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +0 -335
- package/scripts/lib/metrics.js +0 -699
- package/scripts/lib/micro-proof.js +0 -133
- package/scripts/lib/next-run-context.js +0 -436
- package/scripts/lib/operating-value.js +0 -1648
- package/scripts/lib/optimization-v3.js +0 -122
- package/scripts/lib/orchestration/adapters/_shared.js +0 -49
- package/scripts/lib/orchestration/adapters/aider.js +0 -18
- package/scripts/lib/orchestration/adapters/claude-code.js +0 -35
- package/scripts/lib/orchestration/adapters/codex.js +0 -35
- package/scripts/lib/orchestration/adapters/gemini-cli.js +0 -18
- package/scripts/lib/orchestration/adapters/git.js +0 -25
- package/scripts/lib/orchestration/adapters/index.js +0 -31
- package/scripts/lib/orchestration/adapters/lm-studio.js +0 -18
- package/scripts/lib/orchestration/adapters/ollama.js +0 -18
- package/scripts/lib/orchestration/adapters/opencode.js +0 -18
- package/scripts/lib/orchestration/adapters/openrouter.js +0 -18
- package/scripts/lib/orchestration/adapters/test-runner.js +0 -25
- package/scripts/lib/orchestration/cli.js +0 -438
- package/scripts/lib/orchestration/execution-manager.js +0 -279
- package/scripts/lib/orchestration/handoff.js +0 -314
- package/scripts/lib/orchestration/index.js +0 -456
- package/scripts/lib/orchestration/inventory.js +0 -47
- package/scripts/lib/orchestration/model-discovery.js +0 -498
- package/scripts/lib/orchestration/model-profiler.js +0 -170
- package/scripts/lib/orchestration/model-profiles.js +0 -252
- package/scripts/lib/orchestration/model-refresh-policy.js +0 -72
- package/scripts/lib/orchestration/proof-writer.js +0 -349
- package/scripts/lib/orchestration/provider-discovery/aider.js +0 -49
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +0 -56
- package/scripts/lib/orchestration/provider-discovery/codex.js +0 -49
- package/scripts/lib/orchestration/provider-discovery/common.js +0 -186
- package/scripts/lib/orchestration/provider-discovery/gemini.js +0 -106
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +0 -118
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +0 -12
- package/scripts/lib/orchestration/provider-discovery/ollama.js +0 -100
- package/scripts/lib/orchestration/provider-discovery/opencode.js +0 -47
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +0 -44
- package/scripts/lib/orchestration/risk-classifier.js +0 -130
- package/scripts/lib/orchestration/routing-policy.js +0 -486
- package/scripts/lib/orchestration/settings.js +0 -112
- package/scripts/lib/orchestration/state.js +0 -165
- package/scripts/lib/orchestration/verification-manager.js +0 -138
- package/scripts/lib/output-profiles.js +0 -146
- package/scripts/lib/package-content-audit.js +0 -368
- package/scripts/lib/package-runtime.js +0 -278
- package/scripts/lib/plan-surface.js +0 -53
- package/scripts/lib/plans.js +0 -2318
- package/scripts/lib/policy-provider.js +0 -27
- package/scripts/lib/prelaunch-activation-readiness.js +0 -409
- package/scripts/lib/prelaunch-evidence-store.js +0 -816
- package/scripts/lib/prelaunch-intelligence.js +0 -869
- package/scripts/lib/pricing-experiment.js +0 -118
- package/scripts/lib/pro-moment-events.js +0 -77
- package/scripts/lib/pro-moment-state.js +0 -227
- package/scripts/lib/pro-moments.js +0 -1216
- package/scripts/lib/product-learning-events.js +0 -629
- package/scripts/lib/project-profile.js +0 -555
- package/scripts/lib/prompt-compiler.js +0 -280
- package/scripts/lib/prompt-lint.js +0 -32
- package/scripts/lib/prompt-suggestions.js +0 -52
- package/scripts/lib/proof-canonical.js +0 -398
- package/scripts/lib/proof-drilldown.js +0 -383
- package/scripts/lib/proof-events.js +0 -342
- package/scripts/lib/proof-history.js +0 -243
- package/scripts/lib/proof-metrics.js +0 -296
- package/scripts/lib/proof-outcome-evidence.js +0 -134
- package/scripts/lib/proof-receipt.js +0 -335
- package/scripts/lib/proof-record.js +0 -461
- package/scripts/lib/public-activation-distribution-gate.js +0 -258
- package/scripts/lib/public-cli.js +0 -3891
- package/scripts/lib/public-distribution-truth.js +0 -211
- package/scripts/lib/public-install-claim-checker.js +0 -294
- package/scripts/lib/publish-provenance-readiness.js +0 -283
- package/scripts/lib/readiness-delta.js +0 -218
- package/scripts/lib/readiness-evidence-closure.js +0 -196
- package/scripts/lib/reentry-memory-capture.js +0 -241
- package/scripts/lib/reentry-memory-retrieval.js +0 -302
- package/scripts/lib/reentry-memory-status.js +0 -146
- package/scripts/lib/reentry-memory-store.js +0 -178
- package/scripts/lib/reentry-state.js +0 -66
- package/scripts/lib/release-candidate-bundle.js +0 -166
- package/scripts/lib/remediation.js +0 -81
- package/scripts/lib/repo-map.js +0 -391
- package/scripts/lib/run-improvements-lifecycle.js +0 -330
- package/scripts/lib/run-improvements.js +0 -789
- package/scripts/lib/runtime-decision-policy.js +0 -387
- package/scripts/lib/safe-path-engine.js +0 -705
- package/scripts/lib/safe-run-controller.js +0 -887
- package/scripts/lib/score.js +0 -262
- package/scripts/lib/seamless-enforcement.js +0 -329
- package/scripts/lib/seamless-outcome.js +0 -689
- package/scripts/lib/seamless-reality-gate.js +0 -5043
- package/scripts/lib/security-risk-classifier.js +0 -511
- package/scripts/lib/security-scan.js +0 -384
- package/scripts/lib/session-context-optimizer.js +0 -1211
- package/scripts/lib/session-timing.js +0 -315
- package/scripts/lib/skill-hygiene.js +0 -805
- package/scripts/lib/skill-packs.js +0 -161
- package/scripts/lib/skills-operating-layer.js +0 -580
- package/scripts/lib/smart-work-routing.js +0 -768
- package/scripts/lib/source-catalog.js +0 -700
- package/scripts/lib/status-value-summary.js +0 -32
- package/scripts/lib/support-bundle.js +0 -578
- package/scripts/lib/task-continuation.js +0 -440
- package/scripts/lib/test-helpers.js +0 -15
- package/scripts/lib/tier.js +0 -38
- package/scripts/lib/token-context-quality-gate.js +0 -370
- package/scripts/lib/token-cost-capture.js +0 -187
- package/scripts/lib/token-cost-intelligence.js +0 -358
- package/scripts/lib/token-efficiency-evidence.js +0 -213
- package/scripts/lib/token-evidence.js +0 -699
- package/scripts/lib/tokenish.js +0 -17
- package/scripts/lib/tool-output-sandbox.js +0 -304
- package/scripts/lib/trust-audit.js +0 -136
- package/scripts/lib/unified-events.js +0 -396
- package/scripts/lib/upgrade-interruption-recovery.js +0 -407
- package/scripts/lib/usage-ledger.js +0 -201
- package/scripts/lib/value-ledger.js +0 -130
- package/scripts/lib/value-proof-calibration.js +0 -531
- package/scripts/lib/visual-qa.js +0 -231
- package/scripts/lib/voice-alpha.js +0 -29
- package/scripts/lib/work-aware-orchestration.js +0 -976
- package/scripts/lib/work-control-receipts.js +0 -577
- package/scripts/lib/work-ledger.js +0 -1123
- package/scripts/lib/work-panel-preview.js +0 -352
- package/scripts/lib/workflow-discipline.js +0 -280
- package/scripts/lib/workflow-signals.js +0 -419
- package/scripts/lib/workspace-map.js +0 -281
- package/scripts/lib/workspace-registry.js +0 -1367
- package/scripts/lib/workspace-resolver.js +0 -480
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// Workflow signals: collects local deterministic signals for workflow discipline.
|
|
4
|
-
// All collectors fail open — missing state/modules return unknown, never throw.
|
|
5
|
-
|
|
6
|
-
const fs = require("fs");
|
|
7
|
-
const path = require("path");
|
|
8
|
-
const { execSync } = require("child_process");
|
|
9
|
-
|
|
10
|
-
const REENTRY_MEMORY_REL = ".claude/cco/state/reentry-memory.jsonl";
|
|
11
|
-
const BUDGET_REL = ".claude/cco/state/context-budget.json";
|
|
12
|
-
const RECEIPTS_REL = ".claude/cco/receipts";
|
|
13
|
-
const PROOF_CANONICAL_REL = ".claude/cco/state";
|
|
14
|
-
const REENTRY_STATE_REL = ".claude/cco/state/reentry-state.json";
|
|
15
|
-
const TASK_COMPLETED_DIR_REL = ".claude/cco/state";
|
|
16
|
-
const MAX_EVIDENCE_BYTES = 64 * 1024;
|
|
17
|
-
|
|
18
|
-
// --- Repo state ---
|
|
19
|
-
|
|
20
|
-
function inferRepoState(options = {}) {
|
|
21
|
-
// Accept injected output for tests; otherwise run git safely.
|
|
22
|
-
const { cwd, _gitStatusOutput } = options;
|
|
23
|
-
|
|
24
|
-
let raw;
|
|
25
|
-
if (typeof _gitStatusOutput === "string") {
|
|
26
|
-
raw = _gitStatusOutput;
|
|
27
|
-
} else {
|
|
28
|
-
try {
|
|
29
|
-
raw = execSync("git status --porcelain", {
|
|
30
|
-
cwd: cwd || process.cwd(),
|
|
31
|
-
timeout: 3000,
|
|
32
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
33
|
-
}).toString("utf8");
|
|
34
|
-
} catch {
|
|
35
|
-
return { repoState: "unknown", changedFilesCount: 0, hasStagedChanges: false, hasUnstagedChanges: false };
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
40
|
-
if (lines.length === 0) {
|
|
41
|
-
return { repoState: "clean", changedFilesCount: 0, hasStagedChanges: false, hasUnstagedChanges: false };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Staged: first char is not space/?
|
|
45
|
-
// Unstaged: second char is not space/?
|
|
46
|
-
const staged = lines.filter((l) => l.length >= 2 && l[0] !== " " && l[0] !== "?").length;
|
|
47
|
-
const unstaged = lines.filter((l) => l.length >= 2 && l[1] !== " " && l[1] !== "?").length;
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
repoState: "modified",
|
|
51
|
-
changedFilesCount: lines.length,
|
|
52
|
-
hasStagedChanges: staged > 0,
|
|
53
|
-
hasUnstagedChanges: unstaged > 0,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// --- Context pressure ---
|
|
58
|
-
|
|
59
|
-
function inferContextPressure(options = {}) {
|
|
60
|
-
const { cwd, budgetStatus } = options;
|
|
61
|
-
|
|
62
|
-
// Accept pre-built budgetStatus (from dashboard) to avoid double-loading.
|
|
63
|
-
if (budgetStatus && typeof budgetStatus === "object") {
|
|
64
|
-
const s = budgetStatus.status;
|
|
65
|
-
if (s === "critical") return { contextPressure: "critical" };
|
|
66
|
-
if (s === "warn") return { contextPressure: "warn" };
|
|
67
|
-
if (s === "ok") return { contextPressure: "ok" };
|
|
68
|
-
return { contextPressure: "unknown" };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Otherwise try to read the stored budget state file directly.
|
|
72
|
-
try {
|
|
73
|
-
const p = path.join(cwd || process.cwd(), BUDGET_REL);
|
|
74
|
-
const data = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
75
|
-
if (data && typeof data.usedPercent === "number" && typeof data.warnAtPercent === "number") {
|
|
76
|
-
const pct = data.usedPercent;
|
|
77
|
-
const blockAt = data.blockAtPercent || 90;
|
|
78
|
-
const warnAt = data.warnAtPercent || 70;
|
|
79
|
-
if (pct >= blockAt) return { contextPressure: "critical" };
|
|
80
|
-
if (pct >= warnAt) return { contextPressure: "warn" };
|
|
81
|
-
return { contextPressure: "ok" };
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
// file missing or parse error — treat as unknown
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return { contextPressure: "unknown" };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// --- Reentry memory state ---
|
|
91
|
-
|
|
92
|
-
function inferReentryState(options = {}) {
|
|
93
|
-
const { cwd } = options;
|
|
94
|
-
try {
|
|
95
|
-
const p = path.join(cwd || process.cwd(), REENTRY_MEMORY_REL);
|
|
96
|
-
const stat = fs.statSync(p);
|
|
97
|
-
if (stat.isFile() && stat.size > 0) {
|
|
98
|
-
return { reentryState: "available" };
|
|
99
|
-
}
|
|
100
|
-
return { reentryState: "missing" };
|
|
101
|
-
} catch {
|
|
102
|
-
return { reentryState: "missing" };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// --- Validation / proof state ---
|
|
107
|
-
|
|
108
|
-
// Conservative: look for any receipt in the receipts dir, or canonical proof files.
|
|
109
|
-
// missing = no receipt files at all
|
|
110
|
-
// partial = at least one receipt exists
|
|
111
|
-
// passed = latest receipt has outcome "completed" or "success"
|
|
112
|
-
function inferValidationState(options = {}) {
|
|
113
|
-
const { cwd } = options;
|
|
114
|
-
try {
|
|
115
|
-
const receiptsDir = path.join(cwd || process.cwd(), RECEIPTS_REL);
|
|
116
|
-
const files = fs.readdirSync(receiptsDir).filter((f) => f.endsWith(".json"));
|
|
117
|
-
if (files.length === 0) {
|
|
118
|
-
return { validationState: "missing" };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Check the most recent receipt for completion status.
|
|
122
|
-
const sorted = files
|
|
123
|
-
.map((f) => ({ f, mtime: fs.statSync(path.join(receiptsDir, f)).mtimeMs }))
|
|
124
|
-
.sort((a, b) => b.mtime - a.mtime);
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
const latest = JSON.parse(fs.readFileSync(path.join(receiptsDir, sorted[0].f), "utf8"));
|
|
128
|
-
// Receipt schema: result.status is the completion_status string.
|
|
129
|
-
// Valid values from proof-receipt.js: "completed", "safe_stop", "partial",
|
|
130
|
-
// "ended_without_completion", "unknown".
|
|
131
|
-
const status = latest?.result?.status || "";
|
|
132
|
-
if (status === "completed" || status === "safe_stop") {
|
|
133
|
-
return { validationState: "passed" };
|
|
134
|
-
}
|
|
135
|
-
if (status === "partial") {
|
|
136
|
-
return { validationState: "partial" };
|
|
137
|
-
}
|
|
138
|
-
} catch {
|
|
139
|
-
// can't read latest; fall through to partial
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return { validationState: "partial" };
|
|
143
|
-
} catch {
|
|
144
|
-
return { validationState: "missing" };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// --- Risk / agent security state ---
|
|
149
|
-
|
|
150
|
-
// Maps existing agent-security mode and scan data to a simple riskLevel.
|
|
151
|
-
// Conservative: only escalate to high if there is evidence from an existing scan.
|
|
152
|
-
function inferRiskState(options = {}) {
|
|
153
|
-
const { cwd, agentSecuritySurface, agentSecurityMode } = options;
|
|
154
|
-
|
|
155
|
-
// Use pre-built surface from dashboard if available.
|
|
156
|
-
if (agentSecuritySurface && typeof agentSecuritySurface === "object") {
|
|
157
|
-
const mode = agentSecuritySurface.mode || "off";
|
|
158
|
-
const summary = agentSecuritySurface.summary || {};
|
|
159
|
-
const highRisk = Number(summary.highRisk || 0);
|
|
160
|
-
const mediumRisk = Number(summary.mediumRisk || 0);
|
|
161
|
-
|
|
162
|
-
if (highRisk > 0) return { riskLevel: "high", agentSecurityState: mode };
|
|
163
|
-
if (mode === "warn" || mode === "approve" || mode === "enforce") return { riskLevel: "medium", agentSecurityState: mode };
|
|
164
|
-
if (mediumRisk > 0) return { riskLevel: "medium", agentSecurityState: mode };
|
|
165
|
-
if (mode === "visibility") return { riskLevel: "low", agentSecurityState: mode };
|
|
166
|
-
return { riskLevel: "low", agentSecurityState: mode };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Fall back to config mode only if surface not available.
|
|
170
|
-
const mode = agentSecurityMode || "off";
|
|
171
|
-
if (mode === "warn" || mode === "approve" || mode === "enforce") return { riskLevel: "medium", agentSecurityState: mode };
|
|
172
|
-
if (mode === "visibility") return { riskLevel: "low", agentSecurityState: mode };
|
|
173
|
-
return { riskLevel: "low", agentSecurityState: mode };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// --- Session evidence collection ---
|
|
177
|
-
|
|
178
|
-
// Reads latest task-completed and reentry-state files for keyword classification.
|
|
179
|
-
// Bounded by MAX_EVIDENCE_BYTES; fails open with empty string on any error.
|
|
180
|
-
function collectTaskEvidence(cwd) {
|
|
181
|
-
const base = cwd || process.cwd();
|
|
182
|
-
const parts = [];
|
|
183
|
-
|
|
184
|
-
// Latest task-completed-*.json: nextBestAction, topReasonCodes
|
|
185
|
-
try {
|
|
186
|
-
const dir = path.join(base, TASK_COMPLETED_DIR_REL);
|
|
187
|
-
const files = fs
|
|
188
|
-
.readdirSync(dir)
|
|
189
|
-
.filter((f) => f.startsWith("task-completed-") && f.endsWith(".json"))
|
|
190
|
-
.map((f) => ({ f, mtime: fs.statSync(path.join(dir, f)).mtimeMs }))
|
|
191
|
-
.sort((a, b) => b.mtime - a.mtime);
|
|
192
|
-
if (files.length > 0) {
|
|
193
|
-
const raw = fs.readFileSync(path.join(dir, files[0].f), "utf8");
|
|
194
|
-
if (raw.length <= MAX_EVIDENCE_BYTES) {
|
|
195
|
-
const data = JSON.parse(raw);
|
|
196
|
-
if (data.nextBestAction) parts.push(data.nextBestAction);
|
|
197
|
-
if (Array.isArray(data.topReasonCodes)) parts.push(data.topReasonCodes.join(" "));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
} catch {
|
|
201
|
-
// ignore
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Stop events: latest stop-*.json: reason, message, nextBoundedAction
|
|
205
|
-
try {
|
|
206
|
-
const dir = path.join(base, TASK_COMPLETED_DIR_REL);
|
|
207
|
-
const files = fs
|
|
208
|
-
.readdirSync(dir)
|
|
209
|
-
.filter((f) => f.startsWith("stop-") && f.endsWith(".json"))
|
|
210
|
-
.map((f) => ({ f, mtime: fs.statSync(path.join(dir, f)).mtimeMs }))
|
|
211
|
-
.sort((a, b) => b.mtime - a.mtime);
|
|
212
|
-
if (files.length > 0) {
|
|
213
|
-
const raw = fs.readFileSync(path.join(dir, files[0].f), "utf8");
|
|
214
|
-
if (raw.length <= MAX_EVIDENCE_BYTES) {
|
|
215
|
-
const data = JSON.parse(raw);
|
|
216
|
-
if (data.reason) parts.push(data.reason);
|
|
217
|
-
if (data.message) parts.push(data.message);
|
|
218
|
-
if (data.nextBoundedAction) parts.push(data.nextBoundedAction);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
} catch {
|
|
222
|
-
// ignore
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Reentry state: nextAction, resumeHint, unresolvedRisk
|
|
226
|
-
try {
|
|
227
|
-
const p = path.join(base, REENTRY_STATE_REL);
|
|
228
|
-
const raw = fs.readFileSync(p, "utf8");
|
|
229
|
-
if (raw.length <= MAX_EVIDENCE_BYTES) {
|
|
230
|
-
const data = JSON.parse(raw);
|
|
231
|
-
if (data.nextAction) parts.push(data.nextAction);
|
|
232
|
-
if (data.resumeHint) parts.push(data.resumeHint);
|
|
233
|
-
if (data.unresolvedRisk) parts.push(data.unresolvedRisk);
|
|
234
|
-
}
|
|
235
|
-
} catch {
|
|
236
|
-
// ignore
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return parts.join(" ").toLowerCase();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// --- Keyword-based task type classification ---
|
|
243
|
-
|
|
244
|
-
// Deterministic keyword rules. Returns { taskType, confidence, reasonCodes }.
|
|
245
|
-
// Confidence: "high" = dominant signal, "medium" = at least one match, "low" = weak.
|
|
246
|
-
function classifyTaskTypeFromText(text) {
|
|
247
|
-
if (!text || text.trim().length === 0) {
|
|
248
|
-
return { taskType: "unknown", confidence: "low", reasonCodes: [] };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const t = text.toLowerCase();
|
|
252
|
-
|
|
253
|
-
// PR/finalization patterns — require specific finalization language; "release" excluded (too generic).
|
|
254
|
-
const prKeywords = ["pull request", " pr ", "merge request", "git commit", "ship the", "shipping", "final check", "proof bundle", "ready to merge"];
|
|
255
|
-
const prMatches = prKeywords.filter((k) => t.includes(k));
|
|
256
|
-
|
|
257
|
-
// Bug patterns
|
|
258
|
-
const bugKeywords = ["failed test", "failing test", "regression", "bug", "error", "exception", " fix ", "broken", "failure", "failing", "debug", "diagnose"];
|
|
259
|
-
const bugMatches = bugKeywords.filter((k) => t.includes(k));
|
|
260
|
-
|
|
261
|
-
// Feature patterns — "add ", "support ", "build ", "create " excluded: too generic in system messages.
|
|
262
|
-
const featureKeywords = ["implement", "introduce", "new feature", "capability", "feature"];
|
|
263
|
-
const featureMatches = featureKeywords.filter((k) => t.includes(k));
|
|
264
|
-
|
|
265
|
-
// Refactor patterns
|
|
266
|
-
const refactorKeywords = ["refactor", "cleanup", "clean up", "simplify", "restructure", "rename", "architecture", "extract ", "consolidate", "reorganize"];
|
|
267
|
-
const refactorMatches = refactorKeywords.filter((k) => t.includes(k));
|
|
268
|
-
|
|
269
|
-
const bugScore = bugMatches.length;
|
|
270
|
-
const featureScore = featureMatches.length;
|
|
271
|
-
const refactorScore = refactorMatches.length;
|
|
272
|
-
const prScore = prMatches.length;
|
|
273
|
-
|
|
274
|
-
// PR wins only with explicit finalization signals
|
|
275
|
-
if (prScore >= 1 && bugScore === 0) {
|
|
276
|
-
return { taskType: "pr", confidence: prScore >= 2 ? "high" : "medium", reasonCodes: prMatches };
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Bug wins over feature/refactor
|
|
280
|
-
if (bugScore > 0 && bugScore >= featureScore && bugScore >= refactorScore) {
|
|
281
|
-
return { taskType: "bug", confidence: bugScore >= 3 ? "high" : "medium", reasonCodes: bugMatches };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Feature beats refactor if it has more matches
|
|
285
|
-
if (featureScore > 0 && featureScore >= refactorScore) {
|
|
286
|
-
return { taskType: "feature", confidence: featureScore >= 2 ? "high" : "medium", reasonCodes: featureMatches };
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (refactorScore > 0) {
|
|
290
|
-
return { taskType: "refactor", confidence: refactorScore >= 2 ? "high" : "medium", reasonCodes: refactorMatches };
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return { taskType: "unknown", confidence: "low", reasonCodes: [] };
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// --- Task type inference ---
|
|
297
|
-
|
|
298
|
-
// Only infer taskType when there is a deterministic local signal.
|
|
299
|
-
// No NLP, no LLM calls. Returns additive fields taskTypeConfidence, taskTypeSource, taskTypeReasonCodes.
|
|
300
|
-
function inferTaskType(options = {}) {
|
|
301
|
-
const { cwd, validationState, hasStagedChanges } = options;
|
|
302
|
-
|
|
303
|
-
// Staged changes + partial/passed validation → likely PR/finalization candidate
|
|
304
|
-
if (hasStagedChanges && (validationState === "partial" || validationState === "passed")) {
|
|
305
|
-
return { taskType: "pr", taskTypeConfidence: "high", taskTypeSource: "receipt+staged", taskTypeReasonCodes: ["STAGED_CHANGES", "VALIDATION_" + (validationState || "unknown").toUpperCase()] };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Try to detect incomplete/stalled session from most recent receipt.
|
|
309
|
-
// "ended_without_completion" → likely a bug or unexpected stop, suggest diagnose.
|
|
310
|
-
let receiptStatus = "";
|
|
311
|
-
try {
|
|
312
|
-
const receiptsDir = path.join(cwd || process.cwd(), RECEIPTS_REL);
|
|
313
|
-
const files = fs.readdirSync(receiptsDir).filter((f) => f.endsWith(".json"));
|
|
314
|
-
if (files.length > 0) {
|
|
315
|
-
const sorted = files
|
|
316
|
-
.map((f) => ({ f, mtime: fs.statSync(path.join(receiptsDir, f)).mtimeMs }))
|
|
317
|
-
.sort((a, b) => b.mtime - a.mtime);
|
|
318
|
-
const latest = JSON.parse(fs.readFileSync(path.join(receiptsDir, sorted[0].f), "utf8"));
|
|
319
|
-
receiptStatus = latest?.result?.status || "";
|
|
320
|
-
}
|
|
321
|
-
} catch {
|
|
322
|
-
// ignore
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (receiptStatus === "ended_without_completion") {
|
|
326
|
-
// Check session evidence for more specific classification before defaulting to bug.
|
|
327
|
-
const evidenceText = collectTaskEvidence(cwd);
|
|
328
|
-
const classified = classifyTaskTypeFromText(evidenceText);
|
|
329
|
-
if (classified.confidence !== "low" && classified.taskType !== "unknown") {
|
|
330
|
-
return {
|
|
331
|
-
taskType: classified.taskType,
|
|
332
|
-
taskTypeConfidence: classified.confidence,
|
|
333
|
-
taskTypeSource: "session-evidence",
|
|
334
|
-
taskTypeReasonCodes: classified.reasonCodes,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
return { taskType: "bug", taskTypeConfidence: "medium", taskTypeSource: "receipt", taskTypeReasonCodes: ["ENDED_WITHOUT_COMPLETION"] };
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// No receipt signal — try session evidence directly.
|
|
341
|
-
const evidenceText = collectTaskEvidence(cwd);
|
|
342
|
-
const classified = classifyTaskTypeFromText(evidenceText);
|
|
343
|
-
if (classified.confidence !== "low" && classified.taskType !== "unknown") {
|
|
344
|
-
return {
|
|
345
|
-
taskType: classified.taskType,
|
|
346
|
-
taskTypeConfidence: classified.confidence,
|
|
347
|
-
taskTypeSource: "session-evidence",
|
|
348
|
-
taskTypeReasonCodes: classified.reasonCodes,
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return { taskType: "unknown", taskTypeConfidence: "low", taskTypeSource: "none", taskTypeReasonCodes: [] };
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// --- Master signal collector ---
|
|
356
|
-
|
|
357
|
-
// Collects all signals. Accepts pre-built surfaces to avoid redundant work.
|
|
358
|
-
// Options:
|
|
359
|
-
// cwd - working directory (default: process.cwd())
|
|
360
|
-
// budgetStatus - pre-built budgetStatus from dashboard (optional)
|
|
361
|
-
// agentSecuritySurface - pre-built agentSecurity from dashboard (optional)
|
|
362
|
-
// agentSecurityMode - raw config mode (fallback if surface absent)
|
|
363
|
-
// _gitStatusOutput - injected git output for tests
|
|
364
|
-
function collectWorkflowSignals(options = {}) {
|
|
365
|
-
const cwd = options.cwd || process.cwd();
|
|
366
|
-
|
|
367
|
-
const repoSignals = inferRepoState({ cwd, _gitStatusOutput: options._gitStatusOutput });
|
|
368
|
-
const pressureSignals = inferContextPressure({ cwd, budgetStatus: options.budgetStatus });
|
|
369
|
-
const reentrySignals = inferReentryState({ cwd });
|
|
370
|
-
const validationSignals = inferValidationState({ cwd });
|
|
371
|
-
const riskSignals = inferRiskState({
|
|
372
|
-
cwd,
|
|
373
|
-
agentSecuritySurface: options.agentSecuritySurface,
|
|
374
|
-
agentSecurityMode: options.agentSecurityMode,
|
|
375
|
-
});
|
|
376
|
-
const taskSignals = inferTaskType({
|
|
377
|
-
cwd,
|
|
378
|
-
repoState: repoSignals.repoState,
|
|
379
|
-
validationState: validationSignals.validationState,
|
|
380
|
-
hasStagedChanges: repoSignals.hasStagedChanges,
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
return {
|
|
384
|
-
repoState: repoSignals.repoState,
|
|
385
|
-
changedFilesCount: repoSignals.changedFilesCount,
|
|
386
|
-
hasStagedChanges: repoSignals.hasStagedChanges,
|
|
387
|
-
hasUnstagedChanges: repoSignals.hasUnstagedChanges,
|
|
388
|
-
contextPressure: pressureSignals.contextPressure,
|
|
389
|
-
reentryState: reentrySignals.reentryState,
|
|
390
|
-
validationState: validationSignals.validationState,
|
|
391
|
-
riskLevel: riskSignals.riskLevel,
|
|
392
|
-
agentSecurityState: riskSignals.agentSecurityState,
|
|
393
|
-
taskType: taskSignals.taskType,
|
|
394
|
-
taskTypeConfidence: taskSignals.taskTypeConfidence || "low",
|
|
395
|
-
taskTypeSource: taskSignals.taskTypeSource || "none",
|
|
396
|
-
taskTypeReasonCodes: taskSignals.taskTypeReasonCodes || [],
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Convenience: build the full workflow-discipline input from local signals.
|
|
401
|
-
// Merges auto-detected signals with any caller-provided overrides.
|
|
402
|
-
function buildWorkflowInput(options = {}) {
|
|
403
|
-
const signals = collectWorkflowSignals(options);
|
|
404
|
-
// Caller overrides take precedence over auto-detected signals.
|
|
405
|
-
return { ...signals, ...(options.overrides || {}) };
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
module.exports = {
|
|
409
|
-
inferRepoState,
|
|
410
|
-
inferContextPressure,
|
|
411
|
-
inferReentryState,
|
|
412
|
-
inferValidationState,
|
|
413
|
-
inferRiskState,
|
|
414
|
-
inferTaskType,
|
|
415
|
-
collectWorkflowSignals,
|
|
416
|
-
buildWorkflowInput,
|
|
417
|
-
collectTaskEvidence,
|
|
418
|
-
classifyTaskTypeFromText,
|
|
419
|
-
};
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const { ensureCcoDirs, safeWriteJson, safeReadJson, nowIso } = require("./fsx");
|
|
6
|
-
|
|
7
|
-
const WORKSPACE_MAP_REL_PATH = ".claude/cco/state/workspace-map.json";
|
|
8
|
-
const IGNORED_DIRS = new Set([
|
|
9
|
-
".git",
|
|
10
|
-
"node_modules",
|
|
11
|
-
"dist",
|
|
12
|
-
"build",
|
|
13
|
-
"coverage",
|
|
14
|
-
".next",
|
|
15
|
-
".turbo",
|
|
16
|
-
".cache",
|
|
17
|
-
".wasp",
|
|
18
|
-
".avorelo",
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
function normalize(value) {
|
|
22
|
-
return String(value || "").replace(/\\/g, "/");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function exists(cwd, relPathValue) {
|
|
26
|
-
return fs.existsSync(path.join(cwd, relPathValue));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function safeReadDir(absPath) {
|
|
30
|
-
try {
|
|
31
|
-
return fs.readdirSync(absPath, { withFileTypes: true });
|
|
32
|
-
} catch {
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function listFiles(cwd, relDir, matcher = () => true, limit = 50) {
|
|
38
|
-
const results = [];
|
|
39
|
-
const startAbs = path.join(cwd, relDir);
|
|
40
|
-
|
|
41
|
-
function walk(currentAbs, currentRel) {
|
|
42
|
-
if (results.length >= limit) return;
|
|
43
|
-
const entries = safeReadDir(currentAbs);
|
|
44
|
-
for (const entry of entries) {
|
|
45
|
-
if (results.length >= limit) break;
|
|
46
|
-
const entryRel = currentRel ? `${currentRel}/${entry.name}` : entry.name;
|
|
47
|
-
if (entry.isDirectory()) {
|
|
48
|
-
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
49
|
-
walk(path.join(currentAbs, entry.name), entryRel);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const normalized = normalize(entryRel);
|
|
53
|
-
if (matcher(normalized)) {
|
|
54
|
-
results.push(normalized);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (fs.existsSync(startAbs)) {
|
|
60
|
-
walk(startAbs, normalize(relDir));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return results;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function readPackageScripts(cwd) {
|
|
67
|
-
try {
|
|
68
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
|
|
69
|
-
return pkg.scripts || {};
|
|
70
|
-
} catch {
|
|
71
|
-
return {};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function readCapabilityPacks() {
|
|
76
|
-
try {
|
|
77
|
-
const { listPacks } = require("./capability-packs");
|
|
78
|
-
return listPacks().map((pack) => pack.id);
|
|
79
|
-
} catch {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function detectSurfaces(cwd) {
|
|
85
|
-
const packageScripts = readPackageScripts(cwd);
|
|
86
|
-
const docs = listFiles(cwd, "docs", (file) => file.endsWith(".md"), 80);
|
|
87
|
-
const tests = listFiles(cwd, "tests", (file) => /\.(js|ts|mjs)$/i.test(file), 80);
|
|
88
|
-
const skills = listFiles(cwd, "skills", (file) => /SKILL\.md$/i.test(file), 80);
|
|
89
|
-
const adapters = [];
|
|
90
|
-
|
|
91
|
-
if (exists(cwd, "bin/avorelo")) adapters.push("cli");
|
|
92
|
-
if (exists(cwd, ".claude/settings.json")) adapters.push("claude-code");
|
|
93
|
-
if (exists(cwd, ".avorelo/generated/codex/AGENTS.md")) adapters.push("codex");
|
|
94
|
-
if (exists(cwd, ".avorelo/generated/cursor/rules/avorelo.mdc")) adapters.push("cursor");
|
|
95
|
-
if (exists(cwd, ".avorelo/generated/gemini/GEMINI.md")) adapters.push("gemini");
|
|
96
|
-
if (exists(cwd, ".avorelo/generated/copilot/copilot-instructions.md")) adapters.push("copilot");
|
|
97
|
-
if (exists(cwd, "apps/public-web")) adapters.push("public-web");
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
packageScripts,
|
|
101
|
-
docs,
|
|
102
|
-
tests,
|
|
103
|
-
skills,
|
|
104
|
-
adapters,
|
|
105
|
-
commands: Object.keys(packageScripts),
|
|
106
|
-
capabilityFiles: [
|
|
107
|
-
"scripts/lib/capability-registry.js",
|
|
108
|
-
"scripts/lib/capability-packs.js",
|
|
109
|
-
"scripts/lib/capability-recommender.js",
|
|
110
|
-
"scripts/lib/prompt-compiler.js",
|
|
111
|
-
"scripts/lib/agent-enforcement.js",
|
|
112
|
-
"scripts/lib/source-catalog.js",
|
|
113
|
-
"scripts/lib/workspace-map.js",
|
|
114
|
-
"scripts/lib/product-learning-events.js",
|
|
115
|
-
].filter((file) => exists(cwd, file)),
|
|
116
|
-
statusFiles: [
|
|
117
|
-
"scripts/cco-status.js",
|
|
118
|
-
"scripts/cco-dashboard.js",
|
|
119
|
-
"scripts/lib/public-cli.js",
|
|
120
|
-
].filter((file) => exists(cwd, file)),
|
|
121
|
-
evidencePaths: [
|
|
122
|
-
".claude/cco/receipts",
|
|
123
|
-
".claude/cco/evidence",
|
|
124
|
-
".claude/cco/security",
|
|
125
|
-
".claude/cco/events",
|
|
126
|
-
WORKSPACE_MAP_REL_PATH,
|
|
127
|
-
].filter((file) => exists(cwd, file)),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function detectGaps(cwd, surfaces) {
|
|
132
|
-
const gaps = [];
|
|
133
|
-
|
|
134
|
-
if (!exists(cwd, "scripts/lib/source-catalog.js")) {
|
|
135
|
-
gaps.push("Reference source catalog is missing.");
|
|
136
|
-
}
|
|
137
|
-
if (!exists(cwd, WORKSPACE_MAP_REL_PATH)) {
|
|
138
|
-
gaps.push("Workspace Map artifact has not been generated yet.");
|
|
139
|
-
}
|
|
140
|
-
if (!exists(cwd, "docs/Product-Learning-Telemetry.md")) {
|
|
141
|
-
gaps.push("Product-learning telemetry doc is missing.");
|
|
142
|
-
}
|
|
143
|
-
if (!surfaces.skills.some((file) => file.startsWith("skills/avorelo/"))) {
|
|
144
|
-
gaps.push("Canonical Avorelo skills are missing.");
|
|
145
|
-
}
|
|
146
|
-
if (!exists(cwd, "scripts/avorelo-sync-adapters.js")) {
|
|
147
|
-
gaps.push("Thin adapter generator is missing.");
|
|
148
|
-
}
|
|
149
|
-
return gaps;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function buildCompactAgentContext(map, options = {}) {
|
|
153
|
-
const task = String(options.task || "").trim();
|
|
154
|
-
const relevantFiles = [];
|
|
155
|
-
|
|
156
|
-
if (/pricing|plan|upgrade/i.test(task)) {
|
|
157
|
-
relevantFiles.push("docs/Pricing-Capability-Mapping.md", "scripts/lib/plans.js", "scripts/lib/entitlements.js");
|
|
158
|
-
}
|
|
159
|
-
if (/workspace|navigation|map/i.test(task)) {
|
|
160
|
-
relevantFiles.push("scripts/lib/workspace-map.js", "scripts/lib/public-cli.js", "tests/workspace-map.test.js");
|
|
161
|
-
}
|
|
162
|
-
if (/source|skill|reference/i.test(task)) {
|
|
163
|
-
relevantFiles.push("scripts/lib/source-catalog.js", "scripts/avorelo-skills.js", "tests/source-catalog.test.js");
|
|
164
|
-
}
|
|
165
|
-
if (/telemetry|learning|event/i.test(task)) {
|
|
166
|
-
relevantFiles.push("scripts/lib/product-learning-events.js", "docs/Product-Learning-Telemetry.md");
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const dedupedFiles = [...new Set(relevantFiles)].filter((file) => exists(options.cwd || process.cwd(), file));
|
|
170
|
-
const likelyDocs = map.docs.slice(0, 8);
|
|
171
|
-
const likelyTests = map.tests.slice(0, 8);
|
|
172
|
-
|
|
173
|
-
return {
|
|
174
|
-
relevantFiles: dedupedFiles,
|
|
175
|
-
likelyTests,
|
|
176
|
-
likelyDocs,
|
|
177
|
-
capabilitySurfaces: map.capabilityFiles.slice(0, 8),
|
|
178
|
-
safetyBoundaries: [
|
|
179
|
-
"Avoid editing generated evidence or temp folders unless the task is explicitly about them.",
|
|
180
|
-
"Do not trust external skill sources without source-catalog review.",
|
|
181
|
-
"Keep plugin-visible guidance thin and public-safe.",
|
|
182
|
-
],
|
|
183
|
-
doNotTouch: [
|
|
184
|
-
".tmp-*",
|
|
185
|
-
".codex-worktree-runtime-*",
|
|
186
|
-
".wasp",
|
|
187
|
-
"node_modules",
|
|
188
|
-
],
|
|
189
|
-
nextAction: map.recommendedNextAction,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function generateWorkspaceMap(cwd, options = {}) {
|
|
194
|
-
ensureCcoDirs(cwd);
|
|
195
|
-
const surfaces = detectSurfaces(cwd);
|
|
196
|
-
const capabilityPackIds = readCapabilityPacks();
|
|
197
|
-
const gaps = detectGaps(cwd, surfaces);
|
|
198
|
-
const status = gaps.length === 0 ? "ready" : capabilityPackIds.length > 0 ? "partial" : "insufficient";
|
|
199
|
-
|
|
200
|
-
const workspaceMap = {
|
|
201
|
-
workspaceMapVersion: 1,
|
|
202
|
-
generatedAt: nowIso(),
|
|
203
|
-
cwd,
|
|
204
|
-
status,
|
|
205
|
-
capabilityPackIds,
|
|
206
|
-
capabilitiesMapped: surfaces.capabilityFiles.length,
|
|
207
|
-
surfacesMapped: surfaces.adapters.length + surfaces.commands.length + surfaces.statusFiles.length,
|
|
208
|
-
testsDetected: surfaces.tests.length,
|
|
209
|
-
docsDetected: surfaces.docs.length,
|
|
210
|
-
adaptersDetected: surfaces.adapters,
|
|
211
|
-
packageScripts: surfaces.packageScripts,
|
|
212
|
-
commandSurfaces: surfaces.commands,
|
|
213
|
-
capabilityFiles: surfaces.capabilityFiles,
|
|
214
|
-
statusFiles: surfaces.statusFiles,
|
|
215
|
-
docs: surfaces.docs.slice(0, 20),
|
|
216
|
-
tests: surfaces.tests.slice(0, 20),
|
|
217
|
-
skills: surfaces.skills.slice(0, 20),
|
|
218
|
-
evidencePaths: surfaces.evidencePaths,
|
|
219
|
-
gapsDetected: gaps.length,
|
|
220
|
-
gaps,
|
|
221
|
-
topGaps: gaps.slice(0, 5),
|
|
222
|
-
recommendedNextAction: gaps.length
|
|
223
|
-
? gaps[0]
|
|
224
|
-
: "Use the Workspace Map artifact as compact agent context before broad repo scans.",
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
workspaceMap.compactAgentContext = buildCompactAgentContext(workspaceMap, {
|
|
228
|
-
cwd,
|
|
229
|
-
task: options.task || "",
|
|
230
|
-
});
|
|
231
|
-
workspaceMap.artifactPath = WORKSPACE_MAP_REL_PATH;
|
|
232
|
-
return workspaceMap;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function writeWorkspaceMap(cwd, options = {}) {
|
|
236
|
-
const map = generateWorkspaceMap(cwd, options);
|
|
237
|
-
safeWriteJson(cwd, WORKSPACE_MAP_REL_PATH, map);
|
|
238
|
-
if (map.gaps.includes("Workspace Map artifact has not been generated yet.")) {
|
|
239
|
-
map.gaps = map.gaps.filter((gap) => gap !== "Workspace Map artifact has not been generated yet.");
|
|
240
|
-
map.gapsDetected = map.gaps.length;
|
|
241
|
-
map.topGaps = map.gaps.slice(0, 5);
|
|
242
|
-
if (map.status === "partial" && map.gaps.length === 0) {
|
|
243
|
-
map.status = "ready";
|
|
244
|
-
map.recommendedNextAction = "Use the Workspace Map artifact as compact agent context before broad repo scans.";
|
|
245
|
-
}
|
|
246
|
-
safeWriteJson(cwd, WORKSPACE_MAP_REL_PATH, map);
|
|
247
|
-
}
|
|
248
|
-
return map;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function readWorkspaceMap(cwd) {
|
|
252
|
-
return safeReadJson(cwd, WORKSPACE_MAP_REL_PATH, null);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function formatWorkspaceMapText(map) {
|
|
256
|
-
if (!map) {
|
|
257
|
-
return "Workspace Map unavailable.";
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return [
|
|
261
|
-
"Avorelo Workspace Map",
|
|
262
|
-
`Status: ${map.status}`,
|
|
263
|
-
`Capabilities mapped: ${map.capabilitiesMapped}`,
|
|
264
|
-
`Surfaces mapped: ${map.surfacesMapped}`,
|
|
265
|
-
`Docs detected: ${map.docsDetected}`,
|
|
266
|
-
`Tests detected: ${map.testsDetected}`,
|
|
267
|
-
`Adapters: ${map.adaptersDetected.join(", ") || "none"}`,
|
|
268
|
-
`Top gaps: ${map.topGaps.join(" | ") || "none"}`,
|
|
269
|
-
`Next: ${map.recommendedNextAction}`,
|
|
270
|
-
`Artifact: ${map.artifactPath}`,
|
|
271
|
-
].join("\n");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
module.exports = {
|
|
275
|
-
WORKSPACE_MAP_REL_PATH,
|
|
276
|
-
generateWorkspaceMap,
|
|
277
|
-
writeWorkspaceMap,
|
|
278
|
-
readWorkspaceMap,
|
|
279
|
-
formatWorkspaceMapText,
|
|
280
|
-
buildCompactAgentContext,
|
|
281
|
-
};
|