@predicatesystems/authority 0.3.1 → 0.3.3
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/dist/canonicalization/desktop.d.ts +115 -0
- package/dist/canonicalization/desktop.d.ts.map +1 -0
- package/dist/canonicalization/desktop.js +187 -0
- package/dist/canonicalization/desktop.js.map +1 -0
- package/dist/canonicalization/index.d.ts +39 -0
- package/dist/canonicalization/index.d.ts.map +1 -0
- package/dist/canonicalization/index.js +68 -0
- package/dist/canonicalization/index.js.map +1 -0
- package/dist/canonicalization/terminal.d.ts +69 -0
- package/dist/canonicalization/terminal.d.ts.map +1 -0
- package/dist/canonicalization/terminal.js +98 -0
- package/dist/canonicalization/terminal.js.map +1 -0
- package/dist/canonicalization/utils.d.ts +108 -0
- package/dist/canonicalization/utils.d.ts.map +1 -0
- package/dist/canonicalization/utils.js +250 -0
- package/dist/canonicalization/utils.js.map +1 -0
- package/dist/contracts/action-request.d.ts.map +1 -0
- package/dist/contracts/action-request.js.map +1 -0
- package/dist/contracts/authorization-decision.d.ts.map +1 -0
- package/dist/contracts/authorization-decision.js.map +1 -0
- package/dist/contracts/decision.d.ts.map +1 -0
- package/dist/contracts/decision.js.map +1 -0
- package/dist/contracts/enums.d.ts.map +1 -0
- package/dist/contracts/enums.js.map +1 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/mandate.d.ts.map +1 -0
- package/dist/contracts/mandate.js.map +1 -0
- package/dist/contracts/policy-rule.d.ts.map +1 -0
- package/dist/contracts/policy-rule.js.map +1 -0
- package/dist/contracts/proof-event.d.ts.map +1 -0
- package/dist/contracts/proof-event.js.map +1 -0
- package/dist/contracts/verification.d.ts.map +1 -0
- package/dist/contracts/verification.js.map +1 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js.map +1 -0
- package/dist/{src/evidence → evidence}/non-web.d.ts +14 -0
- package/dist/evidence/non-web.d.ts.map +1 -0
- package/dist/evidence/non-web.js +95 -0
- package/dist/evidence/non-web.js.map +1 -0
- package/dist/evidence/web-state.d.ts.map +1 -0
- package/dist/evidence/web-state.js.map +1 -0
- package/dist/guard/action-guard.d.ts.map +1 -0
- package/dist/guard/action-guard.js.map +1 -0
- package/dist/{src/index.d.ts → index.d.ts} +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/{src/index.js → index.js} +8 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/matching.d.ts.map +1 -0
- package/dist/policy/matching.js.map +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js.map +1 -0
- package/dist/wrappers/sensitive-operations.d.ts.map +1 -0
- package/dist/wrappers/sensitive-operations.js.map +1 -0
- package/package.json +1 -1
- package/dist/src/contracts/action-request.d.ts.map +0 -1
- package/dist/src/contracts/action-request.js.map +0 -1
- package/dist/src/contracts/authorization-decision.d.ts.map +0 -1
- package/dist/src/contracts/authorization-decision.js.map +0 -1
- package/dist/src/contracts/decision.d.ts.map +0 -1
- package/dist/src/contracts/decision.js.map +0 -1
- package/dist/src/contracts/enums.d.ts.map +0 -1
- package/dist/src/contracts/enums.js.map +0 -1
- package/dist/src/contracts/index.d.ts.map +0 -1
- package/dist/src/contracts/index.js.map +0 -1
- package/dist/src/contracts/mandate.d.ts.map +0 -1
- package/dist/src/contracts/mandate.js.map +0 -1
- package/dist/src/contracts/policy-rule.d.ts.map +0 -1
- package/dist/src/contracts/policy-rule.js.map +0 -1
- package/dist/src/contracts/proof-event.d.ts.map +0 -1
- package/dist/src/contracts/proof-event.js.map +0 -1
- package/dist/src/contracts/verification.d.ts.map +0 -1
- package/dist/src/contracts/verification.js.map +0 -1
- package/dist/src/errors.d.ts.map +0 -1
- package/dist/src/errors.js.map +0 -1
- package/dist/src/evidence/non-web.d.ts.map +0 -1
- package/dist/src/evidence/non-web.js +0 -58
- package/dist/src/evidence/non-web.js.map +0 -1
- package/dist/src/evidence/web-state.d.ts.map +0 -1
- package/dist/src/evidence/web-state.js.map +0 -1
- package/dist/src/guard/action-guard.d.ts.map +0 -1
- package/dist/src/guard/action-guard.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/policy/engine.d.ts.map +0 -1
- package/dist/src/policy/engine.js.map +0 -1
- package/dist/src/policy/matching.d.ts.map +0 -1
- package/dist/src/policy/matching.js.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js.map +0 -1
- package/dist/src/wrappers/sensitive-operations.d.ts.map +0 -1
- package/dist/src/wrappers/sensitive-operations.js.map +0 -1
- /package/dist/{src/contracts → contracts}/action-request.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/action-request.js +0 -0
- /package/dist/{src/contracts → contracts}/authorization-decision.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/authorization-decision.js +0 -0
- /package/dist/{src/contracts → contracts}/decision.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/decision.js +0 -0
- /package/dist/{src/contracts → contracts}/enums.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/enums.js +0 -0
- /package/dist/{src/contracts → contracts}/index.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/index.js +0 -0
- /package/dist/{src/contracts → contracts}/mandate.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/mandate.js +0 -0
- /package/dist/{src/contracts → contracts}/policy-rule.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/policy-rule.js +0 -0
- /package/dist/{src/contracts → contracts}/proof-event.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/proof-event.js +0 -0
- /package/dist/{src/contracts → contracts}/verification.d.ts +0 -0
- /package/dist/{src/contracts → contracts}/verification.js +0 -0
- /package/dist/{src/errors.d.ts → errors.d.ts} +0 -0
- /package/dist/{src/errors.js → errors.js} +0 -0
- /package/dist/{src/evidence → evidence}/web-state.d.ts +0 -0
- /package/dist/{src/evidence → evidence}/web-state.js +0 -0
- /package/dist/{src/guard → guard}/action-guard.d.ts +0 -0
- /package/dist/{src/guard → guard}/action-guard.js +0 -0
- /package/dist/{src/policy → policy}/engine.d.ts +0 -0
- /package/dist/{src/policy → policy}/engine.js +0 -0
- /package/dist/{src/policy → policy}/matching.d.ts +0 -0
- /package/dist/{src/policy → policy}/matching.js +0 -0
- /package/dist/{src/types.d.ts → types.d.ts} +0 -0
- /package/dist/{src/types.js → types.js} +0 -0
- /package/dist/{src/wrappers → wrappers}/sensitive-operations.d.ts +0 -0
- /package/dist/{src/wrappers → wrappers}/sensitive-operations.js +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop accessibility tree canonicalization for reproducible state hashes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides canonical normalization for desktop accessibility snapshots,
|
|
5
|
+
* ensuring that equivalent UI states produce identical hashes regardless of
|
|
6
|
+
* superficial differences (whitespace, element order, transient attributes).
|
|
7
|
+
*/
|
|
8
|
+
import { type Platform } from "./utils.js";
|
|
9
|
+
/**
|
|
10
|
+
* Raw accessibility tree node from the runtime environment.
|
|
11
|
+
*/
|
|
12
|
+
export interface AccessibilityNode {
|
|
13
|
+
role?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
children?: AccessibilityNode[];
|
|
16
|
+
pid?: number;
|
|
17
|
+
position?: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
};
|
|
21
|
+
focused?: boolean;
|
|
22
|
+
selected?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Raw desktop accessibility snapshot from the runtime environment.
|
|
26
|
+
*/
|
|
27
|
+
export interface DesktopAccessibilitySnapshot {
|
|
28
|
+
app_name?: string;
|
|
29
|
+
window_title?: string;
|
|
30
|
+
focused_role?: string;
|
|
31
|
+
focused_name?: string;
|
|
32
|
+
ui_tree?: AccessibilityNode;
|
|
33
|
+
ui_tree_text?: string;
|
|
34
|
+
platform?: Platform;
|
|
35
|
+
observed_at?: string;
|
|
36
|
+
confidence?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Canonical accessibility node with normalized fields.
|
|
40
|
+
*/
|
|
41
|
+
export interface CanonicalAccessibilityNode {
|
|
42
|
+
role: string;
|
|
43
|
+
name_norm: string;
|
|
44
|
+
children: CanonicalAccessibilityNode[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Canonical desktop snapshot with normalized fields.
|
|
48
|
+
*
|
|
49
|
+
* This is the deterministic representation used for hashing.
|
|
50
|
+
*/
|
|
51
|
+
export interface CanonicalDesktopSnapshot {
|
|
52
|
+
app_name_norm: string;
|
|
53
|
+
window_title_norm: string;
|
|
54
|
+
focused_path: string;
|
|
55
|
+
tree_hash: string;
|
|
56
|
+
platform: Platform;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Canonicalize an accessibility tree node.
|
|
60
|
+
*
|
|
61
|
+
* Normalizes:
|
|
62
|
+
* - `role`: Lowercase, trimmed
|
|
63
|
+
* - `name`: Text normalization (whitespace, case, length)
|
|
64
|
+
* - `children`: Recursively canonicalized, sorted by (role, name)
|
|
65
|
+
*
|
|
66
|
+
* Ignores transient attributes: pid, position, focused, selected.
|
|
67
|
+
*
|
|
68
|
+
* @param node - Raw accessibility node
|
|
69
|
+
* @param depth - Current depth (for truncation)
|
|
70
|
+
* @returns Canonical node
|
|
71
|
+
*/
|
|
72
|
+
export declare function canonicalizeAccessibilityNode(node: AccessibilityNode | null | undefined, depth?: number): CanonicalAccessibilityNode;
|
|
73
|
+
/**
|
|
74
|
+
* Build a focused element path string.
|
|
75
|
+
*
|
|
76
|
+
* Creates a path like "window/toolbar/button[Save]" representing
|
|
77
|
+
* the path to the focused element in the accessibility tree.
|
|
78
|
+
*
|
|
79
|
+
* @param focusedRole - Role of the focused element
|
|
80
|
+
* @param focusedName - Name of the focused element
|
|
81
|
+
* @returns Path string
|
|
82
|
+
*/
|
|
83
|
+
export declare function buildFocusedPath(focusedRole?: string, focusedName?: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* Canonicalize a desktop accessibility snapshot.
|
|
86
|
+
*
|
|
87
|
+
* Normalizes all fields to produce a deterministic representation:
|
|
88
|
+
* - `app_name`: Lowercase, trimmed
|
|
89
|
+
* - `window_title`: Text normalization (capped at 100 chars)
|
|
90
|
+
* - `focused_path`: Built from focused element info
|
|
91
|
+
* - `tree_hash`: SHA-256 of canonical tree JSON
|
|
92
|
+
*
|
|
93
|
+
* @param snapshot - Raw desktop accessibility snapshot
|
|
94
|
+
* @returns Canonical snapshot for hashing
|
|
95
|
+
*/
|
|
96
|
+
export declare function canonicalizeDesktopSnapshot(snapshot: DesktopAccessibilitySnapshot): CanonicalDesktopSnapshot;
|
|
97
|
+
/**
|
|
98
|
+
* Compute state hash for a desktop accessibility snapshot.
|
|
99
|
+
*
|
|
100
|
+
* The hash includes all canonical fields in a deterministic order.
|
|
101
|
+
* Platform is included because different platforms have different
|
|
102
|
+
* accessibility APIs and security contexts.
|
|
103
|
+
*
|
|
104
|
+
* @param snapshot - Raw or canonical desktop snapshot
|
|
105
|
+
* @returns SHA-256 hash prefixed with "sha256:"
|
|
106
|
+
*/
|
|
107
|
+
export declare function computeDesktopStateHash(snapshot: DesktopAccessibilitySnapshot | CanonicalDesktopSnapshot): string;
|
|
108
|
+
/**
|
|
109
|
+
* Current schema version for desktop canonicalization.
|
|
110
|
+
*
|
|
111
|
+
* Increment major version for breaking changes to canonical format.
|
|
112
|
+
* Increment minor version for additions that don't change existing hashes.
|
|
113
|
+
*/
|
|
114
|
+
export declare const DESKTOP_SCHEMA_VERSION = "desktop:v1.0";
|
|
115
|
+
//# sourceMappingURL=desktop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.d.ts","sourceRoot":"","sources":["../../src/canonicalization/desktop.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,YAAY,CAAC;AAMlE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAE/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,EAC1C,KAAK,SAAI,GACR,0BAA0B,CAyC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,CAAC,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAaR;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,4BAA4B,GACrC,wBAAwB,CAsB1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,4BAA4B,GAAG,wBAAwB,GAChE,MAAM,CAgBR;AAoCD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop accessibility tree canonicalization for reproducible state hashes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides canonical normalization for desktop accessibility snapshots,
|
|
5
|
+
* ensuring that equivalent UI states produce identical hashes regardless of
|
|
6
|
+
* superficial differences (whitespace, element order, transient attributes).
|
|
7
|
+
*/
|
|
8
|
+
import { normalizeText, sha256 } from "./utils.js";
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Constants
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/** Maximum depth for UI tree canonicalization */
|
|
13
|
+
const MAX_TREE_DEPTH = 10;
|
|
14
|
+
/** Maximum children per node */
|
|
15
|
+
const MAX_CHILDREN_PER_NODE = 50;
|
|
16
|
+
/** Maximum length for window title */
|
|
17
|
+
const MAX_WINDOW_TITLE_LENGTH = 100;
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Accessibility Node Canonicalization
|
|
20
|
+
// =============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Canonicalize an accessibility tree node.
|
|
23
|
+
*
|
|
24
|
+
* Normalizes:
|
|
25
|
+
* - `role`: Lowercase, trimmed
|
|
26
|
+
* - `name`: Text normalization (whitespace, case, length)
|
|
27
|
+
* - `children`: Recursively canonicalized, sorted by (role, name)
|
|
28
|
+
*
|
|
29
|
+
* Ignores transient attributes: pid, position, focused, selected.
|
|
30
|
+
*
|
|
31
|
+
* @param node - Raw accessibility node
|
|
32
|
+
* @param depth - Current depth (for truncation)
|
|
33
|
+
* @returns Canonical node
|
|
34
|
+
*/
|
|
35
|
+
export function canonicalizeAccessibilityNode(node, depth = 0) {
|
|
36
|
+
if (!node) {
|
|
37
|
+
return { role: "", name_norm: "", children: [] };
|
|
38
|
+
}
|
|
39
|
+
const role = (node.role ?? "").toLowerCase().trim();
|
|
40
|
+
const nameNorm = normalizeText(node.name);
|
|
41
|
+
// Truncate at max depth
|
|
42
|
+
if (depth >= MAX_TREE_DEPTH) {
|
|
43
|
+
return {
|
|
44
|
+
role,
|
|
45
|
+
name_norm: nameNorm,
|
|
46
|
+
children: [], // Truncated
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Canonicalize children
|
|
50
|
+
let children = [];
|
|
51
|
+
if (node.children && Array.isArray(node.children)) {
|
|
52
|
+
// Limit children count
|
|
53
|
+
const limitedChildren = node.children.slice(0, MAX_CHILDREN_PER_NODE);
|
|
54
|
+
// Canonicalize each child
|
|
55
|
+
children = limitedChildren.map((child) => canonicalizeAccessibilityNode(child, depth + 1));
|
|
56
|
+
// Sort children by (role, name_norm) for determinism
|
|
57
|
+
children.sort((a, b) => {
|
|
58
|
+
const roleCompare = a.role.localeCompare(b.role);
|
|
59
|
+
if (roleCompare !== 0)
|
|
60
|
+
return roleCompare;
|
|
61
|
+
return a.name_norm.localeCompare(b.name_norm);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
role,
|
|
66
|
+
name_norm: nameNorm,
|
|
67
|
+
children,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build a focused element path string.
|
|
72
|
+
*
|
|
73
|
+
* Creates a path like "window/toolbar/button[Save]" representing
|
|
74
|
+
* the path to the focused element in the accessibility tree.
|
|
75
|
+
*
|
|
76
|
+
* @param focusedRole - Role of the focused element
|
|
77
|
+
* @param focusedName - Name of the focused element
|
|
78
|
+
* @returns Path string
|
|
79
|
+
*/
|
|
80
|
+
export function buildFocusedPath(focusedRole, focusedName) {
|
|
81
|
+
const role = (focusedRole ?? "").toLowerCase().trim();
|
|
82
|
+
const name = normalizeText(focusedName);
|
|
83
|
+
if (!role && !name) {
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
if (!name) {
|
|
87
|
+
return role;
|
|
88
|
+
}
|
|
89
|
+
return `${role}[${name}]`;
|
|
90
|
+
}
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Desktop Snapshot Canonicalization
|
|
93
|
+
// =============================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Canonicalize a desktop accessibility snapshot.
|
|
96
|
+
*
|
|
97
|
+
* Normalizes all fields to produce a deterministic representation:
|
|
98
|
+
* - `app_name`: Lowercase, trimmed
|
|
99
|
+
* - `window_title`: Text normalization (capped at 100 chars)
|
|
100
|
+
* - `focused_path`: Built from focused element info
|
|
101
|
+
* - `tree_hash`: SHA-256 of canonical tree JSON
|
|
102
|
+
*
|
|
103
|
+
* @param snapshot - Raw desktop accessibility snapshot
|
|
104
|
+
* @returns Canonical snapshot for hashing
|
|
105
|
+
*/
|
|
106
|
+
export function canonicalizeDesktopSnapshot(snapshot) {
|
|
107
|
+
const platform = snapshot.platform ?? detectPlatform();
|
|
108
|
+
// Canonicalize the UI tree if present
|
|
109
|
+
let treeHash;
|
|
110
|
+
if (snapshot.ui_tree) {
|
|
111
|
+
const canonicalTree = canonicalizeAccessibilityNode(snapshot.ui_tree);
|
|
112
|
+
treeHash = sha256(JSON.stringify(canonicalTree));
|
|
113
|
+
}
|
|
114
|
+
else if (snapshot.ui_tree_text) {
|
|
115
|
+
// Fallback: hash the raw text if no structured tree
|
|
116
|
+
treeHash = sha256(normalizeText(snapshot.ui_tree_text, 10000));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
treeHash = sha256("");
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
app_name_norm: normalizeText(snapshot.app_name),
|
|
123
|
+
window_title_norm: normalizeText(snapshot.window_title, MAX_WINDOW_TITLE_LENGTH),
|
|
124
|
+
focused_path: buildFocusedPath(snapshot.focused_role, snapshot.focused_name),
|
|
125
|
+
tree_hash: treeHash,
|
|
126
|
+
platform,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Compute state hash for a desktop accessibility snapshot.
|
|
131
|
+
*
|
|
132
|
+
* The hash includes all canonical fields in a deterministic order.
|
|
133
|
+
* Platform is included because different platforms have different
|
|
134
|
+
* accessibility APIs and security contexts.
|
|
135
|
+
*
|
|
136
|
+
* @param snapshot - Raw or canonical desktop snapshot
|
|
137
|
+
* @returns SHA-256 hash prefixed with "sha256:"
|
|
138
|
+
*/
|
|
139
|
+
export function computeDesktopStateHash(snapshot) {
|
|
140
|
+
// Canonicalize if not already canonical
|
|
141
|
+
const canonical = isCanonicalDesktopSnapshot(snapshot)
|
|
142
|
+
? snapshot
|
|
143
|
+
: canonicalizeDesktopSnapshot(snapshot);
|
|
144
|
+
// Build deterministic JSON (sorted keys)
|
|
145
|
+
const hashInput = JSON.stringify({
|
|
146
|
+
app_name_norm: canonical.app_name_norm,
|
|
147
|
+
focused_path: canonical.focused_path,
|
|
148
|
+
platform: canonical.platform,
|
|
149
|
+
tree_hash: canonical.tree_hash,
|
|
150
|
+
window_title_norm: canonical.window_title_norm,
|
|
151
|
+
});
|
|
152
|
+
return `sha256:${sha256(hashInput)}`;
|
|
153
|
+
}
|
|
154
|
+
// =============================================================================
|
|
155
|
+
// Helpers
|
|
156
|
+
// =============================================================================
|
|
157
|
+
/**
|
|
158
|
+
* Detect the current platform.
|
|
159
|
+
*/
|
|
160
|
+
function detectPlatform() {
|
|
161
|
+
const p = process.platform;
|
|
162
|
+
if (p === "darwin" || p === "linux" || p === "win32") {
|
|
163
|
+
return p;
|
|
164
|
+
}
|
|
165
|
+
// Default to linux for unknown Unix-like platforms
|
|
166
|
+
return "linux";
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Type guard to check if a snapshot is already canonical.
|
|
170
|
+
*/
|
|
171
|
+
function isCanonicalDesktopSnapshot(snapshot) {
|
|
172
|
+
return ("app_name_norm" in snapshot &&
|
|
173
|
+
"window_title_norm" in snapshot &&
|
|
174
|
+
"focused_path" in snapshot &&
|
|
175
|
+
"tree_hash" in snapshot);
|
|
176
|
+
}
|
|
177
|
+
// =============================================================================
|
|
178
|
+
// Schema Version
|
|
179
|
+
// =============================================================================
|
|
180
|
+
/**
|
|
181
|
+
* Current schema version for desktop canonicalization.
|
|
182
|
+
*
|
|
183
|
+
* Increment major version for breaking changes to canonical format.
|
|
184
|
+
* Increment minor version for additions that don't change existing hashes.
|
|
185
|
+
*/
|
|
186
|
+
export const DESKTOP_SCHEMA_VERSION = "desktop:v1.0";
|
|
187
|
+
//# sourceMappingURL=desktop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.js","sourceRoot":"","sources":["../../src/canonicalization/desktop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalization module for non-web state evidence.
|
|
3
|
+
*
|
|
4
|
+
* This module provides consistent normalization for terminal and desktop
|
|
5
|
+
* accessibility snapshots, ensuring reproducible state hashes across
|
|
6
|
+
* different runs, platforms, and environments.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import {
|
|
11
|
+
* canonicalizeTerminalSnapshot,
|
|
12
|
+
* computeTerminalStateHash,
|
|
13
|
+
* canonicalizeDesktopSnapshot,
|
|
14
|
+
* computeDesktopStateHash,
|
|
15
|
+
* } from "@predicatesystems/authority/canonicalization";
|
|
16
|
+
*
|
|
17
|
+
* // Terminal session
|
|
18
|
+
* const terminalHash = computeTerminalStateHash({
|
|
19
|
+
* session_id: "sess-123",
|
|
20
|
+
* cwd: "~/projects/myapp",
|
|
21
|
+
* command: "npm test", // Extra whitespace normalized
|
|
22
|
+
* transcript: "\x1b[32mPASS\x1b[0m all tests", // ANSI stripped
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Desktop accessibility
|
|
26
|
+
* const desktopHash = computeDesktopStateHash({
|
|
27
|
+
* app_name: "Firefox",
|
|
28
|
+
* window_title: " GitHub - My Repo ", // Whitespace normalized
|
|
29
|
+
* focused_role: "button",
|
|
30
|
+
* focused_name: "Submit",
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module canonicalization
|
|
35
|
+
*/
|
|
36
|
+
export { type Platform, normalizeText, normalizeCommand, stripAnsi, normalizeTimestamps, normalizeTranscript, normalizePath, isSecretKey, hashEnvironment, sha256, } from "./utils.js";
|
|
37
|
+
export { type TerminalSessionSnapshot, type CanonicalTerminalSnapshot, canonicalizeTerminalSnapshot, computeTerminalStateHash, TERMINAL_SCHEMA_VERSION, } from "./terminal.js";
|
|
38
|
+
export { type AccessibilityNode, type DesktopAccessibilitySnapshot, type CanonicalAccessibilityNode, type CanonicalDesktopSnapshot, canonicalizeAccessibilityNode, buildFocusedPath, canonicalizeDesktopSnapshot, computeDesktopStateHash, DESKTOP_SCHEMA_VERSION, } from "./desktop.js";
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canonicalization/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,OAAO,EAEL,KAAK,QAAQ,EAEb,aAAa,EACb,gBAAgB,EAEhB,SAAS,EACT,mBAAmB,EAEnB,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,eAAe,EAEf,MAAM,GACP,MAAM,YAAY,CAAC;AAMpB,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAE9B,4BAA4B,EAC5B,wBAAwB,EAExB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAMvB,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAE7B,6BAA6B,EAC7B,gBAAgB,EAChB,2BAA2B,EAC3B,uBAAuB,EAEvB,sBAAsB,GACvB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalization module for non-web state evidence.
|
|
3
|
+
*
|
|
4
|
+
* This module provides consistent normalization for terminal and desktop
|
|
5
|
+
* accessibility snapshots, ensuring reproducible state hashes across
|
|
6
|
+
* different runs, platforms, and environments.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import {
|
|
11
|
+
* canonicalizeTerminalSnapshot,
|
|
12
|
+
* computeTerminalStateHash,
|
|
13
|
+
* canonicalizeDesktopSnapshot,
|
|
14
|
+
* computeDesktopStateHash,
|
|
15
|
+
* } from "@predicatesystems/authority/canonicalization";
|
|
16
|
+
*
|
|
17
|
+
* // Terminal session
|
|
18
|
+
* const terminalHash = computeTerminalStateHash({
|
|
19
|
+
* session_id: "sess-123",
|
|
20
|
+
* cwd: "~/projects/myapp",
|
|
21
|
+
* command: "npm test", // Extra whitespace normalized
|
|
22
|
+
* transcript: "\x1b[32mPASS\x1b[0m all tests", // ANSI stripped
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Desktop accessibility
|
|
26
|
+
* const desktopHash = computeDesktopStateHash({
|
|
27
|
+
* app_name: "Firefox",
|
|
28
|
+
* window_title: " GitHub - My Repo ", // Whitespace normalized
|
|
29
|
+
* focused_role: "button",
|
|
30
|
+
* focused_name: "Submit",
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module canonicalization
|
|
35
|
+
*/
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// Re-exports: Utilities
|
|
38
|
+
// =============================================================================
|
|
39
|
+
export {
|
|
40
|
+
// Text normalization
|
|
41
|
+
normalizeText, normalizeCommand,
|
|
42
|
+
// ANSI and timestamp handling
|
|
43
|
+
stripAnsi, normalizeTimestamps,
|
|
44
|
+
// Transcript normalization
|
|
45
|
+
normalizeTranscript,
|
|
46
|
+
// Path normalization
|
|
47
|
+
normalizePath,
|
|
48
|
+
// Environment hashing
|
|
49
|
+
isSecretKey, hashEnvironment,
|
|
50
|
+
// Core hashing
|
|
51
|
+
sha256, } from "./utils.js";
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Re-exports: Terminal Canonicalization
|
|
54
|
+
// =============================================================================
|
|
55
|
+
export {
|
|
56
|
+
// Functions
|
|
57
|
+
canonicalizeTerminalSnapshot, computeTerminalStateHash,
|
|
58
|
+
// Schema version
|
|
59
|
+
TERMINAL_SCHEMA_VERSION, } from "./terminal.js";
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// Re-exports: Desktop Canonicalization
|
|
62
|
+
// =============================================================================
|
|
63
|
+
export {
|
|
64
|
+
// Functions
|
|
65
|
+
canonicalizeAccessibilityNode, buildFocusedPath, canonicalizeDesktopSnapshot, computeDesktopStateHash,
|
|
66
|
+
// Schema version
|
|
67
|
+
DESKTOP_SCHEMA_VERSION, } from "./desktop.js";
|
|
68
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/canonicalization/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,gFAAgF;AAChF,wBAAwB;AACxB,gFAAgF;AAEhF,OAAO;AAGL,qBAAqB;AACrB,aAAa,EACb,gBAAgB;AAChB,8BAA8B;AAC9B,SAAS,EACT,mBAAmB;AACnB,2BAA2B;AAC3B,mBAAmB;AACnB,qBAAqB;AACrB,aAAa;AACb,sBAAsB;AACtB,WAAW,EACX,eAAe;AACf,eAAe;AACf,MAAM,GACP,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,wCAAwC;AACxC,gFAAgF;AAEhF,OAAO;AAIL,YAAY;AACZ,4BAA4B,EAC5B,wBAAwB;AACxB,iBAAiB;AACjB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,gFAAgF;AAChF,uCAAuC;AACvC,gFAAgF;AAEhF,OAAO;AAML,YAAY;AACZ,6BAA6B,EAC7B,gBAAgB,EAChB,2BAA2B,EAC3B,uBAAuB;AACvB,iBAAiB;AACjB,sBAAsB,GACvB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal session canonicalization for reproducible state hashes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides canonical normalization for terminal sessions,
|
|
5
|
+
* ensuring that equivalent terminal states produce identical hashes
|
|
6
|
+
* regardless of superficial differences (whitespace, ANSI codes, timestamps).
|
|
7
|
+
*/
|
|
8
|
+
import { type Platform } from "./utils.js";
|
|
9
|
+
/**
|
|
10
|
+
* Raw terminal session snapshot from the runtime environment.
|
|
11
|
+
*/
|
|
12
|
+
export interface TerminalSessionSnapshot {
|
|
13
|
+
session_id: string;
|
|
14
|
+
terminal_id?: string;
|
|
15
|
+
cwd?: string;
|
|
16
|
+
command?: string;
|
|
17
|
+
transcript?: string;
|
|
18
|
+
exit_code?: number | null;
|
|
19
|
+
env?: Record<string, string>;
|
|
20
|
+
platform?: Platform;
|
|
21
|
+
observed_at?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Canonical terminal snapshot with normalized fields.
|
|
25
|
+
*
|
|
26
|
+
* This is the deterministic representation used for hashing.
|
|
27
|
+
*/
|
|
28
|
+
export interface CanonicalTerminalSnapshot {
|
|
29
|
+
session_id: string;
|
|
30
|
+
terminal_id: string;
|
|
31
|
+
cwd_normalized: string;
|
|
32
|
+
command_normalized: string;
|
|
33
|
+
transcript_normalized: string;
|
|
34
|
+
exit_code: number | null;
|
|
35
|
+
env_hash: string;
|
|
36
|
+
platform: Platform;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Canonicalize a terminal session snapshot.
|
|
40
|
+
*
|
|
41
|
+
* Normalizes all fields to produce a deterministic representation:
|
|
42
|
+
* - `cwd`: Resolved to absolute path
|
|
43
|
+
* - `command`: Trimmed and whitespace-collapsed (case preserved)
|
|
44
|
+
* - `transcript`: ANSI stripped, timestamps normalized, whitespace collapsed
|
|
45
|
+
* - `env`: Sorted, secrets redacted, then hashed
|
|
46
|
+
*
|
|
47
|
+
* @param snapshot - Raw terminal session snapshot
|
|
48
|
+
* @returns Canonical snapshot for hashing
|
|
49
|
+
*/
|
|
50
|
+
export declare function canonicalizeTerminalSnapshot(snapshot: TerminalSessionSnapshot): CanonicalTerminalSnapshot;
|
|
51
|
+
/**
|
|
52
|
+
* Compute state hash for a terminal session snapshot.
|
|
53
|
+
*
|
|
54
|
+
* The hash includes all canonical fields in a deterministic order.
|
|
55
|
+
* Platform is included because different platforms have different
|
|
56
|
+
* security contexts (e.g., Unix vs Windows permissions).
|
|
57
|
+
*
|
|
58
|
+
* @param snapshot - Raw or canonical terminal snapshot
|
|
59
|
+
* @returns SHA-256 hash prefixed with "sha256:"
|
|
60
|
+
*/
|
|
61
|
+
export declare function computeTerminalStateHash(snapshot: TerminalSessionSnapshot | CanonicalTerminalSnapshot): string;
|
|
62
|
+
/**
|
|
63
|
+
* Current schema version for terminal canonicalization.
|
|
64
|
+
*
|
|
65
|
+
* Increment major version for breaking changes to canonical format.
|
|
66
|
+
* Increment minor version for additions that don't change existing hashes.
|
|
67
|
+
*/
|
|
68
|
+
export declare const TERMINAL_SCHEMA_VERSION = "terminal:v1.0";
|
|
69
|
+
//# sourceMappingURL=terminal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/canonicalization/terminal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,KAAK,QAAQ,EAMd,MAAM,YAAY,CAAC;AAMpB;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,uBAAuB,GAChC,yBAAyB,CAa3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,uBAAuB,GAAG,yBAAyB,GAC5D,MAAM,CAmBR;AAoCD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal session canonicalization for reproducible state hashes.
|
|
3
|
+
*
|
|
4
|
+
* This module provides canonical normalization for terminal sessions,
|
|
5
|
+
* ensuring that equivalent terminal states produce identical hashes
|
|
6
|
+
* regardless of superficial differences (whitespace, ANSI codes, timestamps).
|
|
7
|
+
*/
|
|
8
|
+
import { hashEnvironment, normalizeCommand, normalizePath, normalizeTranscript, sha256, } from "./utils.js";
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Canonicalization
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Canonicalize a terminal session snapshot.
|
|
14
|
+
*
|
|
15
|
+
* Normalizes all fields to produce a deterministic representation:
|
|
16
|
+
* - `cwd`: Resolved to absolute path
|
|
17
|
+
* - `command`: Trimmed and whitespace-collapsed (case preserved)
|
|
18
|
+
* - `transcript`: ANSI stripped, timestamps normalized, whitespace collapsed
|
|
19
|
+
* - `env`: Sorted, secrets redacted, then hashed
|
|
20
|
+
*
|
|
21
|
+
* @param snapshot - Raw terminal session snapshot
|
|
22
|
+
* @returns Canonical snapshot for hashing
|
|
23
|
+
*/
|
|
24
|
+
export function canonicalizeTerminalSnapshot(snapshot) {
|
|
25
|
+
const platform = snapshot.platform ?? detectPlatform();
|
|
26
|
+
return {
|
|
27
|
+
session_id: snapshot.session_id,
|
|
28
|
+
terminal_id: snapshot.terminal_id ?? "",
|
|
29
|
+
cwd_normalized: normalizePath(snapshot.cwd),
|
|
30
|
+
command_normalized: normalizeCommand(snapshot.command),
|
|
31
|
+
transcript_normalized: normalizeTranscript(snapshot.transcript),
|
|
32
|
+
exit_code: snapshot.exit_code ?? null,
|
|
33
|
+
env_hash: hashEnvironment(snapshot.env),
|
|
34
|
+
platform,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Compute state hash for a terminal session snapshot.
|
|
39
|
+
*
|
|
40
|
+
* The hash includes all canonical fields in a deterministic order.
|
|
41
|
+
* Platform is included because different platforms have different
|
|
42
|
+
* security contexts (e.g., Unix vs Windows permissions).
|
|
43
|
+
*
|
|
44
|
+
* @param snapshot - Raw or canonical terminal snapshot
|
|
45
|
+
* @returns SHA-256 hash prefixed with "sha256:"
|
|
46
|
+
*/
|
|
47
|
+
export function computeTerminalStateHash(snapshot) {
|
|
48
|
+
// Canonicalize if not already canonical
|
|
49
|
+
const canonical = isCanonicalTerminalSnapshot(snapshot)
|
|
50
|
+
? snapshot
|
|
51
|
+
: canonicalizeTerminalSnapshot(snapshot);
|
|
52
|
+
// Build deterministic JSON (sorted keys)
|
|
53
|
+
const hashInput = JSON.stringify({
|
|
54
|
+
command_normalized: canonical.command_normalized,
|
|
55
|
+
cwd_normalized: canonical.cwd_normalized,
|
|
56
|
+
env_hash: canonical.env_hash,
|
|
57
|
+
exit_code: canonical.exit_code,
|
|
58
|
+
platform: canonical.platform,
|
|
59
|
+
session_id: canonical.session_id,
|
|
60
|
+
terminal_id: canonical.terminal_id,
|
|
61
|
+
transcript_normalized: canonical.transcript_normalized,
|
|
62
|
+
});
|
|
63
|
+
return `sha256:${sha256(hashInput)}`;
|
|
64
|
+
}
|
|
65
|
+
// =============================================================================
|
|
66
|
+
// Helpers
|
|
67
|
+
// =============================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Detect the current platform.
|
|
70
|
+
*/
|
|
71
|
+
function detectPlatform() {
|
|
72
|
+
const p = process.platform;
|
|
73
|
+
if (p === "darwin" || p === "linux" || p === "win32") {
|
|
74
|
+
return p;
|
|
75
|
+
}
|
|
76
|
+
// Default to linux for unknown Unix-like platforms
|
|
77
|
+
return "linux";
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Type guard to check if a snapshot is already canonical.
|
|
81
|
+
*/
|
|
82
|
+
function isCanonicalTerminalSnapshot(snapshot) {
|
|
83
|
+
return ("cwd_normalized" in snapshot &&
|
|
84
|
+
"command_normalized" in snapshot &&
|
|
85
|
+
"transcript_normalized" in snapshot &&
|
|
86
|
+
"env_hash" in snapshot);
|
|
87
|
+
}
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// Schema Version
|
|
90
|
+
// =============================================================================
|
|
91
|
+
/**
|
|
92
|
+
* Current schema version for terminal canonicalization.
|
|
93
|
+
*
|
|
94
|
+
* Increment major version for breaking changes to canonical format.
|
|
95
|
+
* Increment minor version for additions that don't change existing hashes.
|
|
96
|
+
*/
|
|
97
|
+
export const TERMINAL_SCHEMA_VERSION = "terminal:v1.0";
|
|
98
|
+
//# sourceMappingURL=terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/canonicalization/terminal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,MAAM,GACP,MAAM,YAAY,CAAC;AAqCpB,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,4BAA4B,CAC1C,QAAiC;IAEjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,cAAc,EAAE,CAAC;IAEvD,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE;QACvC,cAAc,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC3C,kBAAkB,EAAE,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC;QACtD,qBAAqB,EAAE,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC/D,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI;QACrC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC;QACvC,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA6D;IAE7D,wCAAwC;IACxC,MAAM,SAAS,GAAG,2BAA2B,CAAC,QAAQ,CAAC;QACrD,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IAE3C,yCAAyC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAC/B,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;QAChD,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,UAAU,EAAE,SAAS,CAAC,UAAU;QAChC,WAAW,EAAE,SAAS,CAAC,WAAW;QAClC,qBAAqB,EAAE,SAAS,CAAC,qBAAqB;KACvD,CAAC,CAAC;IAEH,OAAO,UAAU,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;AACvC,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;GAEG;AACH,SAAS,cAAc;IACrB,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC3B,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;QACrD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,mDAAmD;IACnD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,2BAA2B,CAClC,QAA6D;IAE7D,OAAO,CACL,gBAAgB,IAAI,QAAQ;QAC5B,oBAAoB,IAAI,QAAQ;QAChC,uBAAuB,IAAI,QAAQ;QACnC,UAAU,IAAI,QAAQ,CACvB,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC"}
|