diff --git a/README.md b/README.md index 113c5d6..f54c2bf 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,8 @@ No model provider is required by core. Local stdio MCP servers already provide repository navigation and separate signed context/graph tools. Claude Code and Codex are first-class target clients; actual -Codex use is recorded, while Claude model/tool acceptance remains open. See the +Codex use and a first Claude read-only task are recorded; full Claude lifecycle +and routine coding acceptance remain open. See the [client and language plan](docs/CLIENTS-AND-LANGUAGES.md) for current capabilities, deeper Rust/TS/Kotlin work and the provider-authentication boundary. diff --git a/RELEASE_EVIDENCE.md b/RELEASE_EVIDENCE.md index f98e5bd..7a24506 100644 --- a/RELEASE_EVIDENCE.md +++ b/RELEASE_EVIDENCE.md @@ -4,6 +4,27 @@ Latest implementation and adoption results are in the [dogfood execution ledger](docs/DOGFOOD-EXECUTION.md). The dated snapshots below remain historical evidence; internal pilot acceptance is separate from G0–G4. +## 0.3.2 shipment checks, 22 September 2026 + +Navigation and exact source packets now accept `.kts`, `.cc`, `.cxx`, `.hh`, +`.hpp` and `.hxx`, matching the broad scanner's existing lexical coverage. +Syntax-aware planning remains TS/JS-only and Dart remains unsupported. +See the [language support matrix](docs/LANGUAGE-SUPPORT.md). + +Local Node 24.21.0 checks passed 402 tests, independent package installation, +both unchanged benchmark gates, navigation stdio smoke, 22 scale tests and the +10k postings probe. Added coverage checks each suffix's search, exact source +lines/hashes, stale rejection and refresh, policy exclusion, unsupported planning +and retrieval through installed stdio MCP. Commit-specific CI, public artifact +checksums and download verification accompany the GitHub release. + +npm authentication still returns HTTP 401; registry publication is outstanding. +Upgrade using matching GitHub tarballs or the source build, then reconnect the +MCP server: refreshing its source index does not reload its implementation. +These checks do not establish new Claude lifecycle acceptance or measured +whole-task/subscription/cash savings. The first actual Claude audit and its +incomplete host-cost coverage are recorded in the execution ledger. + ## 0.3.1 shipment, 22 September 2026 This patch adds an installed, read-only `doctor` command that verifies the exact diff --git a/docs/CLIENTS-AND-LANGUAGES.md b/docs/CLIENTS-AND-LANGUAGES.md index b52fc9c..339f570 100644 --- a/docs/CLIENTS-AND-LANGUAGES.md +++ b/docs/CLIENTS-AND-LANGUAGES.md @@ -47,15 +47,18 @@ contracts, keeping unsigned navigation and signed evidence clearly distinguished Actual Codex calls have succeeded, including this review. The recorded Claude Code health check connected, but a previous Haiku attempt returned HTTP 429 for a weekly limit before tool use. This is historical evidence, not a current quota -check. Claude task acceptance remains unverified. See +check. On 22 September, Claude Code 2.1.278 used all four tools from an installed +0.3.1 package for a [language coverage audit](LANGUAGE-SUPPORT.md). The read-only +task was accepted after host corrections; actual-client edit/stale/refresh, +restart/disable and consequential task qualification remain open. See [the pilot record](DOGFOOD.md) and [navigation contract](LOCAL-NAVIGATION.md). ## OS1 client and retrieval assignments | Task | Owner / where | Model and effort | Acceptance | | --- | --- | --- | --- | -| **OS1a — Claude Code alongside Codex. Next** | Context integration owner, Node tools, public setup docs and isolated client fixtures | Flash/thinking off for bounded docs/fixtures; Terra/medium integration; **Claude Sonnet 5/medium** as the first real Claude executor; **Claude Opus 5/high** for one consequential source-backed task after basic acceptance | A pinned package launches in both clients against an explicit root; real tool discovery, status/refresh/search, bounded evidence, edit/stale/refresh, restart and disable work. Record actual client/model/effort and accepted task, not just Connected | -| **OS1b — Sufficient evidence through MCP. Implemented locally; live client qualification remains** | Context implementation owner, shared packet module plus `packages/context-tools` adapters/tests | Terra/medium implementation; Sol/high boundary review; Flash/off for scoped fixtures | `repository_packet` returns bounded exact ranges or complete selected TS/JS blocks with provenance and stale rejection. Installed-tarball stdio retrieval, edit/refresh and restart pass. Reconnect existing clients to discover the new tool; actual Claude use remains open. No shell helper required by the consuming model; no arbitrary path escape | +| **OS1a — Claude Code alongside Codex. Partial: read-only audit accepted** | Context integration owner, Node tools, public setup docs and isolated client fixtures | Flash/thinking off for bounded docs/fixtures; Terra/medium integration; **Claude Sonnet 5/medium** as the first real Claude executor; **Claude Opus 5/high** for one consequential source-backed task after basic acceptance | A pinned package launches in both clients against an explicit root; real tool discovery, status/refresh/search, bounded evidence, edit/stale/refresh, restart and disable work. Record actual client/model/effort and accepted task, not just Connected | +| **OS1b — Sufficient evidence through MCP. Shipped; first Claude use recorded** | Context implementation owner, shared packet module plus `packages/context-tools` adapters/tests | Terra/medium implementation; Sol/high boundary review; Flash/off for scoped fixtures | `repository_packet` returns bounded exact ranges or complete selected TS/JS blocks with provenance and stale rejection. Installed-tarball stdio retrieval, edit/refresh and restart pass. Reconnect existing clients to discover the new tool; first Claude read-only use is recorded, while lifecycle qualification remains open. No shell helper required by the consuming model; no arbitrary path escape | | **OS1c — Graph questions through MCP** | Context graph owner, same tools adapter; follows OS3/OS4 evidence integration | Terra/medium; Sol/high review of scope/provenance | Bounded repository symbol/neighbour/path queries return precise source and derivation metadata in both clients; do not mistake the existing signed-cache graph tools for this capability | | **OS1d — Other client surfaces** | Context integration owner, portable examples and clean-client acceptance | Flash/off for docs, Terra/medium review; user's chosen model for the actual client | Claude Desktop is separately qualified after Claude Code; other MCP clients follow demand. Never infer their acceptance from Claude Code or Codex | @@ -80,6 +83,10 @@ client support does not require repeating every benchmark on every model. ## Current language depth and priorities +The [selected suffix audit](LANGUAGE-SUPPORT.md) records exact navigation, broad +scan, build-packet and plan-packet outcomes for Kotlin, C/C++, Dart and TypeScript, +with source references and explicit test gaps. + These findings come from this repository's source and tests, not a new scan of every ForgeSworn project. The captured Heartwood pilot confirms Rust, TS/JS and Kotlin inputs. Python also implements this project's new snapshot helpers. diff --git a/docs/DAILY-USAGE.md b/docs/DAILY-USAGE.md index ac00a14..a505502 100644 --- a/docs/DAILY-USAGE.md +++ b/docs/DAILY-USAGE.md @@ -213,7 +213,7 @@ same-model task comparisons. Pricing estimates and invoice attribution are different evidence. Account identifiers group usage; no subscription charge is invented or multiplied by the number of tasks. -Remaining FS2 work: real Claude export acceptance, client-version coverage, +Remaining FS2 work: wider client-version coverage, complete everyday host/worker/review captures and convenient weekly report rendering. Explicit task boundaries and worker-helper receipt imports are available. The current tool handles explicit exports immediately; automatic session discovery, provider authentication and telemetry are excluded. @@ -230,6 +230,29 @@ metadata was unavailable and all whole-task coverage assertions were false. This is a partial Context **development** window, not an accepted Heartwood task, a baseline, a complete cost of this implementation or evidence of savings. No real Claude export was present in the selected Context export directory; the -Claude adapter has synthetic fixture acceptance only. The active Heartwood +Claude adapter had synthetic fixture acceptance only at that point. The active Heartwood session was not inspected or modified. Private evidence is recorded in the [execution ledger](DOGFOOD-EXECUTION.md). + +## First real Claude export acceptance + +On 22 September 2026, Claude Code 2.1.278 completed a read-only Context language +coverage audit using an independently installed 0.3.1 MCP package. Its frozen +transcript contained 19 assistant entries representing seven unique message IDs. +The existing importer removed 12 identical usage copies, found no conflicts and +reconciled exactly with the CLI result: 166,442 total input tokens (130,617 cache +reads, 35,811 cache creation and 14 fresh input) plus 5,322 output tokens. Cache +creation's nested breakdown was not added again. No adapter code change was needed. + +The observed model was `claude-sonnet-5`; medium effort was requested in the launch +command, but transcript effort remains unknown to the adapter. The CLI separately +reported 1,310 thinking tokens within output; this adapter deliberately leaves +reasoning unknown for its supported transcript shape. The result's list-price +cost is not an invoice or subscription charge. + +The audited document was accepted after host source-review corrections. Only the +Claude execution counters are complete here: Codex preparation, integration and +review are not fully captured, and review duration is unknown. Task coverage stays +incomplete. This validates one real Claude export shape and read-only task use; +it does not establish whole-task cost, normal-session lifecycle acceptance or +savings. See [the audit](LANGUAGE-SUPPORT.md) and [ledger](DOGFOOD-EXECUTION.md). diff --git a/docs/DOGFOOD-EXECUTION.md b/docs/DOGFOOD-EXECUTION.md index a613261..ee13515 100644 --- a/docs/DOGFOOD-EXECUTION.md +++ b/docs/DOGFOOD-EXECUTION.md @@ -926,3 +926,79 @@ The local release-check blocker is resolved. Doctor and benchmark changes remain uncommitted and unpublished; this is not new CI, registry or client acceptance. Next adoption gate: a real Claude source-packet task and usage import. The existing Heartwood owner retains its application task; no consumer checkout was changed. + +## 22 September 2026 — First Claude task and real export import + +After the 0.3.1 shipment, an independent installation of its downloaded GitHub +tarballs passed `doctor` against the Context checkout at `bb83fa3`. Claude Code +2.1.278 then ran a useful read-only language coverage audit using that installed +MCP server. The actual model was `claude-sonnet-5`, with medium effort requested. +The existing Max subscription login was used; no new API credential was supplied. +One client invocation completed successfully, with no reported provider refusal, +tool error or permission denial and no host replay. Heartwood was not inspected or modified. + +The invocation supplied an explicit MCP binding, `--strict-mcp-config`, the four +allowed repository tools, no built-in tools, and disabled skills for this bounded +audit. It preserved saved client settings. This establishes real Claude Code +print-mode use with an explicit binding, not acceptance of every interactive +configuration. [CLI flag reference](https://code.claude.com/docs/en/cli-reference). + +The model called status once, refresh once, search eight times and packet once. +The source-backed result needed host corrections: it falsely called `.kts` +absent from broad scanning, misstated the number of packet suffixes, described +the planner rejection incorrectly and omitted `.hh` from its proposed alignment. +The reviewed [support matrix](LANGUAGE-SUPPORT.md) is accepted after those +corrections; the original draft remains partial, retained privately. No second +model pass was needed. The audit identifies a concrete next task: align Kotlin +script and C++ suffix eligibility across navigation and exact source packets, +with per-suffix tests and no broader parsing claim. + +The completed transcript was copied from this explicitly created session only. +The existing daily importer accepted its real shape without code changes: 19 +assistant entries became seven unique request records, with 12 identical copies +removed and no conflicts. Imported totals exactly match the CLI result: +166,442 input tokens (130,617 cache reads, 35,811 cache creation, 14 fresh input), +5,322 output tokens, 171,764 combined. The separate CLI thinking count is included +in output; imported reasoning and effective effort remain unknown. Reported +list-price cost is not subscription billing and is not treated as cash spend. + +Private launch, transcript, original answer, review, reconciled receipt and task +summary are retained outside Git. Only the observed Claude execution is fully +accounted here. Codex preparation, repair/integration and review usage are not +fully captured; review duration and whole-task cost remain unknown. Coverage +assertions explicitly retain those gaps. This is Context development, not an +accepted Heartwood application task, a controlled comparison or evidence of +token/subscription/cash savings. + +OS1a and FS2 now have first real Claude read-only tool-use and export evidence. +Actual-client edit → stale → refresh, restart/disable, a consequential task and +complete everyday host/worker/review receipts remain open. Eight searches before +one packet are an observation to review on further tasks, not a demonstrated +regression or causal savings claim. Documentation links and source assertions +were checked; no production code or language eligibility changed in this slice. + +## 22 September 2026 — Kotlin script and C++ retrieval alignment (0.3.2) + +The language audit's six concrete gaps are fixed: `.kts`, `.cc`, `.cxx`, `.hh`, +`.hpp` and `.hxx` are eligible for navigation and exact packets. Broad scanning +already recognised them; syntax planning remains TS/JS-only. No new parser or +semantic-resolution claim is made. The support matrix now documents this state. + +The M4 worker endpoint was occupied by another live session, so no inference was +dispatched or interrupted. The host implemented and reviewed the small allowlist +change and regression tests. The first focused run failed seven assertions on +test error wording; the repair checks actual stale status and the existing +refresh-required error. All 26 focused tests then passed. Whole host usage and +review cost remain incomplete; no worker-token or monetary saving is claimed. + +Local shipment checks passed 402 tests, independent installed-package smoke, +both unchanged benchmark gates, navigation stdio smoke, 22 scale tests and the +10k postings probe. Per-suffix MCP tests cover search, source hashes/lines, +checkout/commit provenance, stale rejection and refresh, Git-ignore exclusions +and unsupported plan requests; the installed smoke retrieves all six suffixes. +Dart remains explicitly unsupported. Publication/CI evidence belongs to the +0.3.2 release, separately from these local checks; npm auth returned HTTP 401. + +Existing servers need a reconnect after the upgrade. No Heartwood checkout, +configuration or live job was changed. Real Claude lifecycle qualification, +routine whole-task receipts and measured benefit remain the next adoption gates. diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index a53c83b..384eba0 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -27,8 +27,8 @@ matching core version: mkdir context-install cd context-install npm init -y -npm install --ignore-scripts /absolute/path/to/forgesworn-context-0.3.1.tgz \ - /absolute/path/to/forgesworn-context-tools-0.3.1.tgz +npm install --ignore-scripts /absolute/path/to/forgesworn-context-0.3.2.tgz \ + /absolute/path/to/forgesworn-context-tools-0.3.2.tgz ``` For that installation, use diff --git a/docs/LANGUAGE-SUPPORT.md b/docs/LANGUAGE-SUPPORT.md new file mode 100644 index 0000000..8c85d6b --- /dev/null +++ b/docs/LANGUAGE-SUPPORT.md @@ -0,0 +1,64 @@ +# Source coverage: Kotlin, C/C++, Dart and TypeScript + +Updated for 0.3.2 on 22 September 2026. The original audit used 0.3.1 +(`bb83fa3`); the six suffix eligibility gaps found there are fixed in 0.3.2. +This is a selected capability audit, not a complete language manifest. Source +allowlists establish eligibility; ignores, selection policy and resource bounds +can still exclude eligible files. + +| Suffix | Repository navigation | Broad source scan | Exact `build` packet | Syntax-aware `plan` packet | +| --- | --- | --- | --- | --- | +| `.kt` | Yes | Kotlin lexical extraction | Yes | Unsupported | +| `.kts` | Yes | Kotlin lexical extraction | Yes | Unsupported | +| `.cpp` | Yes | C++ lexical extraction | Yes | Unsupported | +| `.cc`, `.cxx` | Yes | C++ lexical extraction | Yes | Unsupported | +| `.h` | Yes | Classified as C; lexical extraction | Yes | Unsupported | +| `.hh`, `.hpp`, `.hxx` | Yes | C++ lexical extraction | Yes | Unsupported | +| `.dart` | Excluded | Unsupported | Rejected | Unsupported | +| `.ts` | Yes | Not handled by this scanner; separate TS/JS scanner exists | Yes | TypeScript syntax blocks | + +The source contracts are +[navigation's suffix allowlist](../packages/context-tools/src/repository-navigation.ts), +[the broad scanner's language map and lexical rules](../packages/context-tools/src/broad-source-scan.ts), +[the TS/JS scanner](../packages/context-tools/src/source-scan.ts), and +[packet source/plan allowlists and guards](../packages/context-tools/src/source-packet.mjs). + + +Navigation provides exact-token line lookup. Broad scanning uses regular +expressions and labels inferred relationships; it is not a language parser. +The dedicated TS/JS scanner and packet planner use TypeScript syntax trees, but +do not establish type-checked semantic resolution. Exact build packets copy +selected lines with provenance; they make no syntax-completeness guarantee. +Unsupported plan suffixes are explicitly rejected by the planner guard before +TypeScript parsing; rejection is not a parser failure on those languages. + +## Test evidence and remaining gaps + +- [MCP packet tests](../packages/context-tools/src/repository-packet-mcp.test.ts) + exercise each added suffix, plus uppercase `.HPP`, through exact search, packet + lines and hashes, checkout/commit provenance, stale rejection, generation + replacement and retrieval after an edit. Git-ignore exclusions still suppress + search and reject packets. Syntax planning still rejects these suffixes. +- [Broad scanner tests](../packages/context-tools/src/broad-source-scan.test.ts) + cover declarations and lexical provenance for all six suffixes and uppercase + `.HPP`. Dart remains explicitly unsupported in scanning and MCP retrieval. +- [Installed package smoke](../test/context-package-smoke.mjs) retrieves all six + suffixes through the installed stdio MCP server outside the workspace. +- Existing packet tests retain TS/JS syntax support and path/policy boundaries. + These tests establish source retrieval and lexical coverage, not compiler-level + understanding or complete evidence for an arbitrary development task. + +Dart extraction and deeper Kotlin/C++ parsing remain separate work. A running +MCP server needs a reconnect after upgrading its implementation; refreshing the +source index alone does not load new server code. Measure benefits on actual +accepted tasks; no token or subscription saving follows from suffix coverage. + +## Qualification provenance + +Claude Code 2.1.278 used the independently installed 0.3.1 repository MCP package +for this audit, with `claude-sonnet-5` and requested medium effort. All four tools +were used. Host source review corrected a false `.kts`-absence claim, an incorrect +suffix count, planner-rejection wording and the incomplete proposed C++ suffix +set before accepting this document. The original draft is retained privately. +See [the execution ledger](DOGFOOD-EXECUTION.md) for usage and remaining client +acceptance limits. This is not a measured savings comparison. diff --git a/docs/OPEN-SOURCE-EXECUTION.md b/docs/OPEN-SOURCE-EXECUTION.md index d23e7b9..f4bb8af 100644 --- a/docs/OPEN-SOURCE-EXECUTION.md +++ b/docs/OPEN-SOURCE-EXECUTION.md @@ -55,7 +55,7 @@ access. The execution lead owns progress until another owner is explicitly named | Luna/medium | `gpt-5.6-luna`, `medium` | Optional small mechanical/documentation fallback; not required for the critical path | | GLM/low | `glm-5.3-flash:cloud`, `low` only after runtime support is verified | Deferred candidate qualification on one useful bounded task; not a dependency | | Pro/off | `deepseek-v4-pro:cloud`, `think=false` after endpoint eligibility/reconciliation | Optional harder-worker experiment; not a dependency | -| Claude Sonnet/medium | `claude-sonnet-5`, `medium` | First Claude Code client qualification and routine coding acceptance; not yet qualified here | +| Claude Sonnet/medium | `claude-sonnet-5`, `medium` | First read-only Claude audit accepted after host corrections; lifecycle and routine coding acceptance remain open | | Claude Opus/high | `claude-opus-5`, `high` | Consequential Claude task/review acceptance after basic MCP qualification; not yet qualified here | See [Claude assignments and official references](CLIENTS-AND-LANGUAGES.md) for @@ -85,7 +85,7 @@ and effort; record the actual values rather than silently switching them. | Goal / status | What needs doing | Owner and location | Implementation | Review | Completion evidence | | --- | --- | --- | --- | --- | --- | | **OS0 — Useful daily task. Next; tools exist** | Supply one sufficient verified packet for a real task; reuse current evidence on two further tasks; capture repairs and usage | Context lead: `scripts/worker-packet.mjs`, `docs/WORKER-PACKETS.md`, private receipts. Heartwood owner: application task in its own checkout | Deterministic first; Flash/off only for a demonstrated small tooling gap. Application work keeps its existing frontier model/effort | Existing application review; Terra/medium for routine Context changes, Sol/high only for a boundary change | Three accepted tasks with task/revision/model, source selection, freshness, checks, failure and usage records. This proves usability, not savings | -| **OS1 — Independent developer installation and MCP clients. Next; partial local proof exists** | Package supported CLI/MCP use for **Claude Code and Codex**; expose bounded verified source packets; eliminate private-helper dependencies; follow OS1a–OS1d | Context implementer: `packages/context-tools`, `scripts`, package manifests, `test/context-package-smoke.mjs`, README and client docs | Flash/off for scoped packaging/docs; Terra/medium integration; Sonnet/medium then Opus/high for Claude qualification | Terra/medium; Sol/high for new disclosure/path boundaries | Pinned install outside workspace; actual task/tool use in both clients, edits → stale → refresh, restart/removal and bounded source; Node/Python prerequisites explicit; no Oathrun/provider credentials in Context/M4 required | +| **OS1 — Independent developer installation and MCP clients. Partial: shipped doctor and first Claude audit** | Package supported CLI/MCP use for **Claude Code and Codex**; expose bounded verified source packets; eliminate private-helper dependencies; follow OS1a–OS1d | Context implementer: `packages/context-tools`, `scripts`, package manifests, `test/context-package-smoke.mjs`, README and client docs | Flash/off for scoped packaging/docs; Terra/medium integration; Sonnet/medium then Opus/high for Claude qualification | Terra/medium; Sol/high for new disclosure/path boundaries | Pinned install outside workspace; actual task/tool use in both clients, edits → stale → refresh, restart/removal and bounded source; Node/Python prerequisites explicit; no Oathrun/provider credentials in Context/M4 required | | **OS2 — Benefits with frontier quality. Open; previous assisted qualification failed** | Qualify the improved packet once, then prospectively lock and run a fair retrieval comparison using the same frontier model per pair; include non-ForgeSworn use | Context lead + reviewer: `benchmarks`, `test/task-cost-report.test.mjs`, `scripts/task-cost-report.mjs`, a new `docs/experiments` directory and private usage receipts; external pilot owns its repository | Deterministic accounting; Flash/off for small reporting gaps; **Sol/high for both new baseline and assisted executors**, separate fresh sessions | Independent Sol/high for protocol and accepted outcomes | Eight paired tasks across at least two explicit repositories, including one outside ForgeSworn; all assisted outcomes accepted; target ≥20% lower aggregate total model tokens and no higher aggregate review time. Report cached/uncached input and output separately; billing unknown leaves cash savings unproven | | **OS3 — Usable local graph. Queued after OS0–OS2** | Bring the original viewer and dependency graph into maintained MIT tooling; expose neighbourhoods, search, source links, edge provenance and incomplete/unknown results | Context implementer: original private prototype as input, maintained implementation under `packages/context-tools`, tests and public fixtures | Flash/off for bounded UI/fixtures; Terra/medium for graph/tool integration | Terra/medium for usability; Sol/high for unsafe-content and source/disclosure boundaries | An independent install visualises a selected repository/ecosystem, explains each relationship and opens exact evidence; works offline without a service; no Graphify code; hostile labels/links and large result bounds tested | | **OS4 — Correct versions and language understanding. Partial; OS4a/b start with OS1** | Connect snapshot evidence; publish exact support levels; deepen Rust and TS/JS, then Kotlin and task-selected wider-stack languages; follow OS4a–OS4d | Context lead: `scripts/ecosystem_resolution.py`, `scripts/ecosystem_snapshot.py`, source/ecosystem scanners in `packages/context-tools`, matching tests and fixtures | Sol/high version/provenance design; Terra/medium parser/integration work; Flash/off mechanically specified fixtures | Independent Sol/high for resolution/identity; Terra/medium ordinary extractor changes | Released package vs HEAD/worktree/ambiguity fixtures; parser-backed relationships and complete packets on real stack tasks; TS/JS syntax hints are not type-checked proof, and lexical inference remains labelled; unsupported cases visible | diff --git a/package-lock.json b/package-lock.json index 4a5ac68..5a08a62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3071,7 +3071,7 @@ }, "packages/context": { "name": "@forgesworn/context", - "version": "0.3.1", + "version": "0.3.2", "license": "MIT", "dependencies": { "@noble/ciphers": "2.1.1", @@ -3089,10 +3089,10 @@ }, "packages/context-tools": { "name": "@forgesworn/context-tools", - "version": "0.3.1", + "version": "0.3.2", "license": "MIT", "dependencies": { - "@forgesworn/context": "0.3.1", + "@forgesworn/context": "0.3.2", "@modelcontextprotocol/sdk": "1.30.0", "@noble/hashes": "1.8.0", "ignore": "7.0.9", diff --git a/packages/context-tools/README.md b/packages/context-tools/README.md index a018ac2..b080827 100644 --- a/packages/context-tools/README.md +++ b/packages/context-tools/README.md @@ -6,12 +6,12 @@ ESM, Node 24+. Separate from the browser-safe core: filesystem and MCP dependencies never enter its root import. No KithMoot or NanoClaw runtime dependency. -The 0.3.1 release tarballs include the setup doctor and require the matching core +The 0.3.2 release tarballs include the setup doctor and require the matching core package. Follow the [installation guide](../../docs/GETTING-STARTED.md) to install both archives together. npm publication is pending; once published, use: ```sh -npm install @forgesworn/context-tools@0.3.1 +npm install @forgesworn/context-tools@0.3.2 ``` The source is maintained in the public Z1P Core workspace. Build with diff --git a/packages/context-tools/THIRD_PARTY_NOTICES.md b/packages/context-tools/THIRD_PARTY_NOTICES.md index 5578d31..64e8d1e 100644 --- a/packages/context-tools/THIRD_PARTY_NOTICES.md +++ b/packages/context-tools/THIRD_PARTY_NOTICES.md @@ -1,6 +1,6 @@ # Third-party notices -These notices accompany `@forgesworn/context-tools@0.3.1`. The package itself is +These notices accompany `@forgesworn/context-tools@0.3.2`. The package itself is MIT licensed, Copyright (c) 2026 TheCryptoDonkey; see `LICENSE`. Runtime dependencies are installed separately by the package manager, not @@ -9,9 +9,9 @@ notices below cover direct runtime dependencies; retain the licence files from transitive dependencies as well when redistributing an installation or bundle. Dependency versions and source links refer to this release. -## @forgesworn/context@0.3.1 +## @forgesworn/context@0.3.2 -Declared licence: MIT. Source package: https://www.npmjs.com/package/@forgesworn/context/v/0.3.1 +Declared licence: MIT. Source package: https://www.npmjs.com/package/@forgesworn/context/v/0.3.2 ```text MIT License diff --git a/packages/context-tools/package.json b/packages/context-tools/package.json index 6e3582b..c1071bb 100644 --- a/packages/context-tools/package.json +++ b/packages/context-tools/package.json @@ -1,6 +1,6 @@ { "name": "@forgesworn/context-tools", - "version": "0.3.1", + "version": "0.3.2", "description": "Local CLI and MCP tools for Z1P Core encrypted context", "license": "MIT", "type": "module", @@ -36,7 +36,7 @@ "test": "vitest run --config vitest.config.ts" }, "dependencies": { - "@forgesworn/context": "0.3.1", + "@forgesworn/context": "0.3.2", "@modelcontextprotocol/sdk": "1.30.0", "@noble/hashes": "1.8.0", "ignore": "7.0.9", diff --git a/packages/context-tools/src/broad-source-scan.test.ts b/packages/context-tools/src/broad-source-scan.test.ts index 56fb389..6101966 100644 --- a/packages/context-tools/src/broad-source-scan.test.ts +++ b/packages/context-tools/src/broad-source-scan.test.ts @@ -17,6 +17,22 @@ function bySource(result: Awaited>, expe } describe('bounded broad-language source graph scan', () => { + it.each(['kts', 'cc', 'cxx', 'hh', 'hpp', 'hxx', 'HPP'])('extracts .%s declarations with lexical provenance', async (extension) => { + const root = await fixture() + await source(root, `sample.${extension}`, 'class SuffixMarker {}\n') + const result = await scanBroadSourceGraph(root, { observedAt: 123 }) + expect(result.languages).toEqual([extension === 'kts' ? 'kotlin' : 'cpp']) + expect(result.records.some(record => record.source.startsWith(`repo://sample.${extension}#`) && record.text.includes('SuffixMarker') && record.provenance?.derivation === 'inferred' && record.provenance.method === 'language-regex')).toBe(true) + }) + + it('does not infer Dart declarations', async () => { + const root = await fixture() + await source(root, 'sample.dart', 'class DartMarker {}\n') + const result = await scanBroadSourceGraph(root, { observedAt: 123 }) + expect(result.languages).toEqual([]) + expect(result.records).toEqual([]) + }) + it('finds representative declarations across every supported language family', async () => { const root = await fixture() const samples: Record = { diff --git a/packages/context-tools/src/repository-navigation.ts b/packages/context-tools/src/repository-navigation.ts index 5cd7ff5..2286659 100644 --- a/packages/context-tools/src/repository-navigation.ts +++ b/packages/context-tools/src/repository-navigation.ts @@ -105,7 +105,8 @@ const DEFAULT_LIMITS: NavigationLimits = { const EXTENSIONS = new Set([ '.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs', - '.py', '.rs', '.go', '.java', '.kt', '.swift', '.c', '.cpp', '.h', + '.py', '.rs', '.go', '.java', '.kt', '.kts', '.swift', + '.c', '.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp', '.hxx', '.cs', '.rb', '.php', '.md', ]); diff --git a/packages/context-tools/src/repository-packet-mcp.test.ts b/packages/context-tools/src/repository-packet-mcp.test.ts index 85f6653..5633308 100644 --- a/packages/context-tools/src/repository-packet-mcp.test.ts +++ b/packages/context-tools/src/repository-packet-mcp.test.ts @@ -1,6 +1,7 @@ import { afterEach, describe, expect, it } from 'vitest' import { execFile } from 'node:child_process' -import { mkdtemp, rm, writeFile } from 'node:fs/promises' +import { createHash } from 'node:crypto' +import { mkdtemp, realpath, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { promisify } from 'node:util' @@ -38,6 +39,93 @@ function call(client: Client, arguments_: object) { return client.callTool({ nam afterEach(async () => { await Promise.all(roots.splice(0).map((value) => rm(value, { recursive: true, force: true }))) }) describe('repository packet MCP adapter', () => { + it.each(['kts', 'cc', 'cxx', 'hh', 'hpp', 'hxx', 'HPP'])('retrieves .%s evidence, refreshes edits and retains policy and planner boundaries', async (extension) => { + const value = await root() + const file = `sample.${extension}` + const content = '// fixture\nclass EvidenceMarker {}\n' + await writeFile(join(value, file), content) + const connection = await connect(value) + const fixtureSpec = (sources: unknown[]) => ({ ...spec(sources), allowedFiles: [file] }) + const search = async (term: string) => { + const result = await connection.client.callTool({ name: 'repository_search', arguments: { term } }) + expect(result.isError).not.toBe(true) + return JSON.parse(text(result)) + } + const refresh = async () => { + const result = await connection.client.callTool({ name: 'repository_refresh', arguments: {} }) + expect(result.isError).not.toBe(true) + return JSON.parse(text(result)).generation as string + } + const build = (expectedGeneration: string) => call(connection.client, { + mode: 'build', expectedGeneration, + spec: fixtureSpec([{ path: file, startLine: 2, endLine: 2 }]), + }) + try { + let generation = await refresh() + const digest = createHash('sha256').update(content).digest('hex') + expect((await search('EvidenceMarker')).results).toEqual([ + { path: file, line: 2, text: 'class EvidenceMarker {}', sha256: digest }, + ]) + const built = await build(generation) + expect(built.isError).not.toBe(true) + const packet = JSON.parse(text(built)).packet + expect(packet.canonicalRoot).toBe(await realpath(value)) + expect(packet.gitHEAD).toBe((await exec('git', ['-C', value, 'rev-parse', 'HEAD'])).stdout.trim()) + expect(packet.sources[0]).toMatchObject({ path: file, sha256: digest, startLine: 2, endLine: 2, lines: [{ line: 2, content: 'class EvidenceMarker {}' }] }) + expect(packet.allowedFiles[0]).toMatchObject({ path: file, state: 'present', sha256: digest }) + const planned = await call(connection.client, { mode: 'plan', expectedGeneration: generation, spec: fixtureSpec([{ path: file, line: 2 }]) }) + expect(planned.isError).toBe(true) + expect(text(planned)).toMatch(/planner source extension is unsupported/) + + const changed = '// fixture\nclass UpdatedEvidenceMarker {}\n' + await writeFile(join(value, file), changed) + const status = await connection.client.callTool({ name: 'repository_status', arguments: {} }) + expect(JSON.parse(text(status)).freshness).toBe('stale') + const stale = await build(generation) + expect(stale.isError).toBe(true) + expect(text(stale)).toMatch(/requires current navigation/) + const previous = generation + generation = await refresh() + expect(generation).not.toBe(previous) + expect((await build(previous)).isError).toBe(true) + expect((await search('EvidenceMarker')).results).toEqual([]) + expect((await search('UpdatedEvidenceMarker')).results[0].path).toBe(file) + const updated = await build(generation) + expect(updated.isError).not.toBe(true) + expect(JSON.parse(text(updated)).packet.sources[0]).toMatchObject({ + sha256: createHash('sha256').update(changed).digest('hex'), + lines: [{ line: 2, content: 'class UpdatedEvidenceMarker {}' }], + }) + + await writeFile(join(value, '.gitignore'), `${file}\n`) + expect((await build(generation)).isError).toBe(true) + generation = await refresh() + expect((await search('UpdatedEvidenceMarker')).results).toEqual([]) + const excluded = await build(generation) + expect(excluded.isError).toBe(true) + expect(text(excluded)).toMatch(/excluded|policy/) + } finally { await connection.close() } + }) + + it('continues to exclude Dart from navigation and reject its build and plan packets', async () => { + const value = await root() + await writeFile(join(value, 'sample.dart'), 'class DartMarker {}\n') + const connection = await connect(value) + try { + const refreshed = await connection.client.callTool({ name: 'repository_refresh', arguments: {} }) + const expectedGeneration = JSON.parse(text(refreshed)).generation + const found = await connection.client.callTool({ name: 'repository_search', arguments: { term: 'DartMarker' } }) + expect(found.isError).not.toBe(true) + expect(JSON.parse(text(found)).results).toEqual([]) + for (const mode of ['build', 'plan']) { + const source = mode === 'build' ? { path: 'sample.dart', startLine: 1, endLine: 1 } : { path: 'sample.dart', line: 1 } + const result = await call(connection.client, { mode, expectedGeneration, spec: { ...spec([source]), allowedFiles: ['sample.dart'] } }) + expect(result.isError).toBe(true) + expect(text(result)).toMatch(/extension is unsupported/) + } + } finally { await connection.close() } + }) + it('discovers inline-only packet input and requires a current matching generation', async () => { const value = await root(); const connection = await connect(value) try { diff --git a/packages/context-tools/src/source-packet.mjs b/packages/context-tools/src/source-packet.mjs index 09d2473..076eeda 100644 --- a/packages/context-tools/src/source-packet.mjs +++ b/packages/context-tools/src/source-packet.mjs @@ -16,7 +16,7 @@ const MAX_PACKET_BYTES = 64 * 1024; const MAX_FILES = 32; const MAX_FILE_BYTES = 1024 * 1024; const MAX_TOTAL_BYTES = 8 * 1024 * 1024; -const SOURCE_EXTENSIONS = new Set(['ts', 'tsx', 'js', 'jsx', 'mts', 'cts', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'kt', 'swift', 'c', 'cpp', 'h', 'cs', 'rb', 'php', 'md']); +const SOURCE_EXTENSIONS = new Set(['ts', 'tsx', 'js', 'jsx', 'mts', 'cts', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'kt', 'kts', 'swift', 'c', 'cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'hxx', 'cs', 'rb', 'php', 'md']); const PLANNABLE_EXTENSIONS = new Set(['ts', 'tsx', 'js', 'jsx', 'mts', 'cts', 'mjs', 'cjs']); const GENERATED_DIRECTORIES = new Set(['node_modules', 'dist', 'build', 'coverage', 'out', 'vendor', 'target']); diff --git a/packages/context/README.md b/packages/context/README.md index 64b52ac..a453c5c 100644 --- a/packages/context/README.md +++ b/packages/context/README.md @@ -9,12 +9,12 @@ This compatibility package is maintained in the public Z1P Core repository alongside its CLI/MCP adapter. Its established package, API and protocol names remain unchanged during the product rebrand. It has its own manifest, exports, build and distributable tarball. -The matching 0.3.1 packages are distributed as GitHub release tarballs; see the +The matching 0.3.2 packages are distributed as GitHub release tarballs; see the [installation guide](../../docs/GETTING-STARTED.md). npm publication is pending. Once the matching version is published, install with: ```sh -npm install @forgesworn/context@0.3.1 +npm install @forgesworn/context@0.3.2 ``` From a source checkout, use `npm ci --ignore-scripts`, diff --git a/packages/context/THIRD_PARTY_NOTICES.md b/packages/context/THIRD_PARTY_NOTICES.md index c6aee6e..4cefd89 100644 --- a/packages/context/THIRD_PARTY_NOTICES.md +++ b/packages/context/THIRD_PARTY_NOTICES.md @@ -1,6 +1,6 @@ # Third-party notices -These notices accompany `@forgesworn/context@0.3.1`. The package itself is +These notices accompany `@forgesworn/context@0.3.2`. The package itself is MIT licensed, Copyright (c) 2026 TheCryptoDonkey; see `LICENSE`. Runtime dependencies are installed separately by the package manager, not diff --git a/packages/context/package.json b/packages/context/package.json index d9468ee..d3dc6f7 100644 --- a/packages/context/package.json +++ b/packages/context/package.json @@ -1,6 +1,6 @@ { "name": "@forgesworn/context", - "version": "0.3.1", + "version": "0.3.2", "description": "Z1P Core portable signed and encrypted context collections", "license": "MIT", "type": "module", diff --git a/test/context-package-smoke.mjs b/test/context-package-smoke.mjs index c62e8ed..d3ae2ac 100644 --- a/test/context-package-smoke.mjs +++ b/test/context-package-smoke.mjs @@ -75,6 +75,9 @@ export const view = await vault.create({ title: 'Independent consumer', scope: ' const packetRoot = join(toolsConsumer, 'packet-repository') mkdirSync(packetRoot) writeFileSync(join(packetRoot, 'example.ts'), 'export function example() {\n return 1\n}\n') + for (const extension of ['kts', 'cc', 'cxx', 'hh', 'hpp', 'hxx']) { + writeFileSync(join(packetRoot, 'example.' + extension), 'class InstalledSuffixMarker {}\n') + } const git = args => execFileSync('git', ['-C', packetRoot, ...args], { stdio: 'pipe', env: Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith('GIT_'))) }) git(['init', '--quiet']) git(['add', 'example.ts']) @@ -121,6 +124,18 @@ export const view = await vault.create({ title: 'Independent consumer', scope: ' assert.equal(value.packet.sources.length, 1) assert.equal(value.packet.sources[0].startLine, 1) assert.equal(value.packet.sources[0].endLine, 3) + const found = await client.callTool({ name: 'repository_search', arguments: { term: 'InstalledSuffixMarker' } }) + assert.notEqual(found.isError, true, text(found)) + assert.deepEqual(JSON.parse(text(found)).results.map(item => item.path).sort(), ['cc', 'cxx', 'hh', 'hpp', 'hxx', 'kts'].map(extension => 'example.' + extension)) + for (const extension of ['kts', 'cc', 'cxx', 'hh', 'hpp', 'hxx']) { + const path = 'example.' + extension + const result = await client.callTool({ name: 'repository_packet', arguments: { + mode: 'build', expectedGeneration: status.generation, + spec: { ...spec, allowedFiles: [path], sources: [{ path, startLine: 1, endLine: 1 }] }, + } }) + assert.notEqual(result.isError, true, text(result)) + assert.deepEqual(JSON.parse(text(result)).packet.sources[0].lines, [{ line: 1, content: 'class InstalledSuffixMarker {}' }]) + } await writeFile(root + '/example.ts', 'export function example() {\\n return 22\\n}\\n') assert.equal((await get(status.generation)).isError, true) const oldGeneration = status.generation