glasspane-mcp 1.19.0 → 1.20.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/README.md +3 -1
- package/dist/dimension.d.ts +64 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/engine-client.d.ts +28 -0
- package/dist/errors.d.ts +46 -0
- package/dist/http-gateway-cli.js +413 -192
- package/dist/http-gateway.js +413 -192
- package/dist/index.js +275 -79
- package/dist/project-registry.d.ts +12 -2
- package/dist/stdio-session.js +275 -79
- package/dist/tools.d.ts +17 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ package alone does not give you a working verification engine.
|
|
|
11
11
|
只装本包不会得到可用的验证引擎——先装引擎:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
|
|
14
|
+
# Fetch install.sh, then run it — two steps on purpose: piped into `sh`, a curl that fails
|
|
15
|
+
# leaves stdin empty and the pipeline exits 0 while nothing was installed.
|
|
16
|
+
curl -fsSL https://raw.githubusercontent.com/jingzhao-l/GlassPane/main/install.sh -o /tmp/gp-install.sh && sh /tmp/gp-install.sh
|
|
15
17
|
# 或:npx glasspane-install
|
|
16
18
|
```
|
|
17
19
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dimension.ts — 面 A's declared review dimension, shape-checked by the kernel (场景② 的对称半边).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS FILE EXISTS. The fork surface (面 B) has carried this argument since the run-plan
|
|
5
|
+
* work: an agent says which dimension a call was serving, the shell refuses a malformed id
|
|
6
|
+
* before the daemon sees anything, strips the annotation from the engine frame, and echoes the
|
|
7
|
+
* declaration back as its own content item. This shell is the other doorway to the same engine,
|
|
8
|
+
* and until now it had no such slot — so a run driven through `glasspane-mcp` could not say what
|
|
9
|
+
* a call was for, and the compaction account could only ever read coverage from the fork's own
|
|
10
|
+
* calls. That asymmetry is the whole reason the dimension counter looked healthy in one harness
|
|
11
|
+
* and empty in the other.
|
|
12
|
+
*
|
|
13
|
+
* WHAT THIS IS NOT. The shape comes from `iterate-kernel/dimension-context`
|
|
14
|
+
* (`DIMENSION_ID_PATTERN` / `DIMENSION_ID_MAX_LENGTH`) — the same constants the run plan is
|
|
15
|
+
* validated against — so a plan id and a declaration cannot be spelled two ways. Nothing here
|
|
16
|
+
* knows what a dimension *means*: it refuses malformed tokens and never checks a name against a
|
|
17
|
+
* list, because the list belongs to whoever configured the run.
|
|
18
|
+
*
|
|
19
|
+
* WHY A MALFORMED ID IS REFUSED AND AN ABSENT ONE IS NOT. `dimensionContext` counts a planned
|
|
20
|
+
* dimension as verified only when a recorded decision carries that id. A declaration that reaches
|
|
21
|
+
* the ledger malformed is therefore the lying case — it would be counted as an *unplanned*
|
|
22
|
+
* dimension and silently rename what the session claims it covered. An honest but unread
|
|
23
|
+
* declaration is merely blind, so absence is legitimate and means "this call served no declared
|
|
24
|
+
* dimension"; compaction then reports that dimension as unverified rather than inventing one.
|
|
25
|
+
*
|
|
26
|
+
* Only `gp_last_evidence`'s reply carries an evidence pack, and a pack is what a decision is
|
|
27
|
+
* recorded from (`Dispatcher.swift:156`), so a dimension declared on `gp_attach`, `gp_observe`,
|
|
28
|
+
* `gp_act` or `gp_diagnose` records nothing and its dimension stays reported unverified. It is
|
|
29
|
+
* still accepted and still echoed on those calls, for the reason in the paragraph above: a
|
|
30
|
+
* refused-but-unreadable declaration is a lie, an echoed-but-unrecorded one is a fact the model
|
|
31
|
+
* can see. The echo is a separate content item so `content[0]` stays the daemon's frame byte for
|
|
32
|
+
* byte — the same rule the provider attribution line follows, and the reason the Python relay can
|
|
33
|
+
* classify per item instead of reading a joined string.
|
|
34
|
+
*/
|
|
35
|
+
import { type ToolErrorText } from "./errors.js";
|
|
36
|
+
/**
|
|
37
|
+
* The advertised half of the kernel's rule, for the JSON Schemas in `tools.ts`.
|
|
38
|
+
* `test/dimension.test.mjs` compares it against the published
|
|
39
|
+
* `kernel/schemas/*.schema.json` and against 面 B's own copy, so no side can be tightened or
|
|
40
|
+
* loosened alone.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DIMENSION_ID_LIMITS: {
|
|
43
|
+
readonly pattern: RegExp;
|
|
44
|
+
readonly maxLength: 64;
|
|
45
|
+
};
|
|
46
|
+
export declare function validateDimension(value: unknown): {
|
|
47
|
+
ok: true;
|
|
48
|
+
dimension?: string;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: ToolErrorText;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Drop the shell-side annotation from what the daemon is asked to do. The engine has no
|
|
55
|
+
* `dimension` parameter and never learns the word; exported so the fixed-point test can name the
|
|
56
|
+
* invariant "the engine never sees our annotation" rather than infer it from a passing call.
|
|
57
|
+
*/
|
|
58
|
+
export declare function engineBody(params: Record<string, unknown>): Record<string, unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* The echo line — one content item, its own prefix, and it claims only what this shell knows.
|
|
61
|
+
* `none` is never printed: an undeclared call keeps the reply byte-identical.
|
|
62
|
+
*/
|
|
63
|
+
export declare function dimensionAttributionLine(dimension: string): string;
|
|
64
|
+
//# sourceMappingURL=dimension.d.ts.map
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-06-18";
|
|
|
26
26
|
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
27
27
|
export declare const SERVER_INFO: {
|
|
28
28
|
readonly name: "glasspane-mcp";
|
|
29
|
-
readonly version: "1.
|
|
29
|
+
readonly version: "1.20.0";
|
|
30
30
|
};
|
|
31
31
|
export declare const PARSE_ERROR = -32700;
|
|
32
32
|
export declare const INVALID_REQUEST = -32600;
|
package/dist/engine-client.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ import { LineIo } from "./io.js";
|
|
|
7
7
|
* restore command: it detects a boot-out'd launchd job, bootstraps it, and
|
|
8
8
|
* verifies the daemon's hello self-report — the only remaining human action
|
|
9
9
|
* (TCC checkbox) stays honest. Falls back to generic wording otherwise.
|
|
10
|
+
*
|
|
11
|
+
* The ", then retry" tail belongs here and only here: every caller of this
|
|
12
|
+
* function is an answer for a request that did *not* go out (the write failed,
|
|
13
|
+
* {@link EngineJsonRpcClient.call}'s catch, or no request was in flight at all),
|
|
14
|
+
* so nothing can be performed twice by following it. A request that was already
|
|
15
|
+
* on the wire when the transport died gets {@link transportDeathRemedy}, which
|
|
16
|
+
* keeps the command and drops the tail for the methods whose re-issue is the
|
|
17
|
+
* harm.
|
|
10
18
|
*/
|
|
11
19
|
export declare function daemonUnreachableRemedy(): string;
|
|
12
20
|
/** Env override for the daemon socket path (default below). */
|
|
@@ -505,6 +513,19 @@ export declare class EngineJsonRpcClient {
|
|
|
505
513
|
* uses it (R9-高1) — and fail that one call only.
|
|
506
514
|
*/
|
|
507
515
|
private failOversizedReply;
|
|
516
|
+
/**
|
|
517
|
+
* The daemon's error frame, mapped into this shell's error.
|
|
518
|
+
*
|
|
519
|
+
* An error frame is a three-field shape — code, message, remedy — and each
|
|
520
|
+
* field has to actually say something for the answer to be usable by an agent.
|
|
521
|
+
* `??` only catches null/undefined, so a frame carrying `code: ""` used to be
|
|
522
|
+
* forwarded verbatim as an error with no name and no cause, while the remedy arm
|
|
523
|
+
* below already treats `""` as absent: one rule for three fields on the same
|
|
524
|
+
* frame. A blank is now read as "not stated" for every one of them, and a
|
|
525
|
+
* non-blank value — including one that merely looks odd — passes through
|
|
526
|
+
* untouched, because this function forwards the daemon's own words and has no
|
|
527
|
+
* authority to rewrite them.
|
|
528
|
+
*/
|
|
508
529
|
private engineError;
|
|
509
530
|
/**
|
|
510
531
|
* Oldest request this client still tracks, settled ones included: that is the
|
|
@@ -549,6 +570,13 @@ export declare class EngineJsonRpcClient {
|
|
|
549
570
|
* "this shell stopped tracking it" from "it never happened" — the difference
|
|
550
571
|
* that decides whether it re-performs an `act` on the user's screen (R9-中1).
|
|
551
572
|
* The reverse mutation is to delete this note and keep the silent clear.
|
|
573
|
+
*
|
|
574
|
+
* The message is one sentence for every request — it states what happened to
|
|
575
|
+
* the transport, which is the same fact for all of them — while the remedy is
|
|
576
|
+
* written per method (`remedyFor`): what the caller may do next depends on
|
|
577
|
+
* whether re-issuing that particular request would perform it a second time,
|
|
578
|
+
* and one remedy for the whole batch is how "…, then retry" reached an
|
|
579
|
+
* outstanding `act` at all. See {@link transportDeathRemedy}.
|
|
552
580
|
*/
|
|
553
581
|
private teardown;
|
|
554
582
|
private report;
|
package/dist/errors.d.ts
CHANGED
|
@@ -70,6 +70,52 @@ export declare const GP_E_UNKNOWN = "GP_E_UNKNOWN";
|
|
|
70
70
|
* `projects.json` for the second case sends it to a file that is fine.
|
|
71
71
|
*/
|
|
72
72
|
export declare const GP_E_NO_USER_RECORD = "GP_E_NO_USER_RECORD";
|
|
73
|
+
/**
|
|
74
|
+
* Shell-only: a state root **the daemon reported about itself** (`hello`'s
|
|
75
|
+
* `stateRoot`) names a path this process will neither create nor re-permission —
|
|
76
|
+
* the filesystem root, the account's home directory itself, or a value that is not
|
|
77
|
+
* an absolute path at all.
|
|
78
|
+
*
|
|
79
|
+
* The daemon refuses the same shapes for its own `--state-dir` (`StateRoot.classify`
|
|
80
|
+
* → `StateRoot.notADedicatedRoot`) and then `tightenPermissions` that root to 0700,
|
|
81
|
+
* so the argument parse is the only thing standing between `--state-dir ~` and a
|
|
82
|
+
* locked home directory. It has no code for the refusal because the refusal is an
|
|
83
|
+
* exit message, not an error frame — which is why this shell cannot reuse one
|
|
84
|
+
* either: the root arrives over a socket with **no peer authentication** (SECURITY.md:
|
|
85
|
+
* same uid = full authority), so a value in a reply frame can name `/Users/<you>` and
|
|
86
|
+
* this shell's own `mkdirSync(…, 0700)` + `chmod` would obey it. `test/remedy-surface.test.mjs`
|
|
87
|
+
* checks this stays absent from the daemon's enum, so the split has to be re-read if
|
|
88
|
+
* the daemon ever does declare it.
|
|
89
|
+
*
|
|
90
|
+
* 它**不**列进下面那份 `SHELL_REQUEST_REFUSAL_CODES`:这一码说的不是"你给的参数不对",
|
|
91
|
+
* 而是"服务报了一个我们不能照做的根",改参数重试不会有用;HTTP 那一侧因此按
|
|
92
|
+
* shell-only 的规矩答 503(与 `GP_E_REGISTRY_DRIFT` 同一族:"什么都没写,去看服务"),
|
|
93
|
+
* 而不是 4xx。
|
|
94
|
+
*/
|
|
95
|
+
export declare const GP_E_STATE_ROOT_REFUSED = "GP_E_STATE_ROOT_REFUSED";
|
|
96
|
+
/**
|
|
97
|
+
* Shell-only: a declared review dimension is malformed. The daemon has no dimension
|
|
98
|
+
* vocabulary at all — a dimension is the harness's annotation on a call, never an engine
|
|
99
|
+
* parameter — so this code can only ever come from the two surfaces that accept the argument,
|
|
100
|
+
* and `test/remedy-surface.test.mjs` checks it is genuinely absent from the daemon's enum.
|
|
101
|
+
* 面 B (`tool/glasspane/kernel.ts:validateDimension`) spells the same code for the same refusal:
|
|
102
|
+
* an agent that drives the app through either doorway must see one vocabulary, and
|
|
103
|
+
* `mcp-shell/test/dimension.test.mjs` is the leg that compares the two surfaces' tool lists so a
|
|
104
|
+
* slot added on one side reddens on the other.
|
|
105
|
+
*/
|
|
106
|
+
export declare const GP_E_DIMENSION = "GP_E_DIMENSION";
|
|
107
|
+
/**
|
|
108
|
+
* Codes this shell authors **about the caller's request**, as opposed to about its own failure.
|
|
109
|
+
*
|
|
110
|
+
* They are absent from the daemon's enum for a reason that has nothing to do with blame: the
|
|
111
|
+
* daemon has no `dimension` concept to declare, because the argument is stripped before the frame
|
|
112
|
+
* is built. So "the daemon does not declare it" cannot be read as "this gateway did not finish the
|
|
113
|
+
* request", and `test/http-gateway.test.mjs` therefore partitions shell-only codes with this list
|
|
114
|
+
* instead of with enum membership — the infrastructure codes (`GP_E_ENGINE_TIMEOUT`,
|
|
115
|
+
* `GP_E_ENGINE_BACKLOG`, …) still may never be answered as a 4xx, while a code listed here must be
|
|
116
|
+
* *proven* to come from argument validation, by the HTTP test that drives the real route.
|
|
117
|
+
*/
|
|
118
|
+
export declare const SHELL_REQUEST_REFUSAL_CODES: readonly string[];
|
|
73
119
|
export interface ToolErrorText {
|
|
74
120
|
code: string;
|
|
75
121
|
message: string;
|