@davesheffer/hunch 1.31.1 → 1.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli/automaticReviewMemory.d.ts +13 -0
- package/dist/cli/dna.d.ts +2 -0
- package/dist/cli/index.d.ts +16 -0
- package/dist/cli/index.js +606 -43
- package/dist/cli/integrations.d.ts +2 -0
- package/dist/cli/integrations.js +5 -2
- package/dist/cli/invocation.d.ts +35 -0
- package/dist/cli/preflight.d.ts +1 -0
- package/dist/cli/reviewMemory.d.ts +4 -0
- package/dist/cli/reviewMemoryProvider.d.ts +14 -0
- package/dist/cli/serve.d.ts +2 -0
- package/dist/cli/taskReport.d.ts +6 -0
- package/dist/cli/taskReport.js +128 -0
- package/dist/cli/update.d.ts +14 -0
- package/dist/client/state.d.ts +248 -0
- package/dist/constitution/adapters.d.ts +29 -0
- package/dist/constitution/behaviorAttestationBinding.d.ts +3 -0
- package/dist/constitution/behaviorEvaluator.d.ts +8 -0
- package/dist/constitution/behaviorProof.d.ts +9 -0
- package/dist/constitution/behaviorWorkspace.d.ts +25 -0
- package/dist/constitution/bootstrap.d.ts +30 -0
- package/dist/constitution/canonical.d.ts +15 -0
- package/dist/constitution/card.d.ts +58 -0
- package/dist/constitution/compiler.d.ts +52 -0
- package/dist/constitution/composition.d.ts +10 -0
- package/dist/constitution/corpus.d.ts +7 -0
- package/dist/constitution/correctionPolicyMaterializer.d.ts +57 -0
- package/dist/constitution/delta.d.ts +4 -0
- package/dist/constitution/disposition.d.ts +20 -0
- package/dist/constitution/evaluator.d.ts +47 -0
- package/dist/constitution/experiment.d.ts +466 -0
- package/dist/constitution/experimentRunner.d.ts +7 -0
- package/dist/constitution/g2.d.ts +209 -0
- package/dist/constitution/g2BehaviorAttestation.d.ts +45 -0
- package/dist/constitution/g2BehaviorCandidates.d.ts +123 -0
- package/dist/constitution/g2BehaviorDependencies.d.ts +83 -0
- package/dist/constitution/g2BehaviorMaterialization.d.ts +77 -0
- package/dist/constitution/g2BehaviorPolicyMaterializer.d.ts +48 -0
- package/dist/constitution/g2CandidateAttestation.d.ts +43 -0
- package/dist/constitution/g2Candidates.d.ts +80 -0
- package/dist/constitution/g2Drills.d.ts +33 -0
- package/dist/constitution/g3.d.ts +311 -0
- package/dist/constitution/g3Conformance.d.ts +33 -0
- package/dist/constitution/lifecycle.d.ts +25 -0
- package/dist/constitution/mutation.d.ts +15 -0
- package/dist/constitution/nodeTestEvidence.d.ts +13 -0
- package/dist/constitution/plan.d.ts +18 -0
- package/dist/constitution/policyRuntime.d.ts +5 -0
- package/dist/constitution/proof.d.ts +11 -0
- package/dist/constitution/repairPolicies.d.ts +34 -0
- package/dist/constitution/replacementFreeGit.d.ts +14 -0
- package/dist/constitution/replay.d.ts +40 -0
- package/dist/constitution/replayCache.d.ts +14 -0
- package/dist/constitution/replayWorker.d.ts +1 -0
- package/dist/constitution/repository.d.ts +129 -0
- package/dist/constitution/safeCheckout.d.ts +9 -0
- package/dist/constitution/schema.d.ts +1763 -0
- package/dist/constitution/scorecard.d.ts +219 -0
- package/dist/constitution/service.d.ts +398 -0
- package/dist/constitution/shadow.d.ts +54 -0
- package/dist/constitution/sourceMutation.d.ts +15 -0
- package/dist/constitution/staticGraphBaseline.d.ts +13 -0
- package/dist/constitution/structural.d.ts +64 -0
- package/dist/core/agenthook.d.ts +63 -0
- package/dist/core/agenthook.js +1 -0
- package/dist/core/automaticReviewMemory.d.ts +60 -0
- package/dist/core/autoreview.d.ts +66 -0
- package/dist/core/canonicalOrder.d.ts +3 -0
- package/dist/core/capturetoken.d.ts +19 -0
- package/dist/core/changeIdentity.d.ts +22 -0
- package/dist/core/changeProof.d.ts +14 -0
- package/dist/core/checkreport.d.ts +140 -0
- package/dist/core/commitrepair.d.ts +171 -0
- package/dist/core/commitrepair.js +238 -0
- package/dist/core/compare.d.ts +21 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/conformance.d.ts +35 -0
- package/dist/core/constraintmatch.d.ts +54 -0
- package/dist/core/correction.d.ts +42 -0
- package/dist/core/correctionStage.d.ts +224 -0
- package/dist/core/declarationClusters.d.ts +149 -0
- package/dist/core/delivery.d.ts +110 -0
- package/dist/core/docanchors.d.ts +32 -0
- package/dist/core/docscan.d.ts +26 -0
- package/dist/core/drift.d.ts +13 -0
- package/dist/core/drift.js +31 -1
- package/dist/core/dupdetect.d.ts +43 -0
- package/dist/core/escalations.d.ts +129 -0
- package/dist/core/escalations.js +165 -0
- package/dist/core/events.d.ts +29 -0
- package/dist/core/evidenceMap.d.ts +164 -0
- package/dist/core/externalImports.d.ts +8 -0
- package/dist/core/format.d.ts +13 -0
- package/dist/core/glob.d.ts +9 -0
- package/dist/core/groundingLag.d.ts +84 -0
- package/dist/core/groundingLag.js +16 -2
- package/dist/core/groundingMerge.d.ts +15 -0
- package/dist/core/groundingMerge.js +95 -0
- package/dist/core/hookObservations.d.ts +9 -0
- package/dist/core/hookObservations.js +33 -0
- package/dist/core/hookcache.d.ts +10 -0
- package/dist/core/hookpolicy.d.ts +47 -0
- package/dist/core/ids.d.ts +36 -0
- package/dist/core/importReview.d.ts +30 -0
- package/dist/core/io.d.ts +23 -0
- package/dist/core/jsonc.d.ts +4 -0
- package/dist/core/landscapeAdoption.d.ts +66 -0
- package/dist/core/landscapeDelivery.d.ts +76 -0
- package/dist/core/memorylog.d.ts +37 -0
- package/dist/core/migrate.d.ts +28 -0
- package/dist/core/outcomeExperience.d.ts +89 -0
- package/dist/core/overlaySafety.d.ts +24 -0
- package/dist/core/overlaySafety.js +7 -1
- package/dist/core/paths.d.ts +31 -0
- package/dist/core/pipeline.d.ts +289 -0
- package/dist/core/premises.d.ts +43 -0
- package/dist/core/provenance.d.ts +21 -0
- package/dist/core/publication.d.ts +54 -0
- package/dist/core/refrepair.d.ts +24 -0
- package/dist/core/refrepair.js +1 -1
- package/dist/core/relativeImports.d.ts +11 -0
- package/dist/core/repair.d.ts +44 -0
- package/dist/core/repairqueue.d.ts +40 -0
- package/dist/core/repairqueue.js +133 -0
- package/dist/core/reviewMemory.d.ts +40 -0
- package/dist/core/reviewqueue.d.ts +54 -0
- package/dist/core/safeRepoFile.d.ts +20 -0
- package/dist/core/served.d.ts +57 -0
- package/dist/core/served.js +14 -0
- package/dist/core/stateContract.d.ts +979 -0
- package/dist/core/stateDelivery.d.ts +78 -0
- package/dist/core/stateRecords.d.ts +383 -0
- package/dist/core/stats.d.ts +88 -0
- package/dist/core/strictgate.d.ts +33 -0
- package/dist/core/taskReport.d.ts +226 -0
- package/dist/core/taskReport.js +514 -0
- package/dist/core/taskReportCapture.d.ts +8 -0
- package/dist/core/taskReportCapture.js +36 -0
- package/dist/core/taskReportEvidence.d.ts +28 -0
- package/dist/core/taskReportEvidence.js +272 -0
- package/dist/core/taskReportHook.d.ts +20 -0
- package/dist/core/taskReportHook.js +76 -0
- package/dist/core/taskReportPaths.d.ts +3 -0
- package/dist/core/taskReportPaths.js +23 -0
- package/dist/core/taskReportPublic.d.ts +31 -0
- package/dist/core/taskReportPublic.js +45 -0
- package/dist/core/taskReportRender.d.ts +6 -0
- package/dist/core/taskReportRender.js +97 -0
- package/dist/core/topics.d.ts +73 -0
- package/dist/core/types.d.ts +1239 -0
- package/dist/core/version.d.ts +10 -0
- package/dist/eval/guards.d.ts +45 -0
- package/dist/eval/harness.d.ts +58 -0
- package/dist/extractors/adrImport.d.ts +59 -0
- package/dist/extractors/comments.d.ts +7 -0
- package/dist/extractors/correctionSources.d.ts +11 -0
- package/dist/extractors/diff.d.ts +40 -0
- package/dist/extractors/git.d.ts +304 -0
- package/dist/extractors/git.js +208 -20
- package/dist/extractors/helm.d.ts +31 -0
- package/dist/extractors/indexer.d.ts +55 -0
- package/dist/extractors/landscapeDiscovery.d.ts +41 -0
- package/dist/extractors/languages.d.ts +77 -0
- package/dist/extractors/nativeTreeSitter.d.ts +16 -0
- package/dist/extractors/parse.d.ts +54 -0
- package/dist/extractors/php.d.ts +26 -0
- package/dist/extractors/repoSource.d.ts +53 -0
- package/dist/extractors/testreport.d.ts +36 -0
- package/dist/integrations/ciAction.d.ts +8 -0
- package/dist/integrations/claudeConfig.d.ts +44 -0
- package/dist/integrations/claudemd.d.ts +13 -0
- package/dist/integrations/claudemd.js +11 -2
- package/dist/integrations/gitignore.d.ts +16 -0
- package/dist/integrations/gitignore.js +7 -0
- package/dist/integrations/health.d.ts +74 -0
- package/dist/integrations/health.js +32 -2
- package/dist/integrations/hooks.d.ts +41 -0
- package/dist/integrations/hooks.js +92 -66
- package/dist/integrations/madrExport.d.ts +39 -0
- package/dist/integrations/madrManifest.d.ts +69 -0
- package/dist/integrations/mergeDriver.d.ts +3 -0
- package/dist/integrations/mergeDriver.js +25 -8
- package/dist/integrations/probe.d.ts +4 -0
- package/dist/integrations/providers.d.ts +103 -0
- package/dist/integrations/scaffold.d.ts +29 -0
- package/dist/integrations/sync.d.ts +30 -0
- package/dist/integrations/sync.js +3 -2
- package/dist/integrations/team.d.ts +70 -0
- package/dist/integrations/worktree.d.ts +8 -0
- package/dist/mcp/roots.d.ts +16 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.js +74 -22
- package/dist/mcp/taskReportTools.d.ts +188 -0
- package/dist/mcp/taskReportTools.js +147 -0
- package/dist/serve/app.d.ts +36 -0
- package/dist/serve/config.d.ts +100 -0
- package/dist/serve/writelock.d.ts +22 -0
- package/dist/store/changeLedger.d.ts +132 -0
- package/dist/store/compact.d.ts +33 -0
- package/dist/store/db.d.ts +9 -0
- package/dist/store/embedder.d.ts +32 -0
- package/dist/store/hunchStore.d.ts +624 -0
- package/dist/store/hunchStore.js +6 -3
- package/dist/store/jsonStore.d.ts +125 -0
- package/dist/store/merge.d.ts +39 -0
- package/dist/store/privateMigrate.d.ts +24 -0
- package/dist/store/replay.d.ts +56 -0
- package/dist/store/schema.d.ts +17 -0
- package/dist/store/stateBinding.d.ts +145 -0
- package/dist/store/stateCapture.d.ts +15 -0
- package/dist/synthesis/cliAdapter.d.ts +22 -0
- package/dist/synthesis/initiator.d.ts +13 -0
- package/dist/synthesis/provider.d.ts +307 -0
- package/dist/synthesis/synthesize.d.ts +117 -0
- package/dist/synthesis/tripwires.d.ts +9 -0
- package/dist/taskReports.d.ts +79 -0
- package/dist/taskReports.js +69 -0
- package/dist/wiki/adopt.d.ts +22 -0
- package/dist/wiki/graph.d.ts +87 -0
- package/dist/wiki/wiki.d.ts +242 -0
- package/package.json +6 -5
- package/server.json +2 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MADR export (the MADR bridge, export half — roadmap's "compiler" projection).
|
|
3
|
+
*
|
|
4
|
+
* Renders the PUBLIC decision graph as a regenerated MADR 3.x corpus: one
|
|
5
|
+
* NNNN-slug.md per decision, superseded links derived from superseded_by /
|
|
6
|
+
* valid_to, rejected alternatives under Considered Options. The projection is a
|
|
7
|
+
* DISPOSABLE build artifact — the graph stays the source of truth, numbers are
|
|
8
|
+
* assigned per export (date order), and every emitted file carries a generated
|
|
9
|
+
* marker. The writer only ever overwrites files bearing that marker: a
|
|
10
|
+
* hand-written ADR corpus in the target directory is untouchable (refused with
|
|
11
|
+
* a warning), so `hunch import-adr` + `hunch export-adr` can share a repo
|
|
12
|
+
* without the export eating its own import source.
|
|
13
|
+
*
|
|
14
|
+
* Privacy boundary: rendering takes an explicit PUBLIC-only decision list —
|
|
15
|
+
* callers must pass store.json.loadAll("decisions"), never the overlay union.
|
|
16
|
+
*/
|
|
17
|
+
import type { Decision } from "../core/types.js";
|
|
18
|
+
export declare const MADR_EXPORT_MARKER = "<!-- hunch:generated madr-export \u2014 regenerated by `hunch export-adr`; edits will be overwritten -->";
|
|
19
|
+
export interface MadrFile {
|
|
20
|
+
/** file name only, NNNN-slug.md */
|
|
21
|
+
name: string;
|
|
22
|
+
text: string;
|
|
23
|
+
decisionId: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MadrExportResult {
|
|
26
|
+
files: MadrFile[];
|
|
27
|
+
/** the one-line Backstage catalog-info annotation for this corpus */
|
|
28
|
+
backstageAnnotation: string;
|
|
29
|
+
}
|
|
30
|
+
/** Render one decision as a MADR 3.x document. Deterministic: content depends
|
|
31
|
+
* only on the decision record and the corpus's name map. */
|
|
32
|
+
export declare function renderMadr(d: Decision, nameOf: Map<string, string>): string;
|
|
33
|
+
/** Project a PUBLIC decision list into a MADR corpus. Numbering is date order
|
|
34
|
+
* (valid_from, then date, then id for determinism) and assigned per export —
|
|
35
|
+
* the projection is disposable, links inside it are internally consistent. */
|
|
36
|
+
export declare function exportMadrCorpus(decisions: readonly Decision[], dirForAnnotation: string): MadrExportResult;
|
|
37
|
+
/** True when an existing file may be overwritten by the export: only our own
|
|
38
|
+
* generated output ever qualifies. */
|
|
39
|
+
export declare function isRegenerableMadr(existingText: string): boolean;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Decision } from "../core/types.js";
|
|
2
|
+
import type { DriftFinding } from "../core/drift.js";
|
|
3
|
+
export interface MadrManifest {
|
|
4
|
+
version: 1;
|
|
5
|
+
/** repo-relative POSIX dir the corpus was exported to */
|
|
6
|
+
dir: string;
|
|
7
|
+
/** keyed by file name (NNNN-slug.md) — the export assigns numbers per run */
|
|
8
|
+
files: Record<string, {
|
|
9
|
+
decision: string;
|
|
10
|
+
hash: string;
|
|
11
|
+
bytes: string;
|
|
12
|
+
generated: string;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
export declare function madrManifestPath(root: string): string;
|
|
16
|
+
export declare function readMadrManifest(root: string): MadrManifest | null;
|
|
17
|
+
export declare function writeMadrManifest(root: string, manifest: MadrManifest): void;
|
|
18
|
+
/** The projected-content hash for one file. Content, not mtime: a re-export that
|
|
19
|
+
* changes nothing must not read as drift. */
|
|
20
|
+
export declare const madrContentHash: (text: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the manifest for a corpus that was just written.
|
|
23
|
+
*
|
|
24
|
+
* `written` carries the bytes actually placed on disk, which may differ from the
|
|
25
|
+
* rendered text when a file was refused (hand-written corpus in the target dir).
|
|
26
|
+
* Refused files are absent from the manifest, so they are never later reported
|
|
27
|
+
* as edited — they were never ours.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildMadrManifest(dir: string, entries: ReadonlyArray<{
|
|
30
|
+
name: string;
|
|
31
|
+
text: string;
|
|
32
|
+
decisionId: string;
|
|
33
|
+
}>, generatedAt: string): MadrManifest;
|
|
34
|
+
/**
|
|
35
|
+
* Drift for the MADR projection. Fires ONLY where a manifest exists — a repo that
|
|
36
|
+
* never ran `hunch export-adr` sees zero noise, matching the wiki's rule.
|
|
37
|
+
*
|
|
38
|
+
* Takes the PUBLIC decision list, never the overlay union: the projection is a
|
|
39
|
+
* committable artifact, so its freshness must be computed from exactly the
|
|
40
|
+
* records that are allowed to reach it. Passing the union here would leak the
|
|
41
|
+
* existence of overlay decisions into a public drift report.
|
|
42
|
+
*/
|
|
43
|
+
export declare function computeMadrDrift(publicDecisions: readonly Decision[], root: string): DriftFinding[];
|
|
44
|
+
/**
|
|
45
|
+
* Keep an adopted corpus fresh automatically.
|
|
46
|
+
*
|
|
47
|
+
* Called from the post-commit sync path (and from any writer that changes the
|
|
48
|
+
* public graph out of band, such as the memory service's HTTP write path), so a
|
|
49
|
+
* user who ran `hunch export-adr` once never has to run it again — the
|
|
50
|
+
* projection tracks the graph the way the SQLite index does.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately narrow:
|
|
53
|
+
* - No manifest → no-op. Adoption stays an explicit act.
|
|
54
|
+
* - Refuses to touch a file that was hand-edited, because silently discarding
|
|
55
|
+
* someone's edit is worse than a stale file; `madr-edited` drift reports it
|
|
56
|
+
* and the human decides.
|
|
57
|
+
* - Removes generated files the new numbering dropped, so the corpus stays
|
|
58
|
+
* internally consistent, but never removes a file it did not generate.
|
|
59
|
+
*
|
|
60
|
+
* Returns what changed so callers can log it; throws nothing the caller must
|
|
61
|
+
* handle — a projection refresh must never take down a commit or an HTTP write.
|
|
62
|
+
*/
|
|
63
|
+
export interface MadrRefreshResult {
|
|
64
|
+
dir: string;
|
|
65
|
+
written: number;
|
|
66
|
+
removed: number;
|
|
67
|
+
skippedEdited: string[];
|
|
68
|
+
}
|
|
69
|
+
export declare function refreshMadrCorpus(publicDecisions: readonly Decision[], root: string, now: string): MadrRefreshResult | null;
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wires up
|
|
3
|
-
* -
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Wires up two independent git merge drivers:
|
|
3
|
+
* - `merge=hunch` — the structured `.hunch/` JSON driver (store/merge.ts):
|
|
4
|
+
* resolves concurrent edits by record id.
|
|
5
|
+
* - `merge=hunch-grounding` — the generated grounding docs (core/groundingMerge.ts):
|
|
6
|
+
* auto-resolves a hard conflict confined to the record-counts sentence,
|
|
7
|
+
* leaving any other conflict untouched (dec_ba5b0dfa22).
|
|
8
|
+
* Both routes live in `.gitattributes` (committed, travels with the repo);
|
|
9
|
+
* both drivers are registered in LOCAL git config only (per-clone, since each
|
|
10
|
+
* references this machine's node + cli path — teammates re-run `hunch init`).
|
|
6
11
|
*/
|
|
7
12
|
import { execFileSync } from "node:child_process";
|
|
8
13
|
import { readFileSync, existsSync } from "node:fs";
|
|
9
14
|
import { writeFileAtomic } from "../core/io.js";
|
|
10
15
|
import { assertSafeTopLevelConfigFile } from "./gitignore.js";
|
|
16
|
+
import { GROUNDING_DOC_PATHS } from "./providers.js";
|
|
11
17
|
// Route the .hunch JSON records through the structured driver — but NOT the
|
|
12
18
|
// manifest (an id-less `{schema_version}` object the driver can't merge by id; a
|
|
13
19
|
// normal text merge with conflict markers is the right behavior for it).
|
|
14
|
-
|
|
20
|
+
//
|
|
21
|
+
// The five generated grounding docs get the OTHER driver — narrower in scope
|
|
22
|
+
// (it only ever touches a hard conflict confined to the counts sentence).
|
|
23
|
+
const ATTR_LINES = [
|
|
24
|
+
".hunch/**/*.json merge=hunch",
|
|
25
|
+
".hunch/manifest.json merge=text",
|
|
26
|
+
...GROUNDING_DOC_PATHS.map((f) => `${f} merge=hunch-grounding`),
|
|
27
|
+
];
|
|
15
28
|
function targetRepositoryEnv() {
|
|
16
29
|
const env = { ...process.env };
|
|
17
30
|
for (const key of [
|
|
@@ -43,17 +56,21 @@ export function installMergeDriver(root, invShell) {
|
|
|
43
56
|
assertSafeTopLevelConfigFile(root, ".gitattributes");
|
|
44
57
|
writeFileAtomic(attrPath, text);
|
|
45
58
|
}
|
|
46
|
-
// 2. Local git config — the driver
|
|
47
|
-
// machine's node + cli path), so
|
|
59
|
+
// 2. Local git config — the driver definitions are per-clone (they reference
|
|
60
|
+
// this machine's node + cli path), so they are NOT committed; teammates
|
|
61
|
+
// re-run init.
|
|
48
62
|
const driver = `${invShell} merge-driver "%O" "%A" "%B" "%P"`;
|
|
63
|
+
const groundingDriver = `${invShell} merge-driver-grounding "%O" "%A" "%B" "%P"`;
|
|
49
64
|
const env = targetRepositoryEnv();
|
|
50
65
|
try {
|
|
51
66
|
execFileSync("git", ["config", "merge.hunch.name", "hunch structured JSON merge"], { cwd: root, env });
|
|
52
67
|
execFileSync("git", ["config", "merge.hunch.driver", driver], { cwd: root, env });
|
|
68
|
+
execFileSync("git", ["config", "merge.hunch-grounding.name", "hunch grounding-counts merge"], { cwd: root, env });
|
|
69
|
+
execFileSync("git", ["config", "merge.hunch-grounding.driver", groundingDriver], { cwd: root, env });
|
|
53
70
|
}
|
|
54
71
|
catch {
|
|
55
72
|
return { action: `${attrAction} .gitattributes — but \`git config\` failed (not a git repo?)` };
|
|
56
73
|
}
|
|
57
|
-
return { action: `${attrAction} .gitattributes + registered merge.hunch
|
|
74
|
+
return { action: `${attrAction} .gitattributes + registered merge.hunch + merge.hunch-grounding drivers` };
|
|
58
75
|
}
|
|
59
76
|
//# sourceMappingURL=mergeDriver.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Harness, type IntegrationHealth } from "./health.js";
|
|
2
|
+
/** Opt-in: starts a fresh configured MCP process, never claims the current
|
|
3
|
+
* harness connection or hook delivery has been tested. No model is invoked. */
|
|
4
|
+
export declare function probeIntegration(root: string, harness: Harness, report: IntegrationHealth, timeoutMs?: number): Promise<void>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { HunchStore } from "../store/hunchStore.js";
|
|
2
|
+
import type { Invocation } from "./scaffold.js";
|
|
3
|
+
/** Cursor: .cursor/mcp.json — same `mcpServers` shape as Claude Desktop/Code. */
|
|
4
|
+
export declare function writeCursorMcp(root: string, inv: Invocation): string;
|
|
5
|
+
/** VS Code (Copilot agent mode): .vscode/mcp.json — root key is `servers`, and
|
|
6
|
+
* each stdio entry carries an explicit `type: "stdio"` (VS Code's schema). */
|
|
7
|
+
export declare function writeVscodeMcp(root: string, inv: Invocation): string;
|
|
8
|
+
/** Google Antigravity's global MCP config moved between releases. Resolve
|
|
9
|
+
* adaptively: an existing config wins, else an existing parent dir, else null
|
|
10
|
+
* (Antigravity not installed — we never create a global config for an absent
|
|
11
|
+
* tool). The current project-local config is handled separately below. `home`
|
|
12
|
+
* is injectable for tests so we never touch the real ~/.gemini. */
|
|
13
|
+
export declare function antigravityMcpFile(home?: string): string | null;
|
|
14
|
+
/** Antigravity: merge the hunch stdio server into the global mcp_config.json — same
|
|
15
|
+
* `mcpServers` { command, args } shape as Cursor/Claude (stdio; `serverUrl` is only for
|
|
16
|
+
* HTTP servers). Returns null when Antigravity isn't detected. Grounding needs nothing
|
|
17
|
+
* extra: Antigravity reads the project-root AGENTS.md Hunch already writes. */
|
|
18
|
+
export declare function writeAntigravityMcp(inv: Invocation, home?: string): string | null;
|
|
19
|
+
/** Current Antigravity IDE/CLI project config. Unlike a global config this is
|
|
20
|
+
* committed with the repository, so every clone gets the same private/local
|
|
21
|
+
* Hunch server without touching a user's home directory. */
|
|
22
|
+
export declare function writeAntigravityWorkspaceMcp(root: string, inv: Invocation): string;
|
|
23
|
+
/** Codex CLI: .codex/config.toml — `[mcp_servers.hunch]` stdio entry. We own only
|
|
24
|
+
* a marker-delimited block; any other TOML the user has is preserved. Paths use
|
|
25
|
+
* TOML single-quote LITERAL strings so Windows backslashes need no escaping. */
|
|
26
|
+
export declare function writeCodexConfig(root: string, inv: Invocation): string;
|
|
27
|
+
/** AGENTS.md — the cross-tool ambient-instruction standard (Codex and a growing
|
|
28
|
+
* set of assistants read it). Marker-delimited so user prose is preserved. */
|
|
29
|
+
export declare function writeAgentsMd(root: string, store: HunchStore): string;
|
|
30
|
+
/** GitHub Copilot custom instructions (VS Code / github.com). Same grounding. */
|
|
31
|
+
export declare function writeCopilotInstructions(root: string, store: HunchStore): string;
|
|
32
|
+
/** Cursor project rule (.mdc = frontmatter + body). `alwaysApply` keeps the Hunch
|
|
33
|
+
* grounding in context for every request. Fully managed by Hunch (overwritten). */
|
|
34
|
+
export declare function writeCursorRule(root: string, store: HunchStore): string;
|
|
35
|
+
/** Windsurf (Cascade): .windsurf/mcp_config.json — same `mcpServers` shape as
|
|
36
|
+
* Cursor. Repo-local (committed, shared via git) to match Hunch's other configs,
|
|
37
|
+
* rather than the global ~/.codeium/windsurf path. Merges; refuses to clobber. */
|
|
38
|
+
export declare function writeWindsurfMcp(root: string, inv: Invocation): string;
|
|
39
|
+
/** Current Windsurf also discovers a user config at ~/.codeium/windsurf. Only
|
|
40
|
+
* touch it when the tool is already installed/configured; Hunch never creates a
|
|
41
|
+
* global configuration for an application the user does not have. */
|
|
42
|
+
export declare function windsurfMcpFile(home?: string): string | null;
|
|
43
|
+
export declare function writeWindsurfGlobalMcp(inv: Invocation, home?: string): string | null;
|
|
44
|
+
/** Windsurf project rule (.windsurf/rules/hunch.md). `trigger: always_on` keeps the
|
|
45
|
+
* Hunch grounding in Cascade's context for every request. Fully managed (overwritten). */
|
|
46
|
+
export declare function writeWindsurfRule(root: string, store: HunchStore): string;
|
|
47
|
+
/** Cursor's hook API is beta, but its project-level config accepts this standard
|
|
48
|
+
* event map. Context delivery is opportunistic; the always-on rule and MCP
|
|
49
|
+
* registration remain the durable grounding path if a Cursor build suppresses
|
|
50
|
+
* a hook's agent_message. */
|
|
51
|
+
export declare function writeCursorHooks(root: string, inv: Invocation): string;
|
|
52
|
+
/** VS Code's native workspace hook location. It supports all lifecycle events
|
|
53
|
+
* Hunch needs and uses the same stdout contract as Claude Code, with different
|
|
54
|
+
* camelCase tool fields normalized in core/agenthook.ts. */
|
|
55
|
+
export declare function writeVscodeHooks(root: string, inv: Invocation): string;
|
|
56
|
+
/** Windsurf's documented workspace hooks. It only supports deterministic
|
|
57
|
+
* pre-hook blocking via exit code 2, so Hunch uses rules + MCP for context and
|
|
58
|
+
* reserves the hook for strict edit protection and pipeline observation. */
|
|
59
|
+
export declare function writeWindsurfHooks(root: string, inv: Invocation): string;
|
|
60
|
+
/** Antigravity keeps hook groups at the top level (not under `hooks`). Hunch
|
|
61
|
+
* owns only the `hunch` group and replaces its own old entries idempotently. */
|
|
62
|
+
export declare function writeAntigravityHooks(root: string, inv: Invocation): string;
|
|
63
|
+
/** Rewrite the auto-maintained Hunch section in EVERY assistant grounding doc
|
|
64
|
+
* (CLAUDE.md, AGENTS.md, Copilot instructions, Cursor + Windsurf rules) from the
|
|
65
|
+
* current store — without touching the MCP/provider config files. `hunch private
|
|
66
|
+
* --migrate` calls this AFTER emptying the public store so the committed public
|
|
67
|
+
* docs reflect that no engineering memory is published here (renderHunchSection
|
|
68
|
+
* reads the public store only, so private records never leak into them). */
|
|
69
|
+
export declare function regenerateGrounding(root: string, store: HunchStore): string[];
|
|
70
|
+
/** The five grounding docs, repo-relative (POSIX separators, as git prints them). */
|
|
71
|
+
export declare const GROUNDING_DOC_PATHS: readonly string[];
|
|
72
|
+
/** Self-heal: refresh the Hunch section in each grounding doc that ALREADY exists,
|
|
73
|
+
* and report which ones actually changed. Unlike regenerateGrounding it NEVER creates
|
|
74
|
+
* a file (so it can't scaffold grounding into a project that opted out of an
|
|
75
|
+
* assistant). Run by `hunch index` and non-hook `hunch sync` so a project silently
|
|
76
|
+
* picks up generator fixes (e.g. corrected MCP tool param names) and fresh record
|
|
77
|
+
* counts on the next refresh — no manual `hunch init`. */
|
|
78
|
+
export declare function refreshExistingGrounding(root: string, store: HunchStore): string[];
|
|
79
|
+
/** Capture-commit refresh: rewrite grounding docs that are git-clean OR whose only
|
|
80
|
+
* divergence from HEAD is generated content, and return the absolute paths to fold
|
|
81
|
+
* into the memory commit (commitAndPushHunch alsoStage). This keeps committed record
|
|
82
|
+
* counts permanently true — every capture used to bump the count and re-stale the
|
|
83
|
+
* committed docs, failing the release gate's clean-tree check on the next CI index
|
|
84
|
+
* (the refresh-counts treadmill). The generated-dirt branch closes the second half
|
|
85
|
+
* (fnd_b269d5c422): once a doc went stale-dirty, the clean-only rule skipped it on
|
|
86
|
+
* every later flush FOREVER, and each release needed a manual chore commit. A doc
|
|
87
|
+
* whose USER PROSE differs from HEAD is still left completely untouched. */
|
|
88
|
+
export declare function refreshCommittableGrounding(root: string, store: HunchStore): string[];
|
|
89
|
+
export interface ProviderScaffold {
|
|
90
|
+
assistant: string;
|
|
91
|
+
files: string[];
|
|
92
|
+
/** Set when this assistant was skipped (e.g. an unparseable existing config we
|
|
93
|
+
* refused to clobber) — surfaced as a warning, not a fatal init failure. */
|
|
94
|
+
error?: string;
|
|
95
|
+
}
|
|
96
|
+
/** Scaffold MCP config + grounding for all supported assistants. Returns a
|
|
97
|
+
* per-assistant summary for `hunch init` to print. Each assistant is isolated:
|
|
98
|
+
* a writer that refuses to clobber a malformed file degrades to a warning rather
|
|
99
|
+
* than aborting the rest. Claude Code is handled separately by scaffold.ts. */
|
|
100
|
+
export declare function scaffoldProviders(root: string, inv: Invocation, store: HunchStore, options?: {
|
|
101
|
+
agentHooks?: boolean;
|
|
102
|
+
home?: string;
|
|
103
|
+
}): ProviderScaffold[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface Invocation {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
/** Merge a `hunch` server entry into .mcp.json, preserving other servers.
|
|
6
|
+
* A non-empty file we cannot parse THROWS instead of being silently replaced
|
|
7
|
+
* (con_8460b6770f — it may hold the user's other MCP servers); the caller
|
|
8
|
+
* degrades that to a warning. */
|
|
9
|
+
export declare function writeMcpJson(root: string, inv: Invocation): string;
|
|
10
|
+
export interface ClaudeHookInstall {
|
|
11
|
+
path: string;
|
|
12
|
+
action: "created" | "updated" | "unchanged";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Install the Claude Code AGENT hooks into `.claude/settings.json` so the agent
|
|
16
|
+
* is grounded in Hunch automatically (not by remembering to call the tools):
|
|
17
|
+
* - PreToolUse (Edit|Write|MultiEdit) → inject the relevant Hunch slice before
|
|
18
|
+
* an edit, and (at strict firmness) deny edits that hit a blocking invariant.
|
|
19
|
+
* - UserPromptSubmit → remind the agent to consult Hunch.
|
|
20
|
+
* Both invoke `hunch hook`, which reads the firmness level from .hunch/config.json
|
|
21
|
+
* at run time — so changing firmness needs no settings.json edit. We own only our
|
|
22
|
+
* entries (matched by isHunchHook): other hooks and settings are preserved, and a
|
|
23
|
+
* non-empty file we cannot parse THROWS rather than clobbering the user's config.
|
|
24
|
+
*/
|
|
25
|
+
export declare function installClaudeHooks(root: string, hookCmd: string): ClaudeHookInstall;
|
|
26
|
+
export declare function writeSlashCommands(root: string): {
|
|
27
|
+
written: string[];
|
|
28
|
+
skipped: string[];
|
|
29
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HunchStore } from "../store/hunchStore.js";
|
|
2
|
+
import { type HunchRemoteContract, type GitMemoryObserver } from "../extractors/git.js";
|
|
3
|
+
/** Bind one command/server Store instance to the graph epoch that admitted it.
|
|
4
|
+
* Every later flush from that instance reuses the same verifying contract. */
|
|
5
|
+
export declare function pinSharedRemote(store: HunchStore, remote: HunchRemoteContract): void;
|
|
6
|
+
/** Return the route admitted for this Store instance. Command paths that flush
|
|
7
|
+
* directly (rather than through flushCapture) must use this accessor too, or a
|
|
8
|
+
* coherent team.json/origin rewrite could switch graphs mid-command. */
|
|
9
|
+
export declare function sharedRemoteFor(store: HunchStore): HunchRemoteContract | undefined;
|
|
10
|
+
export type MemoryHome = "public" | "private";
|
|
11
|
+
/** Flush one exact artifact home. Constitution repositories can explicitly
|
|
12
|
+
* choose public even in unified mode, so this must not infer routing through
|
|
13
|
+
* captureHome(isPrivate). The caller supplies the repository's actual home. */
|
|
14
|
+
export declare function flushMemoryHome(store: HunchStore, publicHunchDir: string, home: MemoryHome, message: string, remoteOverride?: HunchRemoteContract): "pushed" | "committed" | null;
|
|
15
|
+
/** One completion flush per touched home. A mixed ingest/bootstrap can write
|
|
16
|
+
* both homes; unchanged homes are cheap no-ops after the memory-only stage
|
|
17
|
+
* check, while each real home becomes durable exactly once. */
|
|
18
|
+
export declare function flushMemoryHomes(store: HunchStore, publicHunchDir: string, homes: Iterable<MemoryHome>, message: string, remoteOverride?: HunchRemoteContract): Partial<Record<MemoryHome, "pushed" | "committed" | null>>;
|
|
19
|
+
/** Auto-commit + push the overlay after a private write, when auto-commit is on. No-op
|
|
20
|
+
* otherwise (manual `hunch private --sync` still works). Never throws. */
|
|
21
|
+
export declare function flushPrivate(store: HunchStore, message: string): void;
|
|
22
|
+
/** Auto-commit the store a capture landed in. Returns what ACTUALLY happened so callers
|
|
23
|
+
* never report a commit that was skipped: "pushed" (overlay committed + pushed),
|
|
24
|
+
* "committed" (commit created but not pushed — public .hunch/ rides the next push; an
|
|
25
|
+
* overlay commit whose merge/push failed retries on the next flush), or null (auto-commit
|
|
26
|
+
* off, no overlay for a private record, or the commit was skipped — lock held, safety
|
|
27
|
+
* backstop, nothing staged; the record stays on disk and the next flush sweeps it up). */
|
|
28
|
+
export declare function flushCapture(store: HunchStore, publicHunchDir: string, isPrivate: boolean, message: string,
|
|
29
|
+
/** Long-lived callers can pin the route snapshot that admitted the write. */
|
|
30
|
+
remoteOverride?: HunchRemoteContract, observe?: GitMemoryObserver): "pushed" | "committed" | null;
|
|
@@ -73,13 +73,14 @@ export function flushPrivate(store, message) {
|
|
|
73
73
|
* backstop, nothing staged; the record stays on disk and the next flush sweeps it up). */
|
|
74
74
|
export function flushCapture(store, publicHunchDir, isPrivate, message,
|
|
75
75
|
/** Long-lived callers can pin the route snapshot that admitted the write. */
|
|
76
|
-
remoteOverride) {
|
|
76
|
+
remoteOverride, observe) {
|
|
77
77
|
// Follow the same routing as HunchStore.captureHome: unified ("shared") mode homes
|
|
78
78
|
// EVERY capture in the overlay, so the flush must go there too — one source of truth.
|
|
79
79
|
if (store.captureHome(isPrivate) === "private") {
|
|
80
80
|
if (store.privateAutoCommit && store.privateDir) {
|
|
81
81
|
return commitAndPushHunch(store.privateDir, message, {
|
|
82
82
|
push: true,
|
|
83
|
+
observe,
|
|
83
84
|
protectedRepoRoot: store.publicRoot,
|
|
84
85
|
remote: remoteOverride ?? sharedRemoteFor(store),
|
|
85
86
|
});
|
|
@@ -92,6 +93,6 @@ remoteOverride) {
|
|
|
92
93
|
// them into the SAME memory commit — otherwise every capture re-stales the committed
|
|
93
94
|
// counts and the release gate's clean-tree check fails on the next CI index.
|
|
94
95
|
const grounding = refreshCommittableGrounding(dirname(publicHunchDir), store);
|
|
95
|
-
return commitAndPushHunch(publicHunchDir, message, { push: false, alsoStage: grounding });
|
|
96
|
+
return commitAndPushHunch(publicHunchDir, message, { push: false, alsoStage: grounding, observe });
|
|
96
97
|
}
|
|
97
98
|
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type HunchRemoteContract } from "../extractors/git.js";
|
|
2
|
+
export interface TeamConfig {
|
|
3
|
+
shared_repo: string;
|
|
4
|
+
/** Canonical remote branch for the one shared graph. Legacy files omit it;
|
|
5
|
+
* route proof then derives the sole existing/upstream branch from the clone. */
|
|
6
|
+
shared_ref?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_TEAM_REF = "refs/heads/main";
|
|
9
|
+
export declare function safeTeamRef(value: string): string | null;
|
|
10
|
+
export declare function teamSharedRef(team: TeamConfig): string;
|
|
11
|
+
/** SECURITY GATE for team.json's URL. team.json is COMMITTED — in a freshly cloned
|
|
12
|
+
* (possibly untrusted) repo it is attacker-controlled, and ensureTeamOverlay auto-clones
|
|
13
|
+
* it on MCP server start. Without this gate a value like `--upload-pack=…` (argument
|
|
14
|
+
* smuggling) or `ext::sh -c …` (git's ext transport) is remote code execution from
|
|
15
|
+
* merely opening a repo. Allow only credential-free https://, ssh://, git://,
|
|
16
|
+
* scp-style git@host:path, and never anything that could parse as a Git flag. */
|
|
17
|
+
export declare function safeGitUrl(url: string): string | null;
|
|
18
|
+
/** The committed team pointer, or null. Tolerant — an invalid file reads as absent, and
|
|
19
|
+
* a URL that fails the safety gate reads as absent too (never propagated to a consumer). */
|
|
20
|
+
export declare function readTeamConfig(root: string): TeamConfig | null;
|
|
21
|
+
/** Publish the team's shared-store URL (atomic; committed with the repo). */
|
|
22
|
+
export declare function writeTeamConfig(root: string, cfg: TeamConfig): void;
|
|
23
|
+
/** Git environment for every shared-route setup operation. Preserve ordinary
|
|
24
|
+
* credential configuration, but discard inherited repository/object selectors
|
|
25
|
+
* and executable transport/prompt/template overrides from the caller. */
|
|
26
|
+
export declare function boundedTeamGitEnv(): NodeJS.ProcessEnv;
|
|
27
|
+
/** Prove that the physical overlay reads from and writes to the repository
|
|
28
|
+
* advertised by the committed team config. Path/mode checks alone are not
|
|
29
|
+
* enough: an old healthy clone can otherwise report "current" against a stale
|
|
30
|
+
* origin after team.json changes, silently splitting the team graph.
|
|
31
|
+
*
|
|
32
|
+
* Require one exact fetch URL and one exact push URL for origin, plus an origin
|
|
33
|
+
* upstream/push selector when those branch-level overrides exist. Git's
|
|
34
|
+
* Applicable local or global URL rewrite rules are rejected, so the exact URLs
|
|
35
|
+
* captured from local config remain the URLs handed to Git at the network seam. */
|
|
36
|
+
export declare function overlayMatchesTeamRemote(root: string, overlayRoot: string): boolean;
|
|
37
|
+
/** Snapshot the effective URLs after proving the committed pointer, local
|
|
38
|
+
* transport configuration, and canonical ref all agree. Sync commands receive
|
|
39
|
+
* this object and re-run `verify` immediately around every network operation. */
|
|
40
|
+
export declare function teamRemoteContract(root: string, overlayRoot: string): HunchRemoteContract | null;
|
|
41
|
+
/** Setup-time form of the same contract, used before team.json is published.
|
|
42
|
+
* It proves the existing overlay's physical origin/config against the explicit
|
|
43
|
+
* command arguments so attach/refresh cannot traverse an ambient refspec or
|
|
44
|
+
* transport override during the setup command itself. */
|
|
45
|
+
export declare function explicitTeamRemoteContract(overlayRoot: string, sharedRepo: string, sharedRepoCwd: string, sharedRef: string): HunchRemoteContract | null;
|
|
46
|
+
/** Undefined means this checkout does not advertise team routing. Once the
|
|
47
|
+
* committed file exists, failure to prove it returns an always-refusing
|
|
48
|
+
* contract so a late config change can strand a local commit but can never fall
|
|
49
|
+
* through to ambient `git push`. */
|
|
50
|
+
export declare function advertisedTeamRemoteContract(root: string, overlayRoot: string): HunchRemoteContract | undefined;
|
|
51
|
+
export type ValidatedTeamClone = {
|
|
52
|
+
sharedRef: string;
|
|
53
|
+
empty: boolean;
|
|
54
|
+
};
|
|
55
|
+
/** Clone a shared memory repository without checking out attacker-controlled
|
|
56
|
+
* paths, validate its exact route/OID/tree/attributes, and only then publish the
|
|
57
|
+
* fully materialized clone at `destination`. Failure removes both quarantine and
|
|
58
|
+
* destination so callers cannot accidentally wire a partially validated graph. */
|
|
59
|
+
export declare function cloneValidatedTeamOverlay(sharedRepo: string, sharedRepoCwd: string, destination: string, opts?: {
|
|
60
|
+
sharedRef?: string;
|
|
61
|
+
timeoutMs?: number;
|
|
62
|
+
}): ValidatedTeamClone | null;
|
|
63
|
+
/** Auto-wire this checkout to the team's shared store advertised in `.hunch/team.json`:
|
|
64
|
+
* clone it to the worktree-stable anchor, and register the gitignored local pointer +
|
|
65
|
+
* the git-common-dir pointer (mode "shared", auto-commit on) so every consumer — CLI,
|
|
66
|
+
* MCP server, hooks, all worktrees — resolves the same single source of truth.
|
|
67
|
+
* No-op (null) when an overlay is already configured, there's no team.json, or the
|
|
68
|
+
* clone fails (best-effort: never throws, never blocks startup). Returns the overlay
|
|
69
|
+
* hunch dir when wired. */
|
|
70
|
+
export declare function ensureTeamOverlay(root: string): string | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Register the resolved private overlay at the shared git common dir, so every worktree
|
|
2
|
+
* of this repo auto-discovers the same memory. Idempotent (writes only when missing or
|
|
3
|
+
* changed). Stored ABSOLUTE — a worktree resolves relative paths from its OWN root.
|
|
4
|
+
* Carries the overlay MODE so every worktree routes captures identically (shared =
|
|
5
|
+
* unified store, private = split). Returns true once the shared pointer is in place
|
|
6
|
+
* (memory is worktree-shared), false when there's no overlay configured or no git
|
|
7
|
+
* common dir. Reused by `init`/`worktree`/`private`/`shared`. */
|
|
8
|
+
export declare function ensureSharedOverlayPointer(root: string, overlayDir: string | undefined, autoCommit: boolean, mode?: "private" | "shared"): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** One canonical spelling per directory. `findRoot` only resolve()s, but a
|
|
2
|
+
* client's roots/list URI can spell the same repo differently — VS Code sends
|
|
3
|
+
* a lowercase drive letter (`c:\…`) while the spawn cwd has `C:\…`, and Git
|
|
4
|
+
* for Windows can surface 8.3/short names. Raw string comparison then treats
|
|
5
|
+
* ONE repo as different roots: a full re-prepare (new store + reindex) on
|
|
6
|
+
* every connect, or a false "multiple roots equally plausible" refusal
|
|
7
|
+
* (issue #54). realpathSync.native returns the on-disk spelling for all of
|
|
8
|
+
* these; fall back to the input when the path is transiently unreadable. */
|
|
9
|
+
export declare function canonicalRootPath(root: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Returns null when several advertised repositories are equally plausible.
|
|
12
|
+
* The roots protocol exposes a set of URI/name pairs, not an "active root" bit;
|
|
13
|
+
* choosing the first Hunch store in that case could silently write repo B's
|
|
14
|
+
* decision into repo A.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveActiveRoot(rootUris: readonly string[], fallbackCwd: string): string | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server — the structured two-way API into the Hunch (DESIGN.md §7 / App. A).
|
|
3
|
+
* Exposes read tools (query/why/bug_lineage/check_constraints/get_dependents) and
|
|
4
|
+
* a write tool (record_decision). Registered with Claude Code via .mcp.json.
|
|
5
|
+
*
|
|
6
|
+
* STDIO PROTOCOL RULE: stdout carries JSON-RPC — never console.log here. All
|
|
7
|
+
* diagnostics go to stderr.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
export declare const publicationVocabulary: (hunchDir: string) => RegExp[];
|
|
11
|
+
export type RootControlledServer = {
|
|
12
|
+
server: McpServer;
|
|
13
|
+
getRoot: () => string;
|
|
14
|
+
setRoot: (next: string) => void;
|
|
15
|
+
/** True when the root was pinned at launch (`hunch mcp --root`): client roots and per-call
|
|
16
|
+
* `cwd` hints are ignored, so a served partition stays the partition whatever workspace
|
|
17
|
+
* the client opened. */
|
|
18
|
+
pinned: boolean;
|
|
19
|
+
/** Drop a swap parked by `setRoot` while a request was in flight. The roots
|
|
20
|
+
* wiring calls this when a LATER resolution is ambiguous, so a stale parked
|
|
21
|
+
* swap can never apply after the client stopped unambiguously advertising it. */
|
|
22
|
+
cancelPendingRoot: () => void;
|
|
23
|
+
};
|
|
24
|
+
export interface RootControlOptions {
|
|
25
|
+
/** Serve exactly `initialRoot`; never re-home to client roots or `cwd` hints. */
|
|
26
|
+
pinned?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function buildServerWithRootControl(initialRoot: string, options?: RootControlOptions): RootControlledServer;
|
|
29
|
+
/** Back-compatible server construction for tests and callers that do not need
|
|
30
|
+
* to drive roots directly. The server still owns and closes its active store. */
|
|
31
|
+
export declare function buildServer(root: string): McpServer;
|
|
32
|
+
/** Query client roots after initialization and follow later list changes.
|
|
33
|
+
* Generation ordering prevents a slow stale roots/list response from winning. */
|
|
34
|
+
export declare function wireClientRoots(control: RootControlledServer, fallback: string): void;
|
|
35
|
+
/** Start the stdio server (called by `hunch mcp`). */
|
|
36
|
+
export declare function startServer(cwd?: string, options?: RootControlOptions): Promise<void>;
|