oc2token 0.1.24 → 0.1.26

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 (64) hide show
  1. package/README.md +23 -14
  2. package/dist/src/application.d.ts +15 -1
  3. package/dist/src/application.js +73 -7
  4. package/dist/src/application.js.map +1 -1
  5. package/dist/src/cache/schema.js +3 -3
  6. package/dist/src/cache/schema.js.map +1 -1
  7. package/dist/src/cli.js +33 -4
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/dashboard/render/ansi.d.ts +2 -0
  10. package/dist/src/dashboard/render/ansi.js +6 -0
  11. package/dist/src/dashboard/render/ansi.js.map +1 -1
  12. package/dist/src/dashboard/render/dashboard.js +38 -24
  13. package/dist/src/dashboard/render/dashboard.js.map +1 -1
  14. package/dist/src/dashboard/render/types.js +8 -4
  15. package/dist/src/dashboard/render/types.js.map +1 -1
  16. package/dist/src/dashboard/settings/index.d.ts +7 -7
  17. package/dist/src/dashboard/settings/index.js +25 -8
  18. package/dist/src/dashboard/settings/index.js.map +1 -1
  19. package/dist/src/deepseek/discovery.d.ts +21 -0
  20. package/dist/src/deepseek/discovery.js +83 -0
  21. package/dist/src/deepseek/discovery.js.map +1 -0
  22. package/dist/src/deepseek/doctor.d.ts +8 -0
  23. package/dist/src/deepseek/doctor.js +103 -0
  24. package/dist/src/deepseek/doctor.js.map +1 -0
  25. package/dist/src/deepseek/index.d.ts +4 -0
  26. package/dist/src/deepseek/index.js +4 -0
  27. package/dist/src/deepseek/index.js.map +1 -0
  28. package/dist/src/deepseek/scanner.d.ts +9 -0
  29. package/dist/src/deepseek/scanner.js +283 -0
  30. package/dist/src/deepseek/scanner.js.map +1 -0
  31. package/dist/src/deepseek/types.d.ts +38 -0
  32. package/dist/src/deepseek/types.js +3 -0
  33. package/dist/src/deepseek/types.js.map +1 -0
  34. package/dist/src/deepseek/zstd.d.ts +11 -0
  35. package/dist/src/deepseek/zstd.js +138 -0
  36. package/dist/src/deepseek/zstd.js.map +1 -0
  37. package/dist/src/domain/contracts.d.ts +2 -2
  38. package/dist/src/domain/contracts.js.map +1 -1
  39. package/dist/src/domain/records.d.ts +1 -1
  40. package/dist/src/domain/records.js +1 -1
  41. package/dist/src/domain/records.js.map +1 -1
  42. package/dist/src/opencode/doctor.d.ts +1 -1
  43. package/dist/src/opencode/doctor.js.map +1 -1
  44. package/dist/src/output/table.js +1 -1
  45. package/dist/src/output/table.js.map +1 -1
  46. package/dist/src/pi/discovery.d.ts +12 -0
  47. package/dist/src/pi/discovery.js +86 -0
  48. package/dist/src/pi/discovery.js.map +1 -0
  49. package/dist/src/pi/doctor.d.ts +8 -0
  50. package/dist/src/pi/doctor.js +55 -0
  51. package/dist/src/pi/doctor.js.map +1 -0
  52. package/dist/src/pi/index.d.ts +3 -0
  53. package/dist/src/pi/index.js +3 -0
  54. package/dist/src/pi/index.js.map +1 -0
  55. package/dist/src/pi/scanner.d.ts +9 -0
  56. package/dist/src/pi/scanner.js +255 -0
  57. package/dist/src/pi/scanner.js.map +1 -0
  58. package/dist/src/pi/types.d.ts +45 -0
  59. package/dist/src/pi/types.js +3 -0
  60. package/dist/src/pi/types.js.map +1 -0
  61. package/dist/src/usage/record-result.d.ts +19 -0
  62. package/dist/src/usage/record-result.js +91 -0
  63. package/dist/src/usage/record-result.js.map +1 -0
  64. package/package.json +7 -2
@@ -0,0 +1,255 @@
1
+ import { promises as nodeFs } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import { containsInstant, createUsageRecord, DomainError, cancellationError, isCancellationError, toCollectionError, } from "../domain/index.js";
4
+ import { UsageRecordReducer } from "../accounting/reducer.js";
5
+ import { buildRecordResult } from "../usage/record-result.js";
6
+ import { discoverPiSessionFiles } from "./discovery.js";
7
+ /** Guards against one giant session file exhausting memory. */
8
+ const MAX_SESSION_BYTES = 256 * 1024 * 1024;
9
+ function assertNotAborted(signal) {
10
+ if (signal?.aborted) {
11
+ const reason = signal.reason;
12
+ throw cancellationError(reason instanceof Error ? reason.message : undefined);
13
+ }
14
+ }
15
+ function safeNumber(value) {
16
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
17
+ }
18
+ function sanitizeRecordID(value, fallback) {
19
+ // eslint-disable-next-line no-control-regex
20
+ const cleaned = value.replace(/[\u0000-\u001f/]/g, "_").trim();
21
+ return cleaned.length > 0 ? cleaned : fallback;
22
+ }
23
+ function parseTimestamp(value) {
24
+ if (value instanceof Date) {
25
+ return Number.isFinite(value.getTime()) ? new Date(value.getTime()) : undefined;
26
+ }
27
+ if (typeof value === "number") {
28
+ if (!Number.isFinite(value))
29
+ return undefined;
30
+ // Pi stores nested message timestamps in milliseconds; accept whole
31
+ // seconds too so old exports do not land in 1970.
32
+ const milliseconds = Math.abs(value) < 100_000_000_000 ? value * 1_000 : value;
33
+ const date = new Date(milliseconds);
34
+ return Number.isFinite(date.getTime()) ? date : undefined;
35
+ }
36
+ if (typeof value === "string") {
37
+ const date = new Date(value);
38
+ return Number.isFinite(date.getTime()) ? date : undefined;
39
+ }
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Pi reports reasoning inside `output` (`usage.reasoning` is a subset), while
44
+ * this project's accounting sums output and reasoning as separate buckets.
45
+ * Subtract it so `recorded_total` never double-counts.
46
+ */
47
+ function tokensForUsage(usage) {
48
+ const reasoning = safeNumber(usage.reasoning);
49
+ const output = Math.max(0, safeNumber(usage.output) - reasoning);
50
+ return {
51
+ input: safeNumber(usage.input),
52
+ output,
53
+ reasoning,
54
+ cacheRead: safeNumber(usage.cacheRead),
55
+ cacheWrite: safeNumber(usage.cacheWrite),
56
+ };
57
+ }
58
+ function modelName(provider, model) {
59
+ const trimmedModel = model?.trim();
60
+ const trimmedProvider = provider?.trim();
61
+ if (trimmedModel === undefined || trimmedModel.length === 0)
62
+ return "unknown";
63
+ if (trimmedProvider === undefined || trimmedProvider.length === 0 || trimmedModel.startsWith(`${trimmedProvider}/`)) {
64
+ return trimmedModel;
65
+ }
66
+ return `${trimmedProvider}/${trimmedModel}`;
67
+ }
68
+ function inRequestedWindow(request, createdAt) {
69
+ return request.windows.some((window) => containsInstant(window, createdAt));
70
+ }
71
+ function addError(state, error, fallback, sessionID) {
72
+ state.fileHasError = true;
73
+ state.errors.push(toCollectionError(error, fallback, sessionID));
74
+ }
75
+ function addUsageRecord(state, request, sessionID, messageID, createdAt, model, usage, project) {
76
+ if (!inRequestedWindow(request, createdAt))
77
+ return;
78
+ const tokens = tokensForUsage(usage);
79
+ if (tokens.input === 0 &&
80
+ tokens.output === 0 &&
81
+ tokens.reasoning === 0 &&
82
+ tokens.cacheRead === 0 &&
83
+ tokens.cacheWrite === 0) {
84
+ return;
85
+ }
86
+ try {
87
+ state.records.push(createUsageRecord({
88
+ sessionID,
89
+ messageID: sanitizeRecordID(messageID, `${createdAt.getTime()}`),
90
+ createdAt,
91
+ model,
92
+ tokens,
93
+ observedAt: new Date(request.capturedAt.getTime()),
94
+ completeness: "final",
95
+ provider: "pi",
96
+ ...(project === undefined ? {} : { project }),
97
+ }));
98
+ }
99
+ catch (error) {
100
+ addError(state, error, "invalid-data", sessionID);
101
+ }
102
+ }
103
+ function usageOf(message) {
104
+ const usage = message?.usage;
105
+ return usage !== null && typeof usage === "object" ? usage : undefined;
106
+ }
107
+ /**
108
+ * Native Pi session scanner. Pi appends JSONL entries to
109
+ * `<agent-dir>/sessions/--<cwd>--/<timestamp>_<id>.jsonl`; assistant messages
110
+ * carry normalized usage and `usage` entries cover non-message model work
111
+ * (for example cache warming). Forked sessions repeat their parent's history,
112
+ * so a fork's pre-header entries are skipped to avoid double counting.
113
+ */
114
+ export async function collectPi(request, root) {
115
+ assertNotAborted(request.signal);
116
+ if (request.windows.length === 0) {
117
+ throw new DomainError("invalid-window", "Collection request must contain at least one usage window");
118
+ }
119
+ const files = discoverPiSessionFiles(root);
120
+ const errors = [];
121
+ const reducer = new UsageRecordReducer();
122
+ let sessionsScanned = 0;
123
+ let sessionsSkipped = 0;
124
+ for (const filePath of files) {
125
+ assertNotAborted(request.signal);
126
+ const fileFallback = sanitizeRecordID(basename(filePath, ".jsonl"), "pi-session");
127
+ const state = { errors: [], records: [], fileHasError: false };
128
+ let content;
129
+ try {
130
+ const stat = await nodeFs.stat(filePath);
131
+ if (stat.size > MAX_SESSION_BYTES) {
132
+ sessionsSkipped += 1;
133
+ errors.push(toCollectionError(new DomainError("invalid-data", `Pi session file exceeds ${MAX_SESSION_BYTES} bytes`, {
134
+ sessionID: fileFallback,
135
+ }), "invalid-data", fileFallback));
136
+ continue;
137
+ }
138
+ content = await nodeFs.readFile(filePath, "utf8");
139
+ }
140
+ catch (error) {
141
+ if (isCancellationError(error))
142
+ throw cancellationError();
143
+ sessionsSkipped += 1;
144
+ errors.push(toCollectionError(error, "transport", fileFallback));
145
+ continue;
146
+ }
147
+ let sessionID = fileFallback;
148
+ let project;
149
+ let forkCutoffMs;
150
+ let currentProvider;
151
+ let currentModel;
152
+ const lines = content.split("\n");
153
+ for (let index = 0; index < lines.length; index += 1) {
154
+ assertNotAborted(request.signal);
155
+ const line = lines[index].trim();
156
+ if (line.length === 0)
157
+ continue;
158
+ let parsed;
159
+ try {
160
+ parsed = JSON.parse(line);
161
+ }
162
+ catch (error) {
163
+ addError(state, error, "invalid-data", sessionID);
164
+ continue;
165
+ }
166
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
167
+ addError(state, new DomainError("invalid-data", "Pi session line is not an object", { sessionID }), "invalid-data", sessionID);
168
+ continue;
169
+ }
170
+ const entry = parsed;
171
+ if (entry.type === "session") {
172
+ const header = entry;
173
+ sessionID = sanitizeRecordID(typeof header.id === "string" && header.id.trim().length > 0 ? header.id : fileFallback, fileFallback);
174
+ if (typeof header.cwd === "string" && header.cwd.trim().length > 0) {
175
+ project = header.cwd.trim();
176
+ }
177
+ const headerTime = parseTimestamp(header.timestamp);
178
+ if (headerTime !== undefined && typeof header.parentSession === "string" && header.parentSession.length > 0) {
179
+ // /fork and /clone copy the parent's entries with their original
180
+ // timestamps. Anything before the new header is inherited, not new
181
+ // billable work in this session.
182
+ forkCutoffMs = headerTime.getTime();
183
+ }
184
+ continue;
185
+ }
186
+ if (entry.type === "model_change") {
187
+ if (typeof entry.provider === "string" && entry.provider.trim().length > 0) {
188
+ currentProvider = entry.provider.trim();
189
+ }
190
+ if (typeof entry.modelId === "string" && entry.modelId.trim().length > 0) {
191
+ currentModel = entry.modelId.trim();
192
+ }
193
+ continue;
194
+ }
195
+ const entryTime = parseTimestamp(entry.timestamp) ?? parseTimestamp(entry.message?.timestamp);
196
+ if (entryTime === undefined) {
197
+ // Model/thinking changes and system entries may omit timestamps; only
198
+ // usage-bearing rows need one.
199
+ if (entry.usage !== undefined || entry.message?.usage !== undefined) {
200
+ addError(state, new DomainError("invalid-data", "Usage entry has no valid timestamp", { sessionID }), "invalid-data", sessionID);
201
+ }
202
+ continue;
203
+ }
204
+ if (forkCutoffMs !== undefined && entryTime.getTime() < forkCutoffMs)
205
+ continue;
206
+ const message = entry.message;
207
+ if (entry.type === "message" && typeof message === "object" && message !== null) {
208
+ if (typeof message.provider === "string" && message.provider.trim().length > 0) {
209
+ currentProvider = message.provider.trim();
210
+ }
211
+ if (typeof message.model === "string" && message.model.trim().length > 0) {
212
+ currentModel = message.model.trim();
213
+ }
214
+ const usage = usageOf(message);
215
+ if (usage === undefined)
216
+ continue;
217
+ addUsageRecord(state, request, sessionID, entry.id ?? `message-${index}`, entryTime, modelName(message.provider ?? currentProvider, message.model ?? currentModel), usage, project);
218
+ continue;
219
+ }
220
+ if (entry.type === "usage") {
221
+ const usage = entry.usage;
222
+ if (usage === null || typeof usage !== "object")
223
+ continue;
224
+ addUsageRecord(state, request, sessionID, entry.id === undefined ? `usage-${index}` : `usage-${entry.id}`, entryTime, modelName(entry.provider ?? currentProvider, entry.model ?? currentModel), usage, project);
225
+ continue;
226
+ }
227
+ if ((entry.type === "compaction" || entry.type === "branch_summary") && entry.usage !== undefined) {
228
+ const usage = entry.usage;
229
+ if (usage === null || typeof usage !== "object")
230
+ continue;
231
+ addUsageRecord(state, request, sessionID, entry.id === undefined ? `${entry.type}-${index}` : `${entry.type}-${entry.id}`, entryTime, modelName(currentProvider, currentModel), usage, project);
232
+ }
233
+ }
234
+ for (const record of state.records)
235
+ reducer.upsert(record);
236
+ errors.push(...state.errors);
237
+ if (state.fileHasError)
238
+ sessionsSkipped += 1;
239
+ else
240
+ sessionsScanned += 1;
241
+ }
242
+ assertNotAborted(request.signal);
243
+ return buildRecordResult({
244
+ capturedAt: request.capturedAt,
245
+ windows: request.windows,
246
+ source: "pi",
247
+ records: reducer.records(),
248
+ sessionsDiscovered: files.length,
249
+ sessionsScanned,
250
+ sessionsSkipped,
251
+ pagesRead: files.length,
252
+ errors,
253
+ });
254
+ }
255
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/pi/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /** Internal Pi session JSONL types. Not part of public domain contracts. */
2
+ export interface PiUsage {
3
+ readonly input?: number;
4
+ readonly output?: number;
5
+ readonly cacheRead?: number;
6
+ readonly cacheWrite?: number;
7
+ readonly cacheWrite1h?: number;
8
+ readonly reasoning?: number;
9
+ readonly totalTokens?: number;
10
+ readonly cost?: {
11
+ readonly input?: number;
12
+ readonly output?: number;
13
+ readonly cacheRead?: number;
14
+ readonly cacheWrite?: number;
15
+ readonly total?: number;
16
+ };
17
+ }
18
+ export interface PiMessage {
19
+ readonly role?: string;
20
+ readonly provider?: string;
21
+ readonly model?: string;
22
+ readonly usage?: PiUsage | null;
23
+ readonly timestamp?: number;
24
+ readonly stopReason?: string;
25
+ }
26
+ export interface PiSessionHeader {
27
+ readonly type: "session";
28
+ readonly version?: number;
29
+ readonly id?: string;
30
+ readonly timestamp?: string | number;
31
+ readonly cwd?: string;
32
+ readonly parentSession?: string;
33
+ }
34
+ export interface PiEntry {
35
+ readonly type?: string;
36
+ readonly id?: string;
37
+ readonly timestamp?: string | number;
38
+ readonly kind?: string;
39
+ readonly provider?: string;
40
+ readonly modelId?: string;
41
+ readonly model?: string;
42
+ readonly cwd?: string;
43
+ readonly usage?: PiUsage | null;
44
+ readonly message?: PiMessage;
45
+ }
@@ -0,0 +1,3 @@
1
+ /** Internal Pi session JSONL types. Not part of public domain contracts. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/pi/types.ts"],"names":[],"mappings":"AAAA,4EAA4E"}
@@ -0,0 +1,19 @@
1
+ import type { CollectionError, CollectionResult, CollectionSource, UsageRecord, UsageWindow } from "../domain/index.js";
2
+ export interface RecordResultInput {
3
+ readonly capturedAt: Date;
4
+ readonly windows: ReadonlyArray<UsageWindow>;
5
+ readonly source: CollectionSource;
6
+ readonly records: ReadonlyArray<UsageRecord>;
7
+ readonly sessionsDiscovered: number;
8
+ readonly sessionsScanned: number;
9
+ readonly sessionsSkipped: number;
10
+ readonly pagesRead: number;
11
+ readonly provisionalMessages?: number;
12
+ readonly errors: ReadonlyArray<CollectionError>;
13
+ }
14
+ /**
15
+ * Shared finalization for local-file scanners. Derives per-window totals and
16
+ * provider/model/project breakdowns from the normalized records so every
17
+ * file-backed provider reports the same shape as the Codex scanner.
18
+ */
19
+ export declare function buildRecordResult(input: RecordResultInput): CollectionResult;
@@ -0,0 +1,91 @@
1
+ import { containsInstant, sumUsageRecords } from "../domain/index.js";
2
+ function sortedErrors(errors) {
3
+ return [...errors].sort((left, right) => (String(left.sessionID ?? "") + "\0" + left.code + "\0" + left.message).localeCompare(String(right.sessionID ?? "") + "\0" + right.code + "\0" + right.message));
4
+ }
5
+ function groupBreakdowns(records, window, select, withProvider = false) {
6
+ const groups = new Map();
7
+ for (const record of records) {
8
+ const name = select(record);
9
+ if (name === undefined || name.length === 0)
10
+ continue;
11
+ const bucket = groups.get(name);
12
+ if (bucket === undefined)
13
+ groups.set(name, [record]);
14
+ else
15
+ bucket.push(record);
16
+ }
17
+ const breakdowns = [];
18
+ for (const [name, group] of groups.entries()) {
19
+ const totals = sumUsageRecords(group, window);
20
+ breakdowns.push(withProvider ? { name, provider: name, totals } : { name, totals });
21
+ }
22
+ return breakdowns.sort((left, right) => right.totals.recorded_total - left.totals.recorded_total || left.name.localeCompare(right.name));
23
+ }
24
+ /**
25
+ * Shared finalization for local-file scanners. Derives per-window totals and
26
+ * provider/model/project breakdowns from the normalized records so every
27
+ * file-backed provider reports the same shape as the Codex scanner.
28
+ */
29
+ export function buildRecordResult(input) {
30
+ const errors = sortedErrors(input.errors);
31
+ const coverage = {
32
+ complete: errors.length === 0 && input.sessionsSkipped === 0,
33
+ sessionsDiscovered: input.sessionsDiscovered,
34
+ sessionsScanned: input.sessionsScanned,
35
+ sessionsSkipped: input.sessionsSkipped,
36
+ pagesRead: input.pagesRead,
37
+ jobsRetried: 0,
38
+ provisionalMessages: input.provisionalMessages ?? 0,
39
+ errors,
40
+ };
41
+ const totalsByWindow = Object.fromEntries(input.windows.map((window) => [window.kind, sumUsageRecords(input.records, window)]));
42
+ const providersByWindow = {};
43
+ const modelsByWindow = {};
44
+ const projectsByWindow = {};
45
+ for (const window of input.windows) {
46
+ const inWindow = input.records.filter((record) => containsInstant(window, record.createdAt));
47
+ if (inWindow.length === 0)
48
+ continue;
49
+ const providers = groupBreakdowns(inWindow, window, (record) => record.provider, true);
50
+ if (providers.length > 0)
51
+ providersByWindow[window.kind] = providers;
52
+ const models = groupBreakdowns(inWindow, window, (record) => record.model);
53
+ if (models.length > 0)
54
+ modelsByWindow[window.kind] = models;
55
+ const projects = groupBreakdowns(inWindow, window, (record) => record.project);
56
+ if (projects.length > 0)
57
+ projectsByWindow[window.kind] = projects;
58
+ }
59
+ const pickGlobal = (byWindow) => {
60
+ const preferred = byWindow.week ?? byWindow.day ?? byWindow.hour;
61
+ if (preferred !== undefined)
62
+ return preferred;
63
+ const all = Object.values(byWindow).flat();
64
+ return all.length > 0 ? all : undefined;
65
+ };
66
+ const providers = pickGlobal(providersByWindow);
67
+ const models = pickGlobal(modelsByWindow);
68
+ const projects = pickGlobal(projectsByWindow);
69
+ const providersByWindowTyped = providersByWindow;
70
+ const modelsByWindowTyped = modelsByWindow;
71
+ const projectsByWindowTyped = projectsByWindow;
72
+ return {
73
+ capturedAt: new Date(input.capturedAt.getTime()),
74
+ windows: input.windows.map((window) => ({
75
+ ...window,
76
+ from: new Date(window.from.getTime()),
77
+ to: new Date(window.to.getTime()),
78
+ })),
79
+ source: input.source,
80
+ records: input.records,
81
+ totalsByWindow,
82
+ ...(providers === undefined ? {} : { providers }),
83
+ ...(models === undefined ? {} : { models }),
84
+ ...(projects === undefined ? {} : { projects }),
85
+ ...(Object.keys(providersByWindow).length === 0 ? {} : { providersByWindow: providersByWindowTyped }),
86
+ ...(Object.keys(modelsByWindow).length === 0 ? {} : { modelsByWindow: modelsByWindowTyped }),
87
+ ...(Object.keys(projectsByWindow).length === 0 ? {} : { projectsByWindow: projectsByWindowTyped }),
88
+ coverage,
89
+ };
90
+ }
91
+ //# sourceMappingURL=record-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-result.js","sourceRoot":"","sources":["../../../src/usage/record-result.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "oc2token",
3
- "version": "0.1.24",
4
- "description": "A macOS-first OpenCode 2 token usage dashboard CLI",
3
+ "version": "0.1.26",
4
+ "description": "A macOS-first token usage dashboard CLI for OpenCode 2, Codex, Antigravity, Pi, and DeepSeek Harness",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "oc2token": "dist/src/cli.js"
@@ -30,6 +30,11 @@
30
30
  },
31
31
  "keywords": [
32
32
  "opencode",
33
+ "codex",
34
+ "antigravity",
35
+ "pi-harness",
36
+ "deepseek-harness",
37
+ "dsh",
33
38
  "tokens",
34
39
  "terminal",
35
40
  "tui"