* chore: rename npm package + bin to @opengsd/gsd-core (functional) - package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core, bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs - package-lock.json: regenerated (npm install --package-lock-only) - tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**, get-shit-done/bin/**, get-shit-done/workflows/**: applied the 4-rule replacement (scoped npm ref, GitHub repo path, bin/clone invocations) per #505 single-source refactor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: sweep live references to @opengsd/gsd-core Update all live documentation (README.md + translations, docs/**, CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md, docs/CANARY.md) to reflect the renamed package and repository. Rules applied: - @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name) - open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo) - GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org) - bare bin/clone refs → gsd-core CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**, and .changeset/** are preserved byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: add negative lookbehind to slash-command regex in bug-2954 test The extractSlashReferences regex matched /gsd-core inside npm package URLs (@opengsd/gsd-core), producing a false /gsd:core command reference. Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#518): add changeset for package rename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#518): update package-identity expectations to the renamed coordinates The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL package.json, so their expected literals must follow the rename. The drift-lint unit test is left as-is — its SEAM is a self-consistent fixture and its stale-literal detection cases would shift if altered; the live-repo scan in it already passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
81 lines
3.0 KiB
JavaScript
81 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Phase Lifecycle Pure Helpers — pure-computation functions extracted from
|
|
* the phase-lifecycle SDK handler.
|
|
*
|
|
* I/O adapter pattern (ADR-3524 Section 4): each side supplies its own I/O
|
|
* (sync readFileSync for CJS, async readFile for SDK); the pure computation
|
|
* logic is shared via this generated artifact.
|
|
*
|
|
* Scope:
|
|
* - deriveProgressFromRoadmap(roadmapContent): count Complete rows => idempotent
|
|
* - clampPercent(completed, total): percent with 100 ceiling
|
|
*
|
|
* These two functions are the root-cause fix for issue #4.
|
|
*
|
|
* References:
|
|
* - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
|
|
* - Issue #4 (open-gsd/gsd-core)
|
|
*/
|
|
|
|
/**
|
|
* Derive completed_phases, total_phases, and total_plans from ROADMAP content.
|
|
* Root cause fix for issue #4 — see gen-phase-lifecycle.mjs for full documentation.
|
|
*/
|
|
function deriveProgressFromRoadmap(roadmapContent) {
|
|
let completedPhases = null;
|
|
let totalPhases = null;
|
|
let totalPlans = null;
|
|
|
|
try {
|
|
// Count Complete rows in the progress table (Status column = "Complete").
|
|
// Pattern: row where the phase cell starts with a digit (data row, not header),
|
|
// followed by any cell content, then a "Complete" status cell.
|
|
// Handles both short form ("| 4. |") and long form ("| 01. Foundation |").
|
|
// See phase-lifecycle.ts ~line 1655 for the original SDK pattern.
|
|
const tableCompletePattern = /\|\s*\d+[^|]*\|\s*[^|]*\|\s*Complete\s*\|/gi;
|
|
const completeMatches = roadmapContent.match(tableCompletePattern);
|
|
completedPhases = completeMatches ? completeMatches.length : null;
|
|
|
|
// Count total phase rows in the progress table.
|
|
// Identify the table by looking for Phase|...|Status|...|Completed header.
|
|
const progressTableMatch = roadmapContent.match(
|
|
/\|\s*Phase\s*\|[^|]*\|[^|]*Status[^|]*\|[^|]*Completed[^|]*\|[\s\S]*?(?=\n\n|\n##|$)/i,
|
|
);
|
|
if (progressTableMatch) {
|
|
const tableText = progressTableMatch[0];
|
|
// Count data rows (rows starting with pipe then a phase number)
|
|
const dataRowPattern = /^\|\s*\d+/gm;
|
|
const dataRows = tableText.match(dataRowPattern);
|
|
totalPhases = dataRows ? dataRows.length : null;
|
|
}
|
|
|
|
// Sum plan counts from M/N columns in progress table
|
|
let totalPlansSum = 0;
|
|
const planCellPattern = /\|\s*\d+[^|]*\|\s*(\d+)\/(\d+)\s*\|/gi;
|
|
let pm;
|
|
// eslint-disable-next-line no-cond-assign
|
|
while ((pm = planCellPattern.exec(roadmapContent)) !== null) {
|
|
totalPlansSum += parseInt(pm[2], 10);
|
|
}
|
|
if (totalPlansSum > 0) totalPlans = totalPlansSum;
|
|
} catch { /* intentionally empty — fall through to existing values */ }
|
|
|
|
return { completedPhases, totalPhases, totalPlans };
|
|
}
|
|
|
|
/**
|
|
* Compute progress percent clamped to 100.
|
|
* Root cause fix for issue #4 — see gen-phase-lifecycle.mjs for full documentation.
|
|
*/
|
|
function clampPercent(completed, total) {
|
|
if (!total || total <= 0) return 0;
|
|
return Math.min(100, Math.round((completed / total) * 100));
|
|
}
|
|
|
|
module.exports = {
|
|
deriveProgressFromRoadmap,
|
|
clampPercent,
|
|
};
|