avorelo 0.1.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 +21 -0
- package/README.md +56 -0
- package/bin/avorelo +9 -0
- package/package.json +135 -0
- package/scripts/README.md +40 -0
- package/scripts/cco-dashboard.js +252 -0
- package/scripts/cco-status.js +430 -0
- package/scripts/lib/activation/account-state.js +37 -0
- package/scripts/lib/activation/activation-runner.js +546 -0
- package/scripts/lib/activation/activation-self-healing.js +480 -0
- package/scripts/lib/activation/activation-state.js +83 -0
- package/scripts/lib/activation/activation-summary.js +191 -0
- package/scripts/lib/activation/adapters/claude-code.js +77 -0
- package/scripts/lib/activation/adapters/codex-cli.js +52 -0
- package/scripts/lib/activation/adapters/cursor.js +37 -0
- package/scripts/lib/activation/adapters/github-agent.js +39 -0
- package/scripts/lib/activation/adapters/terminal.js +42 -0
- package/scripts/lib/activation/adapters/vscode.js +39 -0
- package/scripts/lib/activation/adapters/windsurf.js +37 -0
- package/scripts/lib/activation/ai-surface-detector.js +151 -0
- package/scripts/lib/activation/connect-account.js +145 -0
- package/scripts/lib/activation/detect-environment.js +75 -0
- package/scripts/lib/activation/detect-hosts.js +62 -0
- package/scripts/lib/activation/format-activation-output.js +109 -0
- package/scripts/lib/activation/next-action.js +43 -0
- package/scripts/lib/activation/repair-engine.js +219 -0
- package/scripts/lib/activation-distribution-readiness.js +507 -0
- package/scripts/lib/adapter-conformance.js +176 -0
- package/scripts/lib/adapter-readiness.js +417 -0
- package/scripts/lib/adapter-safety-boundaries.js +335 -0
- package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
- package/scripts/lib/agent-access-governance.js +455 -0
- package/scripts/lib/agent-enforcement.js +765 -0
- package/scripts/lib/agent-policy-profile.js +210 -0
- package/scripts/lib/agent-security/action-evaluator.js +507 -0
- package/scripts/lib/agent-security/adapter-registry.js +98 -0
- package/scripts/lib/agent-security/auto-policy.js +139 -0
- package/scripts/lib/agent-security/bounded-scan.js +93 -0
- package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
- package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
- package/scripts/lib/agent-security/file-write-adapter.js +183 -0
- package/scripts/lib/agent-security/file-write-rules.js +178 -0
- package/scripts/lib/agent-security/index.js +3342 -0
- package/scripts/lib/agent-security/instruction-risk.js +181 -0
- package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
- package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
- package/scripts/lib/agent-security/package-action-adapter.js +175 -0
- package/scripts/lib/agent-security/package-action-rules.js +233 -0
- package/scripts/lib/agent-security/performance.js +148 -0
- package/scripts/lib/agent-security/permission-minimizer.js +403 -0
- package/scripts/lib/agent-security/scan-cache.js +74 -0
- package/scripts/lib/agent-security/source-trust.js +146 -0
- package/scripts/lib/ai-install-prompt.js +288 -0
- package/scripts/lib/ai-workspace-hygiene.js +1499 -0
- package/scripts/lib/alpha-activation.js +520 -0
- package/scripts/lib/alpha-feedback.js +263 -0
- package/scripts/lib/alpha-readiness-gate.js +332 -0
- package/scripts/lib/anti-gaming.js +169 -0
- package/scripts/lib/artifact-health.js +431 -0
- package/scripts/lib/attribution.js +180 -0
- package/scripts/lib/audit.js +289 -0
- package/scripts/lib/avorelo-skill-registry.js +810 -0
- package/scripts/lib/batch-jobs.js +71 -0
- package/scripts/lib/brain-pack.js +578 -0
- package/scripts/lib/brand-boundary.js +424 -0
- package/scripts/lib/brand.js +74 -0
- package/scripts/lib/browser-capability.js +1048 -0
- package/scripts/lib/browser-proof-preflight.js +321 -0
- package/scripts/lib/cache-readiness.js +187 -0
- package/scripts/lib/canonical-reentry.js +162 -0
- package/scripts/lib/capability-packs.js +314 -0
- package/scripts/lib/capability-recommender.js +512 -0
- package/scripts/lib/capability-registry.js +1059 -0
- package/scripts/lib/carry-forward-surfacing.js +194 -0
- package/scripts/lib/ccusage-adapter.js +188 -0
- package/scripts/lib/company-loop.js +1149 -0
- package/scripts/lib/config.js +637 -0
- package/scripts/lib/context-acquisition-plan.js +287 -0
- package/scripts/lib/context-budget-guard.js +170 -0
- package/scripts/lib/context-budget-scanner.js +257 -0
- package/scripts/lib/context-optimizer.js +715 -0
- package/scripts/lib/context-reduction-plan.js +178 -0
- package/scripts/lib/context-safety.js +88 -0
- package/scripts/lib/context-savings-engine.js +158 -0
- package/scripts/lib/cost-evidence.js +254 -0
- package/scripts/lib/cross-host-install-plan.js +308 -0
- package/scripts/lib/cross-host-install-readiness.js +237 -0
- package/scripts/lib/cross-host-value-flow.js +268 -0
- package/scripts/lib/dashboard.js +900 -0
- package/scripts/lib/design-partner-feedback.js +346 -0
- package/scripts/lib/entitlements.js +100 -0
- package/scripts/lib/execution-packet.js +559 -0
- package/scripts/lib/experimentation-events.js +547 -0
- package/scripts/lib/external-capability-compliance.js +107 -0
- package/scripts/lib/external-user-simulation.js +166 -0
- package/scripts/lib/failure-recovery-readiness.js +81 -0
- package/scripts/lib/failure-recovery.js +419 -0
- package/scripts/lib/feedback-intelligence.js +537 -0
- package/scripts/lib/feedback-signals.js +205 -0
- package/scripts/lib/file-integrity.js +68 -0
- package/scripts/lib/fsx.js +127 -0
- package/scripts/lib/full-readiness-gate.js +451 -0
- package/scripts/lib/guidance-builder.js +174 -0
- package/scripts/lib/hook-apply.js +1019 -0
- package/scripts/lib/hook-baseline.js +310 -0
- package/scripts/lib/hook-config-preview.js +275 -0
- package/scripts/lib/hook-contracts.js +290 -0
- package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
- package/scripts/lib/host-capability-matrix.js +351 -0
- package/scripts/lib/host-support-context.js +254 -0
- package/scripts/lib/http-hook-action.js +538 -0
- package/scripts/lib/install-ai-readiness.js +84 -0
- package/scripts/lib/install-intake-risk.js +1037 -0
- package/scripts/lib/install-journey-intelligence.js +329 -0
- package/scripts/lib/intervention-guidance.js +57 -0
- package/scripts/lib/known-limitations.js +115 -0
- package/scripts/lib/l8-path-truth.js +146 -0
- package/scripts/lib/launch-hardening-gate.js +436 -0
- package/scripts/lib/launch-readiness.js +628 -0
- package/scripts/lib/learning-memory.js +686 -0
- package/scripts/lib/lifecycle-hooks.js +802 -0
- package/scripts/lib/local-package-smoke.js +423 -0
- package/scripts/lib/local-pricing.js +299 -0
- package/scripts/lib/mcp-enforcement.js +311 -0
- package/scripts/lib/mcp-least-privilege-policy.js +303 -0
- package/scripts/lib/mcp-tool-inventory.js +388 -0
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +335 -0
- package/scripts/lib/metrics.js +699 -0
- package/scripts/lib/micro-proof.js +133 -0
- package/scripts/lib/next-run-context.js +436 -0
- package/scripts/lib/operating-value.js +1648 -0
- package/scripts/lib/optimization-v3.js +122 -0
- package/scripts/lib/orchestration/adapters/_shared.js +49 -0
- package/scripts/lib/orchestration/adapters/aider.js +18 -0
- package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
- package/scripts/lib/orchestration/adapters/codex.js +35 -0
- package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
- package/scripts/lib/orchestration/adapters/git.js +25 -0
- package/scripts/lib/orchestration/adapters/index.js +31 -0
- package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
- package/scripts/lib/orchestration/adapters/ollama.js +18 -0
- package/scripts/lib/orchestration/adapters/opencode.js +18 -0
- package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
- package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
- package/scripts/lib/orchestration/cli.js +438 -0
- package/scripts/lib/orchestration/execution-manager.js +279 -0
- package/scripts/lib/orchestration/handoff.js +314 -0
- package/scripts/lib/orchestration/index.js +456 -0
- package/scripts/lib/orchestration/inventory.js +47 -0
- package/scripts/lib/orchestration/model-discovery.js +498 -0
- package/scripts/lib/orchestration/model-profiler.js +170 -0
- package/scripts/lib/orchestration/model-profiles.js +252 -0
- package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
- package/scripts/lib/orchestration/proof-writer.js +349 -0
- package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
- package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
- package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
- package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
- package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
- package/scripts/lib/orchestration/risk-classifier.js +130 -0
- package/scripts/lib/orchestration/routing-policy.js +486 -0
- package/scripts/lib/orchestration/settings.js +112 -0
- package/scripts/lib/orchestration/state.js +165 -0
- package/scripts/lib/orchestration/verification-manager.js +138 -0
- package/scripts/lib/output-profiles.js +146 -0
- package/scripts/lib/package-content-audit.js +368 -0
- package/scripts/lib/package-runtime.js +278 -0
- package/scripts/lib/plan-surface.js +53 -0
- package/scripts/lib/plans.js +2318 -0
- package/scripts/lib/policy-provider.js +27 -0
- package/scripts/lib/prelaunch-activation-readiness.js +409 -0
- package/scripts/lib/prelaunch-evidence-store.js +816 -0
- package/scripts/lib/prelaunch-intelligence.js +869 -0
- package/scripts/lib/pricing-experiment.js +118 -0
- package/scripts/lib/pro-moment-events.js +77 -0
- package/scripts/lib/pro-moment-state.js +227 -0
- package/scripts/lib/pro-moments.js +1216 -0
- package/scripts/lib/product-learning-events.js +629 -0
- package/scripts/lib/project-profile.js +555 -0
- package/scripts/lib/prompt-compiler.js +280 -0
- package/scripts/lib/prompt-lint.js +32 -0
- package/scripts/lib/prompt-suggestions.js +52 -0
- package/scripts/lib/proof-canonical.js +398 -0
- package/scripts/lib/proof-drilldown.js +383 -0
- package/scripts/lib/proof-events.js +342 -0
- package/scripts/lib/proof-history.js +243 -0
- package/scripts/lib/proof-metrics.js +296 -0
- package/scripts/lib/proof-outcome-evidence.js +134 -0
- package/scripts/lib/proof-receipt.js +335 -0
- package/scripts/lib/proof-record.js +461 -0
- package/scripts/lib/public-activation-distribution-gate.js +258 -0
- package/scripts/lib/public-cli.js +3891 -0
- package/scripts/lib/public-distribution-truth.js +211 -0
- package/scripts/lib/public-install-claim-checker.js +294 -0
- package/scripts/lib/publish-provenance-readiness.js +283 -0
- package/scripts/lib/readiness-delta.js +218 -0
- package/scripts/lib/readiness-evidence-closure.js +196 -0
- package/scripts/lib/reentry-memory-capture.js +241 -0
- package/scripts/lib/reentry-memory-retrieval.js +302 -0
- package/scripts/lib/reentry-memory-status.js +146 -0
- package/scripts/lib/reentry-memory-store.js +178 -0
- package/scripts/lib/reentry-state.js +66 -0
- package/scripts/lib/release-candidate-bundle.js +166 -0
- package/scripts/lib/remediation.js +81 -0
- package/scripts/lib/repo-map.js +391 -0
- package/scripts/lib/run-improvements-lifecycle.js +330 -0
- package/scripts/lib/run-improvements.js +789 -0
- package/scripts/lib/runtime-decision-policy.js +387 -0
- package/scripts/lib/safe-path-engine.js +705 -0
- package/scripts/lib/safe-run-controller.js +887 -0
- package/scripts/lib/score.js +262 -0
- package/scripts/lib/seamless-enforcement.js +329 -0
- package/scripts/lib/seamless-outcome.js +689 -0
- package/scripts/lib/seamless-reality-gate.js +5043 -0
- package/scripts/lib/security-risk-classifier.js +511 -0
- package/scripts/lib/security-scan.js +384 -0
- package/scripts/lib/session-context-optimizer.js +1211 -0
- package/scripts/lib/session-timing.js +315 -0
- package/scripts/lib/skill-hygiene.js +805 -0
- package/scripts/lib/skill-packs.js +161 -0
- package/scripts/lib/skills-operating-layer.js +580 -0
- package/scripts/lib/smart-work-routing.js +768 -0
- package/scripts/lib/source-catalog.js +700 -0
- package/scripts/lib/status-value-summary.js +32 -0
- package/scripts/lib/support-bundle.js +578 -0
- package/scripts/lib/task-continuation.js +440 -0
- package/scripts/lib/test-helpers.js +15 -0
- package/scripts/lib/tier.js +38 -0
- package/scripts/lib/token-context-quality-gate.js +370 -0
- package/scripts/lib/token-cost-capture.js +187 -0
- package/scripts/lib/token-cost-intelligence.js +358 -0
- package/scripts/lib/token-efficiency-evidence.js +213 -0
- package/scripts/lib/token-evidence.js +699 -0
- package/scripts/lib/tokenish.js +17 -0
- package/scripts/lib/tool-output-sandbox.js +304 -0
- package/scripts/lib/trust-audit.js +136 -0
- package/scripts/lib/unified-events.js +396 -0
- package/scripts/lib/upgrade-interruption-recovery.js +407 -0
- package/scripts/lib/usage-ledger.js +201 -0
- package/scripts/lib/value-ledger.js +130 -0
- package/scripts/lib/value-proof-calibration.js +531 -0
- package/scripts/lib/visual-qa.js +231 -0
- package/scripts/lib/voice-alpha.js +29 -0
- package/scripts/lib/work-aware-orchestration.js +976 -0
- package/scripts/lib/work-control-receipts.js +577 -0
- package/scripts/lib/work-ledger.js +1123 -0
- package/scripts/lib/work-panel-preview.js +352 -0
- package/scripts/lib/workflow-discipline.js +280 -0
- package/scripts/lib/workflow-signals.js +419 -0
- package/scripts/lib/workspace-map.js +281 -0
- package/scripts/lib/workspace-registry.js +1367 -0
- package/scripts/lib/workspace-resolver.js +480 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// ── Design Partner Feedback ───────────────────────────────────────────────────
|
|
4
|
+
// Contract: avorelo.designPartnerFeedback.v1
|
|
5
|
+
//
|
|
6
|
+
// Captures and summarizes structured feedback from named design partner sessions.
|
|
7
|
+
// Strictly source=design_partner only — dogfood is NOT counted here.
|
|
8
|
+
// No raw PII, no secrets, no exact cost claims, no public launch claims.
|
|
9
|
+
// Honest insufficient_data when no qualifying sessions exist.
|
|
10
|
+
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const crypto = require("crypto");
|
|
14
|
+
const { nowIso } = require("./fsx");
|
|
15
|
+
const { appendProductLearningEvent } = require("./product-learning-events");
|
|
16
|
+
|
|
17
|
+
const CONTRACT = "avorelo.designPartnerFeedback.v1";
|
|
18
|
+
const SCHEMA_VERSION = 1;
|
|
19
|
+
const DP_DIR_REL = ".claude/cco/feedback/design-partner";
|
|
20
|
+
const SESSIONS_DIR_REL = DP_DIR_REL + "/sessions";
|
|
21
|
+
const SUMMARY_ARTIFACT_REL = DP_DIR_REL + "/latest-summary.json";
|
|
22
|
+
|
|
23
|
+
// Valid values (keep consistent with alpha-feedback)
|
|
24
|
+
const VALID_FRICTION_TYPES = new Set([
|
|
25
|
+
"install_confusion", "ai_prompt_unclear", "hook_approval_unclear",
|
|
26
|
+
"mcp_governance_warn", "token_context_unknown", "proof_missing",
|
|
27
|
+
"support_bundle_missing", "command_noise", "recovery_needed",
|
|
28
|
+
"first_value_unclear", "verification_missing", "missing_evidence",
|
|
29
|
+
"exact_savings_unavailable", "browser_proof_missing",
|
|
30
|
+
"plugin_distribution_unclear", "other", "unknown",
|
|
31
|
+
]);
|
|
32
|
+
const VALID_SEVERITIES = new Set(["low", "medium", "high", "blocker"]);
|
|
33
|
+
const VALID_ACTIVATION_STAGES = new Set([
|
|
34
|
+
"unknown", "first_run", "activation", "first_value", "repeat_use", "handoff", "support",
|
|
35
|
+
]);
|
|
36
|
+
const VALID_CONSENT_VALUES = new Set(["provided", "not_recorded"]);
|
|
37
|
+
|
|
38
|
+
const MAX_TEXT_LENGTH = 500;
|
|
39
|
+
const MAX_FIELD_LENGTH = 64;
|
|
40
|
+
|
|
41
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
function makeSessionId() {
|
|
44
|
+
return `dpf-${Date.now()}-${crypto.randomBytes(3).toString("hex")}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function sanitizeText(text, maxLen) {
|
|
48
|
+
if (!text || typeof text !== "string") return "";
|
|
49
|
+
return text.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, "").slice(0, maxLen).trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function sanitizeField(text) {
|
|
53
|
+
return sanitizeText(text, MAX_FIELD_LENGTH);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function redactText(text) {
|
|
57
|
+
if (!text) return "";
|
|
58
|
+
return text
|
|
59
|
+
.replace(/sk-[A-Za-z0-9]{16,}/g, "[redacted-key]")
|
|
60
|
+
.replace(/ghp_[A-Za-z0-9]{20,}/g, "[redacted-token]")
|
|
61
|
+
.replace(/AKIA[0-9A-Z]{16}/g, "[redacted-aws-key]")
|
|
62
|
+
.replace(/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g, "[redacted-email]");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function safeReadJson(absPath) {
|
|
66
|
+
try {
|
|
67
|
+
if (!fs.existsSync(absPath)) return null;
|
|
68
|
+
return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^/, ""));
|
|
69
|
+
} catch { return null; }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function ensureDirs(cwd) {
|
|
73
|
+
[DP_DIR_REL, SESSIONS_DIR_REL].forEach(function(rel) {
|
|
74
|
+
var dir = path.join(cwd, rel);
|
|
75
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Session builder ───────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
function buildDesignPartnerFeedbackSession(cwd, opts) {
|
|
82
|
+
opts = opts || {};
|
|
83
|
+
var errors = [];
|
|
84
|
+
|
|
85
|
+
var partnerAlias = sanitizeField(opts.partnerAlias || "");
|
|
86
|
+
var activationStage = VALID_ACTIVATION_STAGES.has(opts.activationStage) ? opts.activationStage : "unknown";
|
|
87
|
+
var frictionType = VALID_FRICTION_TYPES.has(opts.frictionType) ? opts.frictionType : "unknown";
|
|
88
|
+
var severity = VALID_SEVERITIES.has(opts.severity) ? opts.severity : "medium";
|
|
89
|
+
var consent = VALID_CONSENT_VALUES.has(opts.consent) ? opts.consent : "not_recorded";
|
|
90
|
+
var summary = sanitizeText(redactText(opts.summary || ""), MAX_TEXT_LENGTH);
|
|
91
|
+
var desiredBehavior = sanitizeText(redactText(opts.desiredBehavior || ""), MAX_TEXT_LENGTH);
|
|
92
|
+
var sessionNotes = sanitizeText(redactText(opts.sessionNotes || ""), MAX_TEXT_LENGTH);
|
|
93
|
+
var theme = sanitizeField(opts.theme || "");
|
|
94
|
+
var issueCategory = sanitizeField(opts.issueCategory || "");
|
|
95
|
+
var consentDetails = opts.consentDetails ? sanitizeText(opts.consentDetails, MAX_TEXT_LENGTH) : null;
|
|
96
|
+
|
|
97
|
+
if (!partnerAlias) errors.push("partnerAlias is required");
|
|
98
|
+
if (!summary) errors.push("summary is required");
|
|
99
|
+
|
|
100
|
+
if (errors.length > 0) {
|
|
101
|
+
return { ok: false, errors: errors, contract: CONTRACT };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
var session = {
|
|
105
|
+
contract: CONTRACT,
|
|
106
|
+
schemaVersion: SCHEMA_VERSION,
|
|
107
|
+
sessionId: makeSessionId(),
|
|
108
|
+
createdAt: nowIso(),
|
|
109
|
+
source: "design_partner",
|
|
110
|
+
partnerAlias: partnerAlias,
|
|
111
|
+
activationStage: activationStage,
|
|
112
|
+
frictionType: frictionType,
|
|
113
|
+
severity: severity,
|
|
114
|
+
consent: consent,
|
|
115
|
+
consentDetails: consentDetails,
|
|
116
|
+
summary: summary,
|
|
117
|
+
desiredBehavior: desiredBehavior,
|
|
118
|
+
sessionNotes: sessionNotes,
|
|
119
|
+
theme: theme || null,
|
|
120
|
+
issueCategory: issueCategory || null,
|
|
121
|
+
simulated: opts.simulated === true,
|
|
122
|
+
redacted: true,
|
|
123
|
+
noPublicLaunchClaim: true,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return { ok: true, session: session, contract: CONTRACT };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function writeDesignPartnerFeedbackSession(cwd, session) {
|
|
130
|
+
ensureDirs(cwd);
|
|
131
|
+
var file = path.join(cwd, SESSIONS_DIR_REL, session.sessionId + ".json");
|
|
132
|
+
fs.writeFileSync(file, JSON.stringify(session, null, 2));
|
|
133
|
+
try {
|
|
134
|
+
appendProductLearningEvent(cwd, {
|
|
135
|
+
eventName: "design_partner_session_captured",
|
|
136
|
+
category: "feedback",
|
|
137
|
+
partnerAlias: session.partnerAlias,
|
|
138
|
+
frictionType: session.frictionType,
|
|
139
|
+
severity: session.severity,
|
|
140
|
+
activationStage: session.activationStage,
|
|
141
|
+
consent: session.consent,
|
|
142
|
+
});
|
|
143
|
+
} catch (e) {}
|
|
144
|
+
return { ok: true, path: file, sessionId: session.sessionId };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ── Import ────────────────────────────────────────────────────────────────────
|
|
148
|
+
// Imports an array of sessions from a JSON file (array or single object).
|
|
149
|
+
// Validates each entry, skips invalid ones, writes accepted ones to disk.
|
|
150
|
+
|
|
151
|
+
function importDesignPartnerFeedback(cwd, filePath, opts) {
|
|
152
|
+
opts = opts || {};
|
|
153
|
+
var absPath = path.isAbsolute(filePath) ? filePath : path.join(cwd, filePath);
|
|
154
|
+
var raw;
|
|
155
|
+
try {
|
|
156
|
+
raw = safeReadJson(absPath);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return { ok: false, error: "Could not read file: " + filePath, acceptedCount: 0, rejectedCount: 0, redacted: true };
|
|
159
|
+
}
|
|
160
|
+
if (!raw) {
|
|
161
|
+
return { ok: false, error: "File not found or invalid JSON: " + filePath, acceptedCount: 0, rejectedCount: 0, redacted: true };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
var entries = Array.isArray(raw) ? raw : [raw];
|
|
165
|
+
var accepted = [], rejected = [];
|
|
166
|
+
|
|
167
|
+
entries.forEach(function(entry) {
|
|
168
|
+
if (!entry || typeof entry !== "object") {
|
|
169
|
+
rejected.push({ reason: "not_an_object" });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Skip non-design-partner sources silently (source must be design_partner)
|
|
173
|
+
if (entry.source && entry.source !== "design_partner") {
|
|
174
|
+
rejected.push({ reason: "wrong_source", source: entry.source });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
var result = buildDesignPartnerFeedbackSession(cwd, Object.assign({ source: "design_partner" }, entry));
|
|
178
|
+
if (!result.ok) {
|
|
179
|
+
rejected.push({ reason: "validation_failed", errors: result.errors });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
var writeResult = writeDesignPartnerFeedbackSession(cwd, result.session);
|
|
183
|
+
accepted.push({ sessionId: result.session.sessionId, path: writeResult.path });
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
ok: true,
|
|
188
|
+
acceptedCount: accepted.length,
|
|
189
|
+
rejectedCount: rejected.length,
|
|
190
|
+
accepted: accepted,
|
|
191
|
+
rejected: rejected,
|
|
192
|
+
redacted: true,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Summary ───────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
function readAllDesignPartnerSessions(cwd) {
|
|
199
|
+
var dir = path.join(cwd, SESSIONS_DIR_REL);
|
|
200
|
+
if (!fs.existsSync(dir)) return [];
|
|
201
|
+
return fs.readdirSync(dir)
|
|
202
|
+
.filter(function(f) { return f.endsWith(".json"); })
|
|
203
|
+
.map(function(f) { return safeReadJson(path.join(dir, f)); })
|
|
204
|
+
.filter(Boolean)
|
|
205
|
+
.filter(function(s) { return s.source === "design_partner"; });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function buildDesignPartnerFeedbackSummary(cwd, opts) {
|
|
209
|
+
opts = opts || {};
|
|
210
|
+
var sessions = readAllDesignPartnerSessions(cwd);
|
|
211
|
+
var nonSimulated = sessions.filter(function(s) { return !s.simulated; });
|
|
212
|
+
|
|
213
|
+
if (nonSimulated.length === 0) {
|
|
214
|
+
return {
|
|
215
|
+
contract: CONTRACT,
|
|
216
|
+
schemaVersion: SCHEMA_VERSION,
|
|
217
|
+
createdAt: nowIso(),
|
|
218
|
+
status: "insufficient_data",
|
|
219
|
+
readinessStatus: "not_ready",
|
|
220
|
+
qualifiedSessionCount: 0,
|
|
221
|
+
totalSessionCount: sessions.length,
|
|
222
|
+
simulatedCount: sessions.length - nonSimulated.length,
|
|
223
|
+
frictionBreakdown: {},
|
|
224
|
+
topFrictions: [],
|
|
225
|
+
topThemes: [],
|
|
226
|
+
blockerCount: 0,
|
|
227
|
+
severityBreakdown: {},
|
|
228
|
+
activationStageBreakdown: {},
|
|
229
|
+
consentBreakdown: {},
|
|
230
|
+
partnerAliasCount: 0,
|
|
231
|
+
noPublicLaunchClaim: true,
|
|
232
|
+
noExternalFeedbackClaim: true,
|
|
233
|
+
redacted: true,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Count friction types
|
|
238
|
+
var frictionCounts = {};
|
|
239
|
+
var themeCounts = {};
|
|
240
|
+
var severityCounts = {};
|
|
241
|
+
var stageCounts = {};
|
|
242
|
+
var consentCounts = {};
|
|
243
|
+
var partnerAliases = new Set();
|
|
244
|
+
|
|
245
|
+
nonSimulated.forEach(function(s) {
|
|
246
|
+
var ft = s.frictionType || "unknown";
|
|
247
|
+
frictionCounts[ft] = (frictionCounts[ft] || 0) + 1;
|
|
248
|
+
if (s.theme) themeCounts[s.theme] = (themeCounts[s.theme] || 0) + 1;
|
|
249
|
+
var sev = s.severity || "medium";
|
|
250
|
+
severityCounts[sev] = (severityCounts[sev] || 0) + 1;
|
|
251
|
+
var stage = s.activationStage || "unknown";
|
|
252
|
+
stageCounts[stage] = (stageCounts[stage] || 0) + 1;
|
|
253
|
+
var consent = s.consent || "not_recorded";
|
|
254
|
+
consentCounts[consent] = (consentCounts[consent] || 0) + 1;
|
|
255
|
+
if (s.partnerAlias) partnerAliases.add(s.partnerAlias);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
var topFrictions = Object.entries(frictionCounts)
|
|
259
|
+
.sort(function(a, b) { return b[1] - a[1]; })
|
|
260
|
+
.slice(0, 5)
|
|
261
|
+
.map(function(e) { return { frictionType: e[0], count: e[1] }; });
|
|
262
|
+
|
|
263
|
+
var topThemes = Object.entries(themeCounts)
|
|
264
|
+
.sort(function(a, b) { return b[1] - a[1]; })
|
|
265
|
+
.slice(0, 5)
|
|
266
|
+
.map(function(e) { return { theme: e[0], count: e[1] }; });
|
|
267
|
+
|
|
268
|
+
var blockerCount = severityCounts["blocker"] || 0;
|
|
269
|
+
var readinessStatus = nonSimulated.length >= 3 ? "sufficient" : "insufficient";
|
|
270
|
+
var status = nonSimulated.length >= 3 ? "ready" : "insufficient_data";
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
contract: CONTRACT,
|
|
274
|
+
schemaVersion: SCHEMA_VERSION,
|
|
275
|
+
createdAt: nowIso(),
|
|
276
|
+
status: status,
|
|
277
|
+
readinessStatus: readinessStatus,
|
|
278
|
+
qualifiedSessionCount: nonSimulated.length,
|
|
279
|
+
totalSessionCount: sessions.length,
|
|
280
|
+
simulatedCount: sessions.length - nonSimulated.length,
|
|
281
|
+
frictionBreakdown: frictionCounts,
|
|
282
|
+
topFrictions: topFrictions,
|
|
283
|
+
topThemes: topThemes,
|
|
284
|
+
blockerCount: blockerCount,
|
|
285
|
+
severityBreakdown: severityCounts,
|
|
286
|
+
activationStageBreakdown: stageCounts,
|
|
287
|
+
consentBreakdown: consentCounts,
|
|
288
|
+
partnerAliasCount: partnerAliases.size,
|
|
289
|
+
noPublicLaunchClaim: true,
|
|
290
|
+
noExternalFeedbackClaim: true,
|
|
291
|
+
redacted: true,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function writeDesignPartnerFeedbackSummary(cwd, summary) {
|
|
296
|
+
ensureDirs(cwd);
|
|
297
|
+
fs.writeFileSync(path.join(cwd, SUMMARY_ARTIFACT_REL), JSON.stringify(summary, null, 2));
|
|
298
|
+
try {
|
|
299
|
+
appendProductLearningEvent(cwd, {
|
|
300
|
+
eventName: "design_partner_feedback_summary_built",
|
|
301
|
+
category: "feedback",
|
|
302
|
+
status: summary.status,
|
|
303
|
+
qualifiedSessionCount: summary.qualifiedSessionCount,
|
|
304
|
+
});
|
|
305
|
+
} catch (e) {}
|
|
306
|
+
return summary;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── Text formatter ────────────────────────────────────────────────────────────
|
|
310
|
+
|
|
311
|
+
function formatDesignPartnerFeedbackText(summary, opts) {
|
|
312
|
+
opts = opts || {};
|
|
313
|
+
var lines = [];
|
|
314
|
+
lines.push("Design partner feedback: " + summary.status);
|
|
315
|
+
lines.push("Sessions (qualified / total): " + summary.qualifiedSessionCount + " / " + summary.totalSessionCount);
|
|
316
|
+
if (summary.simulatedCount > 0) lines.push(" Simulated (not counted): " + summary.simulatedCount);
|
|
317
|
+
lines.push("Partners: " + summary.partnerAliasCount);
|
|
318
|
+
lines.push("Blockers: " + summary.blockerCount);
|
|
319
|
+
if (summary.topFrictions && summary.topFrictions.length > 0) {
|
|
320
|
+
lines.push("Top frictions:");
|
|
321
|
+
summary.topFrictions.forEach(function(f) {
|
|
322
|
+
lines.push(" " + f.frictionType + " (" + f.count + ")");
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (summary.topThemes && summary.topThemes.length > 0) {
|
|
326
|
+
lines.push("Top themes: " + summary.topThemes.map(function(t) { return t.theme + " (" + t.count + ")"; }).join(", "));
|
|
327
|
+
}
|
|
328
|
+
lines.push("No public launch claim.");
|
|
329
|
+
return lines.join("\n");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
module.exports = {
|
|
335
|
+
CONTRACT,
|
|
336
|
+
SCHEMA_VERSION,
|
|
337
|
+
SUMMARY_ARTIFACT_REL,
|
|
338
|
+
SESSIONS_DIR_REL,
|
|
339
|
+
buildDesignPartnerFeedbackSession,
|
|
340
|
+
writeDesignPartnerFeedbackSession,
|
|
341
|
+
importDesignPartnerFeedback,
|
|
342
|
+
buildDesignPartnerFeedbackSummary,
|
|
343
|
+
writeDesignPartnerFeedbackSummary,
|
|
344
|
+
formatDesignPartnerFeedbackText,
|
|
345
|
+
readAllDesignPartnerSessions,
|
|
346
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { safeReadJson } = require("./fsx");
|
|
5
|
+
const {
|
|
6
|
+
getPlan,
|
|
7
|
+
getCapability,
|
|
8
|
+
isCapabilityEnabled,
|
|
9
|
+
comparePlans,
|
|
10
|
+
} = require("./plans");
|
|
11
|
+
|
|
12
|
+
const PLAN_ENV = "AVORELO_PLAN";
|
|
13
|
+
const SUPPORTED_PUBLIC_PLANS = new Set(["free", "pro"]);
|
|
14
|
+
|
|
15
|
+
function normalizePlanName(value) {
|
|
16
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
17
|
+
if (normalized === "teams") return "pro";
|
|
18
|
+
if (normalized === "enterprise") return "pro";
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolvePlanFromAccountState(cwd) {
|
|
23
|
+
const account = safeReadJson(cwd, ".claude/cco/state/account.json", null);
|
|
24
|
+
const fromAccount = normalizePlanName(account?.plan);
|
|
25
|
+
if (SUPPORTED_PUBLIC_PLANS.has(fromAccount)) return fromAccount;
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolvePlanFromProjectConfig(cwd) {
|
|
30
|
+
const config = safeReadJson(cwd, ".claude/cco/config.json", null);
|
|
31
|
+
const fromConfig = normalizePlanName(config?.tier);
|
|
32
|
+
if (SUPPORTED_PUBLIC_PLANS.has(fromConfig)) return fromConfig;
|
|
33
|
+
if (fromConfig === "teams") return "pro";
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getCurrentPlan(options = {}) {
|
|
38
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
39
|
+
const explicitPlan = normalizePlanName(options.plan);
|
|
40
|
+
if (SUPPORTED_PUBLIC_PLANS.has(explicitPlan)) {
|
|
41
|
+
return explicitPlan;
|
|
42
|
+
}
|
|
43
|
+
const envPlan = normalizePlanName(process.env[PLAN_ENV]);
|
|
44
|
+
if (envPlan) {
|
|
45
|
+
return SUPPORTED_PUBLIC_PLANS.has(envPlan) ? envPlan : "free";
|
|
46
|
+
}
|
|
47
|
+
return resolvePlanFromAccountState(cwd) || resolvePlanFromProjectConfig(cwd) || "free";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function capabilityEnabled(capabilityId, options = {}) {
|
|
51
|
+
return isCapabilityEnabled(getCurrentPlan(options), capabilityId);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function requireCapability(capabilityId, options = {}) {
|
|
55
|
+
if (capabilityEnabled(capabilityId, options)) {
|
|
56
|
+
return getCapability(capabilityId);
|
|
57
|
+
}
|
|
58
|
+
const plan = getCurrentPlan(options);
|
|
59
|
+
const capability = getCapability(capabilityId);
|
|
60
|
+
const comparison = comparePlans();
|
|
61
|
+
const unlock = comparison.upgradeUnlocks.find((item) => item.id === capabilityId);
|
|
62
|
+
const label = capability?.label || capabilityId;
|
|
63
|
+
const note = unlock ? ` Upgrade to Pro to unlock ${label.toLowerCase()}.` : "";
|
|
64
|
+
throw new Error(`${label} is not available on the ${getPlan(plan)?.name || plan} plan.${note}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getQuota(capabilityId, options = {}) {
|
|
68
|
+
const plan = getCurrentPlan(options);
|
|
69
|
+
const capability = requireCapability(capabilityId, options);
|
|
70
|
+
if (!capability.quota) return null;
|
|
71
|
+
|
|
72
|
+
if (capabilityId === "visual_qa_weekly" && plan === "free") {
|
|
73
|
+
return { ...capability.quota };
|
|
74
|
+
}
|
|
75
|
+
if (capabilityId === "visual_qa_weekly" && plan === "pro") {
|
|
76
|
+
const advanced = getCapability("visual_qa_advanced");
|
|
77
|
+
return advanced?.quota ? { ...advanced.quota } : { period: "month", limit: 50 };
|
|
78
|
+
}
|
|
79
|
+
return { ...capability.quota };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getHistoryRetention(planName = getCurrentPlan()) {
|
|
83
|
+
const plan = getPlan(planName) || getPlan("free");
|
|
84
|
+
return { ...(plan.historyRetention || { mode: "latest_only", maxReports: 1, retentionDays: 7 }) };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function canExportReports(planName = getCurrentPlan()) {
|
|
88
|
+
const plan = getPlan(planName) || getPlan("free");
|
|
89
|
+
return plan.exportReports === true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
PLAN_ENV,
|
|
94
|
+
getCurrentPlan,
|
|
95
|
+
capabilityEnabled,
|
|
96
|
+
requireCapability,
|
|
97
|
+
getQuota,
|
|
98
|
+
getHistoryRetention,
|
|
99
|
+
canExportReports,
|
|
100
|
+
};
|