granttap-mcp 0.8.95 → 0.8.96
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/apps/bridge/src/engine/README.md +7 -0
- package/apps/bridge/src/engine/distribution/artifacts.ts +2 -2
- package/apps/bridge/src/engine/protocol/project-relationships/README.md +12 -0
- package/apps/bridge/src/engine/protocol/project-relationships/index.ts +41 -0
- package/apps/bridge/src/engine/protocol/transport/protocol-types.ts +3 -0
- package/apps/bridge/src/engine/protocol/transport/result-parser.ts +2 -0
- package/apps/bridge/src/engine/runtime/engine-client.ts +1 -0
- package/apps/bridge/src/engine/runtime/project-relationships/README.md +19 -0
- package/apps/bridge/src/engine/runtime/project-relationships/index.ts +71 -0
- package/apps/bridge/src/engine/runtime/repository-graph-jobs.ts +6 -0
- package/apps/bridge/src/mesh/runtime/graph/README.md +7 -0
- package/apps/bridge/src/mesh/runtime/graph/analysis.ts +7 -1
- package/apps/bridge/src/mesh/runtime/snapshot/enriched.ts +6 -1
- package/cursor-plugin/README.md +1 -1
- package/cursor-plugin/mcp.json +1 -1
- package/cursor-plugin/stdio-bootstrap.cjs +1 -1
- package/package.json +1 -1
|
@@ -25,6 +25,13 @@ reports are retained in a bounded private computer cache across restarts, served
|
|
|
25
25
|
while a new observation runs, and refreshed after the observation expires. Git
|
|
26
26
|
admission revision (`sourceRevision`) remains separate from Weavatrix's content
|
|
27
27
|
fingerprint (`revision`). Failed analyses cannot erase the durable last report.
|
|
28
|
+
Explicit Graph builds also invoke the Engine's `graph.analyze_project` for two
|
|
29
|
+
to eight admitted local repositories. The projection labels these shared static
|
|
30
|
+
contracts and keeps their runtime destination unverified. They do not become
|
|
31
|
+
verified Backbone dependencies or merge Project grants. The Apple Silicon
|
|
32
|
+
artifact pins Engine 0.1.3 with Weavatrix 2.17.5; unsupported Engine operations
|
|
33
|
+
leave this analysis unavailable. See `runtime/project-relationships/README.md`.
|
|
34
|
+
|
|
28
35
|
Claude, Codex, and Cursor hooks can evaluate the engine's local Project
|
|
29
36
|
Governance policy only when both `GRANTTAP_ENGINE_ENABLED` and
|
|
30
37
|
`GRANTTAP_PROJECT_POLICY_ENABLED` are enabled. Project `DENY` and `ASK` precede
|
|
@@ -8,8 +8,8 @@ export type EngineArtifact = {
|
|
|
8
8
|
|
|
9
9
|
/** Release hashes are part of the reviewed MCP, never supplied by a remote manifest. */
|
|
10
10
|
export const ENGINE_ARTIFACTS: readonly EngineArtifact[] = [
|
|
11
|
-
{ version: "0.1.
|
|
12
|
-
sha256: "
|
|
11
|
+
{ version: "0.1.3", platform: "darwin", arch: "arm64",
|
|
12
|
+
sha256: "d948b6cfc572fa062af602c72d7b0e14bedcc5b48ecb8fb8d7af5b6fc33e9920", bytes: 12185568 },
|
|
13
13
|
{ version: "0.1.2", platform: "darwin", arch: "x64",
|
|
14
14
|
sha256: "b3235a15936a77ec323d5ecbc54a0bc19994fe6e5a36044da964b68524b4c1dd", bytes: 13944984 },
|
|
15
15
|
{ version: "0.1.2", platform: "linux", arch: "x64",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Project relationship wire contract
|
|
2
|
+
|
|
3
|
+
`index.ts` validates the Engine's bounded static contract report. Repository IDs
|
|
4
|
+
must belong to its selected set; locations are relative paths in the source
|
|
5
|
+
repository, and the relation remains `contract_match`. Source excerpts,
|
|
6
|
+
absolute paths, foreign identities and unexpected fields fail closed.
|
|
7
|
+
|
|
8
|
+
The public framed-client and parser tests live with the consuming feature in
|
|
9
|
+
`../../runtime/project-relationships/tests/`. Runtime projection is documented
|
|
10
|
+
in that feature's README.
|
|
11
|
+
|
|
12
|
+
License: GrantTap Commercial Source License. See the repository-root `LICENSE`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { EngineProtocolError } from "../transport/protocol-base";
|
|
3
|
+
|
|
4
|
+
const text = z.string().min(1).max(512).refine(value => !/[\x00-\x1f\x7f]/.test(value));
|
|
5
|
+
const location = z.object({
|
|
6
|
+
repository_id: text,
|
|
7
|
+
path: text.refine(value => !/^(?:[A-Za-z]:|[\\/])/.test(value)
|
|
8
|
+
&& !value.split(/[\\/]/).includes("..")),
|
|
9
|
+
line: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
10
|
+
}).strict();
|
|
11
|
+
const schema = z.object({
|
|
12
|
+
project_id: text.max(128),
|
|
13
|
+
weavatrix_version: text.max(64),
|
|
14
|
+
analysis_status: z.enum(["COMPLETE", "INCOMPLETE"]),
|
|
15
|
+
repositories: z.array(z.object({ repository_id: text, revision: text }).strict()).min(2).max(8),
|
|
16
|
+
matches: z.array(z.object({
|
|
17
|
+
source: text,
|
|
18
|
+
target: text,
|
|
19
|
+
transport: z.enum(["http", "graphql", "grpc", "event"]),
|
|
20
|
+
relation: z.literal("contract_match"),
|
|
21
|
+
evidence_count: z.number().int().positive().max(1_000_000),
|
|
22
|
+
evidence: z.array(location).min(1).max(16),
|
|
23
|
+
}).strict()).max(128),
|
|
24
|
+
truncated: z.boolean(),
|
|
25
|
+
}).strict().superRefine((value, context) => {
|
|
26
|
+
const ids = new Set(value.repositories.map(item => item.repository_id));
|
|
27
|
+
if (ids.size !== value.repositories.length || value.matches.some(edge =>
|
|
28
|
+
edge.source === edge.target || !ids.has(edge.source) || !ids.has(edge.target)
|
|
29
|
+
|| edge.evidence_count < edge.evidence.length
|
|
30
|
+
|| edge.evidence.some(item => item.repository_id !== edge.source))) {
|
|
31
|
+
context.addIssue({ code: "custom", message: "relationship scope is invalid" });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export type EngineProjectRelationships = z.infer<typeof schema>;
|
|
36
|
+
|
|
37
|
+
export function parseProjectRelationships(value: unknown): void {
|
|
38
|
+
if (Buffer.byteLength(JSON.stringify(value), "utf8") > 65_536 || !schema.safeParse(value).success) {
|
|
39
|
+
throw new EngineProtocolError("Project relationship evidence is invalid");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EngineProjectRelationships } from "../project-relationships";
|
|
1
2
|
import type {
|
|
2
3
|
EnginePolicyOperation,
|
|
3
4
|
EnginePolicyResult,
|
|
@@ -105,6 +106,7 @@ export type EngineOperation = EnginePolicyOperation | InvocationEngineOperation
|
|
|
105
106
|
| { operation: "project.get"; input: { project_id: string } }
|
|
106
107
|
| { operation: "project.list"; input: { after_project_id?: string; limit: number } }
|
|
107
108
|
| { operation: "project.list_bindings"; input: { project_id: string } }
|
|
109
|
+
| { operation: "graph.analyze_project"; input: {project_id:string;repository_ids:string[]} }
|
|
108
110
|
| { operation: "graph.get_backbone"; input: { project_id: string } }
|
|
109
111
|
| { operation: "graph.analyze_repository"; input: {
|
|
110
112
|
project_id: string; repository_id: string;
|
|
@@ -136,6 +138,7 @@ export type EngineResult = EnginePolicyResult | InvocationEngineResult | MemoryE
|
|
|
136
138
|
projects: EngineProject[]; next_after_project_id: string | null;
|
|
137
139
|
} }
|
|
138
140
|
| { operation: "project.bindings"; bindings: EngineProjectBinding[] }
|
|
141
|
+
| { operation: "graph.project_relationships"; graph:EngineProjectRelationships }
|
|
139
142
|
| { operation: "graph.backbone"; backbone: EngineProjectBackbone }
|
|
140
143
|
| { operation: "graph.repository"; graph: EngineRepositoryGraph }
|
|
141
144
|
| { operation: "context.compiled"; compilation: EngineContextCompilation }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseProjectRelationships } from "../project-relationships";
|
|
1
2
|
import { parseInvocationResult } from "../engine-invocation-protocol";
|
|
2
3
|
import { parseMemoryResult } from "../engine-memory-protocol";
|
|
3
4
|
import { parsePolicyResult } from "../engine-policy-protocol";
|
|
@@ -47,6 +48,7 @@ function parseResult(value: unknown): EngineResult {
|
|
|
47
48
|
else if (operation === "project.listed") parseProjectCatalog(result.page);
|
|
48
49
|
else if (operation === "project.bindings") parseBindings(result.bindings);
|
|
49
50
|
else if (operation === "project.binding_upserted") parseBinding(result.binding);
|
|
51
|
+
else if (operation === "graph.project_relationships") parseProjectRelationships(result.graph);
|
|
50
52
|
else if (operation === "graph.backbone") parseBackbone(result.backbone);
|
|
51
53
|
else if (operation === "graph.repository") parseRepositoryGraph(result.graph);
|
|
52
54
|
else if (operation === "context.compiled") {
|
|
@@ -201,6 +201,7 @@ function expectedResultOperation(
|
|
|
201
201
|
if (operation === "graph.get_backbone") return "graph.backbone";
|
|
202
202
|
if (operation === "graph.get_heads") return "graph.heads";
|
|
203
203
|
if (operation === "graph.compute_impact") return "graph.impact";
|
|
204
|
+
if (operation === "graph.analyze_project") return "graph.project_relationships";
|
|
204
205
|
if (operation === "graph.analyze_repository") return "graph.repository";
|
|
205
206
|
if (operation === "context.compile_project") return "context.compiled";
|
|
206
207
|
if (operation === "invocation.observe") return "invocation.observed";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Project relationship projection
|
|
2
|
+
|
|
3
|
+
`projectRelationshipPeers` connects the Engine's `graph.analyze_project` to the
|
|
4
|
+
existing Graph refresh. Only distinct repository IDs from admitted local
|
|
5
|
+
Project bindings are selected, with a limit of eight. A separate Engine socket
|
|
6
|
+
keeps expensive analysis off the policy channel.
|
|
7
|
+
|
|
8
|
+
Explicit Graph builds refresh static contract matches. Background snapshots
|
|
9
|
+
read the bounded retained result for the same binding/revision key; they do not
|
|
10
|
+
start additional cross-repository scans. Stale or unavailable results do not
|
|
11
|
+
establish a missing dependency.
|
|
12
|
+
|
|
13
|
+
The existing compatibility graph shows these edges as shared contracts, with
|
|
14
|
+
an explicit static/runtime-unverified explanation. They never enter the
|
|
15
|
+
verified Backbone and never merge independent Project groups or change grants.
|
|
16
|
+
Full relative source evidence stays in the typed Engine response. No source
|
|
17
|
+
excerpts or absolute machine roots are published to the phone.
|
|
18
|
+
|
|
19
|
+
License: GrantTap Commercial Source License. See the repository-root `LICENSE`.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { IntegrationPeer, ProjectBindingSummary } from "../../../../../../packages/protocol/schema";
|
|
3
|
+
import type { EngineProjectRelationships } from "../../protocol/project-relationships";
|
|
4
|
+
import { configDir } from "../../../config/runtime/paths";
|
|
5
|
+
import { EngineClient } from "../engine-client";
|
|
6
|
+
import { engineFeatureEnabled, type EngineClientLike } from "../engine-supervisor";
|
|
7
|
+
import { RepositoryGraphJobs } from "../repository-graph-jobs";
|
|
8
|
+
|
|
9
|
+
type Analysis = { graph: EngineProjectRelationships; observedAt: number };
|
|
10
|
+
const jobs = new RepositoryGraphJobs<Analysis>(Date.now, 120_000, 300_000, 8);
|
|
11
|
+
const STATIC_CONTRACT_PREFIX = "Weavatrix: static ";
|
|
12
|
+
|
|
13
|
+
/** Static compatibility is shown as shared contracts, never a proven dependency. */
|
|
14
|
+
export async function projectRelationshipPeers(
|
|
15
|
+
projectId: string,
|
|
16
|
+
bindings: ProjectBindingSummary[],
|
|
17
|
+
options: { env?: NodeJS.ProcessEnv; client?: EngineClientLike; background?: boolean } = {},
|
|
18
|
+
): Promise<IntegrationPeer[]> {
|
|
19
|
+
if (!engineFeatureEnabled(options.env ?? process.env)) return [];
|
|
20
|
+
const ids = [...new Set(bindings.map(binding => binding.repositoryId))].sort();
|
|
21
|
+
if (ids.length < 2 || ids.length > 8) return [];
|
|
22
|
+
const key = JSON.stringify([
|
|
23
|
+
projectId, ids, bindings.map(item => [item.bindingId, item.revision]).sort(),
|
|
24
|
+
]);
|
|
25
|
+
// Background snapshots read retained results; explicit Graph builds start analysis.
|
|
26
|
+
const result = options.background
|
|
27
|
+
? jobs.cached(key)
|
|
28
|
+
: await jobs.refresh(key, () => analyze(projectId, ids, options.client));
|
|
29
|
+
if (!result) return [];
|
|
30
|
+
return result.graph.matches.flatMap(edge => {
|
|
31
|
+
if (edge.target.length > 160) return [];
|
|
32
|
+
return [{
|
|
33
|
+
projectId,
|
|
34
|
+
repositoryId: edge.source,
|
|
35
|
+
peer: edge.target,
|
|
36
|
+
via: edge.transport === "event" ? "kafka" as const : "api" as const,
|
|
37
|
+
relation: "shares" as const,
|
|
38
|
+
through: `${STATIC_CONTRACT_PREFIX}${edge.transport.toUpperCase()} contract; runtime target unverified`,
|
|
39
|
+
updatedAt: result.observedAt,
|
|
40
|
+
}];
|
|
41
|
+
}).slice(0, 64);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function analyze(
|
|
45
|
+
projectId: string, ids: string[], supplied?: EngineClientLike,
|
|
46
|
+
): Promise<Analysis | undefined> {
|
|
47
|
+
const client = supplied ?? new EngineClient({
|
|
48
|
+
socketPath: join(configDir(), "engine.sock"), connectTimeoutMs: 10_000,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
const result = await client.request({
|
|
52
|
+
operation: "graph.analyze_project",
|
|
53
|
+
input: { project_id: projectId, repository_ids: ids },
|
|
54
|
+
}, { timeoutMs: 120_000 });
|
|
55
|
+
if (result.operation !== "graph.project_relationships" || result.graph.project_id !== projectId
|
|
56
|
+
|| JSON.stringify(result.graph.repositories.map(item => item.repository_id).sort()) !== JSON.stringify(ids)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return { graph: result.graph, observedAt: Date.now() };
|
|
60
|
+
} catch { return undefined; }
|
|
61
|
+
finally { if (!supplied) client.close(); }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function mergeRelationshipPeers(
|
|
65
|
+
current: IntegrationPeer[] | undefined, analyzed: IntegrationPeer[],
|
|
66
|
+
): IntegrationPeer[] {
|
|
67
|
+
return [
|
|
68
|
+
...(current ?? []).filter(peer => !peer.through?.startsWith(STATIC_CONTRACT_PREFIX)),
|
|
69
|
+
...analyzed,
|
|
70
|
+
].slice(0, 64);
|
|
71
|
+
}
|
|
@@ -56,6 +56,12 @@ export class RepositoryGraphJobs<T> {
|
|
|
56
56
|
return new Promise(resolve => entry.listeners.push(resolve));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** Read a fresh in-memory result without starting or queueing an analysis. */
|
|
60
|
+
cached(key: string): T | undefined {
|
|
61
|
+
const entry = this.entries.get(key);
|
|
62
|
+
return entry && this.now() < entry.retryAt ? entry.value : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
private admit(priority: number): boolean {
|
|
60
66
|
if (this.queue.length < this.capacity) return true;
|
|
61
67
|
const last = this.queue[this.queue.length - 1];
|
|
@@ -18,6 +18,13 @@ computer analyzes only its own endpoint bindings. Failed bindings remain visible
|
|
|
18
18
|
projection and phone refresh use this rule. The graph contains actual Engine
|
|
19
19
|
analysis; unavailable analysis is never synthesized as a successful graph.
|
|
20
20
|
|
|
21
|
+
After repository analysis, explicit builds request bounded cross-repository
|
|
22
|
+
contract matches from the same admitted bindings. These are projected as shared
|
|
23
|
+
static contracts with an unverified runtime target. Background snapshots reuse
|
|
24
|
+
fresh in-memory results; they do not queue additional multi-repository scans.
|
|
25
|
+
A verified Backbone remains authoritative. Project identities and grants are
|
|
26
|
+
preserved.
|
|
27
|
+
|
|
21
28
|
Behavior tests: `tests/`, root `tests/graph/graph-binding-sync.test.ts`, and
|
|
22
29
|
`apps/mcp/src/desktop/projection/tests/graph-refresh.test.ts`. The optional
|
|
23
30
|
`engine-selection-live.test.ts` uses `GRANTTAP_ENGINE_TEST_BINARY` to verify the
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { projectRelationshipPeers, mergeRelationshipPeers } from "../../../engine/runtime/project-relationships";
|
|
1
2
|
import type { RelayClient } from "../../../../../../packages/core/relay-client";
|
|
2
3
|
import type { MeshSnapshot } from "../../../../../../packages/protocol/schema";
|
|
3
4
|
import { projectBackbone, projectRepositoryGraphs, waitForProjectBindingSync } from "../../../engine/runtime/engine-projects";
|
|
@@ -17,6 +18,7 @@ type GraphAnalysisDependencies = {
|
|
|
17
18
|
sync?: typeof refreshLocalGraphBindings;
|
|
18
19
|
backbone: typeof projectBackbone;
|
|
19
20
|
graphs: typeof projectRepositoryGraphs;
|
|
21
|
+
relationships?: typeof projectRelationshipPeers;
|
|
20
22
|
send: (client: RelayClient, snapshot: MeshSnapshot) => Promise<void>;
|
|
21
23
|
endpoint?: () => string;
|
|
22
24
|
details?: (snapshot: MeshSnapshot) => ReturnType<typeof repositoryDetails>;
|
|
@@ -28,6 +30,7 @@ const graphAnalysisDependencies: GraphAnalysisDependencies = {
|
|
|
28
30
|
sync: refreshLocalGraphBindings,
|
|
29
31
|
backbone: projectBackbone,
|
|
30
32
|
graphs: projectRepositoryGraphs,
|
|
33
|
+
relationships: projectRelationshipPeers,
|
|
31
34
|
endpoint: computerId,
|
|
32
35
|
details: snapshot => repositoryDetails(snapshot, computerId()),
|
|
33
36
|
send: (client, snapshot) => sendMeshPayload(client, snapshot, "phone", {
|
|
@@ -61,6 +64,9 @@ export async function analyzeProjectGraphNow(
|
|
|
61
64
|
dependencies.graphs(projectId, bindings, { background: false }),
|
|
62
65
|
dependencies.details?.(current),
|
|
63
66
|
]);
|
|
67
|
+
const relationships = await dependencies.relationships?.(projectId, bindings, { background: false });
|
|
68
|
+
const peers = relationships === undefined ? current.peers
|
|
69
|
+
: mergeRelationshipPeers(current.peers, relationships);
|
|
64
70
|
const observed = [...repositoryGraphs, ...failures];
|
|
65
71
|
const reports = observed.length > 0 ? observed : [{
|
|
66
72
|
projectId, repositoryId: current.project.canonicalRepositoryId,
|
|
@@ -71,7 +77,7 @@ export async function analyzeProjectGraphNow(
|
|
|
71
77
|
const receipts = requestIds?.size ? requestIds : new Set<string | undefined>([undefined]);
|
|
72
78
|
for (const id of receipts) {
|
|
73
79
|
await dependencies.send(client, {
|
|
74
|
-
...current, backbone, repositoryGraphs: reports, generatedAt: Date.now(),
|
|
80
|
+
...current, backbone, peers, repositoryGraphs: reports, generatedAt: Date.now(),
|
|
75
81
|
...(details ? { repositoryDetails: details } : {}),
|
|
76
82
|
...(id ? { graphAnalysisRequestId: id } : {}),
|
|
77
83
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { projectRelationshipPeers, mergeRelationshipPeers } from "../../../engine/runtime/project-relationships";
|
|
1
2
|
import { refreshLocalGraphBindings } from "../graph/binding-sync";
|
|
2
3
|
import { graphAnalysisBindings } from "../graph/checkout-identity";
|
|
3
4
|
import type { MeshSnapshot } from "../../../../../../packages/protocol/schema";
|
|
@@ -33,6 +34,10 @@ export async function enrichMeshSnapshot(
|
|
|
33
34
|
projectKnowledge(snapshot.projectId),
|
|
34
35
|
repositoryDetails(snapshot, computerId()),
|
|
35
36
|
]);
|
|
37
|
+
const relationships = await projectRelationshipPeers(snapshot.projectId, bindings, {
|
|
38
|
+
background: options.refreshGraph !== true,
|
|
39
|
+
});
|
|
40
|
+
const peers = mergeRelationshipPeers(snapshot.peers, relationships);
|
|
36
41
|
const sharedKnowledge = knowledge?.filter((item) => item.visibility === "project");
|
|
37
42
|
if (sharedKnowledge) localMeshStore().cacheKnowledge(snapshot.projectId, sharedKnowledge);
|
|
38
43
|
const memoryRows = new Map((snapshot.knowledge ?? []).map((item) => [item.recordId, item]));
|
|
@@ -42,7 +47,7 @@ export async function enrichMeshSnapshot(
|
|
|
42
47
|
...(snapshot.supersededKnowledgeRecordIds ?? []),
|
|
43
48
|
...supersededProjectKnowledgeIds(snapshot.projectId, allMemory),
|
|
44
49
|
])].sort().slice(-128);
|
|
45
|
-
const enriched = { ...snapshot, backbone, ...(repositoryGraphs.length || identityFailures.length
|
|
50
|
+
const enriched = { ...snapshot, backbone, peers, ...(repositoryGraphs.length || identityFailures.length
|
|
46
51
|
? { repositoryGraphs: [...repositoryGraphs, ...identityFailures] } : {}),
|
|
47
52
|
repositoryDetails: details,
|
|
48
53
|
knowledge: activeProjectKnowledge(snapshot.projectId, allMemory)
|
package/cursor-plugin/README.md
CHANGED
|
@@ -10,7 +10,7 @@ keeps each phone response tied to the exact originating chat and prompt.
|
|
|
10
10
|
Install the supported CLI on this computer, then run:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g granttap-mcp@0.8.
|
|
13
|
+
npm install -g granttap-mcp@0.8.96
|
|
14
14
|
granttap setup
|
|
15
15
|
granttap status
|
|
16
16
|
```
|
package/cursor-plugin/mcp.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"command": "node",
|
|
5
5
|
"args": [
|
|
6
6
|
"-e",
|
|
7
|
-
"\"use strict\";\n\n// Cursor may start this MCP from any cwd. Execute JavaScript entry points with\n// Node itself: Windows batch shims require shell quoting that differs by host.\nconst { spawn } = require(\"node:child_process\");\nconst { existsSync } = require(\"node:fs\");\nconst { delimiter, dirname, join } = require(\"node:path\");\n\nconst PACKAGE = \"granttap-mcp@0.8.
|
|
7
|
+
"\"use strict\";\n\n// Cursor may start this MCP from any cwd. Execute JavaScript entry points with\n// Node itself: Windows batch shims require shell quoting that differs by host.\nconst { spawn } = require(\"node:child_process\");\nconst { existsSync } = require(\"node:fs\");\nconst { delimiter, dirname, join } = require(\"node:path\");\n\nconst PACKAGE = \"granttap-mcp@0.8.96\";\nconst dryRun = process.env.GRANTTAP_BOOTSTRAP_DRY_RUN === \"1\";\nconst platform = dryRun && process.env.GRANTTAP_BOOTSTRAP_PLATFORM\n ? process.env.GRANTTAP_BOOTSTRAP_PLATFORM : process.platform;\nconst nodeRoot = dryRun && process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT\n ? process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT : dirname(process.execPath);\nconst pathRoots = (process.env.PATH || \"\").split(delimiter).filter(Boolean);\nconst appData = process.env.APPDATA;\nconst roots = [nodeRoot, ...pathRoots, ...(appData ? [join(appData, \"npm\")] : [])];\nconst first = (paths) => paths.find((path) => existsSync(path));\n\nfunction launch() {\n if (platform !== \"win32\") {\n const installed = first(roots.map((root) => join(root, \"granttap-mcp\")));\n if (installed) return { command: installed, args: [] };\n const npx = first(roots.map((root) => join(root, \"npx\"))) || \"npx\";\n return { command: npx, args: [\"-y\", PACKAGE] };\n }\n const installed = first(roots.map((root) =>\n join(root, \"node_modules\", \"granttap-mcp\", \"bin\", \"granttap-mcp.mjs\")));\n if (installed) return { command: process.execPath, args: [installed] };\n const npx = first(roots.map((root) =>\n join(root, \"node_modules\", \"npm\", \"bin\", \"npx-cli.js\")));\n if (npx) return { command: process.execPath, args: [npx, \"-y\", PACKAGE] };\n throw new Error(\"Node.js/npm 22.13.0+ is required on this Windows device. Install npm and retry GrantTap.\");\n}\n\nlet target;\ntry { target = launch(); }\ncatch (error) {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n}\n\nif (dryRun) {\n process.stdout.write(JSON.stringify(target));\n process.exit(0);\n}\n\nconst child = spawn(target.command, target.args, { stdio: \"inherit\", windowsHide: true });\nchild.on(\"error\", (error) => {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n});\nchild.on(\"exit\", (code, signal) => {\n if (signal && platform !== \"win32\") {\n try { process.kill(process.pid, signal); } catch { process.exit(code ?? 1); }\n return;\n }\n process.exit(code ?? 1);\n});\n"
|
|
8
8
|
]
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -7,7 +7,7 @@ const { spawn } = require("node:child_process");
|
|
|
7
7
|
const { existsSync } = require("node:fs");
|
|
8
8
|
const { delimiter, dirname, join } = require("node:path");
|
|
9
9
|
|
|
10
|
-
const PACKAGE = "granttap-mcp@0.8.
|
|
10
|
+
const PACKAGE = "granttap-mcp@0.8.96";
|
|
11
11
|
const dryRun = process.env.GRANTTAP_BOOTSTRAP_DRY_RUN === "1";
|
|
12
12
|
const platform = dryRun && process.env.GRANTTAP_BOOTSTRAP_PLATFORM
|
|
13
13
|
? process.env.GRANTTAP_BOOTSTRAP_PLATFORM : process.platform;
|