unfairly 0.8.3 → 0.8.4
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/CHANGELOG.md +4 -0
- package/LICENSE +15 -0
- package/dist/auth/browser-flow.d.ts +0 -1
- package/dist/auth/browser-flow.js +5 -81
- package/dist/cmd/connect.d.ts +0 -1
- package/dist/cmd/connect.js +1 -164
- package/dist/cmd/init.d.ts +0 -1
- package/dist/cmd/init.js +2 -138
- package/dist/cmd/invite.d.ts +0 -1
- package/dist/cmd/invite.js +4 -73
- package/dist/cmd/join.d.ts +0 -1
- package/dist/cmd/join.js +1 -91
- package/dist/cmd/login.d.ts +0 -1
- package/dist/cmd/login.js +3 -41
- package/dist/cmd/mcp.d.ts +0 -1
- package/dist/cmd/mcp.js +2 -86
- package/dist/cmd/pace.d.ts +2 -2
- package/dist/cmd/pace.js +4 -426
- package/dist/cmd/parse-share-input.d.ts +0 -1
- package/dist/cmd/parse-share-input.js +1 -56
- package/dist/cmd/pull.d.ts +0 -1
- package/dist/cmd/pull.js +7 -143
- package/dist/cmd/push.d.ts +0 -1
- package/dist/cmd/push.js +1 -85
- package/dist/cmd/resolve.d.ts +0 -1
- package/dist/cmd/resolve.js +1 -35
- package/dist/cmd/setup.d.ts +0 -1
- package/dist/cmd/setup.js +2 -345
- package/dist/cmd/status-card.d.ts +0 -1
- package/dist/cmd/status-card.js +2 -156
- package/dist/cmd/status.d.ts +0 -1
- package/dist/cmd/status.js +3 -29
- package/dist/cmd/watch.d.ts +0 -1
- package/dist/cmd/watch.js +1 -26
- package/dist/hosts/claude-code.d.ts +0 -1
- package/dist/hosts/claude-code.js +3 -180
- package/dist/hosts/claude-desktop.d.ts +0 -1
- package/dist/hosts/claude-desktop.js +3 -222
- package/dist/hosts/codex.d.ts +0 -1
- package/dist/hosts/codex.js +20 -234
- package/dist/hosts/shell-env.d.ts +0 -1
- package/dist/hosts/shell-env.js +9 -81
- package/dist/index.d.ts +0 -1
- package/dist/index.js +14 -206
- package/dist/lib/client.d.ts +0 -1
- package/dist/lib/client.js +1 -58
- package/dist/lib/events/emit.d.ts +0 -1
- package/dist/lib/events/emit.js +1 -28
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +1 -11
- package/dist/lib/transport.d.ts +0 -1
- package/dist/lib/transport.js +1 -85
- package/dist/lib/types/index.d.ts +0 -1
- package/dist/lib/types/index.js +1 -50
- package/dist/lib/vault/checkpoint.d.ts +0 -1
- package/dist/lib/vault/checkpoint.js +1 -18
- package/dist/lib/vault/read.d.ts +0 -1
- package/dist/lib/vault/read.js +1 -9
- package/dist/lib/vault/search.d.ts +0 -1
- package/dist/lib/vault/search.js +1 -10
- package/dist/pace/device.d.ts +0 -1
- package/dist/pace/device.js +2 -149
- package/dist/pace/enroll.d.ts +0 -1
- package/dist/pace/enroll.js +2 -138
- package/dist/pace/identity.d.ts +0 -1
- package/dist/pace/identity.js +1 -17
- package/dist/pace/install.d.ts +0 -1
- package/dist/pace/install.js +4 -127
- package/dist/pace/local-evidence.d.ts +0 -1
- package/dist/pace/local-evidence.js +2 -228
- package/dist/pace/local-sessions.d.ts +0 -1
- package/dist/pace/local-sessions.js +1 -254
- package/dist/pace/managed-config.d.ts +0 -1
- package/dist/pace/managed-config.js +8 -102
- package/dist/pace/normalize.d.ts +0 -1
- package/dist/pace/normalize.js +1 -293
- package/dist/pace/repository.d.ts +0 -1
- package/dist/pace/repository.js +2 -120
- package/dist/pace/schema.d.ts +0 -1
- package/dist/pace/schema.js +1 -134
- package/dist/pace/session-summary.d.ts +0 -1
- package/dist/pace/session-summary.js +2 -140
- package/dist/pace/spool.d.ts +0 -1
- package/dist/pace/spool.js +8 -87
- package/dist/pace-runtime.d.ts +0 -1
- package/dist/pace-runtime.js +2 -67
- package/dist/sync/api.d.ts +0 -1
- package/dist/sync/api.js +1 -55
- package/dist/sync/autoloader.d.ts +0 -1
- package/dist/sync/autoloader.js +5 -127
- package/dist/sync/conflict.d.ts +0 -1
- package/dist/sync/conflict.js +5 -15
- package/dist/sync/credentials.d.ts +0 -1
- package/dist/sync/credentials.js +1 -51
- package/dist/sync/files.d.ts +0 -1
- package/dist/sync/files.js +1 -71
- package/dist/sync/manifest.d.ts +0 -1
- package/dist/sync/manifest.js +1 -37
- package/dist/sync/repo-root.d.ts +0 -1
- package/dist/sync/repo-root.js +1 -24
- package/dist/sync/stitch-claude-md.d.ts +0 -1
- package/dist/sync/stitch-claude-md.js +8 -48
- package/dist/ui/colors.d.ts +0 -1
- package/dist/ui/colors.js +1 -28
- package/dist/ui/screens.d.ts +0 -1
- package/dist/ui/screens.js +5 -135
- package/package.json +5 -12
- package/plugin/.cursor-plugin/plugin.json +0 -2
- package/plugin/.mcp.json +1 -1
- package/plugin/LICENSE +15 -0
- package/plugin/gemini/gemini-extension.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/plugin.json +0 -2
- package/plugin/runtime/unfairly-intelligence.mjs +14 -5512
- package/dist/auth/browser-flow.d.ts.map +0 -1
- package/dist/auth/browser-flow.js.map +0 -1
- package/dist/cmd/connect.d.ts.map +0 -1
- package/dist/cmd/connect.js.map +0 -1
- package/dist/cmd/init.d.ts.map +0 -1
- package/dist/cmd/init.js.map +0 -1
- package/dist/cmd/invite.d.ts.map +0 -1
- package/dist/cmd/invite.js.map +0 -1
- package/dist/cmd/join.d.ts.map +0 -1
- package/dist/cmd/join.js.map +0 -1
- package/dist/cmd/login.d.ts.map +0 -1
- package/dist/cmd/login.js.map +0 -1
- package/dist/cmd/mcp.d.ts.map +0 -1
- package/dist/cmd/mcp.js.map +0 -1
- package/dist/cmd/pace.d.ts.map +0 -1
- package/dist/cmd/pace.js.map +0 -1
- package/dist/cmd/parse-share-input.d.ts.map +0 -1
- package/dist/cmd/parse-share-input.js.map +0 -1
- package/dist/cmd/pull.d.ts.map +0 -1
- package/dist/cmd/pull.js.map +0 -1
- package/dist/cmd/push.d.ts.map +0 -1
- package/dist/cmd/push.js.map +0 -1
- package/dist/cmd/resolve.d.ts.map +0 -1
- package/dist/cmd/resolve.js.map +0 -1
- package/dist/cmd/setup.d.ts.map +0 -1
- package/dist/cmd/setup.js.map +0 -1
- package/dist/cmd/status-card.d.ts.map +0 -1
- package/dist/cmd/status-card.js.map +0 -1
- package/dist/cmd/status.d.ts.map +0 -1
- package/dist/cmd/status.js.map +0 -1
- package/dist/cmd/watch.d.ts.map +0 -1
- package/dist/cmd/watch.js.map +0 -1
- package/dist/hosts/claude-code.d.ts.map +0 -1
- package/dist/hosts/claude-code.js.map +0 -1
- package/dist/hosts/claude-desktop.d.ts.map +0 -1
- package/dist/hosts/claude-desktop.js.map +0 -1
- package/dist/hosts/codex.d.ts.map +0 -1
- package/dist/hosts/codex.js.map +0 -1
- package/dist/hosts/shell-env.d.ts.map +0 -1
- package/dist/hosts/shell-env.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/client.d.ts.map +0 -1
- package/dist/lib/client.js.map +0 -1
- package/dist/lib/events/emit.d.ts.map +0 -1
- package/dist/lib/events/emit.js.map +0 -1
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/transport.d.ts.map +0 -1
- package/dist/lib/transport.js.map +0 -1
- package/dist/lib/types/index.d.ts.map +0 -1
- package/dist/lib/types/index.js.map +0 -1
- package/dist/lib/vault/checkpoint.d.ts.map +0 -1
- package/dist/lib/vault/checkpoint.js.map +0 -1
- package/dist/lib/vault/read.d.ts.map +0 -1
- package/dist/lib/vault/read.js.map +0 -1
- package/dist/lib/vault/search.d.ts.map +0 -1
- package/dist/lib/vault/search.js.map +0 -1
- package/dist/pace/device.d.ts.map +0 -1
- package/dist/pace/device.js.map +0 -1
- package/dist/pace/enroll.d.ts.map +0 -1
- package/dist/pace/enroll.js.map +0 -1
- package/dist/pace/identity.d.ts.map +0 -1
- package/dist/pace/identity.js.map +0 -1
- package/dist/pace/install.d.ts.map +0 -1
- package/dist/pace/install.js.map +0 -1
- package/dist/pace/local-evidence.d.ts.map +0 -1
- package/dist/pace/local-evidence.js.map +0 -1
- package/dist/pace/local-sessions.d.ts.map +0 -1
- package/dist/pace/local-sessions.js.map +0 -1
- package/dist/pace/managed-config.d.ts.map +0 -1
- package/dist/pace/managed-config.js.map +0 -1
- package/dist/pace/normalize.d.ts.map +0 -1
- package/dist/pace/normalize.js.map +0 -1
- package/dist/pace/repository.d.ts.map +0 -1
- package/dist/pace/repository.js.map +0 -1
- package/dist/pace/schema.d.ts.map +0 -1
- package/dist/pace/schema.js.map +0 -1
- package/dist/pace/session-summary.d.ts.map +0 -1
- package/dist/pace/session-summary.js.map +0 -1
- package/dist/pace/spool.d.ts.map +0 -1
- package/dist/pace/spool.js.map +0 -1
- package/dist/pace-runtime.d.ts.map +0 -1
- package/dist/pace-runtime.js.map +0 -1
- package/dist/sync/api.d.ts.map +0 -1
- package/dist/sync/api.js.map +0 -1
- package/dist/sync/autoloader.d.ts.map +0 -1
- package/dist/sync/autoloader.js.map +0 -1
- package/dist/sync/conflict.d.ts.map +0 -1
- package/dist/sync/conflict.js.map +0 -1
- package/dist/sync/credentials.d.ts.map +0 -1
- package/dist/sync/credentials.js.map +0 -1
- package/dist/sync/files.d.ts.map +0 -1
- package/dist/sync/files.js.map +0 -1
- package/dist/sync/manifest.d.ts.map +0 -1
- package/dist/sync/manifest.js.map +0 -1
- package/dist/sync/repo-root.d.ts.map +0 -1
- package/dist/sync/repo-root.js.map +0 -1
- package/dist/sync/stitch-claude-md.d.ts.map +0 -1
- package/dist/sync/stitch-claude-md.js.map +0 -1
- package/dist/ui/colors.d.ts.map +0 -1
- package/dist/ui/colors.js.map +0 -1
- package/dist/ui/screens.d.ts.map +0 -1
- package/dist/ui/screens.js.map +0 -1
|
@@ -1,254 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createReadStream } from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import readline from "node:readline";
|
|
6
|
-
const RUN_SKILL_TOOL = /^mcp__.+__(run_skill|get_playbook)$/;
|
|
7
|
-
const emptyTokens = () => ({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
|
|
8
|
-
function topKey(counts) {
|
|
9
|
-
let best = null;
|
|
10
|
-
for (const [key, value] of Object.entries(counts))
|
|
11
|
-
if (best === null || value > counts[best])
|
|
12
|
-
best = key;
|
|
13
|
-
return best;
|
|
14
|
-
}
|
|
15
|
-
async function* jsonLines(file) {
|
|
16
|
-
const lines = readline.createInterface({ input: createReadStream(file, { encoding: "utf8" }), crlfDelay: Infinity });
|
|
17
|
-
for await (const line of lines) {
|
|
18
|
-
if (!line)
|
|
19
|
-
continue;
|
|
20
|
-
try {
|
|
21
|
-
const parsed = JSON.parse(line);
|
|
22
|
-
if (parsed && typeof parsed === "object")
|
|
23
|
-
yield parsed;
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
// A partially written trailing line is normal for a live session.
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
const DENIAL = /doesn't want to proceed|user denied|permission denied|was rejected|not allowed/i;
|
|
31
|
-
function asRecord(value) {
|
|
32
|
-
return value && typeof value === "object" ? value : {};
|
|
33
|
-
}
|
|
34
|
-
function num(value) {
|
|
35
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
36
|
-
}
|
|
37
|
-
export async function readClaudeCodeSession(file) {
|
|
38
|
-
const models = {};
|
|
39
|
-
const branches = {};
|
|
40
|
-
const skills = new Set();
|
|
41
|
-
const tokens = emptyTokens();
|
|
42
|
-
const seenMessages = new Set();
|
|
43
|
-
let startedAt = null;
|
|
44
|
-
let endedAt = null;
|
|
45
|
-
let cwd = null;
|
|
46
|
-
let sessionId = path.basename(file, ".jsonl");
|
|
47
|
-
let userTurns = 0;
|
|
48
|
-
let toolCalls = 0;
|
|
49
|
-
let toolErrors = 0;
|
|
50
|
-
let approvalDenials = 0;
|
|
51
|
-
const delegated = file.includes(`${path.sep}subagents${path.sep}`);
|
|
52
|
-
for await (const line of jsonLines(file)) {
|
|
53
|
-
const ts = typeof line.timestamp === "string" ? line.timestamp : null;
|
|
54
|
-
if (ts) {
|
|
55
|
-
startedAt ??= ts;
|
|
56
|
-
endedAt = ts;
|
|
57
|
-
}
|
|
58
|
-
// Subagent transcripts repeat their parent's sessionId; keep the file's own id so the two never collide.
|
|
59
|
-
if (typeof line.sessionId === "string" && !delegated)
|
|
60
|
-
sessionId = line.sessionId;
|
|
61
|
-
if (typeof line.cwd === "string")
|
|
62
|
-
cwd ??= line.cwd;
|
|
63
|
-
if (typeof line.gitBranch === "string" && line.gitBranch && line.gitBranch !== "HEAD")
|
|
64
|
-
branches[line.gitBranch] = (branches[line.gitBranch] ?? 0) + 1;
|
|
65
|
-
const message = asRecord(line.message);
|
|
66
|
-
if (line.type === "user") {
|
|
67
|
-
const content = message.content;
|
|
68
|
-
if (typeof content === "string")
|
|
69
|
-
userTurns += 1;
|
|
70
|
-
else if (Array.isArray(content)) {
|
|
71
|
-
for (const block of content.map(asRecord)) {
|
|
72
|
-
if (block.type === "text")
|
|
73
|
-
userTurns += 1;
|
|
74
|
-
if (block.type === "tool_result" && block.is_error === true) {
|
|
75
|
-
toolErrors += 1;
|
|
76
|
-
// Classified in memory and immediately discarded; only the count survives.
|
|
77
|
-
if (DENIAL.test(JSON.stringify(block.content ?? "").slice(0, 400)))
|
|
78
|
-
approvalDenials += 1;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (line.type === "assistant") {
|
|
84
|
-
const model = typeof message.model === "string" ? message.model : null;
|
|
85
|
-
if (!model || model === "<synthetic>")
|
|
86
|
-
continue;
|
|
87
|
-
for (const block of Array.isArray(message.content) ? message.content.map(asRecord) : []) {
|
|
88
|
-
if (block.type !== "tool_use")
|
|
89
|
-
continue;
|
|
90
|
-
toolCalls += 1;
|
|
91
|
-
const input = asRecord(block.input);
|
|
92
|
-
const name = typeof block.name === "string" ? block.name : "";
|
|
93
|
-
const skill = name === "Skill" ? input.skill : RUN_SKILL_TOOL.test(name) ? input.name ?? input.skill ?? input.slug : undefined;
|
|
94
|
-
if (typeof skill === "string" && skill.trim())
|
|
95
|
-
skills.add(skill.trim().toLowerCase().slice(0, 120));
|
|
96
|
-
}
|
|
97
|
-
// Claude Code writes one line per content block and repeats the message's
|
|
98
|
-
// usage on each; count each API message once.
|
|
99
|
-
const messageId = typeof message.id === "string" ? message.id : null;
|
|
100
|
-
if (messageId && seenMessages.has(messageId))
|
|
101
|
-
continue;
|
|
102
|
-
if (messageId)
|
|
103
|
-
seenMessages.add(messageId);
|
|
104
|
-
models[model] = (models[model] ?? 0) + 1;
|
|
105
|
-
const usage = asRecord(message.usage);
|
|
106
|
-
tokens.input += num(usage.input_tokens);
|
|
107
|
-
tokens.output += num(usage.output_tokens);
|
|
108
|
-
tokens.cacheRead += num(usage.cache_read_input_tokens);
|
|
109
|
-
tokens.cacheWrite += num(usage.cache_creation_input_tokens);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (!startedAt || !endedAt || !Object.keys(models).length)
|
|
113
|
-
return null;
|
|
114
|
-
return {
|
|
115
|
-
sessionId,
|
|
116
|
-
client: "claude_code",
|
|
117
|
-
delegated,
|
|
118
|
-
launchedBy: null,
|
|
119
|
-
startedAt,
|
|
120
|
-
endedAt,
|
|
121
|
-
models,
|
|
122
|
-
primaryModel: topKey(models),
|
|
123
|
-
tokens,
|
|
124
|
-
userTurns,
|
|
125
|
-
toolCalls,
|
|
126
|
-
toolErrors,
|
|
127
|
-
approvalDenials,
|
|
128
|
-
cwd,
|
|
129
|
-
branch: topKey(branches),
|
|
130
|
-
skills: [...skills],
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
export async function readCodexSession(file) {
|
|
134
|
-
const models = {};
|
|
135
|
-
let tokens = emptyTokens();
|
|
136
|
-
let startedAt = null;
|
|
137
|
-
let endedAt = null;
|
|
138
|
-
let cwd = null;
|
|
139
|
-
let branch = null;
|
|
140
|
-
let sessionId = path.basename(file, ".jsonl");
|
|
141
|
-
let delegated = false;
|
|
142
|
-
let launchedBy = null;
|
|
143
|
-
let userTurns = 0;
|
|
144
|
-
let toolCalls = 0;
|
|
145
|
-
let toolErrors = 0;
|
|
146
|
-
const skills = new Set();
|
|
147
|
-
for await (const line of jsonLines(file)) {
|
|
148
|
-
const ts = typeof line.timestamp === "string" ? line.timestamp : null;
|
|
149
|
-
if (ts) {
|
|
150
|
-
startedAt ??= ts;
|
|
151
|
-
endedAt = ts;
|
|
152
|
-
}
|
|
153
|
-
const payload = asRecord(line.payload);
|
|
154
|
-
if (line.type === "response_item" && payload.type === "function_call" && typeof payload.name === "string" && RUN_SKILL_TOOL.test(payload.name)) {
|
|
155
|
-
try {
|
|
156
|
-
const args = asRecord(JSON.parse(String(payload.arguments ?? "{}")));
|
|
157
|
-
const skill = args.name ?? args.skill ?? args.slug;
|
|
158
|
-
if (typeof skill === "string" && skill.trim())
|
|
159
|
-
skills.add(skill.trim().toLowerCase().slice(0, 120));
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
// Arguments are discarded; only a recognizable skill name is kept.
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (line.type === "session_meta") {
|
|
166
|
-
if (typeof payload.id === "string")
|
|
167
|
-
sessionId = payload.id;
|
|
168
|
-
if (typeof payload.cwd === "string")
|
|
169
|
-
cwd = payload.cwd;
|
|
170
|
-
const git = asRecord(payload.git);
|
|
171
|
-
if (typeof git.branch === "string" && git.branch && git.branch !== "HEAD")
|
|
172
|
-
branch = git.branch;
|
|
173
|
-
if (payload.originator === "Claude Code")
|
|
174
|
-
launchedBy = "claude_code";
|
|
175
|
-
if (payload.source && typeof payload.source === "object")
|
|
176
|
-
delegated = true;
|
|
177
|
-
}
|
|
178
|
-
if (line.type === "turn_context" && typeof payload.model === "string")
|
|
179
|
-
models[payload.model] = (models[payload.model] ?? 0) + 1;
|
|
180
|
-
if (line.type === "event_msg" && payload.type === "user_message")
|
|
181
|
-
userTurns += 1;
|
|
182
|
-
if (line.type === "event_msg" && payload.type === "token_count") {
|
|
183
|
-
// Codex reports a cumulative total; the last one wins. Input includes the cached share.
|
|
184
|
-
const total = asRecord(asRecord(payload.info).total_token_usage);
|
|
185
|
-
if (Object.keys(total).length) {
|
|
186
|
-
const cached = num(total.cached_input_tokens);
|
|
187
|
-
tokens = { input: Math.max(0, num(total.input_tokens) - cached), output: num(total.output_tokens), cacheRead: cached, cacheWrite: num(total.cache_write_input_tokens) };
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (line.type === "response_item" && (payload.type === "function_call" || payload.type === "custom_tool_call"))
|
|
191
|
-
toolCalls += 1;
|
|
192
|
-
if (line.type === "event_msg" && payload.type === "exec_command_end" && num(payload.exit_code) !== 0)
|
|
193
|
-
toolErrors += 1;
|
|
194
|
-
}
|
|
195
|
-
if (!startedAt || !endedAt || !Object.keys(models).length)
|
|
196
|
-
return null;
|
|
197
|
-
return {
|
|
198
|
-
sessionId,
|
|
199
|
-
client: "codex",
|
|
200
|
-
delegated: delegated || launchedBy !== null,
|
|
201
|
-
launchedBy,
|
|
202
|
-
startedAt,
|
|
203
|
-
endedAt,
|
|
204
|
-
models,
|
|
205
|
-
primaryModel: topKey(models),
|
|
206
|
-
tokens,
|
|
207
|
-
userTurns,
|
|
208
|
-
toolCalls,
|
|
209
|
-
toolErrors,
|
|
210
|
-
approvalDenials: 0,
|
|
211
|
-
cwd,
|
|
212
|
-
branch,
|
|
213
|
-
skills: [...skills],
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
async function listJsonl(root, maxDepth, since) {
|
|
217
|
-
const found = [];
|
|
218
|
-
const walk = async (dir, depth) => {
|
|
219
|
-
let entries;
|
|
220
|
-
try {
|
|
221
|
-
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
for (const entry of entries) {
|
|
227
|
-
const full = path.join(dir, entry.name);
|
|
228
|
-
if (entry.isDirectory() && depth < maxDepth)
|
|
229
|
-
await walk(full, depth + 1);
|
|
230
|
-
else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
231
|
-
const stat = await fs.stat(full).catch(() => null);
|
|
232
|
-
if (stat && stat.mtimeMs >= since)
|
|
233
|
-
found.push(full);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
await walk(root, 0);
|
|
238
|
-
return found;
|
|
239
|
-
}
|
|
240
|
-
/** Sessions whose transcript changed at or after `since` (epoch ms). */
|
|
241
|
-
export async function collectLocalSessions(options) {
|
|
242
|
-
const home = options.home ?? os.homedir();
|
|
243
|
-
const since = options.since;
|
|
244
|
-
const [claudeFiles, codexFiles] = await Promise.all([
|
|
245
|
-
listJsonl(path.join(home, ".claude", "projects"), 4, since),
|
|
246
|
-
listJsonl(path.join(home, ".codex", "sessions"), 4, since),
|
|
247
|
-
]);
|
|
248
|
-
const results = await Promise.all([
|
|
249
|
-
...claudeFiles.map((file) => readClaudeCodeSession(file).catch(() => null)),
|
|
250
|
-
...codexFiles.map((file) => readCodexSession(file).catch(() => null)),
|
|
251
|
-
]);
|
|
252
|
-
return results.filter((item) => item !== null);
|
|
253
|
-
}
|
|
254
|
-
//# sourceMappingURL=local-sessions.js.map
|
|
1
|
+
import L from"node:fs/promises";import{createReadStream as E}from"node:fs";import F from"node:os";import k from"node:path";import M from"node:readline";const B=/^mcp__.+__(run_skill|get_playbook)$/,D=()=>({input:0,output:0,cacheRead:0,cacheWrite:0});function I(e){let n=null;for(const[l,i]of Object.entries(e))(n===null||i>e[n])&&(n=l);return n}async function*N(e){const n=M.createInterface({input:E(e,{encoding:"utf8"}),crlfDelay:1/0});for await(const l of n)if(l)try{const i=JSON.parse(l);i&&typeof i=="object"&&(yield i)}catch{}}const T=/doesn't want to proceed|user denied|permission denied|was rejected|not allowed/i;function d(e){return e&&typeof e=="object"?e:{}}function h(e){return typeof e=="number"&&Number.isFinite(e)?e:0}async function J(e){const n={},l={},i=new Set,r=D(),m=new Set;let c=null,y=null,f=null,p=k.basename(e,".jsonl"),g=0,w=0,b=0,j=0;const u=e.includes(`${k.sep}subagents${k.sep}`);for await(const o of N(e)){const t=typeof o.timestamp=="string"?o.timestamp:null;t&&(c??=t,y=t),typeof o.sessionId=="string"&&!u&&(p=o.sessionId),typeof o.cwd=="string"&&(f??=o.cwd),typeof o.gitBranch=="string"&&o.gitBranch&&o.gitBranch!=="HEAD"&&(l[o.gitBranch]=(l[o.gitBranch]??0)+1);const s=d(o.message);if(o.type==="user"){const a=s.content;if(typeof a=="string")g+=1;else if(Array.isArray(a))for(const _ of a.map(d))_.type==="text"&&(g+=1),_.type==="tool_result"&&_.is_error===!0&&(b+=1,T.test(JSON.stringify(_.content??"").slice(0,400))&&(j+=1))}if(o.type==="assistant"){const a=typeof s.model=="string"?s.model:null;if(!a||a==="<synthetic>")continue;for(const x of Array.isArray(s.content)?s.content.map(d):[]){if(x.type!=="tool_use")continue;w+=1;const A=d(x.input),O=typeof x.name=="string"?x.name:"",C=O==="Skill"?A.skill:B.test(O)?A.name??A.skill??A.slug:void 0;typeof C=="string"&&C.trim()&&i.add(C.trim().toLowerCase().slice(0,120))}const _=typeof s.id=="string"?s.id:null;if(_&&m.has(_))continue;_&&m.add(_),n[a]=(n[a]??0)+1;const S=d(s.usage);r.input+=h(S.input_tokens),r.output+=h(S.output_tokens),r.cacheRead+=h(S.cache_read_input_tokens),r.cacheWrite+=h(S.cache_creation_input_tokens)}}return!c||!y||!Object.keys(n).length?null:{sessionId:p,client:"claude_code",delegated:u,launchedBy:null,startedAt:c,endedAt:y,models:n,primaryModel:I(n),tokens:r,userTurns:g,toolCalls:w,toolErrors:b,approvalDenials:j,cwd:f,branch:I(l),skills:[...i]}}async function W(e){const n={};let l=D(),i=null,r=null,m=null,c=null,y=k.basename(e,".jsonl"),f=!1,p=null,g=0,w=0,b=0;const j=new Set;for await(const u of N(e)){const o=typeof u.timestamp=="string"?u.timestamp:null;o&&(i??=o,r=o);const t=d(u.payload);if(u.type==="response_item"&&t.type==="function_call"&&typeof t.name=="string"&&B.test(t.name))try{const s=d(JSON.parse(String(t.arguments??"{}"))),a=s.name??s.skill??s.slug;typeof a=="string"&&a.trim()&&j.add(a.trim().toLowerCase().slice(0,120))}catch{}if(u.type==="session_meta"){typeof t.id=="string"&&(y=t.id),typeof t.cwd=="string"&&(m=t.cwd);const s=d(t.git);typeof s.branch=="string"&&s.branch&&s.branch!=="HEAD"&&(c=s.branch),t.originator==="Claude Code"&&(p="claude_code"),t.source&&typeof t.source=="object"&&(f=!0)}if(u.type==="turn_context"&&typeof t.model=="string"&&(n[t.model]=(n[t.model]??0)+1),u.type==="event_msg"&&t.type==="user_message"&&(g+=1),u.type==="event_msg"&&t.type==="token_count"){const s=d(d(t.info).total_token_usage);if(Object.keys(s).length){const a=h(s.cached_input_tokens);l={input:Math.max(0,h(s.input_tokens)-a),output:h(s.output_tokens),cacheRead:a,cacheWrite:h(s.cache_write_input_tokens)}}}u.type==="response_item"&&(t.type==="function_call"||t.type==="custom_tool_call")&&(w+=1),u.type==="event_msg"&&t.type==="exec_command_end"&&h(t.exit_code)!==0&&(b+=1)}return!i||!r||!Object.keys(n).length?null:{sessionId:y,client:"codex",delegated:f||p!==null,launchedBy:p,startedAt:i,endedAt:r,models:n,primaryModel:I(n),tokens:l,userTurns:g,toolCalls:w,toolErrors:b,approvalDenials:0,cwd:m,branch:c,skills:[...j]}}async function R(e,n,l){const i=[],r=async(m,c)=>{let y;try{y=await L.readdir(m,{withFileTypes:!0})}catch{return}for(const f of y){const p=k.join(m,f.name);if(f.isDirectory()&&c<n)await r(p,c+1);else if(f.isFile()&&f.name.endsWith(".jsonl")){const g=await L.stat(p).catch(()=>null);g&&g.mtimeMs>=l&&i.push(p)}}};return await r(e,0),i}async function U(e){const n=e.home??F.homedir(),l=e.since,[i,r]=await Promise.all([R(k.join(n,".claude","projects"),4,l),R(k.join(n,".codex","sessions"),4,l)]);return(await Promise.all([...i.map(c=>J(c).catch(()=>null)),...r.map(c=>W(c).catch(()=>null))])).filter(c=>c!==null)}export{U as collectLocalSessions,J as readClaudeCodeSession,W as readCodexSession};
|
|
@@ -1,102 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
roots: (input.evidenceRoots ?? []).map((root, index) => ({
|
|
10
|
-
path: root,
|
|
11
|
-
label: `approved-output-${index + 1}`,
|
|
12
|
-
kind: "output",
|
|
13
|
-
})),
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
const EVENTS = {
|
|
17
|
-
sessionStart: { codex: "SessionStart", claude: "SessionStart", gemini: "SessionStart" },
|
|
18
|
-
toolCompleted: { codex: "PostToolUse", claude: "PostToolUse", gemini: "AfterTool" },
|
|
19
|
-
toolFailed: { codex: "PostToolUseFailure", claude: "PostToolUseFailure", gemini: "Notification" },
|
|
20
|
-
sessionEnd: { codex: "SessionEnd", claude: "SessionEnd", gemini: "SessionEnd" },
|
|
21
|
-
};
|
|
22
|
-
function hookCommand(command, source, event) {
|
|
23
|
-
return `${command} pace capture --source ${source} --event ${event}`;
|
|
24
|
-
}
|
|
25
|
-
function jsonHook(command, source, event, name) {
|
|
26
|
-
return [{
|
|
27
|
-
matcher: "*",
|
|
28
|
-
hooks: [{
|
|
29
|
-
name: `ai-pace-${name}`,
|
|
30
|
-
type: "command",
|
|
31
|
-
command: hookCommand(command, source, event),
|
|
32
|
-
}],
|
|
33
|
-
}];
|
|
34
|
-
}
|
|
35
|
-
export function renderCodexRequirements(options) {
|
|
36
|
-
const lines = [
|
|
37
|
-
"# Generated by `unfairly pace config`. Deploy with MDM; do not add secrets.",
|
|
38
|
-
"allow_managed_hooks_only = true",
|
|
39
|
-
"",
|
|
40
|
-
"[features]",
|
|
41
|
-
"hooks = true",
|
|
42
|
-
"",
|
|
43
|
-
"[hooks]",
|
|
44
|
-
`managed_dir = ${JSON.stringify(options.managedDir)}`,
|
|
45
|
-
`windows_managed_dir = ${JSON.stringify(options.managedDir)}`,
|
|
46
|
-
"",
|
|
47
|
-
];
|
|
48
|
-
for (const [name, event] of Object.entries(EVENTS)) {
|
|
49
|
-
lines.push(`[[hooks.${event.codex}]]`, 'matcher = ".*"', "", `[[hooks.${event.codex}.hooks]]`, 'type = "command"', `command = ${JSON.stringify(hookCommand(options.command, "codex", event.codex))}`, "timeout = 10", `statusMessage = ${JSON.stringify(`Recording ${name} evidence`)}`, "");
|
|
50
|
-
}
|
|
51
|
-
return `${lines.join("\n").trim()}\n`;
|
|
52
|
-
}
|
|
53
|
-
export function renderClaudeSettings(command) {
|
|
54
|
-
return {
|
|
55
|
-
hooks: Object.fromEntries(Object.entries(EVENTS).map(([name, event]) => [
|
|
56
|
-
event.claude,
|
|
57
|
-
jsonHook(command, "claude_code", event.claude, name),
|
|
58
|
-
])),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
export function renderGeminiSettings(command) {
|
|
62
|
-
return {
|
|
63
|
-
hooksConfig: { enabled: true, notifications: false },
|
|
64
|
-
hooks: Object.fromEntries(Object.entries(EVENTS).map(([name, event]) => [
|
|
65
|
-
event.gemini,
|
|
66
|
-
jsonHook(command, "gemini_cli", event.gemini, name),
|
|
67
|
-
])),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
export function renderCursorSettings(command) {
|
|
71
|
-
const events = {
|
|
72
|
-
sessionStart: "sessionStart",
|
|
73
|
-
postToolUse: "postToolUse",
|
|
74
|
-
postToolUseFailure: "postToolUseFailure",
|
|
75
|
-
sessionEnd: "sessionEnd",
|
|
76
|
-
};
|
|
77
|
-
return {
|
|
78
|
-
version: 1,
|
|
79
|
-
hooks: Object.fromEntries(Object.entries(events).map(([name, event]) => [
|
|
80
|
-
event,
|
|
81
|
-
[{
|
|
82
|
-
command: hookCommand(command, "cursor", event),
|
|
83
|
-
timeout: 10,
|
|
84
|
-
...(name.includes("Tool") ? { matcher: ".*" } : {}),
|
|
85
|
-
}],
|
|
86
|
-
])),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
export async function writeManagedConfigs(input) {
|
|
90
|
-
await fs.mkdir(input.outputDir, { recursive: true });
|
|
91
|
-
const files = {
|
|
92
|
-
"codex-requirements.toml": renderCodexRequirements(input),
|
|
93
|
-
"claude-settings.json": `${JSON.stringify(renderClaudeSettings(input.command), null, 2)}\n`,
|
|
94
|
-
"cursor-hooks.json": `${JSON.stringify(renderCursorSettings(input.command), null, 2)}\n`,
|
|
95
|
-
"gemini-settings.json": `${JSON.stringify(renderGeminiSettings(input.command), null, 2)}\n`,
|
|
96
|
-
"evidence-policy.json": `${JSON.stringify(renderEvidencePolicy(input), null, 2)}\n`,
|
|
97
|
-
"repository-policy.json": `${JSON.stringify({ version: 1, mappings: [] }, null, 2)}\n`,
|
|
98
|
-
};
|
|
99
|
-
await Promise.all(Object.entries(files).map(([name, contents]) => fs.writeFile(path.join(input.outputDir, name), contents, { encoding: "utf8", mode: 0o644 })));
|
|
100
|
-
return Object.keys(files).map((name) => path.join(input.outputDir, name));
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=managed-config.js.map
|
|
1
|
+
import r from"node:fs/promises";import a from"node:path";function d(e){return{version:1,include_file_names:e.includeFileNames??!1,scan_interval_seconds:60,max_files_per_root:5e3,roots:(e.evidenceRoots??[]).map((n,o)=>({path:n,label:`approved-output-${o+1}`,kind:"output"}))}}const t={sessionStart:{codex:"SessionStart",claude:"SessionStart",gemini:"SessionStart"},toolCompleted:{codex:"PostToolUse",claude:"PostToolUse",gemini:"AfterTool"},toolFailed:{codex:"PostToolUseFailure",claude:"PostToolUseFailure",gemini:"Notification"},sessionEnd:{codex:"SessionEnd",claude:"SessionEnd",gemini:"SessionEnd"}};function i(e,n,o){return`${e} pace capture --source ${n} --event ${o}`}function c(e,n,o,s){return[{matcher:"*",hooks:[{name:`ai-pace-${s}`,type:"command",command:i(e,n,o)}]}]}function m(e){const n=["# Generated by `unfairly pace config`. Deploy with MDM; do not add secrets.","allow_managed_hooks_only = true","","[features]","hooks = true","","[hooks]",`managed_dir = ${JSON.stringify(e.managedDir)}`,`windows_managed_dir = ${JSON.stringify(e.managedDir)}`,""];for(const[o,s]of Object.entries(t))n.push(`[[hooks.${s.codex}]]`,'matcher = ".*"',"",`[[hooks.${s.codex}.hooks]]`,'type = "command"',`command = ${JSON.stringify(i(e.command,"codex",s.codex))}`,"timeout = 10",`statusMessage = ${JSON.stringify(`Recording ${o} evidence`)}`,"");return`${n.join(`
|
|
2
|
+
`).trim()}
|
|
3
|
+
`}function l(e){return{hooks:Object.fromEntries(Object.entries(t).map(([n,o])=>[o.claude,c(e,"claude_code",o.claude,n)]))}}function u(e){return{hooksConfig:{enabled:!0,notifications:!1},hooks:Object.fromEntries(Object.entries(t).map(([n,o])=>[o.gemini,c(e,"gemini_cli",o.gemini,n)]))}}function f(e){return{version:1,hooks:Object.fromEntries(Object.entries({sessionStart:"sessionStart",postToolUse:"postToolUse",postToolUseFailure:"postToolUseFailure",sessionEnd:"sessionEnd"}).map(([o,s])=>[s,[{command:i(e,"cursor",s),timeout:10,...o.includes("Tool")?{matcher:".*"}:{}}]]))}}async function S(e){await r.mkdir(e.outputDir,{recursive:!0});const n={"codex-requirements.toml":m(e),"claude-settings.json":`${JSON.stringify(l(e.command),null,2)}
|
|
4
|
+
`,"cursor-hooks.json":`${JSON.stringify(f(e.command),null,2)}
|
|
5
|
+
`,"gemini-settings.json":`${JSON.stringify(u(e.command),null,2)}
|
|
6
|
+
`,"evidence-policy.json":`${JSON.stringify(d(e),null,2)}
|
|
7
|
+
`,"repository-policy.json":`${JSON.stringify({version:1,mappings:[]},null,2)}
|
|
8
|
+
`};return await Promise.all(Object.entries(n).map(([o,s])=>r.writeFile(a.join(e.outputDir,o),s,{encoding:"utf8",mode:420}))),Object.keys(n).map(o=>a.join(e.outputDir,o))}export{l as renderClaudeSettings,m as renderCodexRequirements,f as renderCursorSettings,d as renderEvidencePolicy,u as renderGeminiSettings,S as writeManagedConfigs};
|
package/dist/pace/normalize.d.ts
CHANGED