Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ The repository is in a stabilize-and-clarify phase:
- the inward-facing cognition thesis has moved to `think`
- `git-mind` is being narrowed around semantic repository intelligence
- existing graph capabilities remain real and useful
- the first `git mind bootstrap` command contract exists, with scanner and
inference behavior planned in follow-up slices
- future work should be judged against the low-input semantic bootstrap hill

## Documentation
Expand Down
12 changes: 6 additions & 6 deletions TECHNICAL-TEARDOWN.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ The distinction matters. The code can already store, inspect, filter, and diff
semantic knowledge. The planned product move is to make the first useful graph
appear from repository artifacts themselves: code files, docs, ADRs, commit
history, issue references, PR references, and eventually review artifacts. The
new feature profile documents and graph data model describe that future contract,
but the CLI does not yet expose a `bootstrap` command.
CLI now exposes the first `git mind bootstrap` command contract, but the
repository scanner and inference pipeline are still planned follow-up slices.

## The Exact Entry Point

Expand Down Expand Up @@ -201,10 +201,10 @@ Program bootstrapping is what `bin/git-mind.js` does every time it starts. It
imports modules, parses arguments, constructs context objects when needed, and
dispatches one command.

Product bootstrapping is the planned Hill 1 feature: `git mind bootstrap`. That
future flow should scan an unfamiliar repository and infer a first semantic map.
The design documents specify this direction, but the current executable command
set does not include that command yet.
Product bootstrapping is the Hill 1 feature surfaced as `git mind bootstrap`.
The current executable command establishes the JSON and dry-run contract. Later
slices will fill that contract by scanning an unfamiliar repository and inferring
a first semantic map.

Runtime begins after command dispatch. At runtime, each command decides whether
it needs a graph, opens that graph with `initGraph(cwd)`, performs reads or
Expand Down
14 changes: 13 additions & 1 deletion bin/git-mind.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Usage: git mind <command> [options]
*/

import { init, link, view, list, remove, nodes, status, at, importCmd, importMarkdownCmd, exportCmd, mergeCmd, installHooks, processCommitCmd, doctor, suggest, review, diff, set, unsetCmd, contentSet, contentShow, contentMeta, contentDelete, extensionList, extensionValidate, extensionAdd, extensionRemove } from '../src/cli/commands.js';
import { init, bootstrap, link, view, list, remove, nodes, status, at, importCmd, importMarkdownCmd, exportCmd, mergeCmd, installHooks, processCommitCmd, doctor, suggest, review, diff, set, unsetCmd, contentSet, contentShow, contentMeta, contentDelete, extensionList, extensionValidate, extensionAdd, extensionRemove } from '../src/cli/commands.js';
import { parseDiffRefs, collectDiffPositionals } from '../src/diff.js';
import { createContext } from '../src/context-envelope.js';
import { registerBuiltinExtensions } from '../src/extension.js';
Expand All @@ -24,6 +24,9 @@ Context flags (read commands: view, nodes, status, export, doctor):

Commands:
init Initialize git-mind in this repo
bootstrap Build the first semantic map skeleton
--dry-run Preview without writing graph state
--json Output as JSON
link <source> <target> Create a semantic edge
--type <type> Edge type (default: relates-to)
--confidence <n> Confidence 0.0-1.0 (default: 1.0)
Expand Down Expand Up @@ -175,6 +178,15 @@ switch (command) {
await init(cwd);
break;

case 'bootstrap': {
const bootstrapFlags = parseFlags(args.slice(1));
await bootstrap(cwd, {
dryRun: bootstrapFlags['dry-run'] === true,
json: bootstrapFlags.json === true,
});
Comment on lines +181 to +186

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject unknown bootstrap flags before running

In the new bootstrap dispatch, parseFlags accepts any unrecognized --... and this handler only reads dry-run/json, so a typo like git mind bootstrap --dryrun --json silently consumes --json as the unknown flag's value and runs in non-dry-run, non-JSON mode instead of failing. Because --dry-run is the command's no-write safety switch, validate the allowed bootstrap flags/positionals before calling bootstrap.

Useful? React with 👍 / 👎.

break;
}

case 'link': {
const source = args[1];
const target = args[2];
Expand Down
1 change: 1 addition & 0 deletions docs/contracts/CLI_CONTRACTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Every `--json` output from the git-mind CLI includes a standard envelope:

| Command | Schema File |
|---------|-------------|
| `bootstrap --json` | [`bootstrap.schema.json`](cli/bootstrap.schema.json) |
| `nodes --id <id> --json` | [`node-detail.schema.json`](cli/node-detail.schema.json) |
| `nodes --json` | [`node-list.schema.json`](cli/node-list.schema.json) |
| `status --json` | [`status.schema.json`](cli/status.schema.json) |
Expand Down
151 changes: 151 additions & 0 deletions docs/contracts/cli/bootstrap.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/neuroglyph/git-mind/docs/contracts/cli/bootstrap.schema.json",
"title": "git-mind bootstrap --json",
"description": "Bootstrap summary output from `git mind bootstrap --json`",
"type": "object",
"required": [
"schemaVersion",
"command",
"dryRun",
"artifacts",
"entities",
"relationships",
"confidence",
"provenance",
"warnings",
"next"
],
"additionalProperties": false,
"properties": {
"schemaVersion": {
"type": "integer",
"const": 1
},
"command": {
"type": "string",
"const": "bootstrap"
},
"dryRun": {
"type": "boolean"
},
"artifacts": {
"type": "object",
"required": ["scanned", "byKind", "skipped", "warnings"],
"additionalProperties": false,
"properties": {
"scanned": {
"type": "integer",
"minimum": 0
},
"byKind": {
"type": "object",
"additionalProperties": {
"type": "integer",
"minimum": 0
}
},
"skipped": {
"type": "integer",
"minimum": 0
},
"warnings": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"entities": {
"type": "object",
"required": ["created", "unchanged", "byPrefix"],
"additionalProperties": false,
"properties": {
"created": {
"type": "integer",
"minimum": 0
},
"unchanged": {
"type": "integer",
"minimum": 0
},
"byPrefix": {
"type": "object",
"additionalProperties": {
"type": "integer",
"minimum": 0
}
}
}
},
"relationships": {
"type": "object",
"required": ["created", "unchanged", "byType"],
"additionalProperties": false,
"properties": {
"created": {
"type": "integer",
"minimum": 0
},
"unchanged": {
"type": "integer",
"minimum": 0
},
"byType": {
"type": "object",
"additionalProperties": {
"type": "integer",
"minimum": 0
}
}
}
},
"confidence": {
"type": "object",
"required": ["high", "medium", "low"],
"additionalProperties": false,
"properties": {
"high": {
"type": "integer",
"minimum": 0
},
"medium": {
"type": "integer",
"minimum": 0
},
"low": {
"type": "integer",
"minimum": 0
}
}
},
"provenance": {
"type": "object",
"required": ["inferred", "missing"],
"additionalProperties": false,
"properties": {
"inferred": {
"type": "integer",
"minimum": 0
},
"missing": {
"type": "integer",
"minimum": 0
}
}
},
"warnings": {
"type": "array",
"items": {
"type": "string"
}
},
"next": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
6 changes: 4 additions & 2 deletions docs/design/feature-profiles/bootstrap-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ Initial JSON shape:
```json
{
"schemaVersion": 1,
"command": "bootstrap",
"dryRun": true,
"artifacts": { "scanned": 0, "byKind": {} },
"artifacts": { "scanned": 0, "byKind": {}, "skipped": 0, "warnings": [] },
"entities": { "created": 0, "unchanged": 0, "byPrefix": {} },
"relationships": { "created": 0, "unchanged": 0, "byType": {} },
"confidence": { "high": 0, "medium": 0, "low": 0 },
"provenance": { "inferred": 0, "missing": 0 },
"warnings": [],
"followUp": []
"next": ["git mind status", "git mind nodes", "git mind review"]
}
```

Expand Down
3 changes: 2 additions & 1 deletion docs/design/h1-semantic-bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ Suggested command shape:
git mind bootstrap
```

> Status: planned contract for Hill 1. This command is not implemented in the current CLI yet.
> Status: initial executable contract. The current CLI exposes the command and
> dry-run JSON shape; repository scanning and inference land in later slices.

Possible compatible aliases later:

Expand Down
68 changes: 68 additions & 0 deletions src/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @module bootstrap
* Hill 1 semantic bootstrap contract helpers.
*/

export const BOOTSTRAP_NEXT_COMMANDS = [
'git mind status',
'git mind nodes',
'git mind review',
];

/**
* @typedef {object} BootstrapSummary
* @property {boolean} dryRun
* @property {{ scanned: number, byKind: Record<string, number>, skipped: number, warnings: string[] }} artifacts
* @property {{ created: number, unchanged: number, byPrefix: Record<string, number> }} entities
* @property {{ created: number, unchanged: number, byType: Record<string, number> }} relationships
* @property {{ high: number, medium: number, low: number }} confidence
* @property {{ inferred: number, missing: number }} provenance
* @property {string[]} warnings
* @property {string[]} next
*/

/**
* Create the current bootstrap summary payload.
*
* This first slice intentionally exposes the command contract before the
* scanner/inference pipeline exists. Keeping the payload construction pure
* makes the dry-run no-write guarantee easy to test and preserves a stable
* shape for later slices to fill with real counts.
*
* @param {{ dryRun?: boolean }} [opts]
* @returns {BootstrapSummary}
*/
export function createBootstrapSummary(opts = {}) {
const dryRun = opts.dryRun === true;

return {
dryRun,
artifacts: {
scanned: 0,
byKind: {},
skipped: 0,
warnings: [],
},
entities: {
created: 0,
unchanged: 0,
byPrefix: {},
},
relationships: {
created: 0,
unchanged: 0,
byType: {},
},
confidence: {
high: 0,
medium: 0,
low: 0,
},
provenance: {
inferred: 0,
missing: 0,
},
warnings: [],
next: [...BOOTSTRAP_NEXT_COMMANDS],
};
}
49 changes: 48 additions & 1 deletion src/cli/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import { computeDiff } from '../diff.js';
import { DEFAULT_CONTEXT } from '../context-envelope.js';
import { loadExtension, registerExtension, removeExtension, listExtensions, validateExtension } from '../extension.js';
import { writeContent, readContent, getContentMeta, deleteContent } from '../content.js';
import { createBootstrapSummary } from '../bootstrap.js';
import { getProp } from '../prop-bag.js';
import { success, error, info, formatEdge, formatView, formatNode, formatNodeList, formatStatus, formatExportResult, formatImportResult, formatDoctorResult, formatSuggestions, formatReviewItem, formatDecisionSummary, formatAtStatus, formatDiff, formatExtensionList, formatContentMeta } from './format.js';
import { success, error, info, formatEdge, formatView, formatNode, formatNodeList, formatStatus, formatBootstrapResult, formatExportResult, formatImportResult, formatDoctorResult, formatSuggestions, formatReviewItem, formatDecisionSummary, formatAtStatus, formatDiff, formatExtensionList, formatContentMeta } from './format.js';

/**
* Write structured JSON to stdout with schemaVersion and command fields.
Expand All @@ -41,6 +42,26 @@ function outputJson(command, data) {
console.log(JSON.stringify(out, null, 2));
}

/**
* Ensure a command is running from inside a Git worktree without mutating repo
* state.
* @param {string} cwd
*/
function assertGitWorktree(cwd) {
try {
const result = execFileSync('git', ['rev-parse', '--is-inside-work-tree'], {
cwd,
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
if (result !== 'true') {
throw new Error('not a worktree');
}
} catch {
throw new Error('Not inside a Git worktree. Run this command from a Git repository.');
}
}

/**
* Resolve a ContextEnvelope to a live graph-like object.
*
Expand Down Expand Up @@ -131,6 +152,32 @@ export async function init(cwd) {
}
}

/**
* Run the Hill 1 bootstrap command contract.
* @param {string} cwd
* @param {{ dryRun?: boolean, json?: boolean }} opts
*/
export async function bootstrap(cwd, opts = {}) {
try {
assertGitWorktree(cwd);

if (!opts.dryRun) {
await initGraph(cwd);
}

const result = createBootstrapSummary({ dryRun: opts.dryRun });

if (opts.json) {
outputJson('bootstrap', result);
} else {
console.log(formatBootstrapResult(result));
}
} catch (err) {
console.error(error(err.message));
process.exitCode = 1;
}
}

/**
* Create a link (edge) between two nodes.
* @param {string} cwd
Expand Down
Loading
Loading