feat(ci): v0.9.0 — Distribution & Expansion milestone complete
---ci---
project: ci
phase: 6
milestone: v0.9
status: complete
artifacts:
tags: [v0.9.0]
decisions:
- id: D-047
decision: v0.9 theme = Distribution & Expansion
rationale: npm publish + OpenAI/Anthropic backends + agent flesh + parallel execution
confidence: 0.92
- id: D-049
decision: Feature milestone — patch tags v0.8.1-v0.8.6 then v0.9.0
rationale: OpenAI backend, agent flesh, npm publish all feat
confidence: 0.95
- id: D-059
decision: Rename OllamaBaseBackend to LLMBaseBackend + thin OllamaBaseBackend subclass
rationale: 15 of 17 methods backend-agnostic
confidence: 0.92
- id: D-060
decision: OpenAI/Anthropic backends use native fetch() not SDK packages
rationale: No dependency bloat; fetch native in Node 18+
confidence: 0.85
- id: D-066
decision: Concurrency limiter internal (no p-limit dependency)
rationale: 15 lines; avoids dependency for trivial feature
confidence: 0.90
- id: D-067
decision: Promise.allSettled for review agents at orchestrator lines 373-400
rationale: Current sequential loop replaced with parallel execution
confidence: 0.88
requirements:
covered: [PUBLISH-01, PUBLISH-02, PUBLISH-03, PUBLISH-04, OPENAI-01, OPENAI-02, OPENAI-03, OPENAI-04, OPENAI-05, FLESH-01, FLESH-02, FLESH-03, FLESH-04, FLESH-05, ANTHROPIC-01, ANTHROPIC-02, FLESH-06, FLESH-07, NPM-01, NPM-02, PARALLEL-01, PARALLEL-02, PARALLEL-03, INTEG-01, INTEG-02, INTEG-03, INTEG-04, INTEG-05]
---/ci---
6 phases, 28 tasks, 4077 net lines added, 57 test suites, 527 tests, zero stub agents
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
|
||||
const pkgPath = path.join(projectRoot, "package.json");
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
||||
const pkgVersion = pkg.version;
|
||||
|
||||
const versionPath = path.join(projectRoot, "src", "version.ts");
|
||||
const versionContent = fs.readFileSync(versionPath, "utf-8");
|
||||
const match = versionContent.match(/VERSION\s*=\s*"([^"]+)"/);
|
||||
|
||||
if (!match) {
|
||||
console.error(`Error: Could not extract VERSION from src/version.ts`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const srcVersion = match[1];
|
||||
|
||||
if (pkgVersion !== srcVersion) {
|
||||
console.error(`Error: Version mismatch — package.json=${pkgVersion}, src/version.ts=${srcVersion}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Version consistency check passed: ${pkgVersion}`);
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,23 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
const cliEntry = path.join(projectRoot, "dist", "cli", "index.js");
|
||||
const shebang = "#!/usr/bin/env node\n";
|
||||
|
||||
if (!fs.existsSync(cliEntry)) {
|
||||
console.log(`dist/cli/index.js not found — skipping shebang check (build may not have run yet)`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(cliEntry, "utf-8");
|
||||
|
||||
if (content.startsWith(shebang.trim())) {
|
||||
console.log("Shebang already present in dist/cli/index.js");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const updated = shebang + content;
|
||||
fs.writeFileSync(cliEntry, updated, "utf-8");
|
||||
console.log("Prepended shebang to dist/cli/index.js");
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,55 @@
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
const ALLOWED_ENTRIES = ["dist/", "opencode/", "templates/", "LICENSE", "README.md", "package.json"];
|
||||
|
||||
function validatePack() {
|
||||
let output;
|
||||
try {
|
||||
output = execSync("npm pack --dry-run --json", { encoding: "utf-8" });
|
||||
} catch (err) {
|
||||
console.error("Failed to run npm pack --dry-run:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let packFiles;
|
||||
try {
|
||||
const parsed = JSON.parse(output);
|
||||
packFiles = Array.isArray(parsed) ? parsed[0].files : parsed.files;
|
||||
} catch (err) {
|
||||
console.error("Failed to parse npm pack output:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!packFiles || !Array.isArray(packFiles)) {
|
||||
console.error("No files array found in npm pack output");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const paths = packFiles.map((f) => f.path || f);
|
||||
|
||||
const unexpected = [];
|
||||
for (const p of paths) {
|
||||
const top = p.split("/")[0] || p;
|
||||
const allowed = ALLOWED_ENTRIES.some((entry) => {
|
||||
const e = entry.replace(/\/$/, "");
|
||||
return top === e || top === entry || p === entry;
|
||||
});
|
||||
if (!allowed) {
|
||||
unexpected.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (unexpected.length > 0) {
|
||||
console.error("Unexpected files in npm pack output:");
|
||||
for (const f of unexpected) {
|
||||
console.error(` - ${f}`);
|
||||
}
|
||||
console.error("");
|
||||
console.error("Allowed top-level entries:", ALLOWED_ENTRIES.join(", "));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("npm pack validation passed — all entries are allowed.");
|
||||
}
|
||||
|
||||
validatePack();
|
||||
Reference in New Issue
Block a user