rudel 0.1.7 → 0.1.9
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 +15 -0
- package/dist/cli.js +412 -246
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
CLI for uploading [Claude Code](https://docs.anthropic.com/en/docs/claude-code) session transcripts to [Rudel](https://app.rudel.ai) for analytics.
|
|
4
4
|
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- [Bun](https://bun.sh) runtime installed
|
|
8
|
+
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
7
11
|
```bash
|
|
@@ -65,6 +69,17 @@ Show the currently authenticated user.
|
|
|
65
69
|
|
|
66
70
|
Clear stored credentials.
|
|
67
71
|
|
|
72
|
+
## What Data Is Collected
|
|
73
|
+
|
|
74
|
+
Each uploaded session includes:
|
|
75
|
+
|
|
76
|
+
- Session ID & timestamps (start, last interaction)
|
|
77
|
+
- User ID & organization ID
|
|
78
|
+
- Project path & package name
|
|
79
|
+
- Git context (repository, branch, SHA, remote)
|
|
80
|
+
- Session transcript (full prompt & response content)
|
|
81
|
+
- Sub-agent usage
|
|
82
|
+
|
|
68
83
|
## Links
|
|
69
84
|
|
|
70
85
|
- **Web App**: [app.rudel.ai](https://app.rudel.ai)
|
package/dist/cli.js
CHANGED
|
@@ -1959,7 +1959,7 @@ async function run(app, inputs, context) {
|
|
|
1959
1959
|
// package.json
|
|
1960
1960
|
var package_default = {
|
|
1961
1961
|
name: "rudel",
|
|
1962
|
-
version: "0.1.
|
|
1962
|
+
version: "0.1.9",
|
|
1963
1963
|
type: "module",
|
|
1964
1964
|
description: "CLI for the Coding Agent Analytics Platform rudel.ai",
|
|
1965
1965
|
license: "MIT",
|
|
@@ -5997,9 +5997,9 @@ var RudelClaudeSessionsRowSchema = exports_external.object({
|
|
|
5997
5997
|
session_id: exports_external.string(),
|
|
5998
5998
|
organization_id: exports_external.string(),
|
|
5999
5999
|
project_path: exports_external.string(),
|
|
6000
|
-
repository: exports_external.string().nullable(),
|
|
6001
6000
|
git_remote: exports_external.string(),
|
|
6002
6001
|
package_name: exports_external.string(),
|
|
6002
|
+
package_type: exports_external.string(),
|
|
6003
6003
|
content: exports_external.string(),
|
|
6004
6004
|
ingested_at: exports_external.string(),
|
|
6005
6005
|
user_id: exports_external.string(),
|
|
@@ -6014,7 +6014,9 @@ var RudelCodexSessionsRowSchema = exports_external.object({
|
|
|
6014
6014
|
session_id: exports_external.string(),
|
|
6015
6015
|
organization_id: exports_external.string(),
|
|
6016
6016
|
project_path: exports_external.string(),
|
|
6017
|
-
|
|
6017
|
+
git_remote: exports_external.string(),
|
|
6018
|
+
package_name: exports_external.string(),
|
|
6019
|
+
package_type: exports_external.string(),
|
|
6018
6020
|
content: exports_external.string(),
|
|
6019
6021
|
ingested_at: exports_external.string(),
|
|
6020
6022
|
user_id: exports_external.string(),
|
|
@@ -6028,9 +6030,9 @@ var RudelSessionAnalyticsRowSchema = exports_external.object({
|
|
|
6028
6030
|
session_id: exports_external.string(),
|
|
6029
6031
|
organization_id: exports_external.string(),
|
|
6030
6032
|
project_path: exports_external.string(),
|
|
6031
|
-
repository: exports_external.string().nullable(),
|
|
6032
6033
|
git_remote: exports_external.string(),
|
|
6033
6034
|
package_name: exports_external.string(),
|
|
6035
|
+
package_type: exports_external.string(),
|
|
6034
6036
|
content: exports_external.string(),
|
|
6035
6037
|
subagents: exports_external.record(exports_external.string(), exports_external.string()),
|
|
6036
6038
|
skills: exports_external.array(exports_external.string()),
|
|
@@ -6130,16 +6132,6 @@ function toDisplayPath(absolutePath) {
|
|
|
6130
6132
|
const home = homedir();
|
|
6131
6133
|
return absolutePath.startsWith(home) ? `~${absolutePath.slice(home.length)}` : absolutePath;
|
|
6132
6134
|
}
|
|
6133
|
-
function groupProjectsForCwd(projects, cwd) {
|
|
6134
|
-
const current = projects.filter((p) => p.projectPath === cwd);
|
|
6135
|
-
const currentSet = new Set(current);
|
|
6136
|
-
const subfolders = projects.filter((p) => !currentSet.has(p) && p.projectPath.startsWith(`${cwd}/`));
|
|
6137
|
-
const subfoldersSet = new Set(subfolders);
|
|
6138
|
-
const others = projects.filter((p) => !currentSet.has(p) && !subfoldersSet.has(p));
|
|
6139
|
-
subfolders.sort((a, b) => a.projectPath.localeCompare(b.projectPath));
|
|
6140
|
-
others.sort((a, b) => a.displayPath.localeCompare(b.displayPath));
|
|
6141
|
-
return { current, subfolders, others };
|
|
6142
|
-
}
|
|
6143
6135
|
|
|
6144
6136
|
// ../../packages/agent-adapters/src/adapters/claude-code/settings.ts
|
|
6145
6137
|
import { execSync } from "child_process";
|
|
@@ -6363,9 +6355,9 @@ class ClaudeCodeAdapter {
|
|
|
6363
6355
|
source: this.source,
|
|
6364
6356
|
sessionId: session.sessionId,
|
|
6365
6357
|
projectPath: session.projectPath,
|
|
6366
|
-
repository: context.gitInfo.repository,
|
|
6367
6358
|
gitRemote: context.gitInfo.gitRemote,
|
|
6368
6359
|
packageName: context.gitInfo.packageName,
|
|
6360
|
+
packageType: context.gitInfo.packageType,
|
|
6369
6361
|
gitBranch: context.gitInfo.branch,
|
|
6370
6362
|
gitSha: context.gitInfo.sha,
|
|
6371
6363
|
tag: context.tag,
|
|
@@ -6418,9 +6410,9 @@ class ClaudeCodeAdapter {
|
|
|
6418
6410
|
session_id: input.sessionId,
|
|
6419
6411
|
organization_id: context.organizationId,
|
|
6420
6412
|
project_path: input.projectPath,
|
|
6421
|
-
repository: input.repository ?? null,
|
|
6422
6413
|
git_remote: input.gitRemote ?? "",
|
|
6423
6414
|
package_name: input.packageName ?? "",
|
|
6415
|
+
package_type: input.packageType ?? "",
|
|
6424
6416
|
content: input.content,
|
|
6425
6417
|
subagents,
|
|
6426
6418
|
ingested_at: now,
|
|
@@ -7695,7 +7687,6 @@ class CodexAdapter {
|
|
|
7695
7687
|
source: this.source,
|
|
7696
7688
|
sessionId: session.sessionId,
|
|
7697
7689
|
projectPath: session.projectPath,
|
|
7698
|
-
repository: context.gitInfo.repository,
|
|
7699
7690
|
gitBranch: session.gitBranch ?? context.gitInfo.branch,
|
|
7700
7691
|
gitSha: session.gitSha ?? context.gitInfo.sha,
|
|
7701
7692
|
tag: context.tag,
|
|
@@ -7741,7 +7732,9 @@ class CodexAdapter {
|
|
|
7741
7732
|
session_id: input.sessionId,
|
|
7742
7733
|
organization_id: context.organizationId,
|
|
7743
7734
|
project_path: input.projectPath,
|
|
7744
|
-
|
|
7735
|
+
git_remote: input.gitRemote ?? "",
|
|
7736
|
+
package_name: input.packageName ?? "",
|
|
7737
|
+
package_type: input.packageType ?? "",
|
|
7745
7738
|
content: input.content,
|
|
7746
7739
|
ingested_at: now,
|
|
7747
7740
|
user_id: context.userId,
|
|
@@ -7775,33 +7768,314 @@ function getAvailableAdapters() {
|
|
|
7775
7768
|
registerAdapter(claudeCodeAdapter);
|
|
7776
7769
|
registerAdapter(codexAdapter);
|
|
7777
7770
|
|
|
7778
|
-
// src/
|
|
7779
|
-
|
|
7771
|
+
// src/lib/project-grouping.ts
|
|
7772
|
+
import { homedir as homedir6 } from "os";
|
|
7773
|
+
|
|
7774
|
+
// src/lib/git-info.ts
|
|
7775
|
+
import { join as join6 } from "path";
|
|
7776
|
+
var {$ } = globalThis.Bun;
|
|
7777
|
+
function normalizeRemoteUrl(url) {
|
|
7778
|
+
return url.replace(/^(https?:\/\/|git@|ssh:\/\/)/, "").replace(/:/, "/").replace(/\.git$/, "");
|
|
7779
|
+
}
|
|
7780
|
+
async function getGitInfo(cwd) {
|
|
7781
|
+
const [remoteUrl, branch, sha, packageInfo] = await Promise.all([
|
|
7782
|
+
getGitRemoteUrl(cwd),
|
|
7783
|
+
getGitBranch(cwd),
|
|
7784
|
+
getGitSha(cwd),
|
|
7785
|
+
getPackageInfo(cwd)
|
|
7786
|
+
]);
|
|
7787
|
+
const gitRemote = remoteUrl ? normalizeRemoteUrl(remoteUrl) : undefined;
|
|
7788
|
+
return {
|
|
7789
|
+
gitRemote,
|
|
7790
|
+
packageName: packageInfo?.name,
|
|
7791
|
+
packageType: packageInfo?.type,
|
|
7792
|
+
branch: branch ?? undefined,
|
|
7793
|
+
sha: sha ?? undefined
|
|
7794
|
+
};
|
|
7795
|
+
}
|
|
7796
|
+
async function getPackageInfo(cwd) {
|
|
7797
|
+
try {
|
|
7798
|
+
const gitRootResult = await $`git -C ${cwd} rev-parse --show-toplevel`.quiet();
|
|
7799
|
+
const root = gitRootResult.exitCode === 0 ? gitRootResult.text().trim() : cwd;
|
|
7800
|
+
return await getNodePackage(root) ?? await getPythonPackage(root) ?? await getRustPackage(root) ?? await getGoModule(root);
|
|
7801
|
+
} catch {
|
|
7802
|
+
return null;
|
|
7803
|
+
}
|
|
7804
|
+
}
|
|
7805
|
+
async function getNodePackage(root) {
|
|
7806
|
+
try {
|
|
7807
|
+
const file = Bun.file(join6(root, "package.json"));
|
|
7808
|
+
if (!await file.exists())
|
|
7809
|
+
return null;
|
|
7810
|
+
const pkg = await file.json();
|
|
7811
|
+
return pkg.name ? { name: pkg.name, type: "package.json" } : null;
|
|
7812
|
+
} catch {
|
|
7813
|
+
return null;
|
|
7814
|
+
}
|
|
7815
|
+
}
|
|
7816
|
+
async function getPythonPackage(root) {
|
|
7817
|
+
try {
|
|
7818
|
+
const file = Bun.file(join6(root, "pyproject.toml"));
|
|
7819
|
+
if (!await file.exists())
|
|
7820
|
+
return null;
|
|
7821
|
+
const content = await file.text();
|
|
7822
|
+
const name = content.match(/^\s*name\s*=\s*"([^"]+)"/m)?.[1];
|
|
7823
|
+
return name ? { name, type: "pyproject.toml" } : null;
|
|
7824
|
+
} catch {
|
|
7825
|
+
return null;
|
|
7826
|
+
}
|
|
7827
|
+
}
|
|
7828
|
+
async function getRustPackage(root) {
|
|
7829
|
+
try {
|
|
7830
|
+
const file = Bun.file(join6(root, "Cargo.toml"));
|
|
7831
|
+
if (!await file.exists())
|
|
7832
|
+
return null;
|
|
7833
|
+
const content = await file.text();
|
|
7834
|
+
const name = content.match(/^\s*name\s*=\s*"([^"]+)"/m)?.[1];
|
|
7835
|
+
return name ? { name, type: "Cargo.toml" } : null;
|
|
7836
|
+
} catch {
|
|
7837
|
+
return null;
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
async function getGoModule(root) {
|
|
7841
|
+
try {
|
|
7842
|
+
const file = Bun.file(join6(root, "go.mod"));
|
|
7843
|
+
if (!await file.exists())
|
|
7844
|
+
return null;
|
|
7845
|
+
const content = await file.text();
|
|
7846
|
+
const name = content.match(/^module\s+(\S+)/m)?.[1];
|
|
7847
|
+
return name ? { name, type: "go.mod" } : null;
|
|
7848
|
+
} catch {
|
|
7849
|
+
return null;
|
|
7850
|
+
}
|
|
7851
|
+
}
|
|
7852
|
+
async function getGitRemoteUrl(cwd) {
|
|
7853
|
+
try {
|
|
7854
|
+
const result = await $`git -C ${cwd} remote get-url origin`.quiet();
|
|
7855
|
+
if (result.exitCode !== 0)
|
|
7856
|
+
return null;
|
|
7857
|
+
return result.text().trim() || null;
|
|
7858
|
+
} catch {
|
|
7859
|
+
return null;
|
|
7860
|
+
}
|
|
7861
|
+
}
|
|
7862
|
+
async function getGitBranch(cwd) {
|
|
7863
|
+
try {
|
|
7864
|
+
const result = await $`git -C ${cwd} rev-parse --abbrev-ref HEAD`.quiet();
|
|
7865
|
+
if (result.exitCode !== 0)
|
|
7866
|
+
return null;
|
|
7867
|
+
return result.text().trim();
|
|
7868
|
+
} catch {
|
|
7869
|
+
return null;
|
|
7870
|
+
}
|
|
7871
|
+
}
|
|
7872
|
+
async function getGitSha(cwd) {
|
|
7873
|
+
try {
|
|
7874
|
+
const result = await $`git -C ${cwd} rev-parse HEAD`.quiet();
|
|
7875
|
+
if (result.exitCode !== 0)
|
|
7876
|
+
return null;
|
|
7877
|
+
return result.text().trim();
|
|
7878
|
+
} catch {
|
|
7879
|
+
return null;
|
|
7880
|
+
}
|
|
7881
|
+
}
|
|
7882
|
+
|
|
7883
|
+
// src/lib/remote-cache.ts
|
|
7884
|
+
import { homedir as homedir5 } from "os";
|
|
7885
|
+
import { join as join7 } from "path";
|
|
7886
|
+
var CACHE_PATH = join7(homedir5(), ".rudel", "remote-cache.json");
|
|
7887
|
+
async function getRemoteCache() {
|
|
7888
|
+
try {
|
|
7889
|
+
const file = Bun.file(CACHE_PATH);
|
|
7890
|
+
if (!await file.exists())
|
|
7891
|
+
return {};
|
|
7892
|
+
return await file.json();
|
|
7893
|
+
} catch {
|
|
7894
|
+
return {};
|
|
7895
|
+
}
|
|
7896
|
+
}
|
|
7897
|
+
function getCachedRemote(cache, encodedDir) {
|
|
7898
|
+
return cache[encodedDir] ?? null;
|
|
7899
|
+
}
|
|
7900
|
+
function cacheRemote(cache, encodedDir, normalizedRemote) {
|
|
7901
|
+
cache[encodedDir] = normalizedRemote;
|
|
7902
|
+
}
|
|
7903
|
+
async function cacheRemotes(cache) {
|
|
7904
|
+
try {
|
|
7905
|
+
const { mkdir } = await import("fs/promises");
|
|
7906
|
+
const { dirname: dirname3 } = await import("path");
|
|
7907
|
+
await mkdir(dirname3(CACHE_PATH), { recursive: true });
|
|
7908
|
+
await Bun.write(CACHE_PATH, JSON.stringify(cache));
|
|
7909
|
+
} catch {}
|
|
7910
|
+
}
|
|
7911
|
+
|
|
7912
|
+
// src/lib/project-grouping.ts
|
|
7913
|
+
async function scanAndGroupProjects(cwd = process.cwd()) {
|
|
7780
7914
|
const adapters2 = getAvailableAdapters();
|
|
7781
|
-
const
|
|
7915
|
+
const projects = [];
|
|
7782
7916
|
for (const adapter of adapters2) {
|
|
7783
|
-
const
|
|
7784
|
-
|
|
7917
|
+
const scanned = await adapter.scanAllSessions();
|
|
7918
|
+
projects.push(...scanned);
|
|
7785
7919
|
}
|
|
7920
|
+
const groups = await groupProjectsByRemote(projects, cwd);
|
|
7921
|
+
return { projects, groups };
|
|
7922
|
+
}
|
|
7923
|
+
function extractDisplayName(normalized) {
|
|
7924
|
+
const parts = normalized.split("/");
|
|
7925
|
+
if (parts.length >= 3) {
|
|
7926
|
+
return parts.slice(1).join("/");
|
|
7927
|
+
}
|
|
7928
|
+
return normalized;
|
|
7929
|
+
}
|
|
7930
|
+
function encodeProjectPath2(projectPath) {
|
|
7931
|
+
return projectPath.replace(/\//g, "-");
|
|
7932
|
+
}
|
|
7933
|
+
async function groupProjectsByRemote(projects, cwd) {
|
|
7934
|
+
const cache = await getRemoteCache();
|
|
7935
|
+
let cacheUpdated = false;
|
|
7936
|
+
const remotes = await Promise.all(projects.map((p) => getGitRemoteUrl(p.projectPath)));
|
|
7937
|
+
const grouped = new Map;
|
|
7938
|
+
const ungrouped = [];
|
|
7939
|
+
for (let i = 0;i < projects.length; i++) {
|
|
7940
|
+
const project = projects[i];
|
|
7941
|
+
const remote = remotes[i];
|
|
7942
|
+
if (remote) {
|
|
7943
|
+
const normalized = normalizeRemoteUrl(remote);
|
|
7944
|
+
const encodedDir = encodeProjectPath2(project.projectPath);
|
|
7945
|
+
if (getCachedRemote(cache, encodedDir) !== normalized) {
|
|
7946
|
+
cacheRemote(cache, encodedDir, normalized);
|
|
7947
|
+
cacheUpdated = true;
|
|
7948
|
+
}
|
|
7949
|
+
const existing = grouped.get(normalized);
|
|
7950
|
+
if (existing) {
|
|
7951
|
+
existing.projects.push(project);
|
|
7952
|
+
} else {
|
|
7953
|
+
grouped.set(normalized, { remote: normalized, projects: [project] });
|
|
7954
|
+
}
|
|
7955
|
+
} else {
|
|
7956
|
+
const encodedDir = encodeProjectPath2(project.projectPath);
|
|
7957
|
+
const cached = getCachedRemote(cache, encodedDir);
|
|
7958
|
+
if (cached) {
|
|
7959
|
+
const existing = grouped.get(cached);
|
|
7960
|
+
if (existing) {
|
|
7961
|
+
existing.projects.push(project);
|
|
7962
|
+
} else {
|
|
7963
|
+
grouped.set(cached, { remote: cached, projects: [project] });
|
|
7964
|
+
}
|
|
7965
|
+
} else {
|
|
7966
|
+
ungrouped.push(project);
|
|
7967
|
+
}
|
|
7968
|
+
}
|
|
7969
|
+
}
|
|
7970
|
+
const groups = [];
|
|
7971
|
+
for (const [, entry] of grouped) {
|
|
7972
|
+
const containsCwd = entry.projects.some((p) => cwd === p.projectPath || cwd.startsWith(`${p.projectPath}/`));
|
|
7973
|
+
groups.push({
|
|
7974
|
+
displayName: extractDisplayName(entry.remote),
|
|
7975
|
+
gitRemote: entry.remote,
|
|
7976
|
+
projects: entry.projects,
|
|
7977
|
+
totalSessions: entry.projects.reduce((s, p) => s + p.sessionCount, 0),
|
|
7978
|
+
containsCwd
|
|
7979
|
+
});
|
|
7980
|
+
}
|
|
7981
|
+
const homeSegments = homedir6().split("/").length;
|
|
7982
|
+
const remainingUngrouped = [];
|
|
7983
|
+
for (const project of ungrouped) {
|
|
7984
|
+
const match = findBestGroupByPath(project, groups, homeSegments);
|
|
7985
|
+
if (match) {
|
|
7986
|
+
match.projects.push(project);
|
|
7987
|
+
match.totalSessions += project.sessionCount;
|
|
7988
|
+
if (cwd === project.projectPath || cwd.startsWith(`${project.projectPath}/`)) {
|
|
7989
|
+
match.containsCwd = true;
|
|
7990
|
+
}
|
|
7991
|
+
} else {
|
|
7992
|
+
remainingUngrouped.push(project);
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7995
|
+
for (const project of remainingUngrouped) {
|
|
7996
|
+
const containsCwd = cwd === project.projectPath || cwd.startsWith(`${project.projectPath}/`);
|
|
7997
|
+
groups.push({
|
|
7998
|
+
displayName: project.displayPath,
|
|
7999
|
+
gitRemote: null,
|
|
8000
|
+
projects: [project],
|
|
8001
|
+
totalSessions: project.sessionCount,
|
|
8002
|
+
containsCwd
|
|
8003
|
+
});
|
|
8004
|
+
}
|
|
8005
|
+
groups.sort((a, b) => {
|
|
8006
|
+
if (a.containsCwd !== b.containsCwd)
|
|
8007
|
+
return a.containsCwd ? -1 : 1;
|
|
8008
|
+
const aHasRemote = a.gitRemote !== null;
|
|
8009
|
+
const bHasRemote = b.gitRemote !== null;
|
|
8010
|
+
if (aHasRemote !== bHasRemote)
|
|
8011
|
+
return aHasRemote ? -1 : 1;
|
|
8012
|
+
return a.displayName.localeCompare(b.displayName);
|
|
8013
|
+
});
|
|
8014
|
+
if (cacheUpdated) {
|
|
8015
|
+
cacheRemotes(cache);
|
|
8016
|
+
}
|
|
8017
|
+
return groups;
|
|
8018
|
+
}
|
|
8019
|
+
function commonPrefixLength(a, b) {
|
|
8020
|
+
const partsA = a.split("/");
|
|
8021
|
+
const partsB = b.split("/");
|
|
8022
|
+
let count = 0;
|
|
8023
|
+
for (let i = 0;i < Math.min(partsA.length, partsB.length); i++) {
|
|
8024
|
+
if (partsA[i] === partsB[i])
|
|
8025
|
+
count++;
|
|
8026
|
+
else
|
|
8027
|
+
break;
|
|
8028
|
+
}
|
|
8029
|
+
return count;
|
|
8030
|
+
}
|
|
8031
|
+
function findBestGroupByPath(project, groups, homeSegments) {
|
|
8032
|
+
let bestGroup = null;
|
|
8033
|
+
let bestLen = 0;
|
|
8034
|
+
let secondBestLen = 0;
|
|
8035
|
+
for (const group2 of groups) {
|
|
8036
|
+
if (!group2.gitRemote)
|
|
8037
|
+
continue;
|
|
8038
|
+
let groupBest = 0;
|
|
8039
|
+
for (const p of group2.projects) {
|
|
8040
|
+
groupBest = Math.max(groupBest, commonPrefixLength(project.projectPath, p.projectPath));
|
|
8041
|
+
}
|
|
8042
|
+
if (groupBest > bestLen) {
|
|
8043
|
+
secondBestLen = bestLen;
|
|
8044
|
+
bestLen = groupBest;
|
|
8045
|
+
bestGroup = group2;
|
|
8046
|
+
} else if (groupBest > secondBestLen) {
|
|
8047
|
+
secondBestLen = groupBest;
|
|
8048
|
+
}
|
|
8049
|
+
}
|
|
8050
|
+
if (bestGroup && bestLen > homeSegments && bestLen > secondBestLen) {
|
|
8051
|
+
return bestGroup;
|
|
8052
|
+
}
|
|
8053
|
+
return null;
|
|
8054
|
+
}
|
|
8055
|
+
|
|
8056
|
+
// src/commands/dev/list-sessions.ts
|
|
8057
|
+
async function runListSessions() {
|
|
8058
|
+
const { projects: allProjects, groups } = await scanAndGroupProjects();
|
|
7786
8059
|
if (allProjects.length === 0) {
|
|
7787
8060
|
console.log("No projects with sessions found.");
|
|
7788
8061
|
return;
|
|
7789
8062
|
}
|
|
7790
|
-
const cwd = process.cwd();
|
|
7791
|
-
const grouped = groupProjectsForCwd(allProjects, cwd);
|
|
7792
8063
|
const lines = [];
|
|
7793
|
-
for (const
|
|
7794
|
-
const
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
const
|
|
7804
|
-
|
|
8064
|
+
for (const group2 of groups) {
|
|
8065
|
+
const isCurrent = group2.containsCwd ? " [current]" : "";
|
|
8066
|
+
if (group2.projects.length === 1) {
|
|
8067
|
+
const proj = group2.projects[0];
|
|
8068
|
+
const name = getAdapter(proj.source).name;
|
|
8069
|
+
lines.push(`[${name}] ${proj.displayPath} (${proj.sessionCount} sessions)${isCurrent}`);
|
|
8070
|
+
continue;
|
|
8071
|
+
}
|
|
8072
|
+
const totalSessions2 = group2.projects.reduce((s, p) => s + p.sessionCount, 0);
|
|
8073
|
+
lines.push(`${group2.displayName} (${group2.projects.length} projects, ${totalSessions2} sessions)${isCurrent}`);
|
|
8074
|
+
for (const proj of group2.projects) {
|
|
8075
|
+
const name = getAdapter(proj.source).name;
|
|
8076
|
+
const cwdMarker = proj.projectPath === process.cwd() ? " [cwd]" : "";
|
|
8077
|
+
lines.push(` [${name}] ${proj.displayPath} (${proj.sessionCount} sessions)${cwdMarker}`);
|
|
8078
|
+
}
|
|
7805
8079
|
}
|
|
7806
8080
|
const totalSessions = allProjects.reduce((s, p) => s + p.sessionCount, 0);
|
|
7807
8081
|
console.log(`${allProjects.length} projects, ${totalSessions} sessions
|
|
@@ -7860,8 +8134,8 @@ var X = (t, e = {}, s = {}) => {
|
|
|
7860
8134
|
const ut = t.slice(C, w) || t.slice(h, o);
|
|
7861
8135
|
v = 0;
|
|
7862
8136
|
for (const Y of ut.replaceAll(ct, "")) {
|
|
7863
|
-
const $ = Y.codePointAt(0) || 0;
|
|
7864
|
-
if (lt($) ? f = m : ht($) ? f = V : E !== A && at($) ? f = E : f = A, c + f > b && (d = Math.min(d, Math.max(C, h) + v)), c + f > i) {
|
|
8137
|
+
const $2 = Y.codePointAt(0) || 0;
|
|
8138
|
+
if (lt($2) ? f = m : ht($2) ? f = V : E !== A && at($2) ? f = E : f = A, c + f > b && (d = Math.min(d, Math.max(C, h) + v)), c + f > i) {
|
|
7865
8139
|
F = true;
|
|
7866
8140
|
break t;
|
|
7867
8141
|
}
|
|
@@ -8498,15 +8772,15 @@ var Fe = /\p{M}+/gu;
|
|
|
8498
8772
|
var ye = { limit: 1 / 0, ellipsis: "" };
|
|
8499
8773
|
var jt = (t, r = {}, s = {}) => {
|
|
8500
8774
|
const i = r.limit ?? 1 / 0, a = r.ellipsis ?? "", o = r?.ellipsisWidth ?? (a ? jt(a, ye, s).width : 0), u = s.ansiWidth ?? 0, l = s.controlWidth ?? 0, n = s.tabWidth ?? 8, c = s.ambiguousWidth ?? 1, g = s.emojiWidth ?? 2, F = s.fullWidthWidth ?? 2, p = s.regularWidth ?? 1, E = s.wideWidth ?? 2;
|
|
8501
|
-
let $ = 0, m = 0, h = t.length, y2 = 0, f = false, v = h, S2 = Math.max(0, i - o), I2 = 0, B2 = 0, A = 0, w = 0;
|
|
8775
|
+
let $2 = 0, m = 0, h = t.length, y2 = 0, f = false, v = h, S2 = Math.max(0, i - o), I2 = 0, B2 = 0, A = 0, w = 0;
|
|
8502
8776
|
t:
|
|
8503
8777
|
for (;; ) {
|
|
8504
|
-
if (B2 > I2 || m >= h && m > $) {
|
|
8505
|
-
const _2 = t.slice(I2, B2) || t.slice(
|
|
8778
|
+
if (B2 > I2 || m >= h && m > $2) {
|
|
8779
|
+
const _2 = t.slice(I2, B2) || t.slice($2, m);
|
|
8506
8780
|
y2 = 0;
|
|
8507
8781
|
for (const D2 of _2.replaceAll(Fe, "")) {
|
|
8508
8782
|
const T2 = D2.codePointAt(0) || 0;
|
|
8509
|
-
if (ge(T2) ? w = F : fe(T2) ? w = E : c !== p && pe(T2) ? w = c : w = p, A + w > S2 && (v = Math.min(v, Math.max(I2, $) + y2)), A + w > i) {
|
|
8783
|
+
if (ge(T2) ? w = F : fe(T2) ? w = E : c !== p && pe(T2) ? w = c : w = p, A + w > S2 && (v = Math.min(v, Math.max(I2, $2) + y2)), A + w > i) {
|
|
8510
8784
|
f = true;
|
|
8511
8785
|
break t;
|
|
8512
8786
|
}
|
|
@@ -8521,7 +8795,7 @@ var jt = (t, r = {}, s = {}) => {
|
|
|
8521
8795
|
f = true;
|
|
8522
8796
|
break;
|
|
8523
8797
|
}
|
|
8524
|
-
A += w, I2 =
|
|
8798
|
+
A += w, I2 = $2, B2 = m, m = $2 = at2.lastIndex;
|
|
8525
8799
|
continue;
|
|
8526
8800
|
}
|
|
8527
8801
|
if (At2.lastIndex = m, At2.test(t)) {
|
|
@@ -8529,7 +8803,7 @@ var jt = (t, r = {}, s = {}) => {
|
|
|
8529
8803
|
f = true;
|
|
8530
8804
|
break;
|
|
8531
8805
|
}
|
|
8532
|
-
A += u, I2 =
|
|
8806
|
+
A += u, I2 = $2, B2 = m, m = $2 = At2.lastIndex;
|
|
8533
8807
|
continue;
|
|
8534
8808
|
}
|
|
8535
8809
|
if (it2.lastIndex = m, it2.test(t)) {
|
|
@@ -8537,7 +8811,7 @@ var jt = (t, r = {}, s = {}) => {
|
|
|
8537
8811
|
f = true;
|
|
8538
8812
|
break;
|
|
8539
8813
|
}
|
|
8540
|
-
A += w, I2 =
|
|
8814
|
+
A += w, I2 = $2, B2 = m, m = $2 = it2.lastIndex;
|
|
8541
8815
|
continue;
|
|
8542
8816
|
}
|
|
8543
8817
|
if (nt2.lastIndex = m, nt2.test(t)) {
|
|
@@ -8545,7 +8819,7 @@ var jt = (t, r = {}, s = {}) => {
|
|
|
8545
8819
|
f = true;
|
|
8546
8820
|
break;
|
|
8547
8821
|
}
|
|
8548
|
-
A += w, I2 =
|
|
8822
|
+
A += w, I2 = $2, B2 = m, m = $2 = nt2.lastIndex;
|
|
8549
8823
|
continue;
|
|
8550
8824
|
}
|
|
8551
8825
|
if (wt2.lastIndex = m, wt2.test(t)) {
|
|
@@ -8553,7 +8827,7 @@ var jt = (t, r = {}, s = {}) => {
|
|
|
8553
8827
|
f = true;
|
|
8554
8828
|
break;
|
|
8555
8829
|
}
|
|
8556
|
-
A += g, I2 =
|
|
8830
|
+
A += g, I2 = $2, B2 = m, m = $2 = wt2.lastIndex;
|
|
8557
8831
|
continue;
|
|
8558
8832
|
}
|
|
8559
8833
|
m += 1;
|
|
@@ -8616,34 +8890,34 @@ var Ie = (t, r, s = {}) => {
|
|
|
8616
8890
|
let i = "", a, o;
|
|
8617
8891
|
const u = t.split(" "), l = Ce(u);
|
|
8618
8892
|
let n = [""];
|
|
8619
|
-
for (const [
|
|
8893
|
+
for (const [$2, m] of u.entries()) {
|
|
8620
8894
|
s.trim !== false && (n[n.length - 1] = (n.at(-1) ?? "").trimStart());
|
|
8621
8895
|
let h = M2(n.at(-1) ?? "");
|
|
8622
|
-
if ($ !== 0 && (h >= r && (s.wordWrap === false || s.trim === false) && (n.push(""), h = 0), (h > 0 || s.trim === false) && (n[n.length - 1] += " ", h++)), s.hard && l[$] > r) {
|
|
8623
|
-
const y2 = r - h, f = 1 + Math.floor((l[$] - y2 - 1) / r);
|
|
8624
|
-
Math.floor((l[$] - 1) / r) < f && n.push(""), It2(n, m, r);
|
|
8896
|
+
if ($2 !== 0 && (h >= r && (s.wordWrap === false || s.trim === false) && (n.push(""), h = 0), (h > 0 || s.trim === false) && (n[n.length - 1] += " ", h++)), s.hard && l[$2] > r) {
|
|
8897
|
+
const y2 = r - h, f = 1 + Math.floor((l[$2] - y2 - 1) / r);
|
|
8898
|
+
Math.floor((l[$2] - 1) / r) < f && n.push(""), It2(n, m, r);
|
|
8625
8899
|
continue;
|
|
8626
8900
|
}
|
|
8627
|
-
if (h + l[$] > r && h > 0 && l[$] > 0) {
|
|
8901
|
+
if (h + l[$2] > r && h > 0 && l[$2] > 0) {
|
|
8628
8902
|
if (s.wordWrap === false && h < r) {
|
|
8629
8903
|
It2(n, m, r);
|
|
8630
8904
|
continue;
|
|
8631
8905
|
}
|
|
8632
8906
|
n.push("");
|
|
8633
8907
|
}
|
|
8634
|
-
if (h + l[$] > r && s.wordWrap === false) {
|
|
8908
|
+
if (h + l[$2] > r && s.wordWrap === false) {
|
|
8635
8909
|
It2(n, m, r);
|
|
8636
8910
|
continue;
|
|
8637
8911
|
}
|
|
8638
8912
|
n[n.length - 1] += m;
|
|
8639
8913
|
}
|
|
8640
|
-
s.trim !== false && (n = n.map(($) => Se($)));
|
|
8914
|
+
s.trim !== false && (n = n.map(($2) => Se($2)));
|
|
8641
8915
|
const c = n.join(`
|
|
8642
8916
|
`), g = c[Symbol.iterator]();
|
|
8643
8917
|
let F = g.next(), p = g.next(), E = 0;
|
|
8644
8918
|
for (;!F.done; ) {
|
|
8645
|
-
const $ = F.value, m = p.value;
|
|
8646
|
-
if (i +=
|
|
8919
|
+
const $2 = F.value, m = p.value;
|
|
8920
|
+
if (i += $2, $2 === ot2 || $2 === Gt) {
|
|
8647
8921
|
Ht.lastIndex = E + 1;
|
|
8648
8922
|
const f = Ht.exec(c)?.groups;
|
|
8649
8923
|
if (f?.code !== undefined) {
|
|
@@ -8654,8 +8928,8 @@ var Ie = (t, r, s = {}) => {
|
|
|
8654
8928
|
}
|
|
8655
8929
|
const h = a ? we(a) : undefined;
|
|
8656
8930
|
m === `
|
|
8657
|
-
` ? (o && (i += Kt("")), a && h && (i += Ut(h))) : $ === `
|
|
8658
|
-
` && (a && h && (i += Ut(a)), o && (i += Kt(o))), E +=
|
|
8931
|
+
` ? (o && (i += Kt("")), a && h && (i += Ut(h))) : $2 === `
|
|
8932
|
+
` && (a && h && (i += Ut(a)), o && (i += Kt(o))), E += $2.length, F = p, p = g.next();
|
|
8659
8933
|
}
|
|
8660
8934
|
return i;
|
|
8661
8935
|
};
|
|
@@ -8677,13 +8951,13 @@ var be = (t, r, s, i, a) => {
|
|
|
8677
8951
|
};
|
|
8678
8952
|
var X2 = (t) => {
|
|
8679
8953
|
const { cursor: r, options: s, style: i } = t, a = t.output ?? process.stdout, o = rt(a), u = t.columnPadding ?? 0, l = t.rowPadding ?? 4, n = o - u, c = nt(a), g = import_picocolors2.default.dim("..."), F = t.maxItems ?? Number.POSITIVE_INFINITY, p = Math.max(c - l, 0), E = Math.max(Math.min(F, p), 5);
|
|
8680
|
-
let $ = 0;
|
|
8681
|
-
r >= E - 3 && ($ = Math.max(Math.min(r - E + 3, s.length - E), 0));
|
|
8682
|
-
let m = E < s.length && $ > 0, h = E < s.length && $ + E < s.length;
|
|
8683
|
-
const y2 = Math.min($ + E, s.length), f = [];
|
|
8954
|
+
let $2 = 0;
|
|
8955
|
+
r >= E - 3 && ($2 = Math.max(Math.min(r - E + 3, s.length - E), 0));
|
|
8956
|
+
let m = E < s.length && $2 > 0, h = E < s.length && $2 + E < s.length;
|
|
8957
|
+
const y2 = Math.min($2 + E, s.length), f = [];
|
|
8684
8958
|
let v = 0;
|
|
8685
8959
|
m && v++, h && v++;
|
|
8686
|
-
const S2 = $ + (m ? 1 : 0), I2 = y2 - (h ? 1 : 0);
|
|
8960
|
+
const S2 = $2 + (m ? 1 : 0), I2 = y2 - (h ? 1 : 0);
|
|
8687
8961
|
for (let A = S2;A < I2; A++) {
|
|
8688
8962
|
const w = J2(i(s[A], A === r), n, { hard: true, trim: false }).split(`
|
|
8689
8963
|
`);
|
|
@@ -8709,8 +8983,8 @@ function Yt(t, r, s, i) {
|
|
|
8709
8983
|
}
|
|
8710
8984
|
var Te = (t) => t;
|
|
8711
8985
|
var Me = (t = "", r = "", s) => {
|
|
8712
|
-
const i = s?.output ?? process.stdout, a = rt(i), o = 2, u = s?.titlePadding ?? 1, l = s?.contentPadding ?? 2, n = s?.width === undefined || s.width === "auto" ? 1 : Math.min(1, s.width), c = s?.withGuide ?? _.withGuide ? `${d} ` : "", g = s?.formatBorder ?? Te, F = ((s?.rounded) ? _e : De).map(g), p = g(rt2), E = g(d), $ = M2(c), m = M2(r), h = a -
|
|
8713
|
-
let y2 = Math.floor(a * n) -
|
|
8986
|
+
const i = s?.output ?? process.stdout, a = rt(i), o = 2, u = s?.titlePadding ?? 1, l = s?.contentPadding ?? 2, n = s?.width === undefined || s.width === "auto" ? 1 : Math.min(1, s.width), c = s?.withGuide ?? _.withGuide ? `${d} ` : "", g = s?.formatBorder ?? Te, F = ((s?.rounded) ? _e : De).map(g), p = g(rt2), E = g(d), $2 = M2(c), m = M2(r), h = a - $2;
|
|
8987
|
+
let y2 = Math.floor(a * n) - $2;
|
|
8714
8988
|
if (s?.width === "auto") {
|
|
8715
8989
|
const _2 = t.split(`
|
|
8716
8990
|
`);
|
|
@@ -8772,8 +9046,8 @@ var R2 = { message: (t = [], { symbol: r = import_picocolors2.default.gray(d), s
|
|
|
8772
9046
|
if (F.length > 0) {
|
|
8773
9047
|
const [p, ...E] = F;
|
|
8774
9048
|
p.length > 0 ? u.push(`${c}${p}`) : u.push(l ? r : "");
|
|
8775
|
-
for (const $ of E)
|
|
8776
|
-
|
|
9049
|
+
for (const $2 of E)
|
|
9050
|
+
$2.length > 0 ? u.push(`${g}${$2}`) : u.push(l ? s : "");
|
|
8777
9051
|
}
|
|
8778
9052
|
i.write(`${u.join(`
|
|
8779
9053
|
`)}
|
|
@@ -8865,7 +9139,7 @@ ${import_picocolors2.default.cyan(x2)}
|
|
|
8865
9139
|
var Ke = import_picocolors2.default.magenta;
|
|
8866
9140
|
var bt2 = ({ indicator: t = "dots", onCancel: r, output: s = process.stdout, cancelMessage: i, errorMessage: a, frames: o = et2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: u = et2 ? 80 : 120, signal: l, ...n } = {}) => {
|
|
8867
9141
|
const c = ct2();
|
|
8868
|
-
let g, F, p = false, E = false, $ = "", m, h = performance.now();
|
|
9142
|
+
let g, F, p = false, E = false, $2 = "", m, h = performance.now();
|
|
8869
9143
|
const y2 = rt(s), f = n?.styleFrame ?? Ke, v = (b) => {
|
|
8870
9144
|
const O2 = b > 1 ? a ?? _.messages.error : i ?? _.messages.cancel;
|
|
8871
9145
|
E = b === 1, p && (L2(O2, b), E && typeof r == "function" && r());
|
|
@@ -8885,22 +9159,22 @@ var bt2 = ({ indicator: t = "dots", onCancel: r, output: s = process.stdout, can
|
|
|
8885
9159
|
const O2 = (performance.now() - b) / 1000, j2 = Math.floor(O2 / 60), G2 = Math.floor(O2 % 60);
|
|
8886
9160
|
return j2 > 0 ? `[${j2}m ${G2}s]` : `[${G2}s]`;
|
|
8887
9161
|
}, T2 = n.withGuide ?? _.withGuide, Y = (b = "") => {
|
|
8888
|
-
p = true, g = Bt({ output: s }), $ = _2(b), h = performance.now(), T2 && s.write(`${import_picocolors2.default.gray(d)}
|
|
9162
|
+
p = true, g = Bt({ output: s }), $2 = _2(b), h = performance.now(), T2 && s.write(`${import_picocolors2.default.gray(d)}
|
|
8889
9163
|
`);
|
|
8890
9164
|
let O2 = 0, j2 = 0;
|
|
8891
9165
|
B2(), F = setInterval(() => {
|
|
8892
|
-
if (c && $ === m)
|
|
9166
|
+
if (c && $2 === m)
|
|
8893
9167
|
return;
|
|
8894
|
-
w(), m =
|
|
9168
|
+
w(), m = $2;
|
|
8895
9169
|
const G2 = f(o[O2]);
|
|
8896
9170
|
let tt2;
|
|
8897
9171
|
if (c)
|
|
8898
|
-
tt2 = `${G2} ${$}...`;
|
|
9172
|
+
tt2 = `${G2} ${$2}...`;
|
|
8899
9173
|
else if (t === "timer")
|
|
8900
|
-
tt2 = `${G2} ${$} ${D2(h)}`;
|
|
9174
|
+
tt2 = `${G2} ${$2} ${D2(h)}`;
|
|
8901
9175
|
else {
|
|
8902
9176
|
const te = ".".repeat(Math.floor(j2)).slice(0, 3);
|
|
8903
|
-
tt2 = `${G2} ${$}${te}`;
|
|
9177
|
+
tt2 = `${G2} ${$2}${te}`;
|
|
8904
9178
|
}
|
|
8905
9179
|
const Zt = J2(tt2, y2, { hard: true, trim: false });
|
|
8906
9180
|
s.write(Zt), O2 = O2 + 1 < o.length ? O2 + 1 : 0, j2 = j2 < 4 ? j2 + 0.125 : 0;
|
|
@@ -8910,12 +9184,12 @@ var bt2 = ({ indicator: t = "dots", onCancel: r, output: s = process.stdout, can
|
|
|
8910
9184
|
return;
|
|
8911
9185
|
p = false, clearInterval(F), w();
|
|
8912
9186
|
const G2 = O2 === 0 ? import_picocolors2.default.green(V) : O2 === 1 ? import_picocolors2.default.red(dt2) : import_picocolors2.default.red($t2);
|
|
8913
|
-
$ = b ??
|
|
8914
|
-
`) : s.write(`${G2} ${$}
|
|
9187
|
+
$2 = b ?? $2, j2 || (t === "timer" ? s.write(`${G2} ${$2} ${D2(h)}
|
|
9188
|
+
`) : s.write(`${G2} ${$2}
|
|
8915
9189
|
`)), A(), g();
|
|
8916
9190
|
};
|
|
8917
9191
|
return { start: Y, stop: (b = "") => L2(b, 0), message: (b = "") => {
|
|
8918
|
-
$ = _2(b ?? $);
|
|
9192
|
+
$2 = _2(b ?? $2);
|
|
8919
9193
|
}, cancel: (b = "") => L2(b, 1), error: (b = "") => L2(b, 2), clear: () => L2("", 0, true), get isCancelled() {
|
|
8920
9194
|
return E;
|
|
8921
9195
|
} };
|
|
@@ -8937,13 +9211,13 @@ function qe({ style: t = "heavy", max: r = 100, size: s = 40, ...i } = {}) {
|
|
|
8937
9211
|
default:
|
|
8938
9212
|
return import_picocolors2.default.magenta;
|
|
8939
9213
|
}
|
|
8940
|
-
}, g = (E, $) => {
|
|
9214
|
+
}, g = (E, $2) => {
|
|
8941
9215
|
const m = Math.floor(o / l * n);
|
|
8942
|
-
return `${c(E)(zt[t].repeat(m))}${import_picocolors2.default.dim(zt[t].repeat(n - m))} ${$}`;
|
|
9216
|
+
return `${c(E)(zt[t].repeat(m))}${import_picocolors2.default.dim(zt[t].repeat(n - m))} ${$2}`;
|
|
8943
9217
|
}, F = (E = "") => {
|
|
8944
9218
|
u = E, a.start(g("initial", E));
|
|
8945
|
-
}, p = (E = 1, $) => {
|
|
8946
|
-
o = Math.min(l, E + o), a.message(g("active", $ ?? u)), u = $ ?? u;
|
|
9219
|
+
}, p = (E = 1, $2) => {
|
|
9220
|
+
o = Math.min(l, E + o), a.message(g("active", $2 ?? u)), u = $2 ?? u;
|
|
8947
9221
|
};
|
|
8948
9222
|
return { start: F, stop: a.stop, cancel: a.cancel, error: a.error, clear: a.clear, advance: p, isCancelled: a.isCancelled, message: (E) => p(0, E) };
|
|
8949
9223
|
}
|
|
@@ -10502,13 +10776,13 @@ import {
|
|
|
10502
10776
|
rmSync,
|
|
10503
10777
|
writeFileSync as writeFileSync3
|
|
10504
10778
|
} from "fs";
|
|
10505
|
-
import { homedir as
|
|
10506
|
-
import { join as
|
|
10779
|
+
import { homedir as homedir7 } from "os";
|
|
10780
|
+
import { join as join8 } from "path";
|
|
10507
10781
|
function getConfigDir() {
|
|
10508
|
-
return process.env.RUDEL_CONFIG_DIR ??
|
|
10782
|
+
return process.env.RUDEL_CONFIG_DIR ?? join8(homedir7(), ".rudel");
|
|
10509
10783
|
}
|
|
10510
10784
|
function getCredentialsPath() {
|
|
10511
|
-
return
|
|
10785
|
+
return join8(getConfigDir(), "credentials.json");
|
|
10512
10786
|
}
|
|
10513
10787
|
function saveCredentials(token, apiBaseUrl) {
|
|
10514
10788
|
const dir = getConfigDir();
|
|
@@ -10691,8 +10965,8 @@ async function pMap(iterable, mapper, {
|
|
|
10691
10965
|
var pMapSkip = Symbol("skip");
|
|
10692
10966
|
|
|
10693
10967
|
// src/lib/failed-uploads.ts
|
|
10694
|
-
import { homedir as
|
|
10695
|
-
import { join as
|
|
10968
|
+
import { homedir as homedir8 } from "os";
|
|
10969
|
+
import { join as join9 } from "path";
|
|
10696
10970
|
|
|
10697
10971
|
// ../../node_modules/.bun/@orpc+contract@1.13.6/node_modules/@orpc/contract/dist/shared/contract.D_dZrO__.mjs
|
|
10698
10972
|
function mergeErrorMap(errorMap1, errorMap2) {
|
|
@@ -10867,7 +11141,8 @@ var OverviewKPIsSchema = exports_external.object({
|
|
|
10867
11141
|
distinct_projects: exports_external.number(),
|
|
10868
11142
|
distinct_subagents: exports_external.number(),
|
|
10869
11143
|
distinct_skills: exports_external.number(),
|
|
10870
|
-
distinct_slash_commands: exports_external.number()
|
|
11144
|
+
distinct_slash_commands: exports_external.number(),
|
|
11145
|
+
total_sessions: exports_external.number()
|
|
10871
11146
|
});
|
|
10872
11147
|
var UsageTrendDataSchema = exports_external.object({
|
|
10873
11148
|
date: exports_external.string(),
|
|
@@ -10946,6 +11221,8 @@ var DeveloperSessionSchema = exports_external.object({
|
|
|
10946
11221
|
session_id: exports_external.string(),
|
|
10947
11222
|
session_date: exports_external.string(),
|
|
10948
11223
|
project_path: exports_external.string(),
|
|
11224
|
+
git_remote: exports_external.string().optional(),
|
|
11225
|
+
package_name: exports_external.string().optional(),
|
|
10949
11226
|
duration_min: exports_external.number(),
|
|
10950
11227
|
total_tokens: exports_external.number(),
|
|
10951
11228
|
has_subagents: exports_external.boolean(),
|
|
@@ -10956,6 +11233,8 @@ var DeveloperSessionSchema = exports_external.object({
|
|
|
10956
11233
|
});
|
|
10957
11234
|
var DeveloperProjectSchema = exports_external.object({
|
|
10958
11235
|
project_path: exports_external.string(),
|
|
11236
|
+
git_remote: exports_external.string().optional(),
|
|
11237
|
+
package_name: exports_external.string().optional(),
|
|
10959
11238
|
sessions: exports_external.number(),
|
|
10960
11239
|
total_duration_min: exports_external.number(),
|
|
10961
11240
|
total_tokens: exports_external.number(),
|
|
@@ -11274,10 +11553,6 @@ var LearningsTrendDataPointSchema = exports_external.record(exports_external.str
|
|
|
11274
11553
|
var LearningsTrendInputSchema = DaysInputSchema.extend({
|
|
11275
11554
|
splitBy: exports_external.enum(["user_id", "repository"])
|
|
11276
11555
|
});
|
|
11277
|
-
var UserMappingSchema = exports_external.object({
|
|
11278
|
-
user_id: exports_external.string(),
|
|
11279
|
-
username: exports_external.string()
|
|
11280
|
-
});
|
|
11281
11556
|
// ../../packages/api-routes/src/index.ts
|
|
11282
11557
|
var HealthSchema = exports_external.object({
|
|
11283
11558
|
status: exports_external.literal("ok"),
|
|
@@ -11313,9 +11588,9 @@ var IngestSessionInputSchema = exports_external.object({
|
|
|
11313
11588
|
source: SourceSchema.default("claude_code"),
|
|
11314
11589
|
sessionId: exports_external.string(),
|
|
11315
11590
|
projectPath: exports_external.string(),
|
|
11316
|
-
repository: exports_external.string().optional(),
|
|
11317
11591
|
gitRemote: exports_external.string().optional(),
|
|
11318
11592
|
packageName: exports_external.string().optional(),
|
|
11593
|
+
packageType: exports_external.string().optional(),
|
|
11319
11594
|
gitBranch: exports_external.string().optional(),
|
|
11320
11595
|
gitSha: exports_external.string().optional(),
|
|
11321
11596
|
tag: SessionTagSchema.optional(),
|
|
@@ -11333,18 +11608,15 @@ var contract = {
|
|
|
11333
11608
|
listMyOrganizations: oc.output(exports_external.array(OrganizationSchema)),
|
|
11334
11609
|
ingestSession: oc.input(IngestSessionInputSchema).output(IngestSessionOutputSchema),
|
|
11335
11610
|
getOrganizationSessionCount: oc.input(exports_external.object({ organizationId: exports_external.string() })).output(exports_external.object({ count: exports_external.number() })),
|
|
11336
|
-
deleteOrganization: oc.input(exports_external.object({
|
|
11337
|
-
organizationId: exports_external.string(),
|
|
11338
|
-
migrateSessionsTo: exports_external.string().optional()
|
|
11339
|
-
})).output(exports_external.object({ success: exports_external.literal(true) })),
|
|
11611
|
+
deleteOrganization: oc.input(exports_external.object({ organizationId: exports_external.string() })).output(exports_external.object({ success: exports_external.literal(true) })),
|
|
11340
11612
|
analytics: {
|
|
11341
11613
|
overview: {
|
|
11342
|
-
kpis: oc.input(
|
|
11343
|
-
usageTrend: oc.input(
|
|
11344
|
-
modelTokensTrend: oc.input(
|
|
11345
|
-
insights: oc.input(
|
|
11346
|
-
teamSummaryComparison: oc.input(
|
|
11347
|
-
successRate: oc.input(
|
|
11614
|
+
kpis: oc.input(DateRangeInputSchema).output(OverviewKPIsSchema),
|
|
11615
|
+
usageTrend: oc.input(DateRangeInputSchema).output(exports_external.array(UsageTrendDataSchema)),
|
|
11616
|
+
modelTokensTrend: oc.input(DateRangeInputSchema).output(exports_external.array(ModelTokensTrendDataSchema)),
|
|
11617
|
+
insights: oc.input(DateRangeInputSchema).output(exports_external.array(InsightSchema)),
|
|
11618
|
+
teamSummaryComparison: oc.input(DateRangeInputSchema).output(TeamSummaryComparisonSchema),
|
|
11619
|
+
successRate: oc.input(DateRangeInputSchema).output(SuccessRateSchema)
|
|
11348
11620
|
},
|
|
11349
11621
|
developers: {
|
|
11350
11622
|
list: oc.input(DaysInputSchema).output(exports_external.array(DeveloperSummarySchema)),
|
|
@@ -11387,15 +11659,12 @@ var contract = {
|
|
|
11387
11659
|
users: oc.output(exports_external.array(exports_external.string())),
|
|
11388
11660
|
projects: oc.output(exports_external.array(exports_external.string())),
|
|
11389
11661
|
trend: oc.input(LearningsTrendInputSchema).output(exports_external.array(LearningsTrendDataPointSchema))
|
|
11390
|
-
},
|
|
11391
|
-
users: {
|
|
11392
|
-
mappings: oc.input(DaysInputSchema).output(exports_external.array(UserMappingSchema))
|
|
11393
11662
|
}
|
|
11394
11663
|
}
|
|
11395
11664
|
};
|
|
11396
11665
|
|
|
11397
11666
|
// src/lib/failed-uploads.ts
|
|
11398
|
-
var FAILED_UPLOADS_PATH =
|
|
11667
|
+
var FAILED_UPLOADS_PATH = join9(homedir8(), ".rudel", "failed-uploads.json");
|
|
11399
11668
|
function normalizeSource(raw) {
|
|
11400
11669
|
if (typeof raw !== "string")
|
|
11401
11670
|
return;
|
|
@@ -11543,101 +11812,16 @@ function renderBatchSummary(summary, options) {
|
|
|
11543
11812
|
}
|
|
11544
11813
|
}
|
|
11545
11814
|
|
|
11546
|
-
// src/lib/git-info.ts
|
|
11547
|
-
import { join as join8 } from "path";
|
|
11548
|
-
var {$ } = globalThis.Bun;
|
|
11549
|
-
function normalizeRemoteUrl(url) {
|
|
11550
|
-
return url.replace(/^(https?:\/\/|git@|ssh:\/\/)/, "").replace(/:/, "/").replace(/\.git$/, "");
|
|
11551
|
-
}
|
|
11552
|
-
async function getGitInfo(cwd) {
|
|
11553
|
-
const [remoteUrl, branch, sha, packageName] = await Promise.all([
|
|
11554
|
-
getGitRemoteUrl(cwd),
|
|
11555
|
-
getGitBranch(cwd),
|
|
11556
|
-
getGitSha(cwd),
|
|
11557
|
-
getPackageName(cwd)
|
|
11558
|
-
]);
|
|
11559
|
-
const gitRemote = remoteUrl ? normalizeRemoteUrl(remoteUrl) : undefined;
|
|
11560
|
-
const repository = getRepositoryName(gitRemote, packageName, cwd);
|
|
11561
|
-
return {
|
|
11562
|
-
repository,
|
|
11563
|
-
gitRemote,
|
|
11564
|
-
packageName: packageName ?? undefined,
|
|
11565
|
-
branch: branch ?? undefined,
|
|
11566
|
-
sha: sha ?? undefined
|
|
11567
|
-
};
|
|
11568
|
-
}
|
|
11569
|
-
function getRepositoryName(gitRemote, packageName, cwd) {
|
|
11570
|
-
if (gitRemote) {
|
|
11571
|
-
const parts = gitRemote.split("/");
|
|
11572
|
-
if (parts.length >= 3) {
|
|
11573
|
-
return parts.slice(1).join("/");
|
|
11574
|
-
}
|
|
11575
|
-
return gitRemote;
|
|
11576
|
-
}
|
|
11577
|
-
if (packageName)
|
|
11578
|
-
return packageName;
|
|
11579
|
-
const dirName = cwd.split("/").pop();
|
|
11580
|
-
return dirName ?? undefined;
|
|
11581
|
-
}
|
|
11582
|
-
async function getPackageName(cwd) {
|
|
11583
|
-
try {
|
|
11584
|
-
const gitRootResult = await $`git -C ${cwd} rev-parse --show-toplevel`.quiet();
|
|
11585
|
-
const gitRoot = gitRootResult.exitCode === 0 ? gitRootResult.text().trim() : cwd;
|
|
11586
|
-
const packageJsonPath = join8(gitRoot, "package.json");
|
|
11587
|
-
const packageFile = Bun.file(packageJsonPath);
|
|
11588
|
-
if (await packageFile.exists()) {
|
|
11589
|
-
try {
|
|
11590
|
-
const packageJson = await packageFile.json();
|
|
11591
|
-
if (packageJson.name)
|
|
11592
|
-
return packageJson.name;
|
|
11593
|
-
} catch {}
|
|
11594
|
-
}
|
|
11595
|
-
return null;
|
|
11596
|
-
} catch {
|
|
11597
|
-
return null;
|
|
11598
|
-
}
|
|
11599
|
-
}
|
|
11600
|
-
async function getGitRemoteUrl(cwd) {
|
|
11601
|
-
try {
|
|
11602
|
-
const result = await $`git -C ${cwd} remote get-url origin`.quiet();
|
|
11603
|
-
if (result.exitCode !== 0)
|
|
11604
|
-
return null;
|
|
11605
|
-
return result.text().trim() || null;
|
|
11606
|
-
} catch {
|
|
11607
|
-
return null;
|
|
11608
|
-
}
|
|
11609
|
-
}
|
|
11610
|
-
async function getGitBranch(cwd) {
|
|
11611
|
-
try {
|
|
11612
|
-
const result = await $`git -C ${cwd} rev-parse --abbrev-ref HEAD`.quiet();
|
|
11613
|
-
if (result.exitCode !== 0)
|
|
11614
|
-
return null;
|
|
11615
|
-
return result.text().trim();
|
|
11616
|
-
} catch {
|
|
11617
|
-
return null;
|
|
11618
|
-
}
|
|
11619
|
-
}
|
|
11620
|
-
async function getGitSha(cwd) {
|
|
11621
|
-
try {
|
|
11622
|
-
const result = await $`git -C ${cwd} rev-parse HEAD`.quiet();
|
|
11623
|
-
if (result.exitCode !== 0)
|
|
11624
|
-
return null;
|
|
11625
|
-
return result.text().trim();
|
|
11626
|
-
} catch {
|
|
11627
|
-
return null;
|
|
11628
|
-
}
|
|
11629
|
-
}
|
|
11630
|
-
|
|
11631
11815
|
// src/lib/project-config.ts
|
|
11632
11816
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
11633
|
-
import { homedir as
|
|
11634
|
-
import { join as
|
|
11817
|
+
import { homedir as homedir9 } from "os";
|
|
11818
|
+
import { join as join10 } from "path";
|
|
11635
11819
|
var {$: $2 } = globalThis.Bun;
|
|
11636
11820
|
function getConfigDir2() {
|
|
11637
|
-
return process.env.RUDEL_CONFIG_DIR ??
|
|
11821
|
+
return process.env.RUDEL_CONFIG_DIR ?? join10(homedir9(), ".rudel");
|
|
11638
11822
|
}
|
|
11639
11823
|
function getProjectsConfigPath() {
|
|
11640
|
-
return
|
|
11824
|
+
return join10(getConfigDir2(), "projects.json");
|
|
11641
11825
|
}
|
|
11642
11826
|
function loadProjectsConfig() {
|
|
11643
11827
|
const path = getProjectsConfigPath();
|
|
@@ -13481,8 +13665,8 @@ var ConfigError = class extends Error {
|
|
|
13481
13665
|
};
|
|
13482
13666
|
|
|
13483
13667
|
// src/logging.ts
|
|
13484
|
-
import { homedir as
|
|
13485
|
-
import { join as
|
|
13668
|
+
import { homedir as homedir10 } from "os";
|
|
13669
|
+
import { join as join12 } from "path";
|
|
13486
13670
|
|
|
13487
13671
|
// ../../node_modules/.bun/@logtape+file@2.0.4+2d5de51540e256d2/node_modules/@logtape/file/dist/filesink.base.js
|
|
13488
13672
|
var AdaptiveFlushStrategy = class {
|
|
@@ -13748,7 +13932,7 @@ function getBaseFileSink(path, options) {
|
|
|
13748
13932
|
|
|
13749
13933
|
// ../../node_modules/.bun/@logtape+file@2.0.4+2d5de51540e256d2/node_modules/@logtape/file/dist/filesink.node.js
|
|
13750
13934
|
import fs from "fs";
|
|
13751
|
-
import { join as
|
|
13935
|
+
import { join as join11 } from "path";
|
|
13752
13936
|
import { promisify } from "util";
|
|
13753
13937
|
var nodeDriver = {
|
|
13754
13938
|
openSync(path) {
|
|
@@ -13788,14 +13972,14 @@ var nodeTimeDriver = {
|
|
|
13788
13972
|
readdirSync: fs.readdirSync,
|
|
13789
13973
|
unlinkSync: fs.unlinkSync,
|
|
13790
13974
|
mkdirSync: fs.mkdirSync,
|
|
13791
|
-
joinPath:
|
|
13975
|
+
joinPath: join11
|
|
13792
13976
|
};
|
|
13793
13977
|
var nodeAsyncTimeDriver = {
|
|
13794
13978
|
...nodeAsyncDriver,
|
|
13795
13979
|
readdirSync: fs.readdirSync,
|
|
13796
13980
|
unlinkSync: fs.unlinkSync,
|
|
13797
13981
|
mkdirSync: fs.mkdirSync,
|
|
13798
|
-
joinPath:
|
|
13982
|
+
joinPath: join11
|
|
13799
13983
|
};
|
|
13800
13984
|
function getFileSink(path, options = {}) {
|
|
13801
13985
|
if (options.nonBlocking)
|
|
@@ -13810,8 +13994,8 @@ function getFileSink(path, options = {}) {
|
|
|
13810
13994
|
}
|
|
13811
13995
|
|
|
13812
13996
|
// src/logging.ts
|
|
13813
|
-
var LOG_DIR =
|
|
13814
|
-
var LOG_FILE =
|
|
13997
|
+
var LOG_DIR = join12(homedir10(), ".rudel", "logs");
|
|
13998
|
+
var LOG_FILE = join12(LOG_DIR, "hook-upload.log");
|
|
13815
13999
|
async function setupHookLogging() {
|
|
13816
14000
|
const { mkdir } = await import("fs/promises");
|
|
13817
14001
|
await mkdir(LOG_DIR, { recursive: true }).catch(() => {});
|
|
@@ -14193,8 +14377,8 @@ var setOrgCommand = buildCommand({
|
|
|
14193
14377
|
|
|
14194
14378
|
// src/lib/classifier.ts
|
|
14195
14379
|
import { mkdir, unlink } from "fs/promises";
|
|
14196
|
-
import { homedir as
|
|
14197
|
-
import { join as
|
|
14380
|
+
import { homedir as homedir11 } from "os";
|
|
14381
|
+
import { join as join13 } from "path";
|
|
14198
14382
|
|
|
14199
14383
|
// src/lib/types.ts
|
|
14200
14384
|
var SESSION_TAGS = [
|
|
@@ -14221,8 +14405,8 @@ var SYSTEM_PROMPT = `You are a session classifier. Analyze the Claude Code sessi
|
|
|
14221
14405
|
CRITICAL: Respond with ONLY the tag name. Nothing else. No explanation, no punctuation, no formatting. Just ONE of: research, new_feature, bug_fix, refactoring, documentation, tests`;
|
|
14222
14406
|
async function classifySession(content) {
|
|
14223
14407
|
const truncatedContent = content.slice(0, 50000);
|
|
14224
|
-
const tempDir =
|
|
14225
|
-
const tempFile =
|
|
14408
|
+
const tempDir = join13(homedir11(), ".claude", "temp");
|
|
14409
|
+
const tempFile = join13(tempDir, `classify-${Date.now()}.txt`);
|
|
14226
14410
|
try {
|
|
14227
14411
|
await mkdir(tempDir, { recursive: true });
|
|
14228
14412
|
await Bun.write(tempFile, `Classify this session transcript:
|
|
@@ -14262,9 +14446,9 @@ ${truncatedContent}`);
|
|
|
14262
14446
|
|
|
14263
14447
|
// src/lib/session-resolver.ts
|
|
14264
14448
|
import { access, readdir as readdir3 } from "fs/promises";
|
|
14265
|
-
import { homedir as
|
|
14266
|
-
import { basename, dirname as dirname3, join as
|
|
14267
|
-
var SESSIONS_BASE_DIR3 =
|
|
14449
|
+
import { homedir as homedir12 } from "os";
|
|
14450
|
+
import { basename, dirname as dirname3, join as join14 } from "path";
|
|
14451
|
+
var SESSIONS_BASE_DIR3 = join14(homedir12(), ".claude", "projects");
|
|
14268
14452
|
async function resolveSession(input) {
|
|
14269
14453
|
const isPath = input.includes("/") || input.endsWith(".jsonl");
|
|
14270
14454
|
if (isPath) {
|
|
@@ -14296,11 +14480,11 @@ async function resolveFromId(sessionId) {
|
|
|
14296
14480
|
throw new Error(`Session not found: ${sessionId}`);
|
|
14297
14481
|
}
|
|
14298
14482
|
for (const projectDir of projectDirs) {
|
|
14299
|
-
const sessionDir =
|
|
14483
|
+
const sessionDir = join14(SESSIONS_BASE_DIR3, projectDir);
|
|
14300
14484
|
try {
|
|
14301
14485
|
const files = await readdir3(sessionDir);
|
|
14302
14486
|
if (files.includes(sessionFileName)) {
|
|
14303
|
-
const transcriptPath =
|
|
14487
|
+
const transcriptPath = join14(sessionDir, sessionFileName);
|
|
14304
14488
|
const projectPath = await decodeProjectPath(projectDir);
|
|
14305
14489
|
return {
|
|
14306
14490
|
transcriptPath,
|
|
@@ -14330,45 +14514,26 @@ async function runInteractiveUpload(flags) {
|
|
|
14330
14514
|
We("rudel upload");
|
|
14331
14515
|
const spin = bt2();
|
|
14332
14516
|
spin.start("Scanning projects...");
|
|
14333
|
-
const
|
|
14334
|
-
const allProjects = [];
|
|
14335
|
-
for (const adapter of adapters2) {
|
|
14336
|
-
const projects = await adapter.scanAllSessions();
|
|
14337
|
-
allProjects.push(...projects);
|
|
14338
|
-
}
|
|
14517
|
+
const { projects: allProjects, groups } = await scanAndGroupProjects();
|
|
14339
14518
|
spin.stop(`Found ${allProjects.length} project(s)`);
|
|
14340
14519
|
if (allProjects.length === 0) {
|
|
14341
14520
|
R2.warn("No projects with sessions found.");
|
|
14342
14521
|
Le("Nothing to upload.");
|
|
14343
14522
|
return;
|
|
14344
14523
|
}
|
|
14345
|
-
const cwd = process.cwd();
|
|
14346
|
-
const grouped = groupProjectsForCwd(allProjects, cwd);
|
|
14347
14524
|
const options = [];
|
|
14348
14525
|
const preSelected = [];
|
|
14349
|
-
for (const
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
value: sub,
|
|
14361
|
-
label: ` [${getAdapterName(sub.source)}] ${relative}`,
|
|
14362
|
-
hint: sessionCountHint(sub.sessionCount)
|
|
14363
|
-
});
|
|
14364
|
-
preSelected.push(sub);
|
|
14365
|
-
}
|
|
14366
|
-
for (const other of grouped.others) {
|
|
14367
|
-
options.push({
|
|
14368
|
-
value: other,
|
|
14369
|
-
label: `[${getAdapterName(other.source)}] ${other.displayPath}`,
|
|
14370
|
-
hint: sessionCountHint(other.sessionCount)
|
|
14371
|
-
});
|
|
14526
|
+
for (const group2 of groups) {
|
|
14527
|
+
for (const proj of group2.projects) {
|
|
14528
|
+
options.push({
|
|
14529
|
+
value: proj,
|
|
14530
|
+
label: `[${getAdapterName(proj.source)}] ${proj.displayPath}`,
|
|
14531
|
+
hint: sessionCountHint(proj.sessionCount)
|
|
14532
|
+
});
|
|
14533
|
+
if (group2.containsCwd) {
|
|
14534
|
+
preSelected.push(proj);
|
|
14535
|
+
}
|
|
14536
|
+
}
|
|
14372
14537
|
}
|
|
14373
14538
|
const selected = await je({
|
|
14374
14539
|
message: "Select projects to upload",
|
|
@@ -14470,8 +14635,9 @@ async function runSingleUpload(flags, session) {
|
|
|
14470
14635
|
}
|
|
14471
14636
|
write(`Found session at: ${sessionInfo.transcriptPath}`);
|
|
14472
14637
|
const gitInfo = await getGitInfo(sessionInfo.projectPath);
|
|
14473
|
-
|
|
14474
|
-
|
|
14638
|
+
const displayName = gitInfo.gitRemote || gitInfo.packageName || sessionInfo.projectPath.split("/").pop();
|
|
14639
|
+
if (displayName)
|
|
14640
|
+
write(`Repository: ${displayName}`);
|
|
14475
14641
|
if (gitInfo.branch)
|
|
14476
14642
|
write(`Branch: ${gitInfo.branch}`);
|
|
14477
14643
|
const organizationId = flags.org ?? await getProjectOrgId(sessionInfo.projectPath);
|