sidekick-shared 0.22.0 → 0.23.1
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/README.md +75 -63
- package/dist/accountManager.js +10 -0
- package/dist/accountRegistry.d.ts +2 -0
- package/dist/accountStatus.d.ts +1 -0
- package/dist/accountStatus.js +6 -0
- package/dist/accounts.js +2 -0
- package/dist/aggregation/EventAggregator.d.ts +36 -2
- package/dist/aggregation/EventAggregator.js +259 -33
- package/dist/aggregation/snapshot.d.ts +1 -1
- package/dist/aggregation/snapshot.js +2 -1
- package/dist/aggregation/types.d.ts +25 -1
- package/dist/analytics/codeImpact.d.ts +20 -0
- package/dist/analytics/codeImpact.js +21 -0
- package/dist/analytics/compactionLedger.d.ts +11 -0
- package/dist/analytics/compactionLedger.js +31 -0
- package/dist/analytics/qualityScore.d.ts +26 -0
- package/dist/analytics/qualityScore.js +115 -0
- package/dist/autoSwitch.d.ts +1 -1
- package/dist/autoSwitch.js +14 -3
- package/dist/codexProfiles.js +2 -0
- package/dist/codexQuota.d.ts +2 -0
- package/dist/codexQuota.js +27 -0
- package/dist/codexQuotaWatcher.d.ts +7 -0
- package/dist/codexQuotaWatcher.js +37 -19
- package/dist/context/composer.d.ts +3 -2
- package/dist/context/composer.js +5 -5
- package/dist/context/sessionContext.js +35 -9
- package/dist/credentialIO.js +19 -5
- package/dist/doctor.d.ts +55 -0
- package/dist/doctor.js +244 -0
- package/dist/errorHistory.d.ts +33 -0
- package/dist/errorHistory.js +95 -0
- package/dist/extractors/errorTaxonomy.d.ts +6 -0
- package/dist/extractors/errorTaxonomy.js +47 -0
- package/dist/extractors/toolCall.d.ts +9 -0
- package/dist/extractors/toolCall.js +79 -0
- package/dist/handoffUrl.d.ts +7 -0
- package/dist/handoffUrl.js +26 -0
- package/dist/index.d.ts +32 -9
- package/dist/index.js +64 -24
- package/dist/modelInfo.js +6 -0
- package/dist/multiProviderQuotaService.js +13 -2
- package/dist/parsers/codexParser.js +17 -1
- package/dist/parsers/openCodeParser.js +13 -0
- package/dist/parsers/planExtractor.js +17 -6
- package/dist/parsers/sessionActivityDetector.js +2 -0
- package/dist/parsers/sessionPathResolver.js +19 -16
- package/dist/parsers/subagentScanner.d.ts +1 -1
- package/dist/parsers/subagentScanner.js +4 -5
- package/dist/parsers/subagentTraceParser.js +4 -7
- package/dist/paths.d.ts +10 -0
- package/dist/paths.js +18 -5
- package/dist/projectMigration.d.ts +23 -0
- package/dist/projectMigration.js +95 -0
- package/dist/providerStatus.js +13 -2
- package/dist/providers/claudeCode.js +18 -4
- package/dist/providers/codex.js +42 -13
- package/dist/providers/codexDatabase.d.ts +1 -11
- package/dist/providers/detect.js +32 -3
- package/dist/providers/openCodeDatabase.d.ts +1 -31
- package/dist/providers/openCodeDatabase.js +21 -11
- package/dist/providers/types.d.ts +1 -0
- package/dist/quota.js +8 -0
- package/dist/quotaPoller.js +17 -6
- package/dist/quotaSnapshots.js +80 -26
- package/dist/readers/decisions.d.ts +2 -1
- package/dist/readers/decisions.js +5 -5
- package/dist/readers/handoff.d.ts +2 -1
- package/dist/readers/handoff.js +13 -8
- package/dist/readers/helpers.d.ts +3 -0
- package/dist/readers/helpers.js +12 -0
- package/dist/readers/notes.d.ts +2 -1
- package/dist/readers/notes.js +11 -8
- package/dist/readers/plans.js +3 -5
- package/dist/readers/tasks.d.ts +2 -1
- package/dist/readers/tasks.js +5 -5
- package/dist/report/htmlHelpers.js +6 -1
- package/dist/report/openBrowser.js +3 -3
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +10 -1
- package/dist/schemas/observedSessionV1.d.ts +499 -0
- package/dist/schemas/observedSessionV1.js +69 -0
- package/dist/schemas/sessionEvent.d.ts +13 -0
- package/dist/schemas/sessionEvent.js +19 -0
- package/dist/search/sessionSearch.d.ts +2 -2
- package/dist/search/sessionSearch.js +2 -3
- package/dist/sessionMonitor.d.ts +29 -0
- package/dist/sessionMonitor.js +71 -0
- package/dist/statusline/BurnRateCalculator.d.ts +14 -0
- package/dist/statusline/BurnRateCalculator.js +45 -0
- package/dist/statusline/formatter.d.ts +16 -0
- package/dist/statusline/formatter.js +84 -0
- package/dist/statusline/index.d.ts +7 -0
- package/dist/statusline/index.js +13 -0
- package/dist/terminalSync.js +16 -7
- package/dist/types/codex.d.ts +2 -0
- package/dist/types/historicalData.d.ts +49 -1
- package/dist/types/historicalData.js +28 -2
- package/dist/types/observedSessionV1.d.ts +70 -0
- package/dist/types/observedSessionV1.js +186 -0
- package/dist/types/opencode.d.ts +1 -0
- package/dist/types/sessionEvent.d.ts +19 -1
- package/dist/watchers/eventBridge.js +1 -0
- package/dist/watchers/factory.js +14 -3
- package/dist/watchers/jsonlTail.js +34 -14
- package/dist/watchers/jsonlWatcher.js +5 -3
- package/dist/watchers/providerReaderWatcher.js +4 -2
- package/dist/watchers/sqliteWatcher.d.ts +2 -0
- package/dist/watchers/sqliteWatcher.js +27 -14
- package/dist/watchers/types.d.ts +5 -0
- package/dist/writers/atomic.d.ts +4 -0
- package/dist/writers/atomic.js +200 -0
- package/dist/writers/decisions.d.ts +12 -0
- package/dist/writers/decisions.js +88 -0
- package/dist/writers/notes.d.ts +8 -0
- package/dist/writers/notes.js +82 -0
- package/dist/writers/tasks.d.ts +6 -0
- package/dist/writers/tasks.js +100 -0
- package/dist/zaiQuotaWatcher.js +6 -0
- package/package.json +5 -1
|
@@ -64,8 +64,12 @@ class OpenCodeDatabase {
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
open() {
|
|
67
|
-
if (this.runtimeStatus)
|
|
68
|
-
return
|
|
67
|
+
if (this.runtimeStatus?.kind === 'available')
|
|
68
|
+
return true;
|
|
69
|
+
if (this.runtimeStatus &&
|
|
70
|
+
['db_missing', 'sqlite_missing', 'sqlite_blocked'].includes(this.runtimeStatus.kind)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
69
73
|
if (!this.isAvailable()) {
|
|
70
74
|
this.runtimeStatus = { available: false, kind: 'db_missing' };
|
|
71
75
|
return false;
|
|
@@ -89,15 +93,16 @@ class OpenCodeDatabase {
|
|
|
89
93
|
query(sql, params = []) {
|
|
90
94
|
if (!this.open())
|
|
91
95
|
return [];
|
|
92
|
-
let
|
|
93
|
-
|
|
96
|
+
let paramIndex = 0;
|
|
97
|
+
const query = sql.replace(/\?/g, () => {
|
|
98
|
+
if (paramIndex >= params.length)
|
|
99
|
+
return '?';
|
|
100
|
+
const param = params[paramIndex++];
|
|
94
101
|
if (typeof param === 'number')
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
}
|
|
102
|
+
return Number.isFinite(param) ? String(param) : '0';
|
|
103
|
+
const escaped = String(param).replace(/'/g, "''");
|
|
104
|
+
return `'${escaped}'`;
|
|
105
|
+
});
|
|
101
106
|
try {
|
|
102
107
|
const result = (0, child_process_1.execFileSync)('sqlite3', ['-json', '-readonly', this.dbPath, query], {
|
|
103
108
|
encoding: 'utf-8',
|
|
@@ -113,7 +118,12 @@ class OpenCodeDatabase {
|
|
|
113
118
|
return JSON.parse(trimmed);
|
|
114
119
|
}
|
|
115
120
|
catch (error) {
|
|
116
|
-
this.runtimeStatus =
|
|
121
|
+
this.runtimeStatus = {
|
|
122
|
+
...toRuntimeStatus(error, 'query_failed'),
|
|
123
|
+
// The database and sqlite binary were successfully opened. A failed
|
|
124
|
+
// query is transient and must not gate the next attempt.
|
|
125
|
+
available: true,
|
|
126
|
+
};
|
|
117
127
|
return [];
|
|
118
128
|
}
|
|
119
129
|
}
|
|
@@ -151,6 +151,7 @@ export interface SessionProviderBase {
|
|
|
151
151
|
/**
|
|
152
152
|
* Original simplified session provider interface.
|
|
153
153
|
* Maintained for backward compatibility with existing CLI and shared code.
|
|
154
|
+
* @deprecated Use SessionProviderBase for new integrations.
|
|
154
155
|
*/
|
|
155
156
|
export interface SessionProvider {
|
|
156
157
|
readonly id: ProviderId;
|
package/dist/quota.js
CHANGED
|
@@ -12,6 +12,7 @@ exports.withQuotaProjections = withQuotaProjections;
|
|
|
12
12
|
exports.fetchQuota = fetchQuota;
|
|
13
13
|
const USAGE_URL = 'https://api.anthropic.com/api/oauth/usage';
|
|
14
14
|
const BETA_HEADER = 'oauth-2025-04-20';
|
|
15
|
+
const FETCH_TIMEOUT_MS = 10_000;
|
|
15
16
|
exports.FIVE_HOUR_WINDOW_MS = 5 * 3_600_000;
|
|
16
17
|
exports.SEVEN_DAY_WINDOW_MS = 7 * 86_400_000;
|
|
17
18
|
/**
|
|
@@ -94,9 +95,13 @@ function parseRetryAfterMs(retryAfter) {
|
|
|
94
95
|
* @returns QuotaState with utilization data and elapsed-time projections
|
|
95
96
|
*/
|
|
96
97
|
async function fetchQuota(accessToken) {
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
100
|
+
timeout.unref();
|
|
97
101
|
try {
|
|
98
102
|
const res = await fetch(USAGE_URL, {
|
|
99
103
|
method: 'GET',
|
|
104
|
+
signal: controller.signal,
|
|
100
105
|
headers: {
|
|
101
106
|
Authorization: `Bearer ${accessToken}`,
|
|
102
107
|
'anthropic-beta': BETA_HEADER,
|
|
@@ -152,4 +157,7 @@ async function fetchQuota(accessToken) {
|
|
|
152
157
|
catch {
|
|
153
158
|
return unavailableState('Network error', { failureKind: 'network' });
|
|
154
159
|
}
|
|
160
|
+
finally {
|
|
161
|
+
clearTimeout(timeout);
|
|
162
|
+
}
|
|
155
163
|
}
|
package/dist/quotaPoller.js
CHANGED
|
@@ -111,10 +111,12 @@ class QuotaPoller {
|
|
|
111
111
|
this.notify(state);
|
|
112
112
|
}
|
|
113
113
|
else if (state.failureKind === 'auth') {
|
|
114
|
-
//
|
|
114
|
+
// Keep polling at the idle cadence so signing in again recovers
|
|
115
|
+
// without an extension/CLI restart.
|
|
115
116
|
this.latest = state;
|
|
116
117
|
this.notify(state);
|
|
117
|
-
this.
|
|
118
|
+
this.consecutiveFailures = 0;
|
|
119
|
+
this.scheduleNext(this.idleIntervalMs);
|
|
118
120
|
return;
|
|
119
121
|
}
|
|
120
122
|
else {
|
|
@@ -134,17 +136,26 @@ class QuotaPoller {
|
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
138
|
}
|
|
137
|
-
catch {
|
|
139
|
+
catch (error) {
|
|
138
140
|
this.consecutiveFailures++;
|
|
141
|
+
const state = {
|
|
142
|
+
fiveHour: { utilization: 0, resetsAt: '' },
|
|
143
|
+
sevenDay: { utilization: 0, resetsAt: '' },
|
|
144
|
+
available: false,
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
failureKind: 'auth',
|
|
147
|
+
};
|
|
148
|
+
this.latest = state;
|
|
149
|
+
this.notify(state);
|
|
139
150
|
}
|
|
140
151
|
this.scheduleNext();
|
|
141
152
|
}
|
|
142
|
-
scheduleNext() {
|
|
153
|
+
scheduleNext(overrideMs) {
|
|
143
154
|
if (this.stopped)
|
|
144
155
|
return;
|
|
145
156
|
const baseInterval = this.isActive ? this.activeIntervalMs : this.idleIntervalMs;
|
|
146
|
-
const backoff = Math.min(baseInterval * Math.pow(2, this.consecutiveFailures), this.maxBackoffMs);
|
|
147
|
-
const delay = this.consecutiveFailures > 0 ? backoff : baseInterval;
|
|
157
|
+
const backoff = Math.min(baseInterval * Math.pow(2, this.consecutiveFailures), Math.max(this.maxBackoffMs, baseInterval));
|
|
158
|
+
const delay = overrideMs ?? (this.consecutiveFailures > 0 ? backoff : baseInterval);
|
|
148
159
|
this.timer = setTimeout(() => void this.poll(), delay);
|
|
149
160
|
}
|
|
150
161
|
notify(state) {
|
package/dist/quotaSnapshots.js
CHANGED
|
@@ -40,6 +40,10 @@ const fs = __importStar(require("fs"));
|
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const paths_1 = require("./paths");
|
|
42
42
|
const codex_1 = require("./types/codex");
|
|
43
|
+
const LOCK_WAIT_MS = 15;
|
|
44
|
+
const LOCK_STALE_MS = 10_000;
|
|
45
|
+
const LOCK_TIMEOUT_MS = 15_000;
|
|
46
|
+
const lockSleepView = new Int32Array(new SharedArrayBuffer(4));
|
|
43
47
|
function getQuotaSnapshotPath() {
|
|
44
48
|
return path.join((0, paths_1.getConfigDir)(), 'quota-snapshots.json');
|
|
45
49
|
}
|
|
@@ -84,6 +88,61 @@ function writeStore(store) {
|
|
|
84
88
|
ensureConfigDir();
|
|
85
89
|
atomicWriteJson(getQuotaSnapshotPath(), store);
|
|
86
90
|
}
|
|
91
|
+
function withSnapshotStoreLock(operation) {
|
|
92
|
+
ensureConfigDir();
|
|
93
|
+
const lockPath = `${getQuotaSnapshotPath()}.lock`;
|
|
94
|
+
const token = `${process.pid}:${crypto.randomBytes(16).toString('hex')}`;
|
|
95
|
+
const deadline = Date.now() + LOCK_TIMEOUT_MS;
|
|
96
|
+
while (true) {
|
|
97
|
+
try {
|
|
98
|
+
const descriptor = fs.openSync(lockPath, 'wx', 0o600);
|
|
99
|
+
fs.writeFileSync(descriptor, token, 'utf8');
|
|
100
|
+
fs.fsyncSync(descriptor);
|
|
101
|
+
fs.closeSync(descriptor);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (error.code !== 'EEXIST')
|
|
106
|
+
throw error;
|
|
107
|
+
try {
|
|
108
|
+
const stat = fs.statSync(lockPath);
|
|
109
|
+
if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {
|
|
110
|
+
const owner = fs.readFileSync(lockPath, 'utf8');
|
|
111
|
+
const ownerPid = Number.parseInt(owner.split(':', 1)[0], 10);
|
|
112
|
+
let ownerAlive = Number.isInteger(ownerPid) && ownerPid > 0;
|
|
113
|
+
if (ownerAlive) {
|
|
114
|
+
try {
|
|
115
|
+
process.kill(ownerPid, 0);
|
|
116
|
+
}
|
|
117
|
+
catch (ownerError) {
|
|
118
|
+
ownerAlive = ownerError.code === 'EPERM';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!ownerAlive)
|
|
122
|
+
fs.rmSync(lockPath, { force: true });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// The owner may have released the lock between checks.
|
|
127
|
+
}
|
|
128
|
+
if (Date.now() >= deadline)
|
|
129
|
+
throw new Error(`Timed out waiting for quota lock: ${lockPath}`);
|
|
130
|
+
Atomics.wait(lockSleepView, 0, 0, LOCK_WAIT_MS);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return operation();
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
try {
|
|
138
|
+
if (fs.readFileSync(lockPath, 'utf8') === token)
|
|
139
|
+
fs.rmSync(lockPath, { force: true });
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Never remove a lock that has already been released or replaced.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
87
146
|
function snapshotTimeMs(quota) {
|
|
88
147
|
const capturedAt = quota.capturedAt ? Date.parse(quota.capturedAt) : NaN;
|
|
89
148
|
return Number.isFinite(capturedAt) ? capturedAt : 0;
|
|
@@ -119,32 +178,27 @@ function shouldKeepExistingSnapshot(existing, next) {
|
|
|
119
178
|
return snapshotTimeMs(existing) > snapshotTimeMs(next);
|
|
120
179
|
}
|
|
121
180
|
function writeQuotaSnapshot(providerId, accountId, quota) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
store.snapshots.push(record);
|
|
146
|
-
}
|
|
147
|
-
writeStore(store);
|
|
181
|
+
withSnapshotStoreLock(() => {
|
|
182
|
+
const store = readStore();
|
|
183
|
+
const index = store.snapshots.findIndex((item) => item.providerId === providerId && item.accountId === accountId);
|
|
184
|
+
const existingQuota = index >= 0 ? store.snapshots[index].quota : undefined;
|
|
185
|
+
const snapshot = {
|
|
186
|
+
...quota,
|
|
187
|
+
providerId,
|
|
188
|
+
capturedAt: quota.capturedAt ?? new Date().toISOString(),
|
|
189
|
+
source: quota.source ?? 'session',
|
|
190
|
+
stale: false,
|
|
191
|
+
resetCredits: quota.resetCredits ?? (providerId === 'codex' ? existingQuota?.resetCredits : undefined),
|
|
192
|
+
};
|
|
193
|
+
if (index >= 0 && shouldKeepExistingSnapshot(store.snapshots[index].quota, snapshot))
|
|
194
|
+
return;
|
|
195
|
+
const record = { providerId, accountId, quota: snapshot };
|
|
196
|
+
if (index >= 0)
|
|
197
|
+
store.snapshots[index] = record;
|
|
198
|
+
else
|
|
199
|
+
store.snapshots.push(record);
|
|
200
|
+
writeStore(store);
|
|
201
|
+
});
|
|
148
202
|
}
|
|
149
203
|
function readQuotaSnapshot(providerId, accountId) {
|
|
150
204
|
const store = readStore();
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Reader for persisted decisions.
|
|
3
3
|
*/
|
|
4
4
|
import type { DecisionEntry } from '../types/decisionLog';
|
|
5
|
+
import type { ProjectIdentity } from '../paths';
|
|
5
6
|
export interface ReadDecisionsOptions {
|
|
6
7
|
search?: string;
|
|
7
8
|
file?: string;
|
|
8
9
|
limit?: number;
|
|
9
10
|
}
|
|
10
|
-
export declare function readDecisions(
|
|
11
|
+
export declare function readDecisions(project: string | ProjectIdentity, opts?: ReadDecisionsOptions): Promise<DecisionEntry[]>;
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.readDecisions = readDecisions;
|
|
7
|
-
const paths_1 = require("../paths");
|
|
8
7
|
const helpers_1 = require("./helpers");
|
|
9
|
-
async function readDecisions(
|
|
10
|
-
const
|
|
11
|
-
const store = await (0, helpers_1.readJsonStore)(filePath);
|
|
8
|
+
async function readDecisions(project, opts) {
|
|
9
|
+
const store = await (0, helpers_1.readProjectJsonStore)(project, 'decisions');
|
|
12
10
|
if (!store)
|
|
13
11
|
return [];
|
|
14
|
-
let decisions =
|
|
12
|
+
let decisions = store.decisions && typeof store.decisions === 'object' && !Array.isArray(store.decisions)
|
|
13
|
+
? Object.values(store.decisions)
|
|
14
|
+
: [];
|
|
15
15
|
// Sort by timestamp descending
|
|
16
16
|
decisions.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
17
17
|
if (opts?.search) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reader for session handoff documents.
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import { type ProjectIdentity } from '../paths';
|
|
5
|
+
export declare function readLatestHandoff(project: string | ProjectIdentity): Promise<string | null>;
|
package/dist/readers/handoff.js
CHANGED
|
@@ -39,13 +39,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.readLatestHandoff = readLatestHandoff;
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const paths_1 = require("../paths");
|
|
42
|
-
async function readLatestHandoff(
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
async function readLatestHandoff(project) {
|
|
43
|
+
const candidates = typeof project === 'string' ? [project] : project.candidates;
|
|
44
|
+
for (const slug of candidates) {
|
|
45
|
+
const filePath = (0, paths_1.getProjectDataPath)(slug, 'handoffs').replace(/\.json$/, '-latest.md');
|
|
46
|
+
try {
|
|
47
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
48
|
+
if (content.trim())
|
|
49
|
+
return content.trim();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Try the legacy candidate.
|
|
53
|
+
}
|
|
50
54
|
}
|
|
55
|
+
return null;
|
|
51
56
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared reader helpers.
|
|
3
3
|
*/
|
|
4
|
+
import { type ProjectIdentity } from '../paths';
|
|
4
5
|
/**
|
|
5
6
|
* Reads and parses a JSON store file. Returns null if file missing or malformed.
|
|
6
7
|
*/
|
|
7
8
|
export declare function readJsonStore<T>(filePath: string): Promise<T | null>;
|
|
9
|
+
/** Reads the canonical project store, falling back to the legacy symlink slug. */
|
|
10
|
+
export declare function readProjectJsonStore<T>(project: string | ProjectIdentity, subdomain: string): Promise<T | null>;
|
package/dist/readers/helpers.js
CHANGED
|
@@ -37,7 +37,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.readJsonStore = readJsonStore;
|
|
40
|
+
exports.readProjectJsonStore = readProjectJsonStore;
|
|
40
41
|
const fs = __importStar(require("fs"));
|
|
42
|
+
const paths_1 = require("../paths");
|
|
41
43
|
/**
|
|
42
44
|
* Reads and parses a JSON store file. Returns null if file missing or malformed.
|
|
43
45
|
*/
|
|
@@ -50,3 +52,13 @@ async function readJsonStore(filePath) {
|
|
|
50
52
|
return null;
|
|
51
53
|
}
|
|
52
54
|
}
|
|
55
|
+
/** Reads the canonical project store, falling back to the legacy symlink slug. */
|
|
56
|
+
async function readProjectJsonStore(project, subdomain) {
|
|
57
|
+
const candidates = typeof project === 'string' ? [project] : project.candidates;
|
|
58
|
+
for (const slug of candidates) {
|
|
59
|
+
const store = await readJsonStore((0, paths_1.getProjectDataPath)(slug, subdomain));
|
|
60
|
+
if (store)
|
|
61
|
+
return store;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
package/dist/readers/notes.d.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Reader for knowledge notes.
|
|
3
3
|
*/
|
|
4
4
|
import type { KnowledgeNote, KnowledgeNoteType, KnowledgeNoteStatus } from '../types/knowledgeNote';
|
|
5
|
+
import type { ProjectIdentity } from '../paths';
|
|
5
6
|
export interface ReadNotesOptions {
|
|
6
7
|
file?: string;
|
|
7
8
|
type?: KnowledgeNoteType;
|
|
8
9
|
status?: KnowledgeNoteStatus;
|
|
9
10
|
}
|
|
10
|
-
export declare function readNotes(
|
|
11
|
+
export declare function readNotes(project: string | ProjectIdentity, opts?: ReadNotesOptions): Promise<KnowledgeNote[]>;
|
package/dist/readers/notes.js
CHANGED
|
@@ -4,29 +4,32 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.readNotes = readNotes;
|
|
7
|
-
const paths_1 = require("../paths");
|
|
8
7
|
const helpers_1 = require("./helpers");
|
|
9
|
-
async function readNotes(
|
|
10
|
-
const
|
|
11
|
-
const store = await (0, helpers_1.readJsonStore)(filePath);
|
|
8
|
+
async function readNotes(project, opts) {
|
|
9
|
+
const store = await (0, helpers_1.readProjectJsonStore)(project, 'knowledge-notes');
|
|
12
10
|
if (!store)
|
|
13
11
|
return [];
|
|
14
12
|
let notes = [];
|
|
13
|
+
const notesByFile = store.notesByFile && typeof store.notesByFile === 'object' && !Array.isArray(store.notesByFile)
|
|
14
|
+
? store.notesByFile
|
|
15
|
+
: {};
|
|
15
16
|
if (opts?.file) {
|
|
16
17
|
// Normalize file path for comparison
|
|
17
18
|
const normalizedFile = opts.file.replace(/\\/g, '/');
|
|
18
|
-
for (const [filePath, fileNotes] of Object.entries(
|
|
19
|
+
for (const [filePath, fileNotes] of Object.entries(notesByFile)) {
|
|
19
20
|
const normalizedKey = filePath.replace(/\\/g, '/');
|
|
20
21
|
if (normalizedKey === normalizedFile ||
|
|
21
22
|
normalizedKey.endsWith('/' + normalizedFile) ||
|
|
22
23
|
normalizedFile.endsWith('/' + normalizedKey)) {
|
|
23
|
-
|
|
24
|
+
if (Array.isArray(fileNotes))
|
|
25
|
+
notes.push(...fileNotes);
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
else {
|
|
28
|
-
for (const fileNotes of Object.values(
|
|
29
|
-
|
|
30
|
+
for (const fileNotes of Object.values(notesByFile)) {
|
|
31
|
+
if (Array.isArray(fileNotes))
|
|
32
|
+
notes.push(...fileNotes);
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
if (opts?.type) {
|
package/dist/readers/plans.js
CHANGED
|
@@ -48,12 +48,13 @@ const plan_1 = require("../types/plan");
|
|
|
48
48
|
const paths_1 = require("../paths");
|
|
49
49
|
const helpers_1 = require("./helpers");
|
|
50
50
|
const planExtractor_1 = require("../parsers/planExtractor");
|
|
51
|
+
const atomic_1 = require("../writers/atomic");
|
|
51
52
|
async function readPlans(slug, opts) {
|
|
52
53
|
const filePath = (0, paths_1.getProjectDataPath)(slug, 'plans');
|
|
53
54
|
const store = await (0, helpers_1.readJsonStore)(filePath);
|
|
54
55
|
if (!store)
|
|
55
56
|
return [];
|
|
56
|
-
let plans = [...store.plans];
|
|
57
|
+
let plans = Array.isArray(store.plans) ? [...store.plans] : [];
|
|
57
58
|
const status = opts?.status ?? 'all';
|
|
58
59
|
if (status !== 'all') {
|
|
59
60
|
plans = plans.filter((p) => p.status === status);
|
|
@@ -170,10 +171,7 @@ async function writePlans(slug, plans) {
|
|
|
170
171
|
plans: capped,
|
|
171
172
|
lastSaved: new Date().toISOString(),
|
|
172
173
|
};
|
|
173
|
-
|
|
174
|
-
const dir = filePath.replace(/[/\\][^/\\]+$/, '');
|
|
175
|
-
await fs.promises.mkdir(dir, { recursive: true });
|
|
176
|
-
await fs.promises.writeFile(filePath, JSON.stringify(store, null, 2), 'utf-8');
|
|
174
|
+
await (0, atomic_1.atomicWriteJson)(filePath, store);
|
|
177
175
|
}
|
|
178
176
|
/**
|
|
179
177
|
* Reads raw plan markdown files from ~/.claude/plans/ that belong to
|
package/dist/readers/tasks.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Reader for persisted tasks.
|
|
3
3
|
*/
|
|
4
4
|
import type { PersistedTask } from '../types/taskPersistence';
|
|
5
|
+
import type { ProjectIdentity } from '../paths';
|
|
5
6
|
export interface ReadTasksOptions {
|
|
6
7
|
status?: 'pending' | 'completed' | 'all';
|
|
7
8
|
}
|
|
8
|
-
export declare function readTasks(
|
|
9
|
+
export declare function readTasks(project: string | ProjectIdentity, opts?: ReadTasksOptions): Promise<PersistedTask[]>;
|
package/dist/readers/tasks.js
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.readTasks = readTasks;
|
|
7
|
-
const paths_1 = require("../paths");
|
|
8
7
|
const helpers_1 = require("./helpers");
|
|
9
|
-
async function readTasks(
|
|
10
|
-
const
|
|
11
|
-
const store = await (0, helpers_1.readJsonStore)(filePath);
|
|
8
|
+
async function readTasks(project, opts) {
|
|
9
|
+
const store = await (0, helpers_1.readProjectJsonStore)(project, 'tasks');
|
|
12
10
|
if (!store)
|
|
13
11
|
return [];
|
|
14
|
-
let tasks =
|
|
12
|
+
let tasks = store.tasks && typeof store.tasks === 'object' && !Array.isArray(store.tasks)
|
|
13
|
+
? Object.values(store.tasks)
|
|
14
|
+
: [];
|
|
15
15
|
const status = opts?.status ?? 'all';
|
|
16
16
|
if (status !== 'all') {
|
|
17
17
|
tasks = tasks.filter((t) => t.status === status);
|
|
@@ -53,7 +53,12 @@ function simpleMarkdownToHtml(text) {
|
|
|
53
53
|
// Inline code (after escaping so backtick content is already safe)
|
|
54
54
|
result = result.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
|
|
55
55
|
// Links [text](url)
|
|
56
|
-
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
56
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, label, url) => {
|
|
57
|
+
const trimmedUrl = url.trim();
|
|
58
|
+
if (!/^(?:https?:|mailto:|#|\/)/i.test(trimmedUrl))
|
|
59
|
+
return match;
|
|
60
|
+
return `<a href="${trimmedUrl}" target="_blank" rel="noopener">${label}</a>`;
|
|
61
|
+
});
|
|
57
62
|
// Unordered lists
|
|
58
63
|
result = result.replace(/^(\s*)[-*] (.+)$/gm, '$1<li>$2</li>');
|
|
59
64
|
// Ordered lists
|
|
@@ -10,13 +10,13 @@ function openInBrowser(filePath) {
|
|
|
10
10
|
const url = `file://${filePath}`;
|
|
11
11
|
switch (process.platform) {
|
|
12
12
|
case 'darwin':
|
|
13
|
-
(0, child_process_1.
|
|
13
|
+
(0, child_process_1.execFile)('open', [url]);
|
|
14
14
|
break;
|
|
15
15
|
case 'win32':
|
|
16
|
-
(0, child_process_1.
|
|
16
|
+
(0, child_process_1.execFile)('rundll32.exe', ['url.dll,FileProtocolHandler', url]);
|
|
17
17
|
break;
|
|
18
18
|
default:
|
|
19
|
-
(0, child_process_1.
|
|
19
|
+
(0, child_process_1.execFile)('xdg-open', [url]);
|
|
20
20
|
break;
|
|
21
21
|
}
|
|
22
22
|
}
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './sessionEvent';
|
|
14
14
|
export type { MessageUsage, SessionMessage, SessionEvent, PermissionMode, } from '../types/sessionEvent';
|
|
15
|
+
export { observationProvenanceV1Schema, observedAgentSessionV1Schema, observedValueV1Schema, pendingUserRequestV1Schema, providerCapabilitiesV1Schema, providerSessionAdapterV1Schema, sessionEvidenceRefV1Schema, } from './observedSessionV1';
|
|
16
|
+
export type { ObservationProvenanceV1, ObservedAgentSessionV1, ObservedValueV1, PendingUserRequestV1, ProviderCapabilitiesV1, ProviderSessionAdapterV1, SessionEvidenceRefV1, } from '../types/observedSessionV1';
|
|
15
17
|
export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './quota';
|
|
16
18
|
export type { CodexResetCredit, CodexResetCreditsSnapshot, QuotaWindow, QuotaState, } from '../quota';
|
|
17
19
|
export type { PeakHoursState } from '../peakHours';
|
package/dist/schemas/index.js
CHANGED
|
@@ -12,13 +12,22 @@
|
|
|
12
12
|
* subpath is self-sufficient for boundary-validation modules.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.
|
|
15
|
+
exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.listAllAccountsResultSchema = exports.savedAccountProfileSchema = exports.accountEntrySchema = exports.accountLoginStatusSchema = exports.beginAccountLoginResultSchema = exports.accountManagerResultSchema = exports.accountProviderIdSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.zaiProviderQuotaStateSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.codexResetCreditsSnapshotSchema = exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.sessionEvidenceRefV1Schema = exports.providerSessionAdapterV1Schema = exports.providerCapabilitiesV1Schema = exports.pendingUserRequestV1Schema = exports.observedValueV1Schema = exports.observedAgentSessionV1Schema = exports.observationProvenanceV1Schema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = void 0;
|
|
16
|
+
exports.assistantTurnToolRefSchema = void 0;
|
|
16
17
|
var sessionEvent_1 = require("./sessionEvent");
|
|
17
18
|
Object.defineProperty(exports, "messageUsageSchema", { enumerable: true, get: function () { return sessionEvent_1.messageUsageSchema; } });
|
|
18
19
|
Object.defineProperty(exports, "sessionMessageSchema", { enumerable: true, get: function () { return sessionEvent_1.sessionMessageSchema; } });
|
|
19
20
|
Object.defineProperty(exports, "sessionEventSchema", { enumerable: true, get: function () { return sessionEvent_1.sessionEventSchema; } });
|
|
20
21
|
Object.defineProperty(exports, "permissionModeSchema", { enumerable: true, get: function () { return sessionEvent_1.permissionModeSchema; } });
|
|
21
22
|
Object.defineProperty(exports, "extractSessionEvents", { enumerable: true, get: function () { return sessionEvent_1.extractSessionEvents; } });
|
|
23
|
+
var observedSessionV1_1 = require("./observedSessionV1");
|
|
24
|
+
Object.defineProperty(exports, "observationProvenanceV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.observationProvenanceV1Schema; } });
|
|
25
|
+
Object.defineProperty(exports, "observedAgentSessionV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.observedAgentSessionV1Schema; } });
|
|
26
|
+
Object.defineProperty(exports, "observedValueV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.observedValueV1Schema; } });
|
|
27
|
+
Object.defineProperty(exports, "pendingUserRequestV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.pendingUserRequestV1Schema; } });
|
|
28
|
+
Object.defineProperty(exports, "providerCapabilitiesV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.providerCapabilitiesV1Schema; } });
|
|
29
|
+
Object.defineProperty(exports, "providerSessionAdapterV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.providerSessionAdapterV1Schema; } });
|
|
30
|
+
Object.defineProperty(exports, "sessionEvidenceRefV1Schema", { enumerable: true, get: function () { return observedSessionV1_1.sessionEvidenceRefV1Schema; } });
|
|
22
31
|
var quota_1 = require("./quota");
|
|
23
32
|
Object.defineProperty(exports, "quotaWindowSchema", { enumerable: true, get: function () { return quota_1.quotaWindowSchema; } });
|
|
24
33
|
Object.defineProperty(exports, "quotaStateSchema", { enumerable: true, get: function () { return quota_1.quotaStateSchema; } });
|