All notable changes to this project will be documented in this file.
This is release history, not the canonical product frame. Older entries will naturally reflect prior roadmap eras and product language.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- git-warp v14 compatibility hardening — Explicit
Mapdetection in property-bag helpers, observermatchvalidation, epoch/review malformed-record filtering, and edge-property normalization for export/merge (#312) - CLI contract canary timeout consistency — Unified the CLI integration harness around a shared timeout budget and added edge-case coverage for the git-warp compatibility boundary (#312)
5.0.0 - 2026-02-25
getNodes(graph)wrapper — Usegraph.getNodes()directly (#295)hasNode(graph, id)wrapper — Usegraph.hasNode(id)directly (#295)saveGraph(graph)wrapper — Dead code with zero call sites (#295)queryEdges(graph, filter)wrapper — Usegraph.getEdges()with inline filter (#295)getNodesByPrefix(graph, prefix)wrapper — Usegraph.getNodes()withstartsWith()filter (#295)
- All internal
loadGraph()calls replaced withinitGraph()—loadGraphkept as deprecated alias for public API backward compatibility (#295)
4.0.1 - 2026-02-22
- OID guard in
writeContent()— Throw ifgetContentOid()returns null after a successful write, enforcing theWriteContentResult.sha: stringcontract (#284) - Error cause chain in
readContent()— Capture original error via{ cause: err }so callers can distinguish blob-not-found from infrastructure failures (#284) - Null guard in
readContent()— Changed!contentBufto explicitcontentBuf == nullfor clearer null/undefined intent (#284) - Null guard in
hasContent()— Changedsha !== nulltosha != nullto catch both null and undefined fromgetContentOid(), consistent with other callers (#284) - ROADMAP stale integrity-check language — Corrected binary content backlog item to reflect WARP-native blob storage; reframed
--verifyflag as OID existence check (#284) - JSDoc typedef terminology — Changed "Git blob SHA" / "Written blob SHA" to "Git blob OID" in
ContentMetaandWriteContentResulttypedefs (#284) - Dead
execSyncimport — Removed unusedexecSyncfromtest/content.test.js; onlyexecFileSyncis used (#284)
- Empty content edge-case test — Verifies
writeContent()handles empty string input correctly (size 0, round-trip intact) (#284)
4.0.0 - 2026-02-22
- BREAKING: Migrate content system to git-warp native API — Replaced custom CAS layer (
git hash-object/git cat-file) with@git-stunts/git-warpnativesetContent()/getContent()API. Content properties now use WARP'sCONTENT_PROPERTY_KEYinstead of custom_content.sha. Removes all direct git subprocess calls from content module (#284) - Test count — 577 tests across 29 files (was 571)
3.3.0 - 2026-02-22
- Content-on-node (M13 VESSEL) — Attach rich content to graph nodes using git's native CAS. Content stored as git blobs via
hash-object, SHA and metadata recorded as WARP node properties under the_content.*prefix (#271) git mind content set <node> --from <file>— Attach content from a file. MIME auto-detected from extension,--mimeoverride supported.--jsonoutput (#273)git mind content show <node>— Display attached content.--rawfor piping (body only, no metadata header).--jsonoutput (#273)git mind content meta <node>— Show content metadata (SHA, MIME, size, encoding).--jsonoutput (#273)git mind content delete <node>— Remove content attachment from a node.--jsonoutput (#273)- Content store API —
writeContent(),readContent(),getContentMeta(),hasContent(),deleteContent()exported from public API (#272) - SHA integrity verification —
readContent()re-hashes retrieved blob and compares to stored SHA on every read (#272) - JSON Schema contracts for content CLI —
content-set.schema.json,content-show.schema.json,content-meta.schema.jsonindocs/contracts/cli/(#274) - ADR-0004: Content Attachments Belong in git-warp — Decision record establishing that CAS-backed content-on-node is a git-warp substrate responsibility, not a git-mind domain concern. Aligns with Paper I's
Atom(p)attachment formalism (#252) - Chalk formatting for
extension list—formatExtensionList()renders extension names in cyan bold, versions dimmed,[builtin]in yellow /[custom]in magenta, consistent with all other CLI commands (#265) - Prefix collision detection —
registerExtension()now checks incoming domain prefixes against all registered extensions and throws a descriptive error on overlap. Idempotent re-registration of the same extension name is still allowed (#264) - Imperative views declared in extension manifests —
milestoneandprogressviews added to the roadmap manifest;traceability,coverage, andonboardingviews added to the architecture manifest. Purely declarative — makesextension listshow the full picture (#268) git mind extension remove <name>subcommand — Removes a custom extension from the registry. Throws on built-in or non-existent extensions.--jsonoutput supported.removeExtension()exported from public API (#263)- JSON Schema contracts for extension CLI output — 4 new schemas in
docs/contracts/cli/:extension-list,extension-validate,extension-add,extension-remove. Valid samples added to the contract test harness (#262) - Deferred items documented in ROADMAP — #261 (ephemeral registration) and #269 (
--extensionflag) documented with rationale and recommended H2 slot
- CRITICAL: Command injection in
readContent()— Replaced allexecSyncshell interpolation withexecFileSyncarg arrays + SHA validation regex. Zero shell invocations in content module (#276) - Dead
encodingparameter removed — Removed unusedencodingfield from content store, CLI format, JSON Schema contracts, and tests. Content is always UTF-8 (#276) - Static imports in content CLI — Replaced dynamic
await import('node:fs/promises')andawait import('node:path')with static imports (#276) nodeIdincontent showmetadata — Non-rawcontent shownow passesnodeIdtoformatContentMetafor consistent display (#276)- Schema
if/then/elseconditional —content-meta.schema.jsonenforcessha,mime, andsizerequired whenhasContentistrue; forbids them whenfalse(#276) - Redundant null check — Removed dead
sha !== undefinedinhasContent()—?? nullguarantees non-undefined (#276) - Misleading integrity test — Split into blob-not-found test + genuine integrity mismatch test using non-UTF-8 blob (#276)
- Test SHA assertions accept both SHA-1 (40 chars) and SHA-256 (64 chars) (#276)
- Schema test compile-once — Content schema validators compiled once in
beforeAllinstead of per-test; removed$idstripping workaround (#276) - Error-path CLI tests — 4 new tests: nonexistent file, node without content, non-existent node for show/delete (#276)
- MIME map extended — Added
.css→text/cssand.svg→image/svg+xml(#276) - YAML MIME type — Changed
.yaml/.ymlmapping fromtext/yamltoapplication/yaml(IANA standard) (#276) - Missing
content-delete.schema.jsoncontract — Added JSON Schema forcontent delete --jsonoutput (#276) - Content subcommand positional parsing —
extractPositionals()helper properly skips--flag valuepairs instead of naive!startsWith('--')check (#276)
- Upgraded
@git-stunts/git-warpfrom v11.3.3 to v11.5.0 registerBuiltinExtensions()memoized — Module-levelbuiltInsLoadedflag prevents redundant YAML file reads on repeated invocations within the same process (#266)- Test count — 571 tests across 29 files (was 537)
3.2.0 - 2026-02-17
- Upgraded
@git-stunts/git-warpfrom v10.3.2 to v11.3.3
- Composable view lenses — Post-filter views with chainable lenses using colon syntax:
git mind view roadmap:incomplete:frontier. Lenses compose left-to-right (#250) - 5 built-in lenses —
incomplete(filter to unfinished nodes),frontier(leaf nodes — ready to start),critical-path(longest dependency chain via DP),blocked(nodes with unresolved blockers),parallel(nodes with no mutual dependencies) (#250) - DAG utilities — Pure graph helpers in
src/dag.js:buildAdjacency,topoSort,detectCycles,walkChain,findRoots(#250) - Lens registry and composition API —
defineLens,getLens,listLenses,composeLenses,resetLenses,captureBuiltInsexported fromsrc/lens.jsand public API (#250) view-lens.schema.jsoncontract — JSON Schema forgit mind view --jsonoutput when lenses are applied, includinglensesarray and strict edge constraints (#250)- Governance tooling — Pre-commit hook, mechanical architecture gate CI workflow, PR template with hard-gate checkboxes, review checklist script (#250)
- Architecture docs —
docs/VISION_NORTH_STAR.md,docs/ARCHITECTURE.md,docs/RISK_REGISTER.md,docs/REVIEW_RUBRIC.md, ADR-0001, ADR-0002 (#250)
renderViewacceptsoptions.lenses— View pipeline applies lens composition after view filtering. Node properties fetched only when view or any lens requires them (#250)git mind viewhelp — Usage string updated toview [name[:lens1:lens2]]with lens list (#250)view --jsonpayload —{ ...result, viewName, lenses? }— spread order fixed sorenderViewproperties are never shadowed (#250)- Blocker and onboarding views — Refactored to use DAG helpers from
src/dag.js(#250) defineLenswarns on built-in overwrite — Console warning emitted if a registered built-in is overwritten beforeresetLenses()is called (#250)- Test count — 461 tests across 24 files (was 412)
3.1.0 - 2026-02-14
git mind set <nodeId> <key> <value>command — Set node properties directly from the CLI. Returnspreviousvalue andchangedboolean for idempotent automation. Supports--jsonoutput (#222)git mind unset <nodeId> <key>command — Remove a node property. Returnspreviousvalue andremovedboolean. Supports--jsonoutput (#222)setNodeProperty()+unsetNodeProperty()API — Programmatic node property CRUD insrc/nodes.js, exported from public API (#222)classifyStatus()helper — Normalizes status values with synonym mapping (WIP→in-progress,Done→done, etc.). Canonical values:todo,in-progress,blocked,done. Exported fromsrc/views.jsand public API (#222)progressview — Groupstask:andfeature:nodes bystatusproperty, shows completion percentage and per-status counts. UsesclassifyStatus()for synonym normalization (#222)- JSON Schema contracts —
set.schema.json,unset.schema.json, andview-progress.schema.jsonindocs/contracts/cli/with integration canary tests (#222) --jsonflag forviewcommand —git mind view progress --jsonreturns structured output validated againstview-progress.schema.json(#222)--scopeflag forview progress—git mind view progress --scope taskfilters by prefix. Default scope:task,feature(#222)ratioandremainingin progress summary —meta.summarynow includesratio(e.g."3/5") andremainingcount for JSON consumers (#222)- Sorted progress bucket IDs —
meta.byStatusarrays are alphabetically sorted for deterministic output (#222)
renderViewpasses node properties and options — View filter functions receive a thirdnodePropsargument and fourthoptionsargument. Only properties fetched when the view declaresneedsProperties: true, so existing views have zero overhead (#222)ViewDefinitiontypedef updated —filterFnsignature now reflects all four parameters (nodes,edges,nodeProps,options) and theneedsPropertiesoption (#222)formatViewuses explicit view name — Progress view routing now checksviewName === 'progress'instead of duck-typingmeta.summary.pct(#222)setcommand rejects flags as values —git mind set task:a status --jsonnow errors instead of storing"--json"as the property value (#222)- Same-tick diff shortcut marks result as skipped —
stats.skipped: trueandtotal: nulldistinguish "graph unchanged" from "empty graph" (#222) formatProgressMetashows remaining count — Terminal header now readsProgress: 60% (3/5 done, 2 remaining)(#222)DiffResulttypedef nullable totals — JSDoc updated:nodes.totalandedges.totalare{ before, after } | nullwhen diff is skipped (#222)- Test count — 412 tests across 22 files (was 371)
- Suppress
DEP0169warning — Shebang updated to--disable-warning=DEP0169; silencesurl.parse()deprecation from transitive deproaring→@mapbox/node-pre-gyp(#222)
3.0.0 - 2026-02-13
schemaVersion: 1andcommandfields in all--jsonoutputs — Every CLI command that supports--jsonnow includes aschemaVersion(integer, currently1) andcommand(string) field in its output envelope. The CLI layer is authoritative via theoutputJson()helper (#205)- JSON Schema files — 13 Draft 2020-12 JSON Schema files in
docs/contracts/cli/for programmatic validation of every--jsonoutput. StrictadditionalProperties: falseat top level; open objects where extensibility is intentional (node properties, prefix maps) (#205) - Contract validation tests —
test/contracts.test.js(17 unit tests) validates schema compilation, envelope requirements, sample payloads, and optional field handling.test/contracts.integration.test.js(12 CLI canary tests) executes the real binary and validates output against schemas usingajv(#205) - CLI Contracts documentation —
docs/contracts/CLI_CONTRACTS.mdwith version policy, command-to-schema table, programmatic validation example, and migration guide (#205)
nodes --jsonoutput wrapped — Previously returned a bare JSON array; now returns{ schemaVersion: 1, command: "nodes", nodes: [...] }. Migration:jq '.[]'→jq '.nodes[]'(#205)review --jsonoutput wrapped — Previously returned a bare JSON array; now returns{ schemaVersion: 1, command: "review", pending: [...] }. Migration:jq '.[].source'→jq '.pending[].source'(#205)
- Test count — 371 tests across 22 files (was 342 across 20)
2.0.0-alpha.5 - 2026-02-13
git mind diffcommand — Compare the knowledge graph between two historical commits. Resolves git refs to epoch markers, materializes both snapshots, and reports node/edge additions and removals with summary tables. Supports range syntax (A..B), two-arg syntax (A B), and shorthand (AforA..HEAD).--jsonoutput includesschemaVersion: 1for forward compatibility.--prefixscopes the diff to a single node prefix (#203)- Diff API —
computeDiff(cwd, refA, refB, opts)for full orchestration,diffSnapshots(graphA, graphB, opts)for pure snapshot comparison insrc/diff.js. Both exported from public API (#203)
--prefixvalue leaks into positional args —git mind diff HEAD~1..HEAD --prefix taskincorrectly treatedtaskas a second ref argument. ExtractedcollectDiffPositionals()helper that skips flag values consumed by non-boolean flags (#203)- Same-tick shortcut reports zero totals — When both refs resolve to the same Lamport tick,
computeDiffreturnedtotal: { before: 0, after: 0 }which misrepresents an unchanged graph as empty. Now includesstats.sameTick: trueso JSON consumers can distinguish "unchanged" from "empty graph" (#203)
- Test count — 342 tests across 20 files (was 312 across 19)
2.0.0-alpha.4 - 2026-02-13
git mind at <ref>command — Time-travel: materialize the graph at a historical point via epoch markers. Resolves git refs to Lamport ticks and filters the CRDT graph to that ceiling. Supports--jsonoutput with epoch metadata (#202)- Epoch API —
getCurrentTick(graph),recordEpoch(graph, sha, tick),lookupEpoch(graph, sha),lookupNearestEpoch(graph, cwd, sha),getEpochForRef(graph, cwd, ref)insrc/epoch.js(#202) - Automatic epoch recording —
processCommitnow records an epoch marker after processing each commit, correlating the commit SHA to the current Lamport tick (#202)
- Shell injection in
src/epoch.js— ReplacedexecSyncstring interpolation withexecFileSyncarray args inlookupNearestEpochandgetEpochForRef, preventing command injection via crafted ref names (#202) - Missing
contentspermission ingitmind-review.yml— Workflow now includescontents: readsoactions/checkoutcan fetch the repo; unspecified scopes default tononewhenpermissionsis explicit (#200) action.ymlignores workflow-levelGITMIND_AGENT— Validation step no longer overrides inherited env var with emptyinputs.agent; suggest step falls back toenv.GITMIND_AGENT(#199)parseReviewCommandaccepts index 0 — Now returnsnullfor index< 1since suggestions are 1-indexed (#200)- Backtick characters in PR suggestion table —
formatSuggestionsAsMarkdownstrips backticks from source/target to prevent breaking inline code spans (#200) findMarkdownFilesswallows all errors — Now only catchesENOENT/ENOTDIR; permission errors and other failures propagate (#196)extractGraphDatastrips extension from directory name —String.replacewithextnameonly replaced the first.mdoccurrence; now usessliceto target only the trailing extension (#196)qualifyNodeIdunhelpful error for non-prefixed IDs — Now throws a descriptive error mentioningprefix:identifierformat instead of falling through tobuildCrossRepoId's generic validation (#197)qualifyNodeIdaccepts multi-colon local IDs —a:b:cnow throws a clear error instead of falling through tobuildCrossRepoId's generic validation (#197)formatSuggestionsAsMarkdowncrashes on missingtype— All suggestion fields (source,target,type,confidence,rationale) now have null-coalescing guards (#200)- Empty pending list produces confusing range —
reviewCmdnow says "No pending suggestions to review" instead of "Index N out of range (1-0)" (#200) import/exportpositional arg breaks with preceding flags — Bothgit mind import --dry-run file.yamlandgit mind export --format json file.yamlnow scan for the first non-flag argument (#196, #195)- Frontmatter closing delimiter matches
---suffix—parseFrontmatternow requires---followed by newline or EOF (#196) - Doctor orphan detection uses hardcoded prefixes — Now uses
SYSTEM_PREFIXESfrom validators plusdecisioninstead of hardcodedstartsWithchecks (#201) - Epoch SHA truncation too short — Widened from 8 to 12 characters to reduce birthday-paradox collision risk (#202)
serializeExportsilently falls back to YAML — Now throws on unsupported format instead of silently defaulting (#195)- Empty
catchinprocessCommit— Epoch recording errors now logged whenGITMIND_DEBUGis set (#202) gitmind-review.ymlechofor untrusted input — Replaced withprintf '%s'to prevent-n/-e/backslash misbehavior (#200)
epochadded toSYSTEM_PREFIXES— Epoch markers use theepoch:prefix, classified as system. Excluded from export and doctor orphan detection (#202)- Permission test skipped under root —
findMarkdownFileschmod test now skips when running as root (CI containers) (#196) - Test count — 312 tests across 19 files (was 286 across 18)
2.0.0-alpha.3 - 2026-02-12
git mind exportcommand — Serialize the graph to YAML or JSON in v1 import-compatible format, enabling round-trip workflows. Supports--format yaml|json,--prefix <prefix>filtering, file output or stdout, and--jsonfor structured metadata (#195)- Export API —
exportGraph(graph, opts),serializeExport(data, format),exportToFile(graph, path, opts)insrc/export.js(#195) git mind import --from-markdowncommand — Import nodes and edges from markdown file frontmatter. Auto-generatesdoc:IDs from file paths, recognizes all 8 edge types as frontmatter fields. Supports--dry-run,--json, glob patterns (#196)- Frontmatter API —
parseFrontmatter(content),extractGraphData(path, frontmatter),findMarkdownFiles(basePath, pattern),importFromMarkdown(graph, cwd, pattern, opts)insrc/frontmatter.js(#196) importDatashared pipeline — Extracted fromimportFileinsrc/import.jsfor reuse by frontmatter import and future merge (#196)- Cross-repo edge protocol —
repo:owner/name:prefix:identifiersyntax for referencing nodes in other repositories.git mind link --remote <owner/name>qualifies local IDs. Validators accept cross-repo format,extractPrefixreturns inner prefix (#197) - Remote API —
parseCrossRepoId,buildCrossRepoId,isCrossRepoId,extractRepo,qualifyNodeIdinsrc/remote.js(#197) git mind mergecommand — Merge another repository's graph into the local graph with cross-repo qualification. Supports--from <path>,--repo-name <owner/name>,--dry-run,--json. Auto-detects repo identifier from origin remote (#198)- Merge API —
mergeFromRepo(localGraph, remotePath, opts),detectRepoIdentifier(repoPath)insrc/merge.js(#198) - GitHub Action — Composite action (
action.yml) that runsgit mind suggeston PRs and posts formatted suggestions as a comment. Configurable agent command via action input or.github/git-mind.yml(#199) - PR suggestion display —
formatSuggestionsAsMarkdownrenders suggestions as a markdown table with/gitmind accept|reject|accept-allcommands.parseReviewCommandparses slash commands from comment bodies (#200) - Slash command workflow —
.github/workflows/gitmind-review.ymlhandles/gitmind accept N,/gitmind reject N, and/gitmind accept-allcommands in PR comments (#200)
- Privileged workflow checkout —
gitmind-review.ymlnow checks out the default branch (trusted code) instead of the PR head ref, preventing untrusted code execution inissue_commentcontext. Permissions scoped topull-requests: writeandissues: writeonly (#200) - Shell injection in
post-comment.js— Comment body passed via stdin (--input -) instead of shell interpolation, preventing backtick command substitution. Repo and PR number validated before use (#199) BOOLEAN_FLAGSmissingdry-runandvalidate—parseFlagsnow treats--dry-runand--validateas boolean flags instead of consuming the next argument as their value (#195, #198)- Pipe characters in markdown table —
formatSuggestionsAsMarkdownescapes|in rationale and type fields to prevent table row corruption (#200) - Frontmatter CRLF handling —
parseFrontmatternow finds the first newline dynamically instead of assuming\nat offset 4, supporting Windows line endings (#196) buildCrossRepoIdvalidation — Throws on malformedlocalIdmissingprefix:identifierformat instead of producing an invalid cross-repo ID (#197)- Orphaned JSDoc —
formatExportResultmoved aboveformatImportResult's JSDoc block to restore correct documentation association (#195) - Accept/reject workflow stubs — Individual
/gitmind accept Nand/gitmind reject Nnow respond with "not yet supported" instead of silently appearing to succeed (#200) action.ymlstderr mixing — Suggest step redirects stderr to/dev/nullinstead of mixing it into JSON output (#199)
repoadded toSYSTEM_PREFIXES— Cross-repo IDs use therepo:prefix, now classified as system (#197)- Test count — 286 tests across 18 files (was 208 across 13)
2.0.0-alpha.2 - 2026-02-11
git mind doctorcommand — Graph integrity checking with four composable detectors: dangling edges (error), orphan milestones (warning), orphan nodes (info), low-confidence edges (info). Supports--fixto auto-remove dangling edges,--jsonfor structured output. Exit code 1 on errors (#193)- Doctor API —
runDoctor(graph),fixIssues(graph, issues), and individual detectors (detectDanglingEdges,detectOrphanMilestones,detectOrphanNodes,detectLowConfidenceEdges) insrc/doctor.js(#193) - Git context extraction —
src/context.jsextracts file, commit, and graph context for LLM prompts. Language inference from file extensions. Size-bounded prompt generation (~4000 chars) (#193) git mind suggestcommand — AI-powered edge suggestions viaGITMIND_AGENTenv var. Shells out to any command (stdin prompt, stdout JSON). Supports--agent <cmd>,--context <sha-range>,--json. Zero new dependencies (#193)- Suggest API —
callAgent(prompt),parseSuggestions(text)(handles raw JSON and markdown code fences),filterRejected(suggestions, graph),generateSuggestions(cwd, graph)insrc/suggest.js(#193) git mind reviewcommand — Interactive review of pending suggestions with[a]ccept / [r]eject / [s]kipprompts via readline. Non-interactive batch mode via--batch accept|reject.--jsonoutput (#193)- Review API —
getPendingSuggestions(graph),acceptSuggestion(promotes confidence to 1.0),rejectSuggestion(removes edge),adjustSuggestion(updates edge props),skipSuggestion(no-op),getReviewHistory,batchDecisioninsrc/review.js(#193) - Decision provenance — Review decisions stored as
decision:prefixed nodes with action, source, target, edgeType, confidence, rationale, timestamp, and reviewer properties. Rejected edges excluded from future suggestions (#193) coverageview — Code-to-spec gap analysis: identifiescrate:/module:/pkg:nodes lackingimplementsedges tospec:/adr:targets. Returnsmeta.linked,meta.unlinked, andmeta.coveragePct(#191)- Echo ecosystem seed fixture —
test/fixtures/echo-seed.yamlwith 55 nodes and 70 edges for integration testing (#191) - PROVING GROUND integration tests —
test/proving-ground.test.jsvalidates 5 real project management questions against the Echo seed with deterministic ground truth (#191) - Dogfood session transcript —
docs/dogfood-session.mddocuments CLI walkthrough of all 5 questions (#191)
parseFlagsboolean flag handling —--jsonand--fixno longer consume the next argument as a value, fixinggit mind suggest --json --agent <cmd>(#193)- Shell injection in
extractCommitContext—opts.rangevalidated against shell metacharacters; commit SHAs validated as hex before interpolation intoexecSync(#193) - ReDoS in
parseSuggestions— Replaced polynomial regex for code fence extraction with non-backtracking pattern; replaced greedy array regex withindexOf/lastIndexOf(#193) - Agent subprocess timeout —
callAgentnow enforces a configurable timeout (default 2 min) viaopts.timeout, killing hung agent processes (#193) - Readline leak in interactive review —
rl.close()now called viatry/finallyto prevent terminal state corruption on error (#193) - Non-atomic edge type change in
adjustSuggestion— New edge created before old edge removed, preventing data loss ifcreateEdgethrows (#193) - Magic confidence default —
adjustSuggestionnow preservesoriginal.confidenceinstead of silently defaulting to 0.8 (#193) batchDecisionaction validation — Throws on invalid action instead of silently falling through to reject (#193)- Loose file node matching —
extractGraphContextuses exact match (file:${fp}) or suffix match instead ofincludes()to prevent false positives (#193) fixResult.detailsguard —formatDoctorResulthandles undefineddetailsarray with nullish coalescing (#193)makeDecisionIdJSDoc — Updated to say "unique" instead of "deterministic" since it includesDate.now()(#193)fixIssuesnamed properties — Usesissue.source/issue.target/issue.edgeTypeinstead of positional destructuring (#193)- N+1 query optimization —
getPendingSuggestions,getReviewHistory, andfilterRejectedusePromise.allfor concurrent node prop fetches (#193) - Consistent flag handling —
doctor,suggest,reviewCLI commands read--json/--fixfromparseFlagsinstead of mixingargs.includes()(#193) - Sanitize
opts.limit—extractCommitContextcoerces limit to safe integer (1–100) before shell interpolation (#193) - Expanded sanitization blocklist —
sanitizeGitArgnow also rejects<,>,\n,\r(#193) - Unused import removed —
extractPrefiximport removed fromsrc/doctor.js(#193) - Decision nodes excluded from orphan detection —
detectOrphanNodesskipsdecision:prefix nodes (#193) - Defensive guard on
result.errors—formatSuggestionsuses optional chaining forresult.errors(#193) - ReDoS fence regex eliminated — Replaced regex-based code fence extraction with
indexOf-based approach (#193) skipSuggestiondocumented as deferred — JSDoc clarifies skip is intentional defer, not dismiss (#193)- Single-writer assumption documented —
acceptSuggestionandadjustSuggestionJSDoc notes edge must exist (#193) formatDecisionSummaryguard —result.decisionsnow defaults to[]via nullish coalescing to prevent TypeError (#193)DoctorIssuetypedef updated — Added optionalsource,target,edgeTypeproperties used by dangling-edge issues (#193)adjustSuggestionsetsreviewedAton type change — New edge created during type change now receives areviewedAttimestamp (#193)generateSuggestionsrejection diagnostic — ReturnsrejectedCountand logs a diagnostic when all suggestions were previously rejected (#193)child.stdinerror handler —callAgentattaches a no-op error listener on stdin to prevent uncaught EPIPE exceptions (#193)- Doctor test fixture corrected — Dangling-edge test issue now includes
source/target/edgeTypematchingfixIssuesexpectations (#193) buildPromptdefensive guards — Handles nullishcontext.graph/commits/fileswith defaults instead of throwing TypeError (#193)fetchDecisionPropsshared helper — Extracted duplicated decision-node fetch logic fromgetPendingSuggestionsandgetReviewHistoryinto a reusable helper (#193)
suggestandreviewstubs replaced with full implementations (#193)- Test count — 208 tests across 13 files (was 143 across 8)
- Node query API —
src/nodes.jspromotes nodes from implicit edge endpoints to first-class queryable entities:getNodes(),hasNode(),getNode(),getNodesByPrefix() getNode()returns full node info — ID, extracted prefix, prefix classification (canonical/system/unknown), and properties from the materialized graphgit mind nodescommand — List and inspect nodes with--prefix <prefix>filtering,--id <nodeId>single-node detail, and--jsonoutput- Node formatting —
formatNode()andformatNodeList()insrc/cli/format.jsfor terminal display git mind statuscommand — Graph health dashboard showing node counts by prefix, edge counts by type, blocked items, low-confidence edges, and orphan nodes. Supports--jsonfor CI pipelines- Status computation API —
computeStatus(graph)insrc/status.jsreturns structured summary of graph state - YAML import pipeline —
git mind import <file>with schema-validated ingestion (version: 1required), idempotent merge semantics, reference validation (no dangling edges), and atomic writes (all-or-nothing) - Import API —
importFile(graph, path, { dryRun }),parseImportFile(),validateImportData()insrc/import.js; exported from public API - Import CLI flags —
--dry-runvalidates without writing,--validate(alias),--jsonfor structured output - Node properties in import — YAML nodes can declare
properties:key/value maps, written viapatch.setProperty() - Declarative view engine —
declareView(name, config)compiles prefix/type filter configs into views; existingroadmap,architecture,backlogviews refactored to declarative configs milestoneview — progress tracking per milestone: child task counts, completion percentage, blockerstraceabilityview — spec-to-implementation gap analysis: identifies unimplemented specs/ADRs, reports coverage percentageblockersview — transitive blocking chain resolution with cycle detection, root blocker identificationonboardingview — topologically-sorted reading order for doc/spec/ADR nodes with cycle detection- Schema validators —
src/validators.jsenforces GRAPH_SCHEMA.md at runtime: node ID grammar (prefix:identifier), edge type validation, confidence type safety (rejects NaN/Infinity/strings), self-edge rejection forblocksanddepends-on, prefix classification with warnings for unknown prefixes - Validator exports —
validateNodeId,validateEdgeType,validateConfidence,validateEdge,extractPrefix,classifyPrefix, plus constantsNODE_ID_REGEX,NODE_ID_MAX_LENGTH,CANONICAL_PREFIXES,SYSTEM_PREFIXES
buildChainstack overflow on cyclic graphs — Root blocker leading into a cycle (e.g.,C → A → B → A) caused infinite recursion; added visited guard (#189)- Duplicate cycle reports in blockers view — Per-root DFS visited sets caused the same cycle to be reported from multiple entry points; switched to global visited set (#189)
- O(n*m) lookups in traceability/onboarding views — Replaced
Array.includes()withSet.has()for spec and sorted membership checks (#189) - YAML arrays now rejected by
parseImportFile—typeof [] === 'object'no longer bypasses the guard; arrays produce "not an object" error instead of a confusing "Missing version" (#187) - Array-typed
node.propertiesrejected during validation —validateImportDatanow rejects arrays inproperties, preventingObject.entriesfrom writing numeric-indexed keys (#187) - Edge
createdAtrenamed toimportedAt— The timestamp on imported edges now honestly reflects import time; avoids misleading "creation" semantics on re-import (#187) --validatealias documented in CLI help — Usage text now shows--dry-run, --validate(#187)
blockedItemsnow counts distinct blocked targets — Previously countedblocksedges; now uses aSeton edge targets so two edges blocking the same node count as one blocked item (#185)isLowConfidence()shared helper — Low-confidence threshold (< 0.5) extracted fromstatus.jsandviews.jsintovalidators.jsto keep the threshold in one place (#185)createEdge()now validates all inputs — Node IDs must useprefix:identifierformat, confidence must be a finite number, self-edges rejected for blocking typesEDGE_TYPEScanonical source moved tovalidators.js(re-exported fromedges.jsfor backwards compatibility)resetViews()for test cleanup — Removes test-registered views from the module-level registry, restoring built-in-only state (#189)builtInNamesinitialized defensively — PreventsTypeErrorifresetViews()is called before module finishes init (#189)- Removed dead
|| 0fallback in onboarding view —inDegreemap is pre-initialized for all doc nodes, so the guard was unreachable (#189) - Milestone view returns self-contained subgraph — Edge filter tightened from
||to&&so returned edges only reference nodes in the result; eliminates danglingimplementsreferences to spec nodes (#189) - Onboarding view returns self-contained subgraph — Same
||→&&fix applied todocEdgesfilter; prevents non-doc nodes (e.g.,file:) from appearing as dangling edge endpoints (#189) declareViewvalidatesconfig.prefixes— Throws on missing or empty prefixes array, surfacing misconfiguration early (#189)- Milestone view O(M×E) → O(E+M) edge lookups — Pre-indexes
belongs-toandblocksedges by target before the milestone loop (#189) - Onboarding ordering loop uses pre-filtered
docEdges— Eliminates redundantdocSet.has()checks in dependency graph construction (#189) - Test count — 143 tests across 8 files (was 74)
2.0.0-alpha.0 - 2026-02-07
Complete rewrite from C23 to Node.js on @git-stunts/git-warp.
- Graph module — Initialize, load, and checkpoint WARP graphs in any Git repo
- Edge CRUD — Create, query, and remove typed edges with confidence scores
- 8 edge types —
implements,augments,relates-to,blocks,belongs-to,consumed-by,depends-on,documents - Observer views — Filtered projections:
roadmap,architecture,backlog,suggestions - Commit hooks — Parse directives (
IMPLEMENTS:,AUGMENTS:, etc.) from commit messages to auto-create edges - CLI —
git mind init,link,list,view,suggest(stub),review(stub) - 25 tests — Full coverage of graph, edges, views, and hooks modules
- License — Changed from MIND-UCAL-1.0 to Apache-2.0
- Architecture — Replaced C23 hexagonal architecture (libgit2, libsodium, CBOR, Roaring Bitmaps) with a thin Node.js wrapper around git-warp's CRDT graph engine
- All C23 source code (archived on
archive/c23-finalbranch) - Meson build system
- Docker-based CI/CD
- All C-specific documentation