@weftlet/toolkit 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -18
- package/THIRD_PARTY_NOTICES.md +3 -1
- package/dist/application/application.d.ts +10 -0
- package/dist/application/application.js +20 -0
- package/dist/application/document-code-bindings.d.ts +11 -0
- package/dist/application/document-code-bindings.js +25 -0
- package/dist/application/document-obligations.d.ts +8 -0
- package/dist/application/document-obligations.js +11 -0
- package/dist/application/draft-facts.d.ts +3 -0
- package/dist/application/draft-facts.js +37 -0
- package/dist/application/extraction-identity.d.ts +2 -2
- package/dist/application/extraction-identity.js +7 -1
- package/dist/application/extractor-results.d.ts +6 -0
- package/dist/application/extractor-results.js +6 -0
- package/dist/application/hydrator.js +38 -18
- package/dist/application/mapping-proposals.d.ts +108 -0
- package/dist/application/mapping-proposals.js +142 -0
- package/dist/application/mapping-service.d.ts +2 -0
- package/dist/application/mapping-service.js +5 -0
- package/dist/application/overlay.js +43 -29
- package/dist/application/saved-code-coverage.d.ts +40 -0
- package/dist/application/saved-code-coverage.js +20 -0
- package/dist/application/saved-compatibility.d.ts +38 -0
- package/dist/application/saved-compatibility.js +20 -0
- package/dist/application/saved-evidence.d.ts +17 -11
- package/dist/application/saved-evidence.js +44 -40
- package/dist/application/saved-exploration.d.ts +57 -0
- package/dist/application/saved-exploration.js +21 -0
- package/dist/application/saved-paths.d.ts +58 -0
- package/dist/application/saved-paths.js +20 -0
- package/dist/application/semantic-run.d.ts +1 -1
- package/dist/extraction/call-syntax.d.ts +18 -0
- package/dist/extraction/call-syntax.js +61 -0
- package/dist/extraction/canonical-document-links.d.ts +5 -1
- package/dist/extraction/canonical-document-links.js +4 -4
- package/dist/extraction/code-inventory.d.ts +6 -0
- package/dist/extraction/code-inventory.js +26 -0
- package/dist/extraction/document-code-bindings.d.ts +14 -0
- package/dist/extraction/document-code-bindings.js +121 -0
- package/dist/extraction/document-obligations.d.ts +12 -0
- package/dist/extraction/document-obligations.js +112 -0
- package/dist/extraction/mapping-candidates.d.ts +13 -0
- package/dist/extraction/mapping-candidates.js +46 -0
- package/dist/extraction/mapping-output.d.ts +75 -0
- package/dist/extraction/mapping-output.js +53 -0
- package/dist/extraction/mapping-plan.d.ts +7 -0
- package/dist/extraction/mapping-plan.js +117 -0
- package/dist/extraction/mapping-prompt.d.ts +2 -0
- package/dist/extraction/mapping-prompt.js +17 -0
- package/dist/extraction/mapping-provider.d.ts +15 -0
- package/dist/extraction/mapping-provider.js +60 -0
- package/dist/extraction/mapping-request.d.ts +3 -0
- package/dist/extraction/mapping-request.js +32 -0
- package/dist/extraction/ontology.d.ts +2 -0
- package/dist/extraction/ontology.js +28 -13
- package/dist/extraction/routing.js +5 -20
- package/dist/extraction/scip-occurrences.d.ts +3 -0
- package/dist/extraction/scip-occurrences.js +102 -0
- package/dist/extraction/scip-ranges.d.ts +6 -0
- package/dist/extraction/scip-ranges.js +31 -0
- package/dist/extraction/scip-runtime.d.ts +39 -0
- package/dist/extraction/scip-runtime.js +8 -0
- package/dist/extraction/scip-symbols.d.ts +21 -0
- package/dist/extraction/scip-symbols.js +91 -0
- package/dist/extraction/semantic.d.ts +1 -1
- package/dist/extraction/semantic.js +5 -17
- package/dist/extraction/static-calls.d.ts +10 -0
- package/dist/extraction/static-calls.js +133 -0
- package/dist/extraction/static.d.ts +3 -20
- package/dist/extraction/static.js +8 -84
- package/dist/extraction/symbol-resolution.d.ts +12 -0
- package/dist/extraction/symbol-resolution.js +51 -0
- package/dist/extraction/symbol-selectors.d.ts +11 -0
- package/dist/extraction/symbol-selectors.js +51 -0
- package/dist/graph/binding-rdf.d.ts +7 -0
- package/dist/graph/binding-rdf.js +109 -0
- package/dist/graph/call-rdf.d.ts +4 -0
- package/dist/graph/call-rdf.js +94 -0
- package/dist/graph/call-shapes.d.ts +2 -0
- package/dist/graph/call-shapes.js +28 -0
- package/dist/graph/code-coverage-projection.d.ts +9 -0
- package/dist/graph/code-coverage-projection.js +117 -0
- package/dist/graph/code-coverage-renderer.d.ts +2 -0
- package/dist/graph/code-coverage-renderer.js +15 -0
- package/dist/graph/code-coverage-request.d.ts +6 -0
- package/dist/graph/code-coverage-request.js +19 -0
- package/dist/graph/code-coverage.d.ts +6 -0
- package/dist/graph/code-coverage.js +54 -0
- package/dist/graph/code-description.d.ts +4 -0
- package/dist/graph/code-description.js +24 -0
- package/dist/graph/code-rdf.d.ts +6 -0
- package/dist/graph/code-rdf.js +79 -0
- package/dist/graph/compatibility-context.d.ts +2 -0
- package/dist/graph/compatibility-context.js +18 -0
- package/dist/graph/compatibility-renderer.d.ts +2 -0
- package/dist/graph/compatibility-renderer.js +45 -0
- package/dist/graph/compatibility-request.d.ts +3 -0
- package/dist/graph/compatibility-request.js +18 -0
- package/dist/graph/compatibility.d.ts +7 -0
- package/dist/graph/compatibility.js +67 -0
- package/dist/graph/constraint-comparison.d.ts +7 -0
- package/dist/graph/constraint-comparison.js +49 -0
- package/dist/graph/coverage.d.ts +2 -2
- package/dist/graph/coverage.js +8 -3
- package/dist/graph/diagnostics.d.ts +1 -1
- package/dist/graph/diagnostics.js +10 -6
- package/dist/graph/evidence-description.d.ts +3 -0
- package/dist/graph/evidence-description.js +13 -0
- package/dist/graph/identity-preflight.js +1 -1
- package/dist/graph/neighborhood-renderer.d.ts +2 -0
- package/dist/graph/neighborhood-renderer.js +38 -0
- package/dist/graph/neighborhood-request.d.ts +9 -0
- package/dist/graph/neighborhood-request.js +37 -0
- package/dist/graph/neighborhood.d.ts +8 -0
- package/dist/graph/neighborhood.js +100 -0
- package/dist/graph/obligation-rdf.d.ts +5 -0
- package/dist/graph/obligation-rdf.js +67 -0
- package/dist/graph/obligation-shapes.d.ts +2 -0
- package/dist/graph/obligation-shapes.js +32 -0
- package/dist/graph/partitioned-shacl.d.ts +14 -0
- package/dist/graph/partitioned-shacl.js +66 -0
- package/dist/graph/path-request.d.ts +11 -0
- package/dist/graph/path-request.js +24 -0
- package/dist/graph/path-search.d.ts +45 -0
- package/dist/graph/path-search.js +101 -0
- package/dist/graph/paths-renderer.d.ts +2 -0
- package/dist/graph/paths-renderer.js +36 -0
- package/dist/graph/paths.d.ts +7 -0
- package/dist/graph/paths.js +74 -0
- package/dist/graph/query.js +23 -6
- package/dist/graph/rdf-partitions.d.ts +24 -0
- package/dist/graph/rdf-partitions.js +170 -0
- package/dist/graph/rdf-projection.d.ts +7 -0
- package/dist/graph/rdf-projection.js +27 -0
- package/dist/graph/rdf-records.d.ts +12 -0
- package/dist/graph/rdf-records.js +90 -0
- package/dist/graph/rdf.d.ts +10 -10
- package/dist/graph/rdf.js +84 -89
- package/dist/graph/shacl-shapes.js +70 -0
- package/dist/graph/snapshot-context.d.ts +3 -0
- package/dist/graph/snapshot-context.js +8 -0
- package/dist/graph/validation-progress.d.ts +4 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.js +22 -0
- package/dist/infrastructure/json-digest.d.ts +3 -0
- package/dist/infrastructure/json-digest.js +3 -0
- package/dist/infrastructure/unique-json.d.ts +2 -0
- package/dist/infrastructure/unique-json.js +20 -0
- package/dist/interfaces/cli.js +33 -1
- package/dist/interfaces/code-coverage.d.ts +46 -0
- package/dist/interfaces/code-coverage.js +18 -0
- package/dist/interfaces/graph-compatibility.d.ts +35 -0
- package/dist/interfaces/graph-compatibility.js +21 -0
- package/dist/interfaces/graph-exploration.d.ts +59 -0
- package/dist/interfaces/graph-exploration.js +27 -0
- package/dist/interfaces/graph-paths.d.ts +77 -0
- package/dist/interfaces/graph-paths.js +31 -0
- package/dist/interfaces/graph-query-args.d.ts +2 -0
- package/dist/interfaces/graph-query-args.js +25 -0
- package/dist/interfaces/mapping-proposals.d.ts +204 -0
- package/dist/interfaces/mapping-proposals.js +74 -0
- package/dist/interfaces/mcp.js +31 -3
- package/dist/storage/mapping-proposals.d.ts +9 -0
- package/dist/storage/mapping-proposals.js +42 -0
- package/dist/storage/storage.d.ts +3 -0
- package/dist/storage/storage.js +37 -13
- package/dist/storage/streaming-json.d.ts +5 -0
- package/dist/storage/streaming-json.js +45 -0
- package/dist/visualization/evidence-sources.d.ts +6 -0
- package/dist/visualization/evidence-sources.js +19 -0
- package/dist/visualization/viewer-interaction.d.ts +5 -8
- package/dist/visualization/viewer-interaction.js +46 -44
- package/dist/visualization/visualization.js +14 -5
- package/docs/1.0-WORK-QUEUE.md +48 -0
- package/docs/ADR-029-exact-graph-neighborhoods.md +70 -0
- package/docs/ADR-030-bounded-evidence-paths.md +97 -0
- package/docs/ADR-031-code-extractor-selection.md +91 -0
- package/docs/ADR-032-scip-code-evidence.md +73 -0
- package/docs/ADR-033-document-symbol-bindings.md +83 -0
- package/docs/ADR-034-mapping-gaps.md +80 -0
- package/docs/ADR-035-static-call-evidence.md +78 -0
- package/docs/ADR-036-contract-obligation-declarations.md +124 -0
- package/docs/ADR-037-selected-contract-compatibility.md +93 -0
- package/docs/ADR-038-monorepo-code-coverage.md +105 -0
- package/docs/ADR-039-mapping-proposals.md +119 -0
- package/docs/ADR-040-bounded-graph-io.md +90 -0
- package/docs/GRAPHIFY-EVALUATION.md +21 -4
- package/docs/PRE-1.0-BASELINE.md +49 -2
- package/docs/RELEASE-1.0-PLAN.md +14 -2
- package/docs/RELEASING.md +3 -3
- package/docs/ROADMAP.md +27 -6
- package/docs/VALIDATION.md +521 -14
- package/docs/benchmarks/large-graph-2026-11-02/result.json +156 -0
- package/docs/extraction-manifest.json +266 -23
- package/package.json +10 -4
- package/templates/context-graph-development/SKILL.md +30 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CodeCoverageService } from '@weftlet/core';
|
|
2
|
+
export declare const graphCoverageTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
additionalProperties: boolean;
|
|
8
|
+
required: string[];
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: {
|
|
11
|
+
type: string;
|
|
12
|
+
minLength: number;
|
|
13
|
+
maxLength: number;
|
|
14
|
+
};
|
|
15
|
+
projectRoot: {
|
|
16
|
+
type: string;
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
};
|
|
20
|
+
maxItems: {
|
|
21
|
+
type: string;
|
|
22
|
+
minimum: number;
|
|
23
|
+
maximum: number;
|
|
24
|
+
default: number;
|
|
25
|
+
};
|
|
26
|
+
continuation: {
|
|
27
|
+
type: string;
|
|
28
|
+
minLength: number;
|
|
29
|
+
maxLength: number;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
annotations: {
|
|
34
|
+
readOnlyHint: boolean;
|
|
35
|
+
destructiveHint: boolean;
|
|
36
|
+
idempotentHint: boolean;
|
|
37
|
+
openWorldHint: boolean;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export declare function handleCodeCoverage(service: CodeCoverageService, value: unknown): Promise<import("@weftlet/core").CodeCoverageReport>;
|
|
41
|
+
export declare function codeCoverageRequestFromArgs(args: readonly string[]): {
|
|
42
|
+
continuation?: string | undefined;
|
|
43
|
+
projectRoot?: string | undefined;
|
|
44
|
+
snapshotId: string;
|
|
45
|
+
maxItems: number;
|
|
46
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { parseCodeCoverageRequest } from '../graph/code-coverage-request.js';
|
|
2
|
+
import { parseGraphQueryArgs } from './graph-query-args.js';
|
|
3
|
+
export const graphCoverageTool = {
|
|
4
|
+
name: 'graph.coverage',
|
|
5
|
+
description: 'Inspect saved TypeScript-family source coverage. Page package boundaries, then select an exact projectRoot to page files. Distinguishes code-root selection, requested index entries, observed SCIP documents, cross-package references and unresolved evidence. Missing or zero observations never prove no impact. Does not rebuild evidence.',
|
|
6
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['snapshotId'], properties: {
|
|
7
|
+
snapshotId: { type: 'string', minLength: 1, maxLength: 256 }, projectRoot: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
8
|
+
maxItems: { type: 'integer', minimum: 1, maximum: 200, default: 50 }, continuation: { type: 'string', minLength: 1, maxLength: 2048 },
|
|
9
|
+
} }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10
|
+
};
|
|
11
|
+
export function handleCodeCoverage(service, value) {
|
|
12
|
+
return service.coverage(parseCodeCoverageRequest(value));
|
|
13
|
+
}
|
|
14
|
+
export function codeCoverageRequestFromArgs(args) {
|
|
15
|
+
return parseCodeCoverageRequest(parseGraphQueryArgs(args, 'coverage', {
|
|
16
|
+
'--snapshot': 'snapshotId', '--project': 'projectRoot', '--max-items': 'maxItems', '--continuation': 'continuation',
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ContractCompatibilityService } from '@weftlet/core';
|
|
2
|
+
export declare const graphCompatibilityTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
additionalProperties: boolean;
|
|
8
|
+
required: string[];
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: {
|
|
11
|
+
type: string;
|
|
12
|
+
minLength: number;
|
|
13
|
+
maxLength: number;
|
|
14
|
+
};
|
|
15
|
+
producerFactId: {
|
|
16
|
+
type: string;
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
};
|
|
20
|
+
consumerFactId: {
|
|
21
|
+
type: string;
|
|
22
|
+
minLength: number;
|
|
23
|
+
maxLength: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
annotations: {
|
|
28
|
+
readOnlyHint: boolean;
|
|
29
|
+
destructiveHint: boolean;
|
|
30
|
+
idempotentHint: boolean;
|
|
31
|
+
openWorldHint: boolean;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export declare function handleGraphCompatibility(service: ContractCompatibilityService, value: unknown): Promise<import("@weftlet/core").ContractCompatibilityReport>;
|
|
35
|
+
export declare function graphCompatibilityRequestFromArgs(args: readonly string[]): import("@weftlet/core").ContractCompatibilityRequest;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parseContractCompatibilityRequest } from '../graph/compatibility-request.js';
|
|
2
|
+
import { parseGraphQueryArgs } from './graph-query-args.js';
|
|
3
|
+
export const graphCompatibilityTool = {
|
|
4
|
+
name: 'graph.compatibility',
|
|
5
|
+
description: 'Compare two exact cited producer/consumer numeric obligations from a saved snapshot. Reports subset, insufficient guarantee, disjoint constraints, required revalidation or unknown. Advisory only: never proves implementation, current-diff validity or a CI policy violation. Discover assertion IDs with graph.neighbors.',
|
|
6
|
+
inputSchema: { type: 'object', additionalProperties: false,
|
|
7
|
+
required: ['snapshotId', 'producerFactId', 'consumerFactId'], properties: {
|
|
8
|
+
snapshotId: { type: 'string', minLength: 1, maxLength: 256 },
|
|
9
|
+
producerFactId: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
10
|
+
consumerFactId: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
11
|
+
} },
|
|
12
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
13
|
+
};
|
|
14
|
+
export function handleGraphCompatibility(service, value) {
|
|
15
|
+
return service.assess(parseContractCompatibilityRequest(value));
|
|
16
|
+
}
|
|
17
|
+
export function graphCompatibilityRequestFromArgs(args) {
|
|
18
|
+
return parseContractCompatibilityRequest(parseGraphQueryArgs(args, 'compatibility', {
|
|
19
|
+
'--snapshot': 'snapshotId', '--producer-fact': 'producerFactId', '--consumer-fact': 'consumerFactId',
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type GraphExplorationService } from '@weftlet/core';
|
|
2
|
+
export declare const graphNeighborsTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
additionalProperties: boolean;
|
|
8
|
+
required: string[];
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: {
|
|
11
|
+
type: string;
|
|
12
|
+
minLength: number;
|
|
13
|
+
maxLength: number;
|
|
14
|
+
};
|
|
15
|
+
nodeId: {
|
|
16
|
+
type: string;
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
};
|
|
20
|
+
direction: {
|
|
21
|
+
type: string;
|
|
22
|
+
enum: string[];
|
|
23
|
+
};
|
|
24
|
+
predicates: {
|
|
25
|
+
type: string;
|
|
26
|
+
maxItems: 16;
|
|
27
|
+
items: {
|
|
28
|
+
type: string;
|
|
29
|
+
enum: ("references" | "realizes" | "implementedBy" | "consumes" | "emits" | "persistsTo" | "governedBy" | "definedBy" | "verifiedBy" | "operationallyOwnedBy" | "decisionAuthority" | "routesThrough" | "authorizedBy" | "sourcedFrom" | "contains" | "calls")[];
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
maxFacts: {
|
|
33
|
+
type: string;
|
|
34
|
+
minimum: number;
|
|
35
|
+
maximum: number;
|
|
36
|
+
};
|
|
37
|
+
continuation: {
|
|
38
|
+
type: string;
|
|
39
|
+
minLength: number;
|
|
40
|
+
maxLength: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
annotations: {
|
|
45
|
+
readOnlyHint: boolean;
|
|
46
|
+
destructiveHint: boolean;
|
|
47
|
+
idempotentHint: boolean;
|
|
48
|
+
openWorldHint: boolean;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export declare function handleGraphNeighbors(service: GraphExplorationService, value: unknown): Promise<import("@weftlet/core").GraphNeighborhood>;
|
|
52
|
+
export declare function graphNeighborsRequestFromArgs(args: readonly string[]): {
|
|
53
|
+
continuation?: string | undefined;
|
|
54
|
+
snapshotId: string;
|
|
55
|
+
nodeId: string;
|
|
56
|
+
direction: "incoming" | "outgoing" | "both";
|
|
57
|
+
predicates: ("references" | "realizes" | "implementedBy" | "consumes" | "emits" | "persistsTo" | "governedBy" | "definedBy" | "verifiedBy" | "operationallyOwnedBy" | "decisionAuthority" | "routesThrough" | "authorizedBy" | "sourcedFrom" | "contains" | "calls")[];
|
|
58
|
+
maxFacts: number;
|
|
59
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { parseGraphQueryArgs } from './graph-query-args.js';
|
|
2
|
+
import { graphPredicates } from '@weftlet/core';
|
|
3
|
+
import { parseGraphNeighborsRequest } from '../graph/neighborhood-request.js';
|
|
4
|
+
export const graphNeighborsTool = {
|
|
5
|
+
name: 'graph.neighbors',
|
|
6
|
+
description: 'Look up an exact node ID in an explicit saved snapshot and page through its cited one-hop relationships. Follow returned neighbor IDs to explore further; no hydration or model calls.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object', additionalProperties: false, required: ['snapshotId', 'nodeId'],
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: { type: 'string', minLength: 1, maxLength: 256 },
|
|
11
|
+
nodeId: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
12
|
+
direction: { type: 'string', enum: ['incoming', 'outgoing', 'both'] },
|
|
13
|
+
predicates: { type: 'array', maxItems: graphPredicates.length, items: { type: 'string', enum: [...graphPredicates] } },
|
|
14
|
+
maxFacts: { type: 'integer', minimum: 1, maximum: 200 },
|
|
15
|
+
continuation: { type: 'string', minLength: 1, maxLength: 2048 },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
19
|
+
};
|
|
20
|
+
export function handleGraphNeighbors(service, value) {
|
|
21
|
+
return service.neighbors(parseGraphNeighborsRequest(value));
|
|
22
|
+
}
|
|
23
|
+
export function graphNeighborsRequestFromArgs(args) {
|
|
24
|
+
const flags = { '--snapshot': 'snapshotId', '--node': 'nodeId',
|
|
25
|
+
'--direction': 'direction', '--predicate': 'predicates', '--max-facts': 'maxFacts', '--continuation': 'continuation' };
|
|
26
|
+
return parseGraphNeighborsRequest(parseGraphQueryArgs(args, 'neighbors', flags));
|
|
27
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type GraphPathQueryService } from '@weftlet/core';
|
|
2
|
+
export declare const graphPathsTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
additionalProperties: boolean;
|
|
8
|
+
required: string[];
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: {
|
|
11
|
+
type: string;
|
|
12
|
+
minLength: number;
|
|
13
|
+
maxLength: number;
|
|
14
|
+
};
|
|
15
|
+
fromNodeId: {
|
|
16
|
+
type: string;
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
};
|
|
20
|
+
toNodeId: {
|
|
21
|
+
type: string;
|
|
22
|
+
minLength: number;
|
|
23
|
+
maxLength: number;
|
|
24
|
+
};
|
|
25
|
+
direction: {
|
|
26
|
+
type: string;
|
|
27
|
+
enum: string[];
|
|
28
|
+
};
|
|
29
|
+
predicates: {
|
|
30
|
+
type: string;
|
|
31
|
+
maxItems: 16;
|
|
32
|
+
items: {
|
|
33
|
+
type: string;
|
|
34
|
+
enum: ("references" | "realizes" | "implementedBy" | "consumes" | "emits" | "persistsTo" | "governedBy" | "definedBy" | "verifiedBy" | "operationallyOwnedBy" | "decisionAuthority" | "routesThrough" | "authorizedBy" | "sourcedFrom" | "contains" | "calls")[];
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
maxDepth: {
|
|
38
|
+
type: string;
|
|
39
|
+
minimum: number;
|
|
40
|
+
maximum: number;
|
|
41
|
+
};
|
|
42
|
+
maxPaths: {
|
|
43
|
+
type: string;
|
|
44
|
+
minimum: number;
|
|
45
|
+
maximum: number;
|
|
46
|
+
};
|
|
47
|
+
maxSteps: {
|
|
48
|
+
type: string;
|
|
49
|
+
minimum: number;
|
|
50
|
+
maximum: number;
|
|
51
|
+
};
|
|
52
|
+
continuation: {
|
|
53
|
+
type: string;
|
|
54
|
+
minLength: number;
|
|
55
|
+
maxLength: number;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
annotations: {
|
|
60
|
+
readOnlyHint: boolean;
|
|
61
|
+
destructiveHint: boolean;
|
|
62
|
+
idempotentHint: boolean;
|
|
63
|
+
openWorldHint: boolean;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
export declare function handleGraphPaths(service: GraphPathQueryService, value: unknown): Promise<import("@weftlet/core").GraphPaths>;
|
|
67
|
+
export declare function graphPathsRequestFromArgs(args: readonly string[]): {
|
|
68
|
+
continuation?: string | undefined;
|
|
69
|
+
snapshotId: string;
|
|
70
|
+
fromNodeId: string;
|
|
71
|
+
toNodeId: string;
|
|
72
|
+
direction: "incoming" | "outgoing" | "both";
|
|
73
|
+
predicates: ("references" | "realizes" | "implementedBy" | "consumes" | "emits" | "persistsTo" | "governedBy" | "definedBy" | "verifiedBy" | "operationallyOwnedBy" | "decisionAuthority" | "routesThrough" | "authorizedBy" | "sourcedFrom" | "contains" | "calls")[];
|
|
74
|
+
maxDepth: number;
|
|
75
|
+
maxPaths: number;
|
|
76
|
+
maxSteps: number;
|
|
77
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseGraphQueryArgs } from './graph-query-args.js';
|
|
2
|
+
import { graphPredicates } from '@weftlet/core';
|
|
3
|
+
import { parseGraphPathsRequest } from '../graph/path-request.js';
|
|
4
|
+
export const graphPathsTool = {
|
|
5
|
+
name: 'graph.paths',
|
|
6
|
+
description: 'Explore simple cited paths between exact node IDs in an explicit saved snapshot. Depth-first assertion order, not shortest/causal paths. Follow continuation with identical selectors; inspect depth/work limits and unexplored frontier. No hydration or model calls.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object', additionalProperties: false, required: ['snapshotId', 'fromNodeId', 'toNodeId'],
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: { type: 'string', minLength: 1, maxLength: 256 },
|
|
11
|
+
fromNodeId: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
12
|
+
toNodeId: { type: 'string', minLength: 1, maxLength: 8192 },
|
|
13
|
+
direction: { type: 'string', enum: ['incoming', 'outgoing', 'both'] },
|
|
14
|
+
predicates: { type: 'array', maxItems: graphPredicates.length, items: { type: 'string', enum: [...graphPredicates] } },
|
|
15
|
+
maxDepth: { type: 'integer', minimum: 1, maximum: 32 },
|
|
16
|
+
maxPaths: { type: 'integer', minimum: 1, maximum: 20 },
|
|
17
|
+
maxSteps: { type: 'integer', minimum: 1, maximum: 10000 },
|
|
18
|
+
continuation: { type: 'string', minLength: 1, maxLength: 2048 },
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
22
|
+
};
|
|
23
|
+
export function handleGraphPaths(service, value) {
|
|
24
|
+
return service.paths(parseGraphPathsRequest(value));
|
|
25
|
+
}
|
|
26
|
+
export function graphPathsRequestFromArgs(args) {
|
|
27
|
+
const flags = { '--snapshot': 'snapshotId', '--from': 'fromNodeId', '--to': 'toNodeId',
|
|
28
|
+
'--direction': 'direction', '--predicate': 'predicates', '--max-depth': 'maxDepth', '--max-paths': 'maxPaths',
|
|
29
|
+
'--max-steps': 'maxSteps', '--continuation': 'continuation' };
|
|
30
|
+
return parseGraphPathsRequest(parseGraphQueryArgs(args, 'paths', flags));
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Shared flag grammar for exact-ID graph queries; semantic validation stays in the query layer. */
|
|
2
|
+
export function parseGraphQueryArgs(args, operation, flags) {
|
|
3
|
+
const values = {};
|
|
4
|
+
for (let index = 0; index < args.length; index++) {
|
|
5
|
+
const flag = args[index];
|
|
6
|
+
if (flag === '--json')
|
|
7
|
+
continue;
|
|
8
|
+
if (flag !== '--config' && !Object.hasOwn(flags, flag))
|
|
9
|
+
throw new Error(`Unknown graph ${operation} argument: ${flag}`);
|
|
10
|
+
const value = args[++index];
|
|
11
|
+
if (value === undefined || value.startsWith('--'))
|
|
12
|
+
throw new Error(`Missing value for ${flag}`);
|
|
13
|
+
if (flag === '--config')
|
|
14
|
+
continue;
|
|
15
|
+
const key = flags[flag];
|
|
16
|
+
if (key === 'predicates')
|
|
17
|
+
values[key] = [...(values[key] ?? []), value];
|
|
18
|
+
else {
|
|
19
|
+
if (Object.hasOwn(values, key))
|
|
20
|
+
throw new Error(`Repeated graph ${operation} argument: ${flag}`);
|
|
21
|
+
values[key] = key.startsWith('max') ? Number(value) : value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return values;
|
|
25
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { MappingProposalService } from '../application/mapping-proposals.js';
|
|
2
|
+
export declare const mappingPlanTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
additionalProperties: boolean;
|
|
8
|
+
required: string[];
|
|
9
|
+
properties: {
|
|
10
|
+
snapshotId: {
|
|
11
|
+
maxLength: number;
|
|
12
|
+
type: string;
|
|
13
|
+
minLength: number;
|
|
14
|
+
};
|
|
15
|
+
ruleId: {
|
|
16
|
+
type: string;
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
};
|
|
20
|
+
documentPath: {
|
|
21
|
+
type: string;
|
|
22
|
+
minLength: number;
|
|
23
|
+
maxLength: number;
|
|
24
|
+
};
|
|
25
|
+
files: {
|
|
26
|
+
type: string;
|
|
27
|
+
minItems: number;
|
|
28
|
+
maxItems: number;
|
|
29
|
+
uniqueItems: boolean;
|
|
30
|
+
items: {
|
|
31
|
+
type: string;
|
|
32
|
+
minLength: number;
|
|
33
|
+
maxLength: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
maxCandidates: {
|
|
37
|
+
type: string;
|
|
38
|
+
minimum: number;
|
|
39
|
+
maximum: number;
|
|
40
|
+
};
|
|
41
|
+
maxInputBytes: {
|
|
42
|
+
type: string;
|
|
43
|
+
minimum: number;
|
|
44
|
+
maximum: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
annotations: {
|
|
49
|
+
readOnlyHint: boolean;
|
|
50
|
+
destructiveHint: boolean;
|
|
51
|
+
idempotentHint: boolean;
|
|
52
|
+
openWorldHint: boolean;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export declare const mappingReadTool: {
|
|
56
|
+
name: string;
|
|
57
|
+
description: string;
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: "object";
|
|
60
|
+
additionalProperties: boolean;
|
|
61
|
+
required: string[];
|
|
62
|
+
properties: {
|
|
63
|
+
snapshotId: {
|
|
64
|
+
maxLength: number;
|
|
65
|
+
type: string;
|
|
66
|
+
minLength: number;
|
|
67
|
+
};
|
|
68
|
+
key: {
|
|
69
|
+
type: string;
|
|
70
|
+
pattern: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
annotations: {
|
|
75
|
+
readOnlyHint: boolean;
|
|
76
|
+
destructiveHint: boolean;
|
|
77
|
+
idempotentHint: boolean;
|
|
78
|
+
openWorldHint: boolean;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export declare function parseMappingRead(value: unknown): {
|
|
82
|
+
snapshotId: string;
|
|
83
|
+
key: string;
|
|
84
|
+
};
|
|
85
|
+
export declare function handleMappingTool(service: MappingProposalService, name: string, value: unknown): Promise<{
|
|
86
|
+
evidenceState: {
|
|
87
|
+
readonly currentCommit?: string;
|
|
88
|
+
readonly excludedWorkingChanges: readonly string[];
|
|
89
|
+
readonly capturedWorkingChanges?: readonly string[];
|
|
90
|
+
readonly changedSinceCapture?: readonly string[];
|
|
91
|
+
readonly overlayFreshness?: "current" | "stale" | "unknown";
|
|
92
|
+
readonly stale: boolean;
|
|
93
|
+
readonly configurationMatches: boolean;
|
|
94
|
+
readonly extractionCompatible?: boolean;
|
|
95
|
+
readonly incompatibleExtractors?: readonly string[];
|
|
96
|
+
readonly eligibleForCurrentDiffValidation: false;
|
|
97
|
+
};
|
|
98
|
+
key: string;
|
|
99
|
+
cached: boolean;
|
|
100
|
+
expectedModelRequests: number;
|
|
101
|
+
timeoutMs: number;
|
|
102
|
+
automaticRetries: number;
|
|
103
|
+
markdown: string;
|
|
104
|
+
ready: boolean;
|
|
105
|
+
issues: {
|
|
106
|
+
readonly code: string;
|
|
107
|
+
readonly path?: string;
|
|
108
|
+
}[];
|
|
109
|
+
version: "mapping-proposal-v1";
|
|
110
|
+
request: Required<import("@weftlet/core").MappingProposalRequest>;
|
|
111
|
+
snapshot: import("@weftlet/core").ContextPack["snapshot"];
|
|
112
|
+
snapshotDigest: string;
|
|
113
|
+
subjectEvidence: readonly import("@weftlet/core").GraphFact[];
|
|
114
|
+
associations: readonly import("@weftlet/core").GraphFact[];
|
|
115
|
+
candidates: readonly import("@weftlet/core").MappingCandidate[];
|
|
116
|
+
candidateEnumeration: {
|
|
117
|
+
readonly complete: boolean;
|
|
118
|
+
readonly observed: number;
|
|
119
|
+
readonly returned: number;
|
|
120
|
+
};
|
|
121
|
+
excluded: readonly {
|
|
122
|
+
readonly path: string;
|
|
123
|
+
readonly reason: string;
|
|
124
|
+
readonly count: number;
|
|
125
|
+
}[];
|
|
126
|
+
inputBytes: number;
|
|
127
|
+
inputDigest: string;
|
|
128
|
+
} | {
|
|
129
|
+
artifact: import("@weftlet/core").MappingProposalArtifact;
|
|
130
|
+
reused: boolean;
|
|
131
|
+
evidenceState: {
|
|
132
|
+
readonly currentCommit?: string;
|
|
133
|
+
readonly excludedWorkingChanges: readonly string[];
|
|
134
|
+
readonly capturedWorkingChanges?: readonly string[];
|
|
135
|
+
readonly changedSinceCapture?: readonly string[];
|
|
136
|
+
readonly overlayFreshness?: "current" | "stale" | "unknown";
|
|
137
|
+
readonly stale: boolean;
|
|
138
|
+
readonly configurationMatches: boolean;
|
|
139
|
+
readonly extractionCompatible?: boolean;
|
|
140
|
+
readonly incompatibleExtractors?: readonly string[];
|
|
141
|
+
readonly eligibleForCurrentDiffValidation: false;
|
|
142
|
+
} | undefined;
|
|
143
|
+
markdown: string;
|
|
144
|
+
}>;
|
|
145
|
+
export declare function runMappingsCommand(service: MappingProposalService, args: readonly string[]): Promise<{
|
|
146
|
+
evidenceState: {
|
|
147
|
+
readonly currentCommit?: string;
|
|
148
|
+
readonly excludedWorkingChanges: readonly string[];
|
|
149
|
+
readonly capturedWorkingChanges?: readonly string[];
|
|
150
|
+
readonly changedSinceCapture?: readonly string[];
|
|
151
|
+
readonly overlayFreshness?: "current" | "stale" | "unknown";
|
|
152
|
+
readonly stale: boolean;
|
|
153
|
+
readonly configurationMatches: boolean;
|
|
154
|
+
readonly extractionCompatible?: boolean;
|
|
155
|
+
readonly incompatibleExtractors?: readonly string[];
|
|
156
|
+
readonly eligibleForCurrentDiffValidation: false;
|
|
157
|
+
};
|
|
158
|
+
key: string;
|
|
159
|
+
cached: boolean;
|
|
160
|
+
expectedModelRequests: number;
|
|
161
|
+
timeoutMs: number;
|
|
162
|
+
automaticRetries: number;
|
|
163
|
+
markdown: string;
|
|
164
|
+
ready: boolean;
|
|
165
|
+
issues: {
|
|
166
|
+
readonly code: string;
|
|
167
|
+
readonly path?: string;
|
|
168
|
+
}[];
|
|
169
|
+
version: "mapping-proposal-v1";
|
|
170
|
+
request: Required<import("@weftlet/core").MappingProposalRequest>;
|
|
171
|
+
snapshot: import("@weftlet/core").ContextPack["snapshot"];
|
|
172
|
+
snapshotDigest: string;
|
|
173
|
+
subjectEvidence: readonly import("@weftlet/core").GraphFact[];
|
|
174
|
+
associations: readonly import("@weftlet/core").GraphFact[];
|
|
175
|
+
candidates: readonly import("@weftlet/core").MappingCandidate[];
|
|
176
|
+
candidateEnumeration: {
|
|
177
|
+
readonly complete: boolean;
|
|
178
|
+
readonly observed: number;
|
|
179
|
+
readonly returned: number;
|
|
180
|
+
};
|
|
181
|
+
excluded: readonly {
|
|
182
|
+
readonly path: string;
|
|
183
|
+
readonly reason: string;
|
|
184
|
+
readonly count: number;
|
|
185
|
+
}[];
|
|
186
|
+
inputBytes: number;
|
|
187
|
+
inputDigest: string;
|
|
188
|
+
} | {
|
|
189
|
+
artifact: import("@weftlet/core").MappingProposalArtifact;
|
|
190
|
+
reused: boolean;
|
|
191
|
+
evidenceState: {
|
|
192
|
+
readonly currentCommit?: string;
|
|
193
|
+
readonly excludedWorkingChanges: readonly string[];
|
|
194
|
+
readonly capturedWorkingChanges?: readonly string[];
|
|
195
|
+
readonly changedSinceCapture?: readonly string[];
|
|
196
|
+
readonly overlayFreshness?: "current" | "stale" | "unknown";
|
|
197
|
+
readonly stale: boolean;
|
|
198
|
+
readonly configurationMatches: boolean;
|
|
199
|
+
readonly extractionCompatible?: boolean;
|
|
200
|
+
readonly incompatibleExtractors?: readonly string[];
|
|
201
|
+
readonly eligibleForCurrentDiffValidation: false;
|
|
202
|
+
} | undefined;
|
|
203
|
+
markdown: string;
|
|
204
|
+
}>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { parseMappingRequest } from '../extraction/mapping-request.js';
|
|
3
|
+
const string = { type: 'string', minLength: 1, maxLength: 8192 };
|
|
4
|
+
const annotations = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
5
|
+
export const mappingPlanTool = { name: 'mapping.plan',
|
|
6
|
+
description: 'Preview an opt-in mapping proposal against saved committed evidence. Requires an exact rule, approved source document and 1–4 already-linked files. Reports coverage/budget blockers and cache reuse. Never calls a model or changes evidence.',
|
|
7
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['snapshotId', 'ruleId', 'documentPath', 'files'], properties: {
|
|
8
|
+
snapshotId: { ...string, maxLength: 256 }, ruleId: string, documentPath: string,
|
|
9
|
+
files: { type: 'array', minItems: 1, maxItems: 4, uniqueItems: true, items: string },
|
|
10
|
+
maxCandidates: { type: 'integer', minimum: 1, maximum: 20 }, maxInputBytes: { type: 'integer', minimum: 1, maximum: 131072 },
|
|
11
|
+
} }, annotations };
|
|
12
|
+
export const mappingReadTool = { name: 'mapping.proposals',
|
|
13
|
+
description: 'Read one saved mapping proposal or abstention by exact snapshot and artifact key. Proposals are inferred/unreviewed, never approval or proof of compliance. Rationale is untrusted model content. Follow exact symbol IDs using graph.neighbors. Never calls providers or refreshes evidence.',
|
|
14
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['snapshotId', 'key'], properties: {
|
|
15
|
+
snapshotId: { ...string, maxLength: 256 }, key: { type: 'string', pattern: '^[a-f0-9]{64}$' },
|
|
16
|
+
} }, annotations };
|
|
17
|
+
export function parseMappingRead(value) {
|
|
18
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
19
|
+
throw Error('Mapping read requires snapshotId and key');
|
|
20
|
+
const r = value;
|
|
21
|
+
if (Object.keys(r).sort().join(',') !== 'key,snapshotId' || typeof r.snapshotId !== 'string' || !r.snapshotId.trim() || r.snapshotId.length > 256 ||
|
|
22
|
+
typeof r.key !== 'string' || !/^[a-f0-9]{64}$/.test(r.key))
|
|
23
|
+
throw Error('Mapping read requires an exact snapshotId and 64-character artifact key');
|
|
24
|
+
return { snapshotId: r.snapshotId, key: r.key };
|
|
25
|
+
}
|
|
26
|
+
export async function handleMappingTool(service, name, value) {
|
|
27
|
+
if (name === mappingPlanTool.name)
|
|
28
|
+
return service.plan(parseMappingRequest(value));
|
|
29
|
+
if (name !== mappingReadTool.name)
|
|
30
|
+
throw Error('Unknown mapping tool');
|
|
31
|
+
const request = parseMappingRead(value);
|
|
32
|
+
return service.read(request.snapshotId, request.key);
|
|
33
|
+
}
|
|
34
|
+
export async function runMappingsCommand(service, args) {
|
|
35
|
+
const [operation, ...flags] = args;
|
|
36
|
+
if (!['plan', 'propose', 'read'].includes(operation ?? ''))
|
|
37
|
+
throw Error('Usage: weftlet mappings plan|propose --request request.json; mappings read --snapshot ID --key KEY');
|
|
38
|
+
const values = new Map();
|
|
39
|
+
const allowed = operation === 'read' ? ['--snapshot', '--key', '--config', '--json'] : ['--request', '--config', '--json', ...(operation === 'propose' ? ['--allow-model', '--quiet'] : [])];
|
|
40
|
+
for (let i = 0; i < flags.length; i++) {
|
|
41
|
+
const flag = flags[i];
|
|
42
|
+
if (!allowed.includes(flag) || values.has(flag))
|
|
43
|
+
throw Error('Unknown or repeated mappings argument');
|
|
44
|
+
if (['--json', '--quiet', '--allow-model'].includes(flag))
|
|
45
|
+
values.set(flag, true);
|
|
46
|
+
else {
|
|
47
|
+
const value = flags[++i];
|
|
48
|
+
if (!value || value.startsWith('--'))
|
|
49
|
+
throw Error('Missing mappings argument');
|
|
50
|
+
values.set(flag, value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (operation === 'read') {
|
|
54
|
+
const r = parseMappingRead({ snapshotId: values.get('--snapshot'), key: values.get('--key') });
|
|
55
|
+
return service.read(r.snapshotId, r.key);
|
|
56
|
+
}
|
|
57
|
+
const path = values.get('--request');
|
|
58
|
+
if (typeof path !== 'string' || (await stat(path)).size > 65536)
|
|
59
|
+
throw Error('A request JSON file of at most 64 KiB is required');
|
|
60
|
+
const request = parseMappingRequest(JSON.parse(await readFile(path, 'utf8')));
|
|
61
|
+
if (operation === 'plan')
|
|
62
|
+
return service.plan(request);
|
|
63
|
+
const controller = new AbortController(), cancel = () => controller.abort();
|
|
64
|
+
process.once('SIGINT', cancel);
|
|
65
|
+
process.once('SIGTERM', cancel);
|
|
66
|
+
try {
|
|
67
|
+
return await service.propose(request, { allowModel: values.has('--allow-model'), signal: controller.signal,
|
|
68
|
+
onProgress: values.has('--quiet') ? undefined : event => process.stderr.write(`${JSON.stringify(event)}\n`) });
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
process.removeListener('SIGINT', cancel);
|
|
72
|
+
process.removeListener('SIGTERM', cancel);
|
|
73
|
+
}
|
|
74
|
+
}
|