tauri-agent-tools 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/tauri-agent-tools/SKILL.md +50 -13
- package/.agents/skills/tauri-bridge-setup/SKILL.md +5 -3
- package/.agents/skills/tauri-debug-quickstart/SKILL.md +9 -6
- package/AGENTS.md +13 -3
- package/README.md +25 -4
- package/dist/bridge/client.d.ts +8 -0
- package/dist/bridge/client.js +20 -0
- package/dist/bridge/client.js.map +1 -1
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/bundle.d.ts +2 -0
- package/dist/commands/bundle.js +251 -0
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/capabilitiesAudit.js +14 -1
- package/dist/commands/capabilitiesAudit.js.map +1 -1
- package/dist/commands/health.js +19 -1
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/ipcMonitor.js +38 -4
- package/dist/commands/ipcMonitor.js.map +1 -1
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +193 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/processTree.js +116 -4
- package/dist/commands/processTree.js.map +1 -1
- package/dist/commands/shared.d.ts +31 -0
- package/dist/commands/shared.js +52 -1
- package/dist/commands/shared.js.map +1 -1
- package/dist/commands/webviewAttach.js +17 -1
- package/dist/commands/webviewAttach.js.map +1 -1
- package/dist/platform/macos.js +35 -15
- package/dist/platform/macos.js.map +1 -1
- package/dist/util/logMerge.d.ts +42 -0
- package/dist/util/logMerge.js +133 -0
- package/dist/util/logMerge.js.map +1 -0
- package/dist/util/mergeByTimestamp.d.ts +18 -0
- package/dist/util/mergeByTimestamp.js +30 -0
- package/dist/util/mergeByTimestamp.js.map +1 -0
- package/dist/util/psTree.d.ts +28 -0
- package/dist/util/psTree.js +76 -0
- package/dist/util/psTree.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { OsLogLevel } from '../schemas/osLog.js';
|
|
2
|
+
import type { RustLogEntry } from '../schemas/bridge.js';
|
|
3
|
+
/**
|
|
4
|
+
* One entry in a merged, cross-source log timeline. Superset of the normalized
|
|
5
|
+
* `os-logs` shape (kept local so the shared `NormalizedLogEntry` schema — and
|
|
6
|
+
* the commands validated against it — are untouched).
|
|
7
|
+
*/
|
|
8
|
+
export interface MergedLogEntry {
|
|
9
|
+
/** ISO-8601 timestamp, or '' when unknown. */
|
|
10
|
+
ts: string;
|
|
11
|
+
level: OsLogLevel;
|
|
12
|
+
/** 'rust' | 'sidecar:<name>' (bridge) or 'file:<basename>' (disk). */
|
|
13
|
+
source: string;
|
|
14
|
+
/** Target/module path, best-effort. */
|
|
15
|
+
subsystem: string;
|
|
16
|
+
message: string;
|
|
17
|
+
origin: 'bridge' | 'file';
|
|
18
|
+
correlation?: Record<string, string>;
|
|
19
|
+
raw?: unknown;
|
|
20
|
+
}
|
|
21
|
+
export declare const LEVEL_RANK: Record<OsLogLevel, number>;
|
|
22
|
+
export interface ParsedLine {
|
|
23
|
+
ts: string;
|
|
24
|
+
level: OsLogLevel;
|
|
25
|
+
subsystem: string;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Best-effort parse of one on-disk log line. Pulls leading bracketed tokens
|
|
30
|
+
* (`[ts][target][LEVEL]` in any order) when present; otherwise treats the whole
|
|
31
|
+
* line as the message and infers the level from inline text. Never throws — an
|
|
32
|
+
* unrecognized line still yields a usable entry (ts='', level='info').
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseLogLine(line: string): ParsedLine;
|
|
35
|
+
/** Normalize a bridge /logs ring-buffer entry into a MergedLogEntry. */
|
|
36
|
+
export declare function normalizeRustLog(e: RustLogEntry): MergedLogEntry;
|
|
37
|
+
/**
|
|
38
|
+
* Best-effort correlation-id inference from a message (e.g. `run_id=abc`,
|
|
39
|
+
* `requestId: xyz`, `block-id=42`). Keys shorter than 4 chars (like `pid`) are
|
|
40
|
+
* ignored to cut noise. Returns undefined when nothing is found.
|
|
41
|
+
*/
|
|
42
|
+
export declare function inferCorrelation(message: string): Record<string, string> | undefined;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export const LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
2
|
+
const LEVEL_ALIASES = {
|
|
3
|
+
trace: 'debug',
|
|
4
|
+
debug: 'debug',
|
|
5
|
+
dbg: 'debug',
|
|
6
|
+
info: 'info',
|
|
7
|
+
information: 'info',
|
|
8
|
+
warn: 'warn',
|
|
9
|
+
warning: 'warn',
|
|
10
|
+
error: 'error',
|
|
11
|
+
err: 'error',
|
|
12
|
+
fatal: 'error',
|
|
13
|
+
crit: 'error',
|
|
14
|
+
critical: 'error',
|
|
15
|
+
};
|
|
16
|
+
function looksLikeTimestampPart(token) {
|
|
17
|
+
return (/\d{4}-\d{2}-\d{2}/.test(token) ||
|
|
18
|
+
/\d{1,2}:\d{2}:\d{2}/.test(token) ||
|
|
19
|
+
/^\d{10,13}$/.test(token));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Normalize a timestamp candidate so `Date.parse` reads it deterministically:
|
|
23
|
+
* unify "date time" → "dateTtime" and, when a time component has no explicit
|
|
24
|
+
* timezone, treat it as UTC (append `Z`). This keeps cross-source ordering — and
|
|
25
|
+
* the emitted ISO output — independent of the host machine's timezone.
|
|
26
|
+
*/
|
|
27
|
+
function normalizeForParse(s) {
|
|
28
|
+
let v = s.trim();
|
|
29
|
+
v = v.replace(/^(\d{4}-\d{2}-\d{2})[ ](\d{2}:\d{2})/, '$1T$2');
|
|
30
|
+
const hasTime = /T\d{2}:\d{2}/.test(v) || /^\d{1,2}:\d{2}:\d{2}/.test(v);
|
|
31
|
+
const hasTz = /[zZ]$/.test(v) || /[+-]\d{2}:?\d{2}$/.test(v);
|
|
32
|
+
if (hasTime && !hasTz)
|
|
33
|
+
v += 'Z';
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
36
|
+
function combineTimestamp(parts) {
|
|
37
|
+
if (parts.length === 0)
|
|
38
|
+
return '';
|
|
39
|
+
if (parts.length === 1 && /^\d{10,13}$/.test(parts[0])) {
|
|
40
|
+
const raw = parts[0];
|
|
41
|
+
const ms = raw.length <= 10 ? Number(raw) * 1000 : Number(raw);
|
|
42
|
+
const d = new Date(ms);
|
|
43
|
+
return Number.isNaN(d.getTime()) ? '' : d.toISOString();
|
|
44
|
+
}
|
|
45
|
+
const candidates = [parts.join('T'), parts.join(' '), parts.join(''), ...parts];
|
|
46
|
+
for (const c of candidates) {
|
|
47
|
+
const t = Date.parse(normalizeForParse(c));
|
|
48
|
+
if (!Number.isNaN(t))
|
|
49
|
+
return new Date(t).toISOString();
|
|
50
|
+
}
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
function inferInlineLevel(text) {
|
|
54
|
+
const m = /\b(TRACE|DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL)\b/i.exec(text);
|
|
55
|
+
if (!m)
|
|
56
|
+
return 'info';
|
|
57
|
+
return LEVEL_ALIASES[m[1].toLowerCase()] ?? 'info';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Best-effort parse of one on-disk log line. Pulls leading bracketed tokens
|
|
61
|
+
* (`[ts][target][LEVEL]` in any order) when present; otherwise treats the whole
|
|
62
|
+
* line as the message and infers the level from inline text. Never throws — an
|
|
63
|
+
* unrecognized line still yields a usable entry (ts='', level='info').
|
|
64
|
+
*/
|
|
65
|
+
export function parseLogLine(line) {
|
|
66
|
+
const m = /^\s*((?:\[[^\]]*\]\s*)+)(.*)$/.exec(line);
|
|
67
|
+
if (!m) {
|
|
68
|
+
return { ts: '', level: inferInlineLevel(line), subsystem: '', message: line.trim() };
|
|
69
|
+
}
|
|
70
|
+
const tokens = [...m[1].matchAll(/\[([^\]]*)\]/g)]
|
|
71
|
+
.map((x) => x[1].trim())
|
|
72
|
+
.filter(Boolean);
|
|
73
|
+
const message = (m[2] ?? '').trim();
|
|
74
|
+
let level = 'info';
|
|
75
|
+
let levelFound = false;
|
|
76
|
+
let subsystem = '';
|
|
77
|
+
const tsParts = [];
|
|
78
|
+
for (const tok of tokens) {
|
|
79
|
+
const lower = tok.toLowerCase();
|
|
80
|
+
if (!levelFound && lower in LEVEL_ALIASES) {
|
|
81
|
+
level = LEVEL_ALIASES[lower];
|
|
82
|
+
levelFound = true;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (looksLikeTimestampPart(tok)) {
|
|
86
|
+
tsParts.push(tok);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!subsystem)
|
|
90
|
+
subsystem = tok;
|
|
91
|
+
}
|
|
92
|
+
if (!levelFound)
|
|
93
|
+
level = inferInlineLevel(message);
|
|
94
|
+
return {
|
|
95
|
+
ts: combineTimestamp(tsParts),
|
|
96
|
+
level,
|
|
97
|
+
subsystem,
|
|
98
|
+
message: message || line.trim(),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Normalize a bridge /logs ring-buffer entry into a MergedLogEntry. */
|
|
102
|
+
export function normalizeRustLog(e) {
|
|
103
|
+
return {
|
|
104
|
+
ts: new Date(e.timestamp).toISOString(),
|
|
105
|
+
level: e.level === 'trace' ? 'debug' : e.level,
|
|
106
|
+
source: e.source,
|
|
107
|
+
subsystem: e.target,
|
|
108
|
+
message: e.message,
|
|
109
|
+
origin: 'bridge',
|
|
110
|
+
raw: e,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const ID_RE = /\b([a-zA-Z][\w]*?(?:[_-]?id))\s*[=:]\s*["']?([\w.\-/]+)/gi;
|
|
114
|
+
/**
|
|
115
|
+
* Best-effort correlation-id inference from a message (e.g. `run_id=abc`,
|
|
116
|
+
* `requestId: xyz`, `block-id=42`). Keys shorter than 4 chars (like `pid`) are
|
|
117
|
+
* ignored to cut noise. Returns undefined when nothing is found.
|
|
118
|
+
*/
|
|
119
|
+
export function inferCorrelation(message) {
|
|
120
|
+
const out = {};
|
|
121
|
+
ID_RE.lastIndex = 0;
|
|
122
|
+
let m;
|
|
123
|
+
while ((m = ID_RE.exec(message)) !== null) {
|
|
124
|
+
const rawKey = m[1];
|
|
125
|
+
if (rawKey.length < 4)
|
|
126
|
+
continue;
|
|
127
|
+
const key = rawKey.replace(/[_-]?id$/i, 'Id');
|
|
128
|
+
if (!(key in out))
|
|
129
|
+
out[key] = m[2];
|
|
130
|
+
}
|
|
131
|
+
return Object.keys(out).length ? out : undefined;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=logMerge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logMerge.js","sourceRoot":"","sources":["../../src/util/logMerge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Minimal shape needed to merge: an ISO-ish timestamp string. */
|
|
2
|
+
export interface HasTs {
|
|
3
|
+
ts: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Stable-merge multiple log arrays into one ascending-by-timestamp stream.
|
|
7
|
+
*
|
|
8
|
+
* Entries whose `ts` is unparseable sort after all parseable entries (treated
|
|
9
|
+
* as +∞) but keep their relative input order. Stability is guaranteed via an
|
|
10
|
+
* insertion-order tiebreaker, so two entries with the same millisecond — or two
|
|
11
|
+
* unparseable entries — keep a deterministic, source-interleaved order.
|
|
12
|
+
*
|
|
13
|
+
* A flat stable sort (rather than a k-way heap) is intentional: the inputs here
|
|
14
|
+
* are bounded (a ring buffer of ≤1000 plus a handful of log files), so O(n log n)
|
|
15
|
+
* on the merged set is simpler and just as fast, with no per-source pre-sort
|
|
16
|
+
* requirement.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mergeByTimestamp<T extends HasTs>(sources: T[][]): T[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable-merge multiple log arrays into one ascending-by-timestamp stream.
|
|
3
|
+
*
|
|
4
|
+
* Entries whose `ts` is unparseable sort after all parseable entries (treated
|
|
5
|
+
* as +∞) but keep their relative input order. Stability is guaranteed via an
|
|
6
|
+
* insertion-order tiebreaker, so two entries with the same millisecond — or two
|
|
7
|
+
* unparseable entries — keep a deterministic, source-interleaved order.
|
|
8
|
+
*
|
|
9
|
+
* A flat stable sort (rather than a k-way heap) is intentional: the inputs here
|
|
10
|
+
* are bounded (a ring buffer of ≤1000 plus a handful of log files), so O(n log n)
|
|
11
|
+
* on the merged set is simpler and just as fast, with no per-source pre-sort
|
|
12
|
+
* requirement.
|
|
13
|
+
*/
|
|
14
|
+
export function mergeByTimestamp(sources) {
|
|
15
|
+
const tagged = [];
|
|
16
|
+
let order = 0;
|
|
17
|
+
for (const src of sources) {
|
|
18
|
+
for (const item of src) {
|
|
19
|
+
const parsed = Date.parse(item.ts);
|
|
20
|
+
tagged.push({
|
|
21
|
+
item,
|
|
22
|
+
key: Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed,
|
|
23
|
+
order: order++,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
tagged.sort((a, b) => a.key - b.key || a.order - b.order);
|
|
28
|
+
return tagged.map((t) => t.item);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mergeByTimestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeByTimestamp.js","sourceRoot":"","sources":["../../src/util/mergeByTimestamp.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAkB,OAAc;IAC9D,MAAM,MAAM,GAAmD,EAAE,CAAC;IAClE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM;gBAC7D,KAAK,EAAE,KAAK,EAAE;aACf,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** A single process row from a `ps` snapshot. */
|
|
2
|
+
export interface PsProc {
|
|
3
|
+
pid: number;
|
|
4
|
+
ppid: number;
|
|
5
|
+
command: string;
|
|
6
|
+
}
|
|
7
|
+
/** A node in a descendant process tree. */
|
|
8
|
+
export interface PsTreeNode extends PsProc {
|
|
9
|
+
children: PsTreeNode[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Snapshot all running processes via `ps` (Unix only: macOS + Linux).
|
|
13
|
+
* Columns are pid, ppid, and the full command line. Returns `[]` on Windows
|
|
14
|
+
* (callers degrade gracefully) and never throws on parse — only the `ps`
|
|
15
|
+
* invocation itself can reject.
|
|
16
|
+
*/
|
|
17
|
+
export declare function snapshotProcesses(timeoutMs?: number): Promise<PsProc[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Build the descendant subtree rooted at `rootPid` from a flat process list.
|
|
20
|
+
* Returns null if `rootPid` is absent from the snapshot. Cycle-safe: a node is
|
|
21
|
+
* never visited twice, so pid-reuse anomalies can't cause infinite recursion.
|
|
22
|
+
* Children are sorted by pid for deterministic output.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildDescendantTree(procs: PsProc[], rootPid: number): PsTreeNode | null;
|
|
25
|
+
/** Flatten a tree depth-first (root first). Cycle-safe. */
|
|
26
|
+
export declare function flattenTree(root: PsTreeNode): PsTreeNode[];
|
|
27
|
+
/** Number of descendants of `root` (the root itself excluded). */
|
|
28
|
+
export declare function countDescendants(root: PsTreeNode): number;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { exec } from './exec.js';
|
|
2
|
+
/**
|
|
3
|
+
* Snapshot all running processes via `ps` (Unix only: macOS + Linux).
|
|
4
|
+
* Columns are pid, ppid, and the full command line. Returns `[]` on Windows
|
|
5
|
+
* (callers degrade gracefully) and never throws on parse — only the `ps`
|
|
6
|
+
* invocation itself can reject.
|
|
7
|
+
*/
|
|
8
|
+
export async function snapshotProcesses(timeoutMs = 5000) {
|
|
9
|
+
if (process.platform === 'win32')
|
|
10
|
+
return [];
|
|
11
|
+
// `-axo pid=,ppid=,command=` works on both BSD (macOS) and procps (Linux);
|
|
12
|
+
// the trailing `=` on each column suppresses the header row.
|
|
13
|
+
const res = await exec('ps', ['-axo', 'pid=,ppid=,command='], { timeout: timeoutMs });
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const line of res.stdout.toString('utf-8').split('\n')) {
|
|
16
|
+
const m = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(line);
|
|
17
|
+
if (!m)
|
|
18
|
+
continue;
|
|
19
|
+
out.push({ pid: Number(m[1]), ppid: Number(m[2]), command: (m[3] ?? '').trim() });
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the descendant subtree rooted at `rootPid` from a flat process list.
|
|
25
|
+
* Returns null if `rootPid` is absent from the snapshot. Cycle-safe: a node is
|
|
26
|
+
* never visited twice, so pid-reuse anomalies can't cause infinite recursion.
|
|
27
|
+
* Children are sorted by pid for deterministic output.
|
|
28
|
+
*/
|
|
29
|
+
export function buildDescendantTree(procs, rootPid) {
|
|
30
|
+
const byPid = new Map();
|
|
31
|
+
for (const p of procs)
|
|
32
|
+
byPid.set(p.pid, { ...p, children: [] });
|
|
33
|
+
for (const node of byPid.values()) {
|
|
34
|
+
if (node.ppid === node.pid)
|
|
35
|
+
continue; // guard self-parenting
|
|
36
|
+
const parent = byPid.get(node.ppid);
|
|
37
|
+
if (parent)
|
|
38
|
+
parent.children.push(node);
|
|
39
|
+
}
|
|
40
|
+
const root = byPid.get(rootPid);
|
|
41
|
+
if (!root)
|
|
42
|
+
return null;
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const sortRec = (n) => {
|
|
45
|
+
if (seen.has(n.pid)) {
|
|
46
|
+
n.children = [];
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
seen.add(n.pid);
|
|
50
|
+
n.children.sort((a, b) => a.pid - b.pid);
|
|
51
|
+
for (const c of n.children)
|
|
52
|
+
sortRec(c);
|
|
53
|
+
};
|
|
54
|
+
sortRec(root);
|
|
55
|
+
return root;
|
|
56
|
+
}
|
|
57
|
+
/** Flatten a tree depth-first (root first). Cycle-safe. */
|
|
58
|
+
export function flattenTree(root) {
|
|
59
|
+
const out = [];
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
const walk = (n) => {
|
|
62
|
+
if (seen.has(n.pid))
|
|
63
|
+
return;
|
|
64
|
+
seen.add(n.pid);
|
|
65
|
+
out.push(n);
|
|
66
|
+
for (const c of n.children)
|
|
67
|
+
walk(c);
|
|
68
|
+
};
|
|
69
|
+
walk(root);
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/** Number of descendants of `root` (the root itself excluded). */
|
|
73
|
+
export function countDescendants(root) {
|
|
74
|
+
return Math.max(0, flattenTree(root).length - 1);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=psTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"psTree.js","sourceRoot":"","sources":["../../src/util/psTree.ts"],"names":[],"mappings":"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"}
|