@nocoo/pew 1.2.0 → 1.4.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.
Files changed (59) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +19 -3
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/notify.d.ts.map +1 -1
  5. package/dist/commands/notify.js +1 -0
  6. package/dist/commands/notify.js.map +1 -1
  7. package/dist/commands/session-sync.d.ts +2 -0
  8. package/dist/commands/session-sync.d.ts.map +1 -1
  9. package/dist/commands/session-sync.js +17 -4
  10. package/dist/commands/session-sync.js.map +1 -1
  11. package/dist/commands/status.d.ts +1 -0
  12. package/dist/commands/status.d.ts.map +1 -1
  13. package/dist/commands/status.js +4 -0
  14. package/dist/commands/status.js.map +1 -1
  15. package/dist/commands/sync.d.ts +4 -0
  16. package/dist/commands/sync.d.ts.map +1 -1
  17. package/dist/commands/sync.js +4 -2
  18. package/dist/commands/sync.js.map +1 -1
  19. package/dist/discovery/sources.d.ts +12 -0
  20. package/dist/discovery/sources.d.ts.map +1 -1
  21. package/dist/discovery/sources.js +57 -0
  22. package/dist/discovery/sources.js.map +1 -1
  23. package/dist/drivers/registry.d.ts +1 -0
  24. package/dist/drivers/registry.d.ts.map +1 -1
  25. package/dist/drivers/registry.js +4 -0
  26. package/dist/drivers/registry.js.map +1 -1
  27. package/dist/drivers/token/vscode-copilot-token-driver.d.ts +12 -0
  28. package/dist/drivers/token/vscode-copilot-token-driver.d.ts.map +1 -0
  29. package/dist/drivers/token/vscode-copilot-token-driver.js +66 -0
  30. package/dist/drivers/token/vscode-copilot-token-driver.js.map +1 -0
  31. package/dist/drivers/types.d.ts +17 -1
  32. package/dist/drivers/types.d.ts.map +1 -1
  33. package/dist/parsers/claude-session.js +5 -6
  34. package/dist/parsers/claude-session.js.map +1 -1
  35. package/dist/parsers/codex-session.d.ts.map +1 -1
  36. package/dist/parsers/codex-session.js +2 -4
  37. package/dist/parsers/codex-session.js.map +1 -1
  38. package/dist/parsers/gemini-session.d.ts.map +1 -1
  39. package/dist/parsers/gemini-session.js +5 -2
  40. package/dist/parsers/gemini-session.js.map +1 -1
  41. package/dist/parsers/openclaw-session.d.ts.map +1 -1
  42. package/dist/parsers/openclaw-session.js +3 -2
  43. package/dist/parsers/openclaw-session.js.map +1 -1
  44. package/dist/parsers/opencode-sqlite-session.d.ts.map +1 -1
  45. package/dist/parsers/opencode-sqlite-session.js +2 -1
  46. package/dist/parsers/opencode-sqlite-session.js.map +1 -1
  47. package/dist/parsers/vscode-copilot.d.ts +64 -0
  48. package/dist/parsers/vscode-copilot.d.ts.map +1 -0
  49. package/dist/parsers/vscode-copilot.js +257 -0
  50. package/dist/parsers/vscode-copilot.js.map +1 -0
  51. package/dist/utils/hash-project-ref.d.ts +23 -0
  52. package/dist/utils/hash-project-ref.d.ts.map +1 -0
  53. package/dist/utils/hash-project-ref.js +31 -0
  54. package/dist/utils/hash-project-ref.js.map +1 -0
  55. package/dist/utils/paths.d.ts +2 -0
  56. package/dist/utils/paths.d.ts.map +1 -1
  57. package/dist/utils/paths.js +35 -0
  58. package/dist/utils/paths.js.map +1 -1
  59. package/package.json +4 -1
@@ -0,0 +1,257 @@
1
+ /**
2
+ * VSCode Copilot Chat JSONL parser.
3
+ *
4
+ * Parses CRDT-style append-only operation logs from VSCode Copilot Chat
5
+ * session files. Three operation kinds:
6
+ *
7
+ * kind=0 (Snapshot) — full session state, first line of file
8
+ * kind=1 (Set) — overwrite value at a JSON path
9
+ * kind=2 (Append) — append to array at path
10
+ *
11
+ * Token data lives in kind=1 lines targeting ["requests", N, "result"],
12
+ * specifically in v.metadata.promptTokens / v.metadata.outputTokens.
13
+ *
14
+ * Model ID and timestamp come from the request itself, either in the
15
+ * kind=0 snapshot's requests array or kind=2 appends to ["requests"].
16
+ *
17
+ * The parser maintains a request-index → metadata mapping so that
18
+ * kind=1 result lines (which only carry the index) can be correlated
19
+ * with their model and timestamp. This mapping is persisted in the
20
+ * cursor for incremental sync.
21
+ */
22
+ import { createReadStream } from "node:fs";
23
+ import { stat } from "node:fs/promises";
24
+ import { createInterface } from "node:readline";
25
+ // ---------------------------------------------------------------------------
26
+ // Helpers
27
+ // ---------------------------------------------------------------------------
28
+ /** Strip "copilot/" prefix from model IDs (e.g. "copilot/claude-opus-4.6" → "claude-opus-4.6") */
29
+ function normalizeModelId(raw) {
30
+ return raw.startsWith("copilot/") ? raw.slice(8) : raw;
31
+ }
32
+ /** Coerce to non-negative integer, returning 0 for invalid values */
33
+ function toNonNegInt(v) {
34
+ const n = Number(v);
35
+ if (!Number.isFinite(n) || n < 0)
36
+ return 0;
37
+ return Math.floor(n);
38
+ }
39
+ /** Extract modelId and timestamp from a request object */
40
+ function extractRequestMeta(req) {
41
+ const rawModelId = req.modelId;
42
+ const rawTimestamp = req.timestamp;
43
+ if (typeof rawModelId !== "string" || !rawModelId)
44
+ return null;
45
+ if (typeof rawTimestamp !== "number" || !Number.isFinite(rawTimestamp))
46
+ return null;
47
+ return {
48
+ modelId: normalizeModelId(rawModelId),
49
+ timestamp: rawTimestamp,
50
+ };
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Main parser
54
+ // ---------------------------------------------------------------------------
55
+ /**
56
+ * Parse a VSCode Copilot Chat JSONL file incrementally from a byte offset.
57
+ *
58
+ * Strategy:
59
+ * 1. Build/extend index→metadata mapping from kind=0 snapshot + kind=2 request appends
60
+ * 2. Extract tokens from kind=1 result lines, correlate with metadata via index
61
+ * 3. Skip requests without exact promptTokens/outputTokens
62
+ * 4. Skip already-processed request indices
63
+ */
64
+ export async function parseVscodeCopilotFile(opts) {
65
+ const { filePath, startOffset, requestMeta: inputMeta, processedRequestIndices: inputProcessed, onSkip } = opts;
66
+ const deltas = [];
67
+ // Clone mutable state from inputs
68
+ const requestMeta = { ...inputMeta };
69
+ const processedSet = new Set(inputProcessed);
70
+ // Track the next request index for kind=2 appends
71
+ // Initialize from the highest known index + 1
72
+ let nextRequestIndex = 0;
73
+ for (const key of Object.keys(requestMeta)) {
74
+ const idx = Number(key);
75
+ if (idx >= nextRequestIndex)
76
+ nextRequestIndex = idx + 1;
77
+ }
78
+ const st = await stat(filePath).catch(() => null);
79
+ if (!st || !st.isFile()) {
80
+ return {
81
+ deltas,
82
+ endOffset: startOffset,
83
+ requestMeta,
84
+ processedRequestIndices: [...processedSet],
85
+ };
86
+ }
87
+ const endOffset = st.size;
88
+ if (startOffset >= endOffset) {
89
+ return {
90
+ deltas,
91
+ endOffset,
92
+ requestMeta,
93
+ processedRequestIndices: [...processedSet],
94
+ };
95
+ }
96
+ const stream = createReadStream(filePath, {
97
+ encoding: "utf8",
98
+ start: startOffset,
99
+ });
100
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
101
+ // Deferred result lines: kind=1 results that arrive before their
102
+ // corresponding kind=0/2 metadata (unusual but possible within
103
+ // the same read window)
104
+ const deferredResults = [];
105
+ try {
106
+ for await (const line of rl) {
107
+ if (!line)
108
+ continue;
109
+ let obj;
110
+ try {
111
+ obj = JSON.parse(line);
112
+ }
113
+ catch {
114
+ continue;
115
+ }
116
+ const kind = obj.kind;
117
+ // ---- kind=0: Snapshot ----
118
+ if (kind === 0) {
119
+ const v = obj.v;
120
+ const requests = v?.requests;
121
+ if (Array.isArray(requests)) {
122
+ for (let i = 0; i < requests.length; i++) {
123
+ const req = requests[i];
124
+ if (!req || typeof req !== "object")
125
+ continue;
126
+ const meta = extractRequestMeta(req);
127
+ if (meta) {
128
+ requestMeta[i] = meta;
129
+ if (i >= nextRequestIndex)
130
+ nextRequestIndex = i + 1;
131
+ }
132
+ }
133
+ }
134
+ continue;
135
+ }
136
+ // ---- kind=2: Append ----
137
+ if (kind === 2) {
138
+ const k = obj.k;
139
+ // Only care about appends to ["requests"] (top-level request array)
140
+ if (!Array.isArray(k) || k.length !== 1 || k[0] !== "requests")
141
+ continue;
142
+ const v = obj.v;
143
+ if (!Array.isArray(v))
144
+ continue;
145
+ for (const req of v) {
146
+ if (!req || typeof req !== "object")
147
+ continue;
148
+ const meta = extractRequestMeta(req);
149
+ if (meta) {
150
+ requestMeta[nextRequestIndex] = meta;
151
+ }
152
+ nextRequestIndex++;
153
+ }
154
+ continue;
155
+ }
156
+ // ---- kind=1: Set ----
157
+ if (kind === 1) {
158
+ const k = obj.k;
159
+ // Only care about ["requests", N, "result"]
160
+ if (!Array.isArray(k) || k.length !== 3)
161
+ continue;
162
+ if (k[0] !== "requests" || k[2] !== "result")
163
+ continue;
164
+ const index = typeof k[1] === "number" ? k[1] : Number(k[1]);
165
+ if (!Number.isFinite(index) || index < 0)
166
+ continue;
167
+ const v = obj.v;
168
+ if (!v || typeof v !== "object")
169
+ continue;
170
+ // Check if already processed
171
+ if (processedSet.has(index))
172
+ continue;
173
+ // Try to resolve metadata now
174
+ const meta = requestMeta[index];
175
+ if (!meta) {
176
+ // Defer: metadata might appear later in the same read window
177
+ deferredResults.push({ index, v });
178
+ continue;
179
+ }
180
+ // Mark as processed regardless of whether we emit a delta
181
+ processedSet.add(index);
182
+ // Extract tokens from result.metadata
183
+ const metadata = v.metadata;
184
+ if (!metadata || typeof metadata !== "object") {
185
+ onSkip?.({ index, reason: "missing metadata object in result" });
186
+ continue;
187
+ }
188
+ const promptTokens = toNonNegInt(metadata.promptTokens);
189
+ const outputTokens = toNonNegInt(metadata.outputTokens);
190
+ // Skip zero-token results
191
+ if (promptTokens === 0 && outputTokens === 0) {
192
+ const modelState = typeof metadata.modelState === "number" ? metadata.modelState : undefined;
193
+ onSkip?.({ index, reason: "zero tokens (promptTokens=0, outputTokens=0)", modelState });
194
+ continue;
195
+ }
196
+ deltas.push({
197
+ source: "vscode-copilot",
198
+ model: meta.modelId,
199
+ timestamp: new Date(meta.timestamp).toISOString(),
200
+ tokens: {
201
+ inputTokens: promptTokens,
202
+ outputTokens,
203
+ cachedInputTokens: 0,
204
+ reasoningOutputTokens: 0,
205
+ },
206
+ });
207
+ }
208
+ }
209
+ }
210
+ finally {
211
+ rl.close();
212
+ stream.destroy();
213
+ }
214
+ // Process deferred results (metadata appeared after the result line)
215
+ for (const { index, v } of deferredResults) {
216
+ if (processedSet.has(index))
217
+ continue;
218
+ const meta = requestMeta[index];
219
+ if (!meta) {
220
+ // Still no metadata — skip this result entirely
221
+ processedSet.add(index);
222
+ onSkip?.({ index, reason: "no request metadata found (deferred)" });
223
+ continue;
224
+ }
225
+ processedSet.add(index);
226
+ const metadata = v.metadata;
227
+ if (!metadata || typeof metadata !== "object") {
228
+ onSkip?.({ index, reason: "missing metadata object in result (deferred)" });
229
+ continue;
230
+ }
231
+ const promptTokens = toNonNegInt(metadata.promptTokens);
232
+ const outputTokens = toNonNegInt(metadata.outputTokens);
233
+ if (promptTokens === 0 && outputTokens === 0) {
234
+ const modelState = typeof metadata.modelState === "number" ? metadata.modelState : undefined;
235
+ onSkip?.({ index, reason: "zero tokens (deferred)", modelState });
236
+ continue;
237
+ }
238
+ deltas.push({
239
+ source: "vscode-copilot",
240
+ model: meta.modelId,
241
+ timestamp: new Date(meta.timestamp).toISOString(),
242
+ tokens: {
243
+ inputTokens: promptTokens,
244
+ outputTokens,
245
+ cachedInputTokens: 0,
246
+ reasoningOutputTokens: 0,
247
+ },
248
+ });
249
+ }
250
+ return {
251
+ deltas,
252
+ endOffset,
253
+ requestMeta,
254
+ processedRequestIndices: [...processedSet],
255
+ };
256
+ }
257
+ //# sourceMappingURL=vscode-copilot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vscode-copilot.js","sourceRoot":"","sources":["../../src/parsers/vscode-copilot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Privacy-safe project reference hashing.
3
+ *
4
+ * All project references are SHA-256 hashed before upload to ensure
5
+ * Pew never transmits plaintext project names, paths, or other
6
+ * identifying information. The hash is truncated to 16 hex chars
7
+ * (64 bits) — enough for uniqueness, short enough for display.
8
+ *
9
+ * This module is the single source of truth for project_ref hashing.
10
+ * Parsers should use it directly, and toQueueRecord() applies it as
11
+ * a defense-in-depth gateway before any data leaves the device.
12
+ */
13
+ /** Length of the hex prefix used for project_ref hashes */
14
+ export declare const PROJECT_REF_HASH_LENGTH = 16;
15
+ /**
16
+ * Hash a project reference string.
17
+ *
18
+ * Returns a 16-char hex prefix of SHA-256(input), or null if input is null/empty.
19
+ * Idempotent in practice: re-hashing a hash produces a different but equally
20
+ * opaque value. The defense-in-depth layer in toQueueRecord() relies on this.
21
+ */
22
+ export declare function hashProjectRef(raw: string | null): string | null;
23
+ //# sourceMappingURL=hash-project-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash-project-ref.d.ts","sourceRoot":"","sources":["../../src/utils/hash-project-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,2DAA2D;AAC3D,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAMhE"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Privacy-safe project reference hashing.
3
+ *
4
+ * All project references are SHA-256 hashed before upload to ensure
5
+ * Pew never transmits plaintext project names, paths, or other
6
+ * identifying information. The hash is truncated to 16 hex chars
7
+ * (64 bits) — enough for uniqueness, short enough for display.
8
+ *
9
+ * This module is the single source of truth for project_ref hashing.
10
+ * Parsers should use it directly, and toQueueRecord() applies it as
11
+ * a defense-in-depth gateway before any data leaves the device.
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ /** Length of the hex prefix used for project_ref hashes */
15
+ export const PROJECT_REF_HASH_LENGTH = 16;
16
+ /**
17
+ * Hash a project reference string.
18
+ *
19
+ * Returns a 16-char hex prefix of SHA-256(input), or null if input is null/empty.
20
+ * Idempotent in practice: re-hashing a hash produces a different but equally
21
+ * opaque value. The defense-in-depth layer in toQueueRecord() relies on this.
22
+ */
23
+ export function hashProjectRef(raw) {
24
+ if (!raw)
25
+ return null;
26
+ return createHash("sha256")
27
+ .update(raw)
28
+ .digest("hex")
29
+ .slice(0, PROJECT_REF_HASH_LENGTH);
30
+ }
31
+ //# sourceMappingURL=hash-project-ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash-project-ref.js","sourceRoot":"","sources":["../../src/utils/hash-project-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAkB;IAC/C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,CAAC;SACX,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACvC,CAAC"}
@@ -21,5 +21,7 @@ export declare function resolveDefaultPaths(home?: string): {
21
21
  openCodeDbPath: string;
22
22
  /** OpenClaw data: ~/.openclaw */
23
23
  openclawDir: string;
24
+ /** VSCode Copilot base dirs (stable + insiders, platform-aware) */
25
+ vscodeCopilotDirs: string[];
24
26
  };
25
27
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,SAAY;IAGhD,0CAA0C;;IAE1C,4CAA4C;;IAE5C,oDAAoD;;IAEpD,kCAAkC;;IAElC,sEAAsE;;IAEtE,iCAAiC;;IAEjC,wEAAwE;;IASxE,oEAAoE;;IAEpE,iCAAiC;;EAGpC"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAwCA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,SAAY;IAGhD,0CAA0C;;IAE1C,4CAA4C;;IAE5C,oDAAoD;;IAEpD,kCAAkC;;IAElC,sEAAsE;;IAEtE,iCAAiC;;IAEjC,wEAAwE;;IASxE,oEAAoE;;IAEpE,iCAAiC;;IAEjC,mEAAmE;;EAGtE"}
@@ -1,5 +1,38 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
+ /**
4
+ * Resolve the platform-specific VSCode Copilot base directories.
5
+ *
6
+ * Returns an array of base dirs for both stable and Insiders builds:
7
+ * macOS: ~/Library/Application Support/Code/User
8
+ * ~/Library/Application Support/Code - Insiders/User
9
+ * Linux: ~/.config/Code/User
10
+ * ~/.config/Code - Insiders/User
11
+ * Windows: %APPDATA%/Code/User
12
+ * %APPDATA%/Code - Insiders/User
13
+ */
14
+ function resolveVscodeCopilotDirs(home) {
15
+ const platform = process.platform;
16
+ if (platform === "darwin") {
17
+ const base = join(home, "Library", "Application Support");
18
+ return [
19
+ join(base, "Code", "User"),
20
+ join(base, "Code - Insiders", "User"),
21
+ ];
22
+ }
23
+ if (platform === "win32") {
24
+ const appdata = process.env.APPDATA || join(home, "AppData", "Roaming");
25
+ return [
26
+ join(appdata, "Code", "User"),
27
+ join(appdata, "Code - Insiders", "User"),
28
+ ];
29
+ }
30
+ // Linux and other Unix
31
+ return [
32
+ join(home, ".config", "Code", "User"),
33
+ join(home, ".config", "Code - Insiders", "User"),
34
+ ];
35
+ }
3
36
  /**
4
37
  * Resolve default paths for Pew state and AI tool data.
5
38
  * All paths can be overridden for testing.
@@ -25,6 +58,8 @@ export function resolveDefaultPaths(home = homedir()) {
25
58
  openCodeDbPath: join(home, ".local", "share", "opencode", "opencode.db"),
26
59
  /** OpenClaw data: ~/.openclaw */
27
60
  openclawDir: join(home, ".openclaw"),
61
+ /** VSCode Copilot base dirs (stable + insiders, platform-aware) */
62
+ vscodeCopilotDirs: resolveVscodeCopilotDirs(home),
28
63
  };
29
64
  }
30
65
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAI,GAAG,OAAO,EAAE;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjE,OAAO;QACL,0CAA0C;QAC1C,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC;QACtC,4CAA4C;QAC5C,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC;QAC3C,oDAAoD;QACpD,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC;QAC7D,kCAAkC;QAClC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAChC,sEAAsE;QACtE,gBAAgB,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAC7C,iCAAiC;QACjC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAChC,wEAAwE;QACxE,kBAAkB,EAAE,IAAI,CACtB,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,UAAU,EACV,SAAS,EACT,SAAS,CACV;QACD,oEAAoE;QACpE,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC;QACxE,iCAAiC;QACjC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;KACrC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;GAUG;AACH,SAAS,wBAAwB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;QAC1D,OAAO;YACL,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC;YAC1B,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC;SACtC,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxE,OAAO;YACL,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC;YAC7B,IAAI,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC;SACzC,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,CAAC;KACjD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAI,GAAG,OAAO,EAAE;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjE,OAAO;QACL,0CAA0C;QAC1C,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC;QACtC,4CAA4C;QAC5C,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC;QAC3C,oDAAoD;QACpD,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC;QAC7D,kCAAkC;QAClC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAChC,sEAAsE;QACtE,gBAAgB,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAC7C,iCAAiC;QACjC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAChC,wEAAwE;QACxE,kBAAkB,EAAE,IAAI,CACtB,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,UAAU,EACV,SAAS,EACT,SAAS,CACV;QACD,oEAAoE;QACpE,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC;QACxE,iCAAiC;QACjC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QACpC,mEAAmE;QACnE,iBAAiB,EAAE,wBAAwB,CAAC,IAAI,CAAC;KAClD,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocoo/pew",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "The contribution graph for AI-native developers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,6 +29,9 @@
29
29
  "codex",
30
30
  "gemini",
31
31
  "opencode",
32
+ "openclaw",
33
+ "copilot",
34
+ "vscode-copilot",
32
35
  "cli"
33
36
  ],
34
37
  "license": "MIT",