+30
-7
@@ -54,3 +54,8 @@ // gspec build — deterministic orchestration runtime. | ||
| // can't spawn unbounded feature-writer agents. Drops are logged, not silent. | ||
| const MAX_FEATURES = 12; | ||
| // The ceiling is decoupled from concurrency: writers run at most | ||
| // FEATURE_WRITER_CONCURRENCY at a time (each is a real headless engine | ||
| // subprocess), so a large but legitimate breakdown gets all its PRDs without a | ||
| // thundering herd of simultaneous agents / API calls. | ||
| const MAX_FEATURES = 24; | ||
| const FEATURE_WRITER_CONCURRENCY = 5; | ||
@@ -121,2 +126,19 @@ // The build stage graph (design §8). Foundation stages are skip-if-present. | ||
| // Map `fn` over `items` with at most `limit` calls in flight, preserving input | ||
| // order in the result. A worker pool (not fixed batches) so a slow item doesn't | ||
| // stall the ones behind it. Used to bound how many headless writer subprocesses | ||
| // the features stage spawns at once — see FEATURE_WRITER_CONCURRENCY. | ||
| async function mapLimit(items, limit, fn) { | ||
| const results = new Array(items.length); | ||
| let next = 0; | ||
| async function worker() { | ||
| while (next < items.length) { | ||
| const i = next++; | ||
| results[i] = await fn(items[i], i); | ||
| } | ||
| } | ||
| await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker)); | ||
| return results; | ||
| } | ||
| // --- learnings capture (the learning loop's build channel) ----------------- | ||
@@ -497,7 +519,8 @@ // | ||
| log(chalk.dim(` decomposed into ${plan.length} feature(s): ${plan.map((f) => f.slug).join(', ')}`)); | ||
| // File-disjoint slugs (dedup guarantees it) → fan out in parallel, like | ||
| // the research stage. The planner already resolved overlap and named | ||
| // dependencies, so each writer cross-links siblings by slug without | ||
| // needing to read a not-yet-written sibling file. | ||
| const runs = await Promise.all(plan.map((f) => { | ||
| // File-disjoint slugs (dedup guarantees it) → fan out, at most | ||
| // FEATURE_WRITER_CONCURRENCY writers in flight so a big breakdown doesn't | ||
| // spawn a thundering herd of headless agents. The planner already | ||
| // resolved overlap and named dependencies, so each writer cross-links | ||
| // siblings by slug without needing to read a not-yet-written sibling file. | ||
| const runs = await mapLimit(plan, FEATURE_WRITER_CONCURRENCY, (f) => { | ||
| const deps = f.dependencies.filter((d) => d !== f.slug); | ||
@@ -512,3 +535,3 @@ const scope = [ | ||
| return runAgent(stage.writer, stageBrief(stage, brief, scope), ctx); | ||
| })); | ||
| }); | ||
| const bad = runs.findIndex((r) => r.code !== 0); | ||
@@ -515,0 +538,0 @@ if (bad >= 0) return { status: 'failed', reason: `${stage.writer} ("${plan[bad].slug}") exited ${runs[bad].code}` }; |
+1
-1
| { | ||
| "name": "gspec", | ||
| "version": "2.2.1", | ||
| "version": "2.2.2", | ||
| "description": "Install gspec specification commands for Claude Code, Cursor, and other AI tools", | ||
@@ -5,0 +5,0 @@ "main": "bin/gspec.js", |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2323176
0.05%4768
0.46%31
-3.12%