@sigloch/graphcode-client 0.1.0
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/LICENSE +21 -0
- package/dist/host-client.d.ts +20 -0
- package/dist/host-client.js +76 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/view-catalog.d.ts +22 -0
- package/dist/view-catalog.js +57 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sigloch Consulting
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Socket filename inside the store dir — beside the lock it is elected by. */
|
|
2
|
+
export declare const HOST_SOCK_BASENAME = "host.sock";
|
|
3
|
+
/** One forwarded tool call on the wire: newline-delimited JSON, one per connection. */
|
|
4
|
+
export interface ShimRequest {
|
|
5
|
+
id: number;
|
|
6
|
+
tool: string;
|
|
7
|
+
input: unknown;
|
|
8
|
+
}
|
|
9
|
+
/** The host's answer to a {@link ShimRequest}. */
|
|
10
|
+
export type ShimResponse = {
|
|
11
|
+
id: number;
|
|
12
|
+
ok: true;
|
|
13
|
+
result: unknown;
|
|
14
|
+
} | {
|
|
15
|
+
id: number;
|
|
16
|
+
ok: false;
|
|
17
|
+
error: string;
|
|
18
|
+
};
|
|
19
|
+
/** One forwarded tool call: connect → send → one response line → close. */
|
|
20
|
+
export declare function callHost(socketPath: string, tool: string, input: unknown): Promise<unknown>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* host-client.ts — the CLIENT half of the graphcode host socket (CR-GC-264).
|
|
3
|
+
*
|
|
4
|
+
* A running `graphcode mcp` host owns the single Kuzu store of a repo and keeps
|
|
5
|
+
* a local Unix socket (`.graphcode/host.sock`) open. Anything that wants to reach
|
|
6
|
+
* the ONE Apply-Gate without becoming a second store owner talks to that socket:
|
|
7
|
+
* later MCP sessions (via graphcode's own proxy registry) and external readers
|
|
8
|
+
* such as the viewer/editor.
|
|
9
|
+
*
|
|
10
|
+
* This module is deliberately the *whole* dependency footprint of that path:
|
|
11
|
+
* `node:net` and nothing else. It lives outside `@sigloch/graphcode` so a
|
|
12
|
+
* consumer that only forwards tool calls does not install kuzu-wasm (~70 MB) and
|
|
13
|
+
* the MCP SDK it structurally cannot use — npm resolves dependencies per package,
|
|
14
|
+
* not per entry point, so a subpath export would not have achieved that.
|
|
15
|
+
*
|
|
16
|
+
* The SERVER half (socket creation, election, proxy registry) stays in
|
|
17
|
+
* graphcode's `host-shim.ts`; it imports the wire types from here so the two
|
|
18
|
+
* halves can never drift apart.
|
|
19
|
+
*
|
|
20
|
+
* @author andreas@siglochconsulting
|
|
21
|
+
*/
|
|
22
|
+
import { connect } from 'node:net';
|
|
23
|
+
/** Socket filename inside the store dir — beside the lock it is elected by. */
|
|
24
|
+
export const HOST_SOCK_BASENAME = 'host.sock';
|
|
25
|
+
/** Connect-retry window: the election winner may still be booting its socket. */
|
|
26
|
+
const CONNECT_RETRIES = 10;
|
|
27
|
+
const CONNECT_RETRY_MS = 200;
|
|
28
|
+
function connectOnce(socketPath) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const socket = connect(socketPath);
|
|
31
|
+
socket.once('connect', () => resolve(socket));
|
|
32
|
+
socket.once('error', reject);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function connectWithRetry(socketPath) {
|
|
36
|
+
let lastErr;
|
|
37
|
+
for (let i = 0; i < CONNECT_RETRIES; i++) {
|
|
38
|
+
try {
|
|
39
|
+
return await connectOnce(socketPath);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
lastErr = err;
|
|
43
|
+
await new Promise((r) => setTimeout(r, CONNECT_RETRY_MS));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
47
|
+
}
|
|
48
|
+
let nextRequestId = 1;
|
|
49
|
+
/** One forwarded tool call: connect → send → one response line → close. */
|
|
50
|
+
export async function callHost(socketPath, tool, input) {
|
|
51
|
+
const socket = await connectWithRetry(socketPath);
|
|
52
|
+
const id = nextRequestId++;
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
let buffer = '';
|
|
55
|
+
socket.on('data', (chunk) => {
|
|
56
|
+
buffer += chunk.toString('utf8');
|
|
57
|
+
const nl = buffer.indexOf('\n');
|
|
58
|
+
if (nl < 0)
|
|
59
|
+
return;
|
|
60
|
+
socket.end();
|
|
61
|
+
try {
|
|
62
|
+
const res = JSON.parse(buffer.slice(0, nl));
|
|
63
|
+
if (res.ok)
|
|
64
|
+
resolve(res.result);
|
|
65
|
+
else
|
|
66
|
+
reject(new Error(res.error));
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
socket.on('error', (err) => reject(err));
|
|
73
|
+
socket.on('close', () => reject(new Error(`host closed the connection before answering (${socketPath})`)));
|
|
74
|
+
socket.write(JSON.stringify({ id, tool, input }) + '\n');
|
|
75
|
+
});
|
|
76
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sigloch/graphcode-client — the read-side of a running graphcode host.
|
|
3
|
+
*
|
|
4
|
+
* Everything a consumer needs to talk to an already-elected `graphcode mcp` host
|
|
5
|
+
* and to project its answers, WITHOUT owning a store: no kuzu-wasm, no MCP SDK,
|
|
6
|
+
* no harness. The write path is unchanged — `callHost` forwards to the host's
|
|
7
|
+
* ONE `mutate()` gate; this package never opens a second one.
|
|
8
|
+
*
|
|
9
|
+
* Scope split (CR-GC-264):
|
|
10
|
+
* - here : host-socket client, view catalog (+ readiness/panels in CR-GC-265)
|
|
11
|
+
* - @sigloch/graphcode : store, gate, MCP server, exporters, host election
|
|
12
|
+
*
|
|
13
|
+
* @author andreas@siglochconsulting
|
|
14
|
+
*/
|
|
15
|
+
export { HOST_SOCK_BASENAME, callHost, type ShimRequest, type ShimResponse, } from './host-client.js';
|
|
16
|
+
export { MARKDOWN_VIEWS, VIEW_FILENAMES, type MarkdownView } from './view-catalog.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sigloch/graphcode-client — the read-side of a running graphcode host.
|
|
3
|
+
*
|
|
4
|
+
* Everything a consumer needs to talk to an already-elected `graphcode mcp` host
|
|
5
|
+
* and to project its answers, WITHOUT owning a store: no kuzu-wasm, no MCP SDK,
|
|
6
|
+
* no harness. The write path is unchanged — `callHost` forwards to the host's
|
|
7
|
+
* ONE `mutate()` gate; this package never opens a second one.
|
|
8
|
+
*
|
|
9
|
+
* Scope split (CR-GC-264):
|
|
10
|
+
* - here : host-socket client, view catalog (+ readiness/panels in CR-GC-265)
|
|
11
|
+
* - @sigloch/graphcode : store, gate, MCP server, exporters, host election
|
|
12
|
+
*
|
|
13
|
+
* @author andreas@siglochconsulting
|
|
14
|
+
*/
|
|
15
|
+
export { HOST_SOCK_BASENAME, callHost, } from './host-client.js';
|
|
16
|
+
export { MARKDOWN_VIEWS, VIEW_FILENAMES } from './view-catalog.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* view-catalog.ts — the markdown view vocabulary (CR-GC-264).
|
|
3
|
+
*
|
|
4
|
+
* Which document views exist, in which order, and under which filename they are
|
|
5
|
+
* exported to `docs/views/`. Pure data: the RENDERERS stay in graphcode's
|
|
6
|
+
* `exporter.ts`, only the catalog moved here so a viewer can list and link the
|
|
7
|
+
* views without depending on the exporter — and through it on the store.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately NO Zod. A library that hands out a `ZodEnum` forces every consumer
|
|
10
|
+
* onto the exact same zod instance; the moment two copies exist (a linked sibling,
|
|
11
|
+
* a non-deduped install) the schema types stop being assignable and the failure
|
|
12
|
+
* reads as an unrelated type error. The list is the shared truth — graphcode
|
|
13
|
+
* builds `MarkdownViewSchema` from it with its OWN zod, so there is still exactly
|
|
14
|
+
* one definition and this package keeps zero runtime dependencies.
|
|
15
|
+
*
|
|
16
|
+
* @author andreas@siglochconsulting
|
|
17
|
+
*/
|
|
18
|
+
/** All supported views, in deterministic order. */
|
|
19
|
+
export declare const MARKDOWN_VIEWS: readonly ["spec", "architecture", "cr-list", "references", "srs", "nfr", "rtm", "icd", "testconcept", "testmatrix", "intplan", "changelog", "fmea", "conops", "trade", "implplan"];
|
|
20
|
+
export type MarkdownView = (typeof MARKDOWN_VIEWS)[number];
|
|
21
|
+
/** Default file name for each view (under docs/views/). */
|
|
22
|
+
export declare const VIEW_FILENAMES: Record<MarkdownView, string>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* view-catalog.ts — the markdown view vocabulary (CR-GC-264).
|
|
3
|
+
*
|
|
4
|
+
* Which document views exist, in which order, and under which filename they are
|
|
5
|
+
* exported to `docs/views/`. Pure data: the RENDERERS stay in graphcode's
|
|
6
|
+
* `exporter.ts`, only the catalog moved here so a viewer can list and link the
|
|
7
|
+
* views without depending on the exporter — and through it on the store.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately NO Zod. A library that hands out a `ZodEnum` forces every consumer
|
|
10
|
+
* onto the exact same zod instance; the moment two copies exist (a linked sibling,
|
|
11
|
+
* a non-deduped install) the schema types stop being assignable and the failure
|
|
12
|
+
* reads as an unrelated type error. The list is the shared truth — graphcode
|
|
13
|
+
* builds `MarkdownViewSchema` from it with its OWN zod, so there is still exactly
|
|
14
|
+
* one definition and this package keeps zero runtime dependencies.
|
|
15
|
+
*
|
|
16
|
+
* @author andreas@siglochconsulting
|
|
17
|
+
*/
|
|
18
|
+
/** All supported views, in deterministic order. */
|
|
19
|
+
export const MARKDOWN_VIEWS = [
|
|
20
|
+
// foundation (CR-GC-113)
|
|
21
|
+
'spec',
|
|
22
|
+
'architecture',
|
|
23
|
+
'cr-list',
|
|
24
|
+
'references',
|
|
25
|
+
// SE-artifact projections (CR-GC-220)
|
|
26
|
+
'srs',
|
|
27
|
+
'nfr',
|
|
28
|
+
'rtm',
|
|
29
|
+
'icd',
|
|
30
|
+
'testconcept',
|
|
31
|
+
'testmatrix',
|
|
32
|
+
'intplan',
|
|
33
|
+
'changelog',
|
|
34
|
+
'fmea',
|
|
35
|
+
'conops',
|
|
36
|
+
'trade',
|
|
37
|
+
'implplan',
|
|
38
|
+
];
|
|
39
|
+
/** Default file name for each view (under docs/views/). */
|
|
40
|
+
export const VIEW_FILENAMES = {
|
|
41
|
+
spec: 'spec.md',
|
|
42
|
+
architecture: 'architecture.md',
|
|
43
|
+
'cr-list': 'cr-list.md',
|
|
44
|
+
references: 'references.md',
|
|
45
|
+
srs: 'srs.md',
|
|
46
|
+
nfr: 'nfr.md',
|
|
47
|
+
rtm: 'rtm.md',
|
|
48
|
+
icd: 'icd.md',
|
|
49
|
+
testconcept: 'testconcept.md',
|
|
50
|
+
testmatrix: 'testmatrix.md',
|
|
51
|
+
intplan: 'intplan.md',
|
|
52
|
+
changelog: 'changelog.md',
|
|
53
|
+
fmea: 'fmea.md',
|
|
54
|
+
conops: 'conops.md',
|
|
55
|
+
trade: 'trade.md',
|
|
56
|
+
implplan: 'implplan.md',
|
|
57
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sigloch/graphcode-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"LICENSE"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "rm -rf dist && tsc",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"description": "Read-side client for a running @sigloch/graphcode host — host-socket calls, dashboard panels, readiness projection and the markdown view catalog. Deliberately free of Kuzu and the MCP SDK so a viewer can depend on it without pulling an embedded graph database.",
|
|
21
|
+
"author": "sigloch-consulting",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/andreassigloch/sigloch-modules.git",
|
|
25
|
+
"directory": "packages/graphcode-client"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/andreassigloch/sigloch-modules#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/andreassigloch/sigloch-modules/issues"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=22"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|