codymaster 4.4.5 ā 4.5.2
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/CHANGELOG.md +33 -0
- package/README.md +29 -14
- package/commands/demo.md +1 -1
- package/dist/context-bus.js +70 -0
- package/dist/context-db.js +265 -0
- package/dist/continuity.js +12 -0
- package/dist/file-watcher.js +79 -0
- package/dist/index.js +152 -1
- package/dist/l0-indexer.js +158 -0
- package/dist/mcp-context-server.js +400 -0
- package/dist/migrate-json-to-sqlite.js +126 -0
- package/dist/skill-chain.js +19 -3
- package/dist/token-budget.js +108 -0
- package/dist/uri-resolver.js +203 -0
- package/package.json +5 -1
- package/scripts/gate-0-secrets.js +63 -0
- package/scripts/gate-1-syntax.js +53 -0
- package/scripts/gate-5-dist-verify.js +55 -0
- package/scripts/gate-6-smoke-test.js +30 -0
- package/scripts/index-codebase.sh +552 -0
- package/scripts/mcp-bridge.js +284 -0
- package/scripts/postinstall.js +301 -0
- package/scripts/security-fixer.js +143 -0
- package/scripts/security-scan.js +55 -0
- package/scripts/test-gemini.js +13 -0
- package/scripts/todo-bridge.js +112 -0
- package/skills/_shared/helpers.md +50 -14
- package/skills/cm-autopilot/SKILL.md +29 -0
- package/skills/cm-autopilot/scripts/autopilot.py +190 -0
- package/skills/cm-continuity/SKILL.md +90 -28
- package/skills/cm-skill-chain/SKILL.md +47 -1
- package/skills/cm-start/SKILL.md +11 -2
- package/skills/boxme-git-config/SKILL.md +0 -56
- package/skills/boxme-local-dev/SKILL.md +0 -66
- package/skills/jobs-to-be-done/SKILL.md +0 -266
- package/skills/jobs-to-be-done/references/case-studies.md +0 -154
- package/skills/jobs-to-be-done/references/competitive-strategy.md +0 -280
- package/skills/jobs-to-be-done/references/diagnostics.md +0 -158
- package/skills/jobs-to-be-done/references/innovation-process.md +0 -392
- package/skills/jobs-to-be-done/references/organizational-change.md +0 -328
- package/skills/marketplace-report-crawler/SKILL.md +0 -176
- package/skills/marketplace-report-crawler/config/accounts.json +0 -41
- package/skills/marketplace-report-crawler/config/report-types.json +0 -422
- package/skills/marketplace-report-crawler/config/sessions.json +0 -3
- package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +0 -102
- package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +0 -114
- package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +0 -94
- package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +0 -272
- package/skills/marketplace-report-crawler/scripts/crawl-runner.js +0 -281
- package/skills/marketplace-report-crawler/scripts/session-check.sh +0 -72
- package/skills/marketplace-report-crawler/scripts/session-manager.sh +0 -349
- package/skills/marketplace-report-crawler/scripts/setup-folders.sh +0 -83
- package/skills/medical-research/SKILL.md +0 -194
- package/skills/medical-research/scripts/evidence_checker.py +0 -288
- package/skills/mom-test/SKILL.md +0 -267
- package/skills/mom-test/references/avoiding-bad-data.md +0 -221
- package/skills/mom-test/references/case-studies.md +0 -306
- package/skills/mom-test/references/commitment-advancement.md +0 -219
- package/skills/mom-test/references/finding-conversations.md +0 -251
- package/skills/mom-test/references/processing-learning.md +0 -256
- package/skills/mom-test/references/question-patterns.md +0 -198
- package/skills/pandasai-analytics/SKILL.md +0 -251
- package/skills/release-it/SKILL.md +0 -235
- package/skills/release-it/references/anti-patterns.md +0 -279
- package/skills/release-it/references/capacity-planning.md +0 -285
- package/skills/release-it/references/chaos-engineering.md +0 -325
- package/skills/release-it/references/deployment-strategies.md +0 -331
- package/skills/release-it/references/observability.md +0 -301
- package/skills/release-it/references/stability-patterns.md +0 -355
- package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +0 -37
- package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +0 -34
- package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +0 -51
- package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +0 -39
- package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +0 -52
- package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +0 -25
- package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +0 -31
- package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +0 -25
- package/skills/skill-creator-ultra/README.md +0 -1242
- package/skills/skill-creator-ultra/SKILL.md +0 -388
- package/skills/skill-creator-ultra/agents/analyzer.md +0 -274
- package/skills/skill-creator-ultra/agents/comparator.md +0 -202
- package/skills/skill-creator-ultra/agents/grader.md +0 -223
- package/skills/skill-creator-ultra/assets/eval_review.html +0 -146
- package/skills/skill-creator-ultra/eval-viewer/generate_review.py +0 -471
- package/skills/skill-creator-ultra/eval-viewer/viewer.html +0 -1325
- package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +0 -109
- package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +0 -116
- package/skills/skill-creator-ultra/examples/example_api_docs.md +0 -189
- package/skills/skill-creator-ultra/examples/example_db_migration.md +0 -253
- package/skills/skill-creator-ultra/examples/example_git_commit.md +0 -111
- package/skills/skill-creator-ultra/install.ps1 +0 -289
- package/skills/skill-creator-ultra/install.sh +0 -313
- package/skills/skill-creator-ultra/phases/phase1_interview.md +0 -202
- package/skills/skill-creator-ultra/phases/phase2_extract.md +0 -55
- package/skills/skill-creator-ultra/phases/phase3_detect.md +0 -57
- package/skills/skill-creator-ultra/phases/phase4_generate.md +0 -543
- package/skills/skill-creator-ultra/phases/phase5_test.md +0 -319
- package/skills/skill-creator-ultra/phases/phase6_eval.md +0 -301
- package/skills/skill-creator-ultra/phases/phase7_iterate.md +0 -103
- package/skills/skill-creator-ultra/phases/phase8_optimize.md +0 -113
- package/skills/skill-creator-ultra/resources/advanced_patterns.md +0 -499
- package/skills/skill-creator-ultra/resources/anti_patterns.md +0 -376
- package/skills/skill-creator-ultra/resources/blueprints.md +0 -498
- package/skills/skill-creator-ultra/resources/checklist.md +0 -243
- package/skills/skill-creator-ultra/resources/composition_cookbook.md +0 -291
- package/skills/skill-creator-ultra/resources/description_optimization.md +0 -90
- package/skills/skill-creator-ultra/resources/eval_guide.md +0 -133
- package/skills/skill-creator-ultra/resources/industry_questions.md +0 -189
- package/skills/skill-creator-ultra/resources/interview_questions.md +0 -200
- package/skills/skill-creator-ultra/resources/pattern_detection.md +0 -200
- package/skills/skill-creator-ultra/resources/prompt_engineering.md +0 -531
- package/skills/skill-creator-ultra/resources/schemas.md +0 -430
- package/skills/skill-creator-ultra/resources/script_integration.md +0 -593
- package/skills/skill-creator-ultra/resources/scripts_guide.md +0 -339
- package/skills/skill-creator-ultra/resources/skill_template.md +0 -124
- package/skills/skill-creator-ultra/resources/skill_writing_guide.md +0 -634
- package/skills/skill-creator-ultra/resources/versioning_guide.md +0 -193
- package/skills/skill-creator-ultra/scripts/ci_eval.py +0 -200
- package/skills/skill-creator-ultra/scripts/package_skill.py +0 -165
- package/skills/skill-creator-ultra/scripts/simulate_skill.py +0 -398
- package/skills/skill-creator-ultra/scripts/skill_audit.py +0 -611
- package/skills/skill-creator-ultra/scripts/skill_compare.py +0 -265
- package/skills/skill-creator-ultra/scripts/skill_export.py +0 -334
- package/skills/skill-creator-ultra/scripts/skill_scaffold.py +0 -403
- package/skills/skill-creator-ultra/scripts/skill_stats.py +0 -339
- package/skills/skill-creator-ultra/scripts/validate_skill.py +0 -411
- package/skills/tailwind-mastery/SKILL.md +0 -229
- package/skills/vercel-react-best-practices/AGENTS.md +0 -3373
- package/skills/vercel-react-best-practices/README.md +0 -123
- package/skills/vercel-react-best-practices/SKILL.md +0 -143
- package/skills/vercel-react-best-practices/rules/_sections.md +0 -46
- package/skills/vercel-react-best-practices/rules/_template.md +0 -28
- package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
- package/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
- package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/skills/web-design-guidelines/SKILL.md +0 -39
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDefaultBudget = getDefaultBudget;
|
|
7
|
+
exports.loadBudget = loadBudget;
|
|
8
|
+
exports.checkBudget = checkBudget;
|
|
9
|
+
exports.estimateTokens = estimateTokens;
|
|
10
|
+
exports.generateBudgetReport = generateBudgetReport;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
// āāā Constants āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
14
|
+
const CM_DIR = '.cm';
|
|
15
|
+
const BUDGET_FILE = 'token-budget.json';
|
|
16
|
+
// āāā Default Budget āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
17
|
+
function getDefaultBudget() {
|
|
18
|
+
return {
|
|
19
|
+
model_context_window: 200000,
|
|
20
|
+
allocations: {
|
|
21
|
+
system_prompt: 5000, // 2.5%
|
|
22
|
+
skill_index_L0: 2500, // 1.25%
|
|
23
|
+
skill_active_full: 5000, // 2.5%
|
|
24
|
+
memory_working: 500, // 0.25%
|
|
25
|
+
memory_learnings: 650, // 0.325%
|
|
26
|
+
codebase_skeleton: 1500, // 0.75%
|
|
27
|
+
context_retrieval: 10000, // 5%
|
|
28
|
+
conversation_history: 30000, // 15%
|
|
29
|
+
generation_budget: 144850, // 72.425%
|
|
30
|
+
},
|
|
31
|
+
enforcement: 'soft',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// āāā Load Budget āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
35
|
+
function loadBudget(projectPath) {
|
|
36
|
+
const budgetPath = path_1.default.join(projectPath, CM_DIR, BUDGET_FILE);
|
|
37
|
+
if (!fs_1.default.existsSync(budgetPath)) {
|
|
38
|
+
return getDefaultBudget();
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const raw = fs_1.default.readFileSync(budgetPath, 'utf-8');
|
|
42
|
+
return JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch (_a) {
|
|
45
|
+
return getDefaultBudget();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// āāā Check Budget āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
49
|
+
function checkBudget(budget, category, tokenCount) {
|
|
50
|
+
const allocs = budget.allocations;
|
|
51
|
+
const allocated = allocs[category];
|
|
52
|
+
if (allocated === undefined) {
|
|
53
|
+
return {
|
|
54
|
+
allowed: false,
|
|
55
|
+
remaining: 0,
|
|
56
|
+
suggestion: `Unknown category "${category}". Valid: ${Object.keys(allocs).join(', ')}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const remaining = allocated - tokenCount;
|
|
60
|
+
const overBudget = remaining < 0;
|
|
61
|
+
if (!overBudget) {
|
|
62
|
+
return { allowed: true, remaining };
|
|
63
|
+
}
|
|
64
|
+
const suggestion = buildSuggestion(category, tokenCount, allocated);
|
|
65
|
+
if (budget.enforcement === 'hard') {
|
|
66
|
+
return { allowed: false, remaining, suggestion };
|
|
67
|
+
}
|
|
68
|
+
// Soft mode: allow but warn
|
|
69
|
+
return { allowed: true, remaining, suggestion };
|
|
70
|
+
}
|
|
71
|
+
function buildSuggestion(category, used, allocated) {
|
|
72
|
+
const over = used - allocated;
|
|
73
|
+
if (category === 'memory_learnings') {
|
|
74
|
+
return `memory_learnings over by ~${over} tokens. Switch to L0 index (cm://memory/learnings/L0) to reduce to ~100 tokens.`;
|
|
75
|
+
}
|
|
76
|
+
if (category === 'codebase_skeleton') {
|
|
77
|
+
return `codebase_skeleton over by ~${over} tokens. Use cm://resources/skeleton/L0 for module-level index (~500 tokens).`;
|
|
78
|
+
}
|
|
79
|
+
if (category === 'memory_working') {
|
|
80
|
+
return `memory_working over by ~${over} tokens. Read CONTINUITY abstract only (first 3 lines).`;
|
|
81
|
+
}
|
|
82
|
+
return `${category} over budget by ~${over} tokens. Consider using L0 index instead of full content.`;
|
|
83
|
+
}
|
|
84
|
+
// āāā Estimate Tokens āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
85
|
+
function estimateTokens(text) {
|
|
86
|
+
if (!text)
|
|
87
|
+
return 0;
|
|
88
|
+
return Math.ceil(text.length / 4);
|
|
89
|
+
}
|
|
90
|
+
// āāā Budget Report āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
91
|
+
function generateBudgetReport(budget) {
|
|
92
|
+
const total = budget.model_context_window;
|
|
93
|
+
const lines = [
|
|
94
|
+
`Token Budget Report (${total.toLocaleString()} context window, enforcement: ${budget.enforcement})`,
|
|
95
|
+
'ā'.repeat(70),
|
|
96
|
+
`${'Category'.padEnd(25)} ${'Allocated'.padStart(10)} ${'% of CTX'.padStart(10)}`,
|
|
97
|
+
'ā'.repeat(70),
|
|
98
|
+
];
|
|
99
|
+
const allocs = budget.allocations;
|
|
100
|
+
for (const [cat, allocated] of Object.entries(allocs)) {
|
|
101
|
+
const pct = ((allocated / total) * 100).toFixed(2);
|
|
102
|
+
lines.push(`${cat.padEnd(25)} ${allocated.toLocaleString().padStart(10)} ${(pct + '%').padStart(10)}`);
|
|
103
|
+
}
|
|
104
|
+
const sum = Object.values(allocs).reduce((a, b) => a + b, 0);
|
|
105
|
+
lines.push('ā'.repeat(70));
|
|
106
|
+
lines.push(`${'TOTAL'.padEnd(25)} ${sum.toLocaleString().padStart(10)} ${(((sum / total) * 100).toFixed(2) + '%').padStart(10)}`);
|
|
107
|
+
return lines.join('\n');
|
|
108
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolve = resolve;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const context_db_1 = require("./context-db");
|
|
10
|
+
const context_bus_1 = require("./context-bus");
|
|
11
|
+
// āāā Main Resolver āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a cm:// URI to content at the requested depth.
|
|
14
|
+
*
|
|
15
|
+
* URI patterns:
|
|
16
|
+
* cm://memory/working ā CONTINUITY.md abstract (L0) or full (L2)
|
|
17
|
+
* cm://memory/learnings ā learnings index (L0) or all learnings (L2)
|
|
18
|
+
* cm://memory/learnings/{id} ā specific learning by ID
|
|
19
|
+
* cm://memory/decisions ā decisions index (L0) or all (L2)
|
|
20
|
+
* cm://skills/{name} ā SKILL.md at depth
|
|
21
|
+
* cm://skills/{name}/L0 ā index entry only
|
|
22
|
+
* cm://resources/skeleton ā skeleton-index.md (L0) or full (L2)
|
|
23
|
+
* cm://resources/architecture ā architecture.mmd
|
|
24
|
+
* cm://pipeline/current ā context bus state
|
|
25
|
+
*/
|
|
26
|
+
function resolve(uri, projectPath, depth = 'L1') {
|
|
27
|
+
if (!uri.startsWith('cm://')) {
|
|
28
|
+
return notFound(uri, depth, `URI must start with cm://`);
|
|
29
|
+
}
|
|
30
|
+
const rest = uri.slice('cm://'.length); // e.g. "memory/learnings/L005"
|
|
31
|
+
const parts = rest.split('/').filter(Boolean);
|
|
32
|
+
if (parts.length === 0) {
|
|
33
|
+
return notFound(uri, depth, 'Empty URI path');
|
|
34
|
+
}
|
|
35
|
+
const [ns, ...tail] = parts;
|
|
36
|
+
switch (ns) {
|
|
37
|
+
case 'memory': return resolveMemory(uri, tail, projectPath, depth);
|
|
38
|
+
case 'skills': return resolveSkill(uri, tail, projectPath, depth);
|
|
39
|
+
case 'resources': return resolveResource(uri, tail, projectPath, depth);
|
|
40
|
+
case 'pipeline': return resolvePipeline(uri, tail, projectPath, depth);
|
|
41
|
+
default:
|
|
42
|
+
return notFound(uri, depth, `Unknown namespace "${ns}". Valid: memory, skills, resources, pipeline`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// āāā memory/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
46
|
+
function resolveMemory(uri, tail, projectPath, depth) {
|
|
47
|
+
const [resource, id] = tail;
|
|
48
|
+
switch (resource) {
|
|
49
|
+
case 'working': {
|
|
50
|
+
const contPath = path_1.default.join(projectPath, '.cm', 'CONTINUITY.md');
|
|
51
|
+
if (!fs_1.default.existsSync(contPath))
|
|
52
|
+
return notFound(uri, depth, 'CONTINUITY.md not found');
|
|
53
|
+
const full = fs_1.default.readFileSync(contPath, 'utf-8');
|
|
54
|
+
if (depth === 'L0' || depth === 'L1') {
|
|
55
|
+
// Return first 10 non-empty lines as abstract
|
|
56
|
+
const abstract = full.split('\n').filter(l => l.trim()).slice(0, 10).join('\n');
|
|
57
|
+
return found(uri, depth, abstract);
|
|
58
|
+
}
|
|
59
|
+
return found(uri, depth, full);
|
|
60
|
+
}
|
|
61
|
+
case 'learnings': {
|
|
62
|
+
if (id) {
|
|
63
|
+
// cm://memory/learnings/L005 ā specific entry
|
|
64
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
65
|
+
const learning = (0, context_db_1.getLearningById)(dbPath, id);
|
|
66
|
+
if (!learning)
|
|
67
|
+
return notFound(uri, depth, `Learning "${id}" not found`);
|
|
68
|
+
return found(uri, depth, formatLearning(learning));
|
|
69
|
+
}
|
|
70
|
+
if (depth === 'L0') {
|
|
71
|
+
// Return cached L0 index
|
|
72
|
+
const indexPath = path_1.default.join(projectPath, '.cm', 'learnings-index.md');
|
|
73
|
+
if (fs_1.default.existsSync(indexPath)) {
|
|
74
|
+
return found(uri, depth, fs_1.default.readFileSync(indexPath, 'utf-8'));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// L1/L2: query all from SQLite
|
|
78
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
79
|
+
const learnings = (0, context_db_1.queryLearnings)(dbPath, '', undefined, 50);
|
|
80
|
+
if (learnings.length === 0) {
|
|
81
|
+
// Fallback to JSON file
|
|
82
|
+
const jsonPath = path_1.default.join(projectPath, '.cm', 'memory', 'learnings.json');
|
|
83
|
+
if (fs_1.default.existsSync(jsonPath)) {
|
|
84
|
+
return found(uri, depth, fs_1.default.readFileSync(jsonPath, 'utf-8'));
|
|
85
|
+
}
|
|
86
|
+
return found(uri, depth, '[]');
|
|
87
|
+
}
|
|
88
|
+
return found(uri, depth, JSON.stringify(learnings, null, 2));
|
|
89
|
+
}
|
|
90
|
+
case 'decisions': {
|
|
91
|
+
if (depth === 'L0') {
|
|
92
|
+
// Short list of decision IDs + 1-line summary
|
|
93
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
94
|
+
const decisions = (0, context_db_1.queryDecisions)(dbPath, '', 20);
|
|
95
|
+
const lines = ['# Decisions Index', ''];
|
|
96
|
+
for (const d of decisions) {
|
|
97
|
+
lines.push(`- ${d.id}: ${d.decision.slice(0, 80)}`);
|
|
98
|
+
}
|
|
99
|
+
return found(uri, depth, lines.join('\n'));
|
|
100
|
+
}
|
|
101
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
102
|
+
const decisions = (0, context_db_1.queryDecisions)(dbPath, '', 50);
|
|
103
|
+
if (decisions.length === 0) {
|
|
104
|
+
const jsonPath = path_1.default.join(projectPath, '.cm', 'memory', 'decisions.json');
|
|
105
|
+
if (fs_1.default.existsSync(jsonPath)) {
|
|
106
|
+
return found(uri, depth, fs_1.default.readFileSync(jsonPath, 'utf-8'));
|
|
107
|
+
}
|
|
108
|
+
return found(uri, depth, '[]');
|
|
109
|
+
}
|
|
110
|
+
return found(uri, depth, JSON.stringify(decisions, null, 2));
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
return notFound(uri, depth, `Unknown memory resource "${resource}". Valid: working, learnings, decisions`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// āāā skills/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
117
|
+
function resolveSkill(uri, tail, projectPath, depth) {
|
|
118
|
+
const [skillName, depthOverride] = tail;
|
|
119
|
+
if (!skillName)
|
|
120
|
+
return notFound(uri, depth, 'Skill name required: cm://skills/{name}');
|
|
121
|
+
const effectiveDepth = depthOverride || depth;
|
|
122
|
+
// Look in project skills/ dir, then global ~/.claude/skills/
|
|
123
|
+
const candidates = [
|
|
124
|
+
path_1.default.join(projectPath, 'skills', skillName, 'SKILL.md'),
|
|
125
|
+
path_1.default.join(projectPath, '.claude', 'skills', skillName, 'SKILL.md'),
|
|
126
|
+
path_1.default.join(process.env.HOME || '', '.claude', 'skills', skillName, 'SKILL.md'),
|
|
127
|
+
];
|
|
128
|
+
const skillPath = candidates.find(p => fs_1.default.existsSync(p));
|
|
129
|
+
if (!skillPath)
|
|
130
|
+
return notFound(uri, depth, `Skill "${skillName}" not found`);
|
|
131
|
+
const full = fs_1.default.readFileSync(skillPath, 'utf-8');
|
|
132
|
+
if (effectiveDepth === 'L0') {
|
|
133
|
+
// Front matter + description only (~50 tokens)
|
|
134
|
+
const lines = full.split('\n');
|
|
135
|
+
const summary = lines.slice(0, 10).join('\n');
|
|
136
|
+
return found(uri, effectiveDepth, summary);
|
|
137
|
+
}
|
|
138
|
+
if (effectiveDepth === 'L1') {
|
|
139
|
+
// First 40 lines (~600 tokens)
|
|
140
|
+
return found(uri, effectiveDepth, full.split('\n').slice(0, 40).join('\n'));
|
|
141
|
+
}
|
|
142
|
+
return found(uri, effectiveDepth, full);
|
|
143
|
+
}
|
|
144
|
+
// āāā resources/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
145
|
+
function resolveResource(uri, tail, projectPath, depth) {
|
|
146
|
+
const [resource] = tail;
|
|
147
|
+
switch (resource) {
|
|
148
|
+
case 'skeleton': {
|
|
149
|
+
if (depth === 'L0' || depth === 'L1') {
|
|
150
|
+
const indexPath = path_1.default.join(projectPath, '.cm', 'skeleton-index.md');
|
|
151
|
+
if (fs_1.default.existsSync(indexPath)) {
|
|
152
|
+
return found(uri, depth, fs_1.default.readFileSync(indexPath, 'utf-8'));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const fullPath = path_1.default.join(projectPath, '.cm', 'skeleton.md');
|
|
156
|
+
if (!fs_1.default.existsSync(fullPath))
|
|
157
|
+
return notFound(uri, depth, 'skeleton.md not found ā run: cm continuity index');
|
|
158
|
+
return found(uri, depth, fs_1.default.readFileSync(fullPath, 'utf-8'));
|
|
159
|
+
}
|
|
160
|
+
case 'architecture': {
|
|
161
|
+
const mmdPath = path_1.default.join(projectPath, '.cm', 'architecture.mmd');
|
|
162
|
+
if (!fs_1.default.existsSync(mmdPath))
|
|
163
|
+
return notFound(uri, depth, 'architecture.mmd not found');
|
|
164
|
+
return found(uri, depth, fs_1.default.readFileSync(mmdPath, 'utf-8'));
|
|
165
|
+
}
|
|
166
|
+
default:
|
|
167
|
+
return notFound(uri, depth, `Unknown resource "${resource}". Valid: skeleton, architecture`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// āāā pipeline/* āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
171
|
+
function resolvePipeline(uri, tail, projectPath, depth) {
|
|
172
|
+
const [sub] = tail;
|
|
173
|
+
if (!sub || sub === 'current') {
|
|
174
|
+
const bus = (0, context_bus_1.readBus)(projectPath);
|
|
175
|
+
if (!bus)
|
|
176
|
+
return notFound(uri, depth, 'No active context bus. Start a chain first.');
|
|
177
|
+
if (depth === 'L0') {
|
|
178
|
+
const summary = `Pipeline: ${bus.pipeline} | Step: ${bus.current_step} | Steps done: ${Object.keys(bus.shared_context).length}`;
|
|
179
|
+
return found(uri, depth, summary);
|
|
180
|
+
}
|
|
181
|
+
return found(uri, depth, JSON.stringify(bus, null, 2));
|
|
182
|
+
}
|
|
183
|
+
return notFound(uri, depth, `Unknown pipeline resource "${sub}"`);
|
|
184
|
+
}
|
|
185
|
+
// āāā Helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
186
|
+
function found(uri, depth, content) {
|
|
187
|
+
return { uri, depth, content, tokenEstimate: Math.ceil(content.length / 4), found: true };
|
|
188
|
+
}
|
|
189
|
+
function notFound(uri, depth, reason) {
|
|
190
|
+
const content = `# Not Found\n\nURI: ${uri}\nReason: ${reason}`;
|
|
191
|
+
return { uri, depth, content, tokenEstimate: Math.ceil(content.length / 4), found: false };
|
|
192
|
+
}
|
|
193
|
+
function formatLearning(l) {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
if (!l)
|
|
196
|
+
return '';
|
|
197
|
+
return [
|
|
198
|
+
`### ${l.id}: ${l.what_failed}`,
|
|
199
|
+
`- **Why:** ${l.why_failed}`,
|
|
200
|
+
`- **Fix:** ${l.how_to_prevent}`,
|
|
201
|
+
`- **Scope:** ${(_a = l.scope) !== null && _a !== void 0 ? _a : 'global'} | **TTL:** ${(_b = l.ttl) !== null && _b !== void 0 ? _b : 60}d`,
|
|
202
|
+
].join('\n');
|
|
203
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codymaster",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "68+ Skills. Ship 10x faster. AI-powered coding skill kit for Claude, Cursor, Gemini & more.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"type": "commonjs",
|
|
47
47
|
"files": [
|
|
48
48
|
"dist/",
|
|
49
|
+
"scripts/",
|
|
49
50
|
"skills/",
|
|
50
51
|
"adapters/",
|
|
51
52
|
"commands/",
|
|
@@ -59,12 +60,15 @@
|
|
|
59
60
|
},
|
|
60
61
|
"dependencies": {
|
|
61
62
|
"@clack/prompts": "^1.1.0",
|
|
63
|
+
"better-sqlite3": "^12.8.0",
|
|
62
64
|
"chalk": "^5.6.2",
|
|
65
|
+
"chokidar": "^5.0.0",
|
|
63
66
|
"commander": "^14.0.3",
|
|
64
67
|
"express": "^5.2.1",
|
|
65
68
|
"prompts": "^2.4.2"
|
|
66
69
|
},
|
|
67
70
|
"devDependencies": {
|
|
71
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
68
72
|
"@types/express": "^5.0.6",
|
|
69
73
|
"@types/node": "^25.5.0",
|
|
70
74
|
"@types/prompts": "^2.4.9",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 0: Secret Hygiene
|
|
4
|
+
* Fastest gate (< 0.5s). Checks for leaked secrets before anything else runs.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
let failed = false;
|
|
10
|
+
|
|
11
|
+
// 1. Check wrangler config files for hardcoded secret values
|
|
12
|
+
const wranglerFiles = ['wrangler.toml', 'wrangler.jsonc', 'wrangler.json'];
|
|
13
|
+
const dangerous = [
|
|
14
|
+
'SERVICE_KEY', 'ANON_KEY', 'DB_PASSWORD', 'SECRET_KEY', 'PRIVATE_KEY', 'API_SECRET',
|
|
15
|
+
'GCP_SERVICE_ACCOUNT', 'AZURE_CONNECTION_STRING', 'HEROKU_API_KEY', 'POSTMAN_API_KEY'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (const wf of wranglerFiles) {
|
|
19
|
+
if (!fs.existsSync(wf)) continue;
|
|
20
|
+
const src = fs.readFileSync(wf, 'utf-8');
|
|
21
|
+
for (const key of dangerous) {
|
|
22
|
+
const valuePattern = new RegExp(key + '\\s*[=:]\\s*["\'][a-zA-Z0-9/+=]{20,}', 'g');
|
|
23
|
+
if (valuePattern.test(src)) {
|
|
24
|
+
console.error('ā DANGEROUS: ' + wf + ' contains a ' + key + ' VALUE');
|
|
25
|
+
console.error(' Fix: wrangler secret put ' + key + ' (then remove from ' + wf + ')');
|
|
26
|
+
failed = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 2. Check .gitignore has required patterns
|
|
32
|
+
if (fs.existsSync('.gitignore')) {
|
|
33
|
+
const gi = fs.readFileSync('.gitignore', 'utf-8');
|
|
34
|
+
const required = ['.env', '.dev.vars'];
|
|
35
|
+
const missing = required.filter(r => !gi.includes(r));
|
|
36
|
+
if (missing.length > 0) {
|
|
37
|
+
console.error('ā .gitignore missing: ' + missing.join(', '));
|
|
38
|
+
failed = true;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
console.error('ā No .gitignore found!');
|
|
42
|
+
failed = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 3. Check .env / .dev.vars files aren't tracked by git
|
|
46
|
+
try {
|
|
47
|
+
const tracked = execSync('git ls-files', { encoding: 'utf-8' });
|
|
48
|
+
const badFiles = ['.env', '.dev.vars', '.env.local', '.env.production'];
|
|
49
|
+
const trackedBad = badFiles.filter(f => tracked.split('\n').includes(f));
|
|
50
|
+
if (trackedBad.length > 0) {
|
|
51
|
+
console.error('ā CRITICAL: Secret files tracked by git: ' + trackedBad.join(', '));
|
|
52
|
+
console.error(' Fix: git rm --cached ' + trackedBad.join(' '));
|
|
53
|
+
failed = true;
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
// Not a git repo ā skip
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (failed) {
|
|
60
|
+
console.error('\nš”ļø Gate 0 FAILED. Fix issues above before deploying.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
console.log('ā
Gate 0 passed: secret hygiene verified');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 1: Syntax Validation
|
|
4
|
+
* Fast-fail (< 2s). Catches syntax errors before the slower test suite.
|
|
5
|
+
* - Parses all JS files in public/js/ with acorn
|
|
6
|
+
* - Runs tsc --noEmit for TypeScript in src/
|
|
7
|
+
*/
|
|
8
|
+
const { parse } = require('acorn');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
let failed = false;
|
|
14
|
+
|
|
15
|
+
// 1. Parse all JS files in public/js/
|
|
16
|
+
const jsDir = 'public/js';
|
|
17
|
+
if (fs.existsSync(jsDir)) {
|
|
18
|
+
const jsFiles = fs.readdirSync(jsDir).filter(f => f.endsWith('.js'));
|
|
19
|
+
for (const file of jsFiles) {
|
|
20
|
+
const filePath = path.join(jsDir, file);
|
|
21
|
+
const code = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
try {
|
|
23
|
+
parse(code, { ecmaVersion: 2022, sourceType: 'script' });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error(`ā Syntax error in ${filePath}:`);
|
|
26
|
+
console.error(` Line ${err.loc?.line}, Column ${err.loc?.column}: ${err.message}`);
|
|
27
|
+
failed = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!failed) {
|
|
31
|
+
console.log(`ā
${jsFiles.length} JS files parsed successfully`);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
console.log('ā No public/js/ directory found, skipping JS syntax check');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. TypeScript compilation check
|
|
38
|
+
if (fs.existsSync('tsconfig.json')) {
|
|
39
|
+
try {
|
|
40
|
+
execSync('npx tsc --noEmit', { encoding: 'utf-8', stdio: 'pipe' });
|
|
41
|
+
console.log('ā
TypeScript compilation check passed');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('ā TypeScript compilation errors:');
|
|
44
|
+
console.error(err.stdout || err.stderr || err.message);
|
|
45
|
+
failed = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (failed) {
|
|
50
|
+
console.error('\nš“ Gate 1 FAILED. Fix syntax errors before proceeding.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
console.log('ā
Gate 1 passed: syntax validation complete');
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 5: Dist Asset Verification
|
|
4
|
+
* Verifies critical files exist in public/ after build:html + docs:build.
|
|
5
|
+
* Build can "succeed" but produce an incomplete output directory.
|
|
6
|
+
*/
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const publicDir = 'public';
|
|
11
|
+
// Critical HTML pages
|
|
12
|
+
const requiredHtml = [
|
|
13
|
+
'dashboard/index.html',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// Critical JS files
|
|
17
|
+
const requiredJs = [
|
|
18
|
+
'dashboard/app.js',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Critical CSS files
|
|
22
|
+
const requiredCss = [
|
|
23
|
+
'dashboard/style.css',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// Build required file list
|
|
27
|
+
const required = [];
|
|
28
|
+
|
|
29
|
+
// HTML pages
|
|
30
|
+
for (const html of requiredHtml) {
|
|
31
|
+
required.push(path.join(publicDir, html));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// JS files
|
|
35
|
+
for (const js of requiredJs) {
|
|
36
|
+
required.push(path.join(publicDir, js));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// CSS files
|
|
40
|
+
for (const css of requiredCss) {
|
|
41
|
+
required.push(path.join(publicDir, css));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// Check all required files
|
|
46
|
+
const missing = required.filter(f => !fs.existsSync(f));
|
|
47
|
+
|
|
48
|
+
if (missing.length > 0) {
|
|
49
|
+
console.error('ā Missing critical files:');
|
|
50
|
+
missing.forEach(f => console.error(' ' + f));
|
|
51
|
+
console.error(`\nš“ Gate 5 FAILED. ${missing.length} file(s) missing from build output.`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(`ā
Gate 5 passed: all ${required.length} critical files present`);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 6: Post-Deploy Smoke Test
|
|
4
|
+
* Verifies the deployed site returns HTTP 200.
|
|
5
|
+
* Usage: node scripts/gate-6-smoke-test.js [optional-url]
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DEPLOY_URL = process.argv[2] || process.env.DEPLOY_URL || 'https://cody.todyle.com';
|
|
9
|
+
|
|
10
|
+
async function smokeTest() {
|
|
11
|
+
console.log(`š Smoke testing: ${DEPLOY_URL}`);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(DEPLOY_URL);
|
|
15
|
+
if (res.status === 200) {
|
|
16
|
+
console.log(`ā
Gate 6 passed: HTTP ${res.status} from ${DEPLOY_URL}`);
|
|
17
|
+
} else {
|
|
18
|
+
console.error(`ā Gate 6 FAILED: HTTP ${res.status} from ${DEPLOY_URL}`);
|
|
19
|
+
console.error(' ā Consider immediate rollback.');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error(`ā Gate 6 FAILED: Could not reach ${DEPLOY_URL}`);
|
|
24
|
+
console.error(` Error: ${err.message}`);
|
|
25
|
+
console.error(' ā Consider immediate rollback.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
smokeTest();
|