@planckspace/cli 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +109 -0
  2. package/dist/__tests__/correlate.test.d.ts +2 -0
  3. package/dist/__tests__/correlate.test.d.ts.map +1 -0
  4. package/dist/__tests__/correlate.test.js +204 -0
  5. package/dist/__tests__/correlate.test.js.map +1 -0
  6. package/dist/commands/init.d.ts +2 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +12 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/login.d.ts +2 -0
  11. package/dist/commands/login.d.ts.map +1 -0
  12. package/dist/commands/login.js +45 -0
  13. package/dist/commands/login.js.map +1 -0
  14. package/dist/commands/logout.d.ts +2 -0
  15. package/dist/commands/logout.d.ts.map +1 -0
  16. package/dist/commands/logout.js +7 -0
  17. package/dist/commands/logout.js.map +1 -0
  18. package/dist/commands/scan.d.ts +5 -0
  19. package/dist/commands/scan.d.ts.map +1 -0
  20. package/dist/commands/scan.js +51 -0
  21. package/dist/commands/scan.js.map +1 -0
  22. package/dist/commands/status.d.ts +2 -0
  23. package/dist/commands/status.d.ts.map +1 -0
  24. package/dist/commands/status.js +31 -0
  25. package/dist/commands/status.js.map +1 -0
  26. package/dist/commands/sync.d.ts +15 -0
  27. package/dist/commands/sync.d.ts.map +1 -0
  28. package/dist/commands/sync.js +77 -0
  29. package/dist/commands/sync.js.map +1 -0
  30. package/dist/config.d.ts +6 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +40 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/correlate.d.ts +21 -0
  35. package/dist/correlate.d.ts.map +1 -0
  36. package/dist/correlate.js +204 -0
  37. package/dist/correlate.js.map +1 -0
  38. package/dist/db/store.d.ts +46 -0
  39. package/dist/db/store.d.ts.map +1 -0
  40. package/dist/db/store.js +210 -0
  41. package/dist/db/store.js.map +1 -0
  42. package/dist/env.d.ts +6 -0
  43. package/dist/env.d.ts.map +1 -0
  44. package/dist/env.js +7 -0
  45. package/dist/env.js.map +1 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +97 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/scrapers/__tests__/claudeCode.test.d.ts +2 -0
  51. package/dist/scrapers/__tests__/claudeCode.test.d.ts.map +1 -0
  52. package/dist/scrapers/__tests__/claudeCode.test.js +115 -0
  53. package/dist/scrapers/__tests__/claudeCode.test.js.map +1 -0
  54. package/dist/scrapers/__tests__/cursor.test.d.ts +2 -0
  55. package/dist/scrapers/__tests__/cursor.test.d.ts.map +1 -0
  56. package/dist/scrapers/__tests__/cursor.test.js +173 -0
  57. package/dist/scrapers/__tests__/cursor.test.js.map +1 -0
  58. package/dist/scrapers/__tests__/windsurf.test.d.ts +2 -0
  59. package/dist/scrapers/__tests__/windsurf.test.d.ts.map +1 -0
  60. package/dist/scrapers/__tests__/windsurf.test.js +87 -0
  61. package/dist/scrapers/__tests__/windsurf.test.js.map +1 -0
  62. package/dist/scrapers/claudeCode.d.ts +4 -0
  63. package/dist/scrapers/claudeCode.d.ts.map +1 -0
  64. package/dist/scrapers/claudeCode.js +211 -0
  65. package/dist/scrapers/claudeCode.js.map +1 -0
  66. package/dist/scrapers/cursor.d.ts +9 -0
  67. package/dist/scrapers/cursor.d.ts.map +1 -0
  68. package/dist/scrapers/cursor.js +280 -0
  69. package/dist/scrapers/cursor.js.map +1 -0
  70. package/dist/scrapers/repo.d.ts +12 -0
  71. package/dist/scrapers/repo.d.ts.map +1 -0
  72. package/dist/scrapers/repo.js +40 -0
  73. package/dist/scrapers/repo.js.map +1 -0
  74. package/dist/scrapers/types.d.ts +36 -0
  75. package/dist/scrapers/types.d.ts.map +1 -0
  76. package/dist/scrapers/types.js +5 -0
  77. package/dist/scrapers/types.js.map +1 -0
  78. package/dist/scrapers/windsurf.d.ts +9 -0
  79. package/dist/scrapers/windsurf.d.ts.map +1 -0
  80. package/dist/scrapers/windsurf.js +255 -0
  81. package/dist/scrapers/windsurf.js.map +1 -0
  82. package/dist/scripts/scanTest.d.ts +3 -0
  83. package/dist/scripts/scanTest.d.ts.map +1 -0
  84. package/dist/scripts/scanTest.js +146 -0
  85. package/dist/scripts/scanTest.js.map +1 -0
  86. package/dist/sync/__tests__/payload.privacy.test.d.ts +2 -0
  87. package/dist/sync/__tests__/payload.privacy.test.d.ts.map +1 -0
  88. package/dist/sync/__tests__/payload.privacy.test.js +100 -0
  89. package/dist/sync/__tests__/payload.privacy.test.js.map +1 -0
  90. package/dist/sync/payload.d.ts +14 -0
  91. package/dist/sync/payload.d.ts.map +1 -0
  92. package/dist/sync/payload.js +36 -0
  93. package/dist/sync/payload.js.map +1 -0
  94. package/dist/sync/syncEngine.d.ts +16 -0
  95. package/dist/sync/syncEngine.d.ts.map +1 -0
  96. package/dist/sync/syncEngine.js +76 -0
  97. package/dist/sync/syncEngine.js.map +1 -0
  98. package/install.sh +126 -0
  99. package/package.json +39 -7
  100. package/index.js +0 -1
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @planckspace/cli
2
+
3
+ PlanckSpace CLI — sync AI token usage from Claude Code, Cursor, and Windsurf to your team ledger.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ curl -fsSL https://planckspace.dev/install | sh
9
+ ```
10
+
11
+ With an invite token:
12
+
13
+ ```sh
14
+ curl -fsSL https://planckspace.dev/install | sh -s -- --token pk_live_xxx
15
+ ```
16
+
17
+ Or install manually:
18
+
19
+ ```sh
20
+ npm install -g @planckspace/cli
21
+ ```
22
+
23
+ See [docs/INSTALL.md](docs/INSTALL.md) for manual steps and troubleshooting.
24
+
25
+ ## Commands
26
+
27
+ | Command | Description |
28
+ |---|---|
29
+ | `planck init` | Initialize `~/.planckspace/` (local DB + config) |
30
+ | `planck login <token>` | Connect to a PlanckSpace workspace |
31
+ | `planck scan` | Ingest local AI session history |
32
+ | `planck sync` | Push unsynced sessions to the team dashboard |
33
+ | `planck sync --watch` | Keep syncing on an interval (default 60 s) |
34
+ | `planck status` | Show connection + session stats |
35
+ | `planck logout` | Disconnect (local data retained) |
36
+
37
+ ### Non-interactive login (CI / install scripts)
38
+
39
+ ```sh
40
+ planck login --token pk_live_xxx
41
+ # or
42
+ PLANCKSPACE_TOKEN=pk_live_xxx planck login
43
+ ```
44
+
45
+ ### Backfill + sync in one step
46
+
47
+ ```sh
48
+ planck scan --sync
49
+ ```
50
+
51
+ ## What gets synced
52
+
53
+ - Session metadata: tool, model, token counts, cost, duration, repo name, outcome
54
+ - Git attribution: `git config user.email` from each repo (maps sessions to team members)
55
+ - **Never synced**: prompt text, code content, file contents, `turnsJson`
56
+
57
+ See [docs/COVERAGE.md](docs/COVERAGE.md) for per-tool capture details.
58
+
59
+ ## Supported editors
60
+
61
+ | Editor | Sessions | Tokens / cost | Notes |
62
+ |---|---|---|---|
63
+ | Claude Code | Yes | Yes | Full |
64
+ | Cursor | Yes | No | Cursor meters server-side; token fields are 0 |
65
+ | Windsurf | Yes (beta) | Provisional | Unverified schema — may vary by version |
66
+
67
+ ## Requirements
68
+
69
+ - Node.js 20+
70
+ - macOS or Linux (Windows: use WSL)
71
+
72
+ ## Publishing
73
+
74
+ Build and publish to npm:
75
+
76
+ ```sh
77
+ npm run release
78
+ # equivalent to: npm run build && npm publish
79
+ ```
80
+
81
+ `prepublishOnly` runs `tsc` automatically before every `npm publish`.
82
+
83
+ To log in to npm first:
84
+
85
+ ```sh
86
+ npm login
87
+ npm run release
88
+ ```
89
+
90
+ The package publishes as `@planckspace/cli` (public scoped package).
91
+
92
+ ## Development
93
+
94
+ ```sh
95
+ npm install
96
+ npm run dev -- scan # run any command via tsx (no build needed)
97
+ npm test # vitest
98
+ npm run build # compile TypeScript → dist/
99
+ ```
100
+
101
+ Override the API endpoint during development:
102
+
103
+ ```sh
104
+ PLANCKSPACE_API_URL=http://localhost:4000 npm run dev -- sync
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=correlate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/correlate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,204 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ import { simpleGit } from "simple-git";
6
+ import { initDb, upsertSessions, getSessions, setSessionCorrelation, closeDb, } from "../db/store.js";
7
+ import { correlateSessions } from "../correlate.js";
8
+ // A fixed reference clock. Commit dates are placed relative to it, and the same
9
+ // value is fed to correlateSessions() so the time-window logic is deterministic.
10
+ const NOW = Date.parse("2026-06-01T12:00:00.000Z");
11
+ const DAY = 24 * 60 * 60 * 1000;
12
+ const HOUR = 60 * 60 * 1000;
13
+ const iso = (ms) => new Date(ms).toISOString();
14
+ const SESSION_EMAIL = "dev@example.com";
15
+ // process.env minus undefined values — simple-git's .env() replaces the child's
16
+ // whole environment, so we must carry PATH etc. through. Editor vars are dropped:
17
+ // simple-git refuses to run with EDITOR/*_EDITOR set in a passed env.
18
+ const BASE_ENV = {};
19
+ for (const [k, v] of Object.entries(process.env)) {
20
+ if (v !== undefined && !/EDITOR/i.test(k))
21
+ BASE_ENV[k] = v;
22
+ }
23
+ let tmpRoot;
24
+ const repoDirs = [];
25
+ beforeAll(() => {
26
+ tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "planck-correlate-"));
27
+ initDb(path.join(tmpRoot, "local.db"));
28
+ });
29
+ afterAll(() => {
30
+ closeDb();
31
+ fs.rmSync(tmpRoot, { recursive: true, force: true });
32
+ });
33
+ // ── Helpers ─────────────────────────────────────────────────────────────────
34
+ async function makeRepo(label) {
35
+ const dir = fs.mkdtempSync(path.join(tmpRoot, `repo-${label}-`));
36
+ repoDirs.push(dir);
37
+ const git = simpleGit(dir);
38
+ await git.init();
39
+ await git.addConfig("user.email", SESSION_EMAIL);
40
+ await git.addConfig("user.name", "Dev");
41
+ await git.addConfig("commit.gpgsign", "false");
42
+ return { dir, git };
43
+ }
44
+ /** Commit a file with explicit author + committer dates (and optional override author). */
45
+ async function commitAt(git, dir, file, whenMs, authorOverride) {
46
+ fs.writeFileSync(path.join(dir, file), `${file} @ ${whenMs}\n`);
47
+ await git.add(file);
48
+ git.env({ ...BASE_ENV, GIT_AUTHOR_DATE: iso(whenMs), GIT_COMMITTER_DATE: iso(whenMs) });
49
+ const opts = authorOverride ? { "--author": authorOverride } : undefined;
50
+ await git.commit(`add ${file}`, undefined, opts);
51
+ }
52
+ /** Rename the (post-first-commit) current branch to a stable name (default "main"). */
53
+ async function renameTo(git, name = "main") {
54
+ await git.branch(["-m", name]);
55
+ }
56
+ const renameToMain = (git) => renameTo(git);
57
+ let sessionCounter = 0;
58
+ function makeSession(over) {
59
+ sessionCounter += 1;
60
+ return {
61
+ sessionId: `corr-session-${sessionCounter}`,
62
+ tool: "claude_code",
63
+ model: "claude-opus-4-8",
64
+ startedAt: iso(NOW - DAY),
65
+ endedAt: iso(NOW - DAY + HOUR),
66
+ inputTokens: 100,
67
+ outputTokens: 200,
68
+ cacheReadTokens: 0,
69
+ cacheWriteTokens: 0,
70
+ costUsd: 0.01,
71
+ turns: [],
72
+ turnCount: 0,
73
+ filesTouchedCount: 0,
74
+ repoName: "repo",
75
+ gitBranch: "main",
76
+ ...over,
77
+ };
78
+ }
79
+ function outcomeOf(id) {
80
+ return getSessions().find((s) => s.id === id)?.outcome;
81
+ }
82
+ function emailOf(id) {
83
+ return getSessions().find((s) => s.id === id)?.gitAuthorEmail;
84
+ }
85
+ // ── Tests ─────────────────────────────────────────────────────────────────────
86
+ describe("correlateSessions", () => {
87
+ it("marks a session shipped when its branch commit merged into main", async () => {
88
+ const { dir, git } = await makeRepo("shipped");
89
+ await commitAt(git, dir, "base.txt", NOW - 10 * DAY);
90
+ await renameToMain(git);
91
+ await git.checkoutLocalBranch("feature");
92
+ await commitAt(git, dir, "feature.txt", NOW - 9 * DAY);
93
+ await git.checkout("main");
94
+ await git.merge(["feature"]); // fast-forward — feature becomes reachable from main
95
+ const session = makeSession({
96
+ workingDir: dir,
97
+ gitBranch: "feature",
98
+ startedAt: iso(NOW - 9.5 * DAY),
99
+ });
100
+ upsertSessions([session]);
101
+ await correlateSessions(NOW);
102
+ expect(outcomeOf(session.sessionId)).toBe("shipped");
103
+ expect(emailOf(session.sessionId)).toBe(SESSION_EMAIL);
104
+ });
105
+ it("ships a commit landed directly on a `master` default branch (not just `main`)", async () => {
106
+ // Regression: resolveDefaultBranch must detect `master`, not always pick the
107
+ // first candidate. A commit on master is, by definition, on the default branch.
108
+ const { dir, git } = await makeRepo("master-default");
109
+ await commitAt(git, dir, "base.txt", NOW - 5 * DAY);
110
+ await renameTo(git, "master");
111
+ await commitAt(git, dir, "work.txt", NOW - 4 * DAY); // committed straight to master
112
+ const session = makeSession({
113
+ workingDir: dir,
114
+ gitBranch: "master",
115
+ startedAt: iso(NOW - 4.5 * DAY),
116
+ });
117
+ upsertSessions([session]);
118
+ await correlateSessions(NOW);
119
+ expect(outcomeOf(session.sessionId)).toBe("shipped");
120
+ });
121
+ it("marks a session partial when commits exist, unmerged, and the window has passed", async () => {
122
+ const { dir, git } = await makeRepo("partial");
123
+ await commitAt(git, dir, "base.txt", NOW - 10 * DAY);
124
+ await renameToMain(git);
125
+ await git.checkoutLocalBranch("feature");
126
+ await commitAt(git, dir, "feature.txt", NOW - 8 * DAY); // never merged
127
+ const session = makeSession({
128
+ workingDir: dir,
129
+ gitBranch: "feature",
130
+ startedAt: iso(NOW - 9 * DAY), // 9 days ago → past the 7-day window
131
+ });
132
+ upsertSessions([session]);
133
+ await correlateSessions(NOW);
134
+ expect(outcomeOf(session.sessionId)).toBe("partial");
135
+ expect(emailOf(session.sessionId)).toBe(SESSION_EMAIL);
136
+ });
137
+ it("keeps a session unknown when commits exist, unmerged, but still inside the window", async () => {
138
+ const { dir, git } = await makeRepo("unknown-fresh");
139
+ await commitAt(git, dir, "base.txt", NOW - 2 * DAY);
140
+ await renameToMain(git);
141
+ await git.checkoutLocalBranch("feature");
142
+ await commitAt(git, dir, "feature.txt", NOW - 0.5 * DAY); // unmerged, recent
143
+ const session = makeSession({
144
+ workingDir: dir,
145
+ gitBranch: "feature",
146
+ startedAt: iso(NOW - DAY), // 1 day ago → still inside the 7-day window
147
+ });
148
+ upsertSessions([session]);
149
+ await correlateSessions(NOW);
150
+ expect(outcomeOf(session.sessionId)).toBe("unknown");
151
+ });
152
+ it("marks a session abandoned when it ended >24h ago with no commits by its author", async () => {
153
+ const { dir, git } = await makeRepo("abandoned");
154
+ // Only commit is authored by someone else, so the session's author has none.
155
+ await commitAt(git, dir, "base.txt", NOW - 5 * DAY, "Other Dev <other@example.com>");
156
+ await renameToMain(git);
157
+ const session = makeSession({
158
+ workingDir: dir,
159
+ gitBranch: "main",
160
+ startedAt: iso(NOW - 50 * HOUR),
161
+ endedAt: iso(NOW - 48 * HOUR), // ended 2 days ago
162
+ });
163
+ upsertSessions([session]);
164
+ await correlateSessions(NOW);
165
+ expect(outcomeOf(session.sessionId)).toBe("abandoned");
166
+ // We still record the session's git email even with no attributable commits.
167
+ expect(emailOf(session.sessionId)).toBe(SESSION_EMAIL);
168
+ });
169
+ it("never overrides a scraper-recorded errored outcome", async () => {
170
+ const { dir, git } = await makeRepo("errored");
171
+ await commitAt(git, dir, "base.txt", NOW - 2 * DAY);
172
+ await renameToMain(git);
173
+ const session = makeSession({ workingDir: dir, gitBranch: "main" });
174
+ upsertSessions([session]);
175
+ setSessionCorrelation(session.sessionId, "errored", null); // as the scraper would
176
+ await correlateSessions(NOW);
177
+ expect(outcomeOf(session.sessionId)).toBe("errored");
178
+ });
179
+ it("skips a workingDir that is not a git repo, leaving the outcome untouched", async () => {
180
+ const notARepo = fs.mkdtempSync(path.join(tmpRoot, "not-a-repo-"));
181
+ const session = makeSession({ workingDir: notARepo, gitBranch: "main" });
182
+ upsertSessions([session]); // default outcome is "unknown"
183
+ await correlateSessions(NOW);
184
+ expect(outcomeOf(session.sessionId)).toBe("unknown");
185
+ expect(emailOf(session.sessionId)).toBeNull();
186
+ });
187
+ it("does not crash on a detached HEAD (null branch) — no commits attributable", async () => {
188
+ const { dir, git } = await makeRepo("detached");
189
+ await commitAt(git, dir, "base.txt", NOW - 3 * DAY);
190
+ await renameToMain(git);
191
+ const session = makeSession({
192
+ workingDir: dir,
193
+ gitBranch: null, // detached HEAD captured as no branch
194
+ startedAt: iso(NOW - 50 * HOUR),
195
+ endedAt: iso(NOW - 48 * HOUR),
196
+ });
197
+ upsertSessions([session]);
198
+ await correlateSessions(NOW);
199
+ // No branch ⇒ no commits ⇒ falls through to the time-based abandoned check.
200
+ expect(outcomeOf(session.sessionId)).toBe("abandoned");
201
+ expect(emailOf(session.sessionId)).toBe(SESSION_EMAIL);
202
+ });
203
+ });
204
+ //# sourceMappingURL=correlate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlate.test.js","sourceRoot":"","sources":["../../src/__tests__/correlate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runInit(): void;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,IAAI,IAAI,CAS9B"}
@@ -0,0 +1,12 @@
1
+ import fs from "fs";
2
+ import { PLANCKSPACE_DIR, DB_PATH, initDb } from "../db/store.js";
3
+ export function runInit() {
4
+ fs.mkdirSync(PLANCKSPACE_DIR, { recursive: true, mode: 0o700 });
5
+ initDb(DB_PATH);
6
+ console.log("PlanckSpace initialized.");
7
+ console.log(` Directory : ${PLANCKSPACE_DIR}`);
8
+ console.log(` Database : ${DB_PATH} (WAL mode)`);
9
+ console.log("");
10
+ console.log("Next step: run `planck login` to connect your workspace.");
11
+ }
12
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,UAAU,OAAO;IACrB,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEhB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,iBAAiB,eAAe,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,aAAa,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runLogin(tokenArg?: string): Promise<void>;
2
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAOA,wBAAsB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiD/D"}
@@ -0,0 +1,45 @@
1
+ import { readConfig, writeConfig, resolveApiUrl } from "../config.js";
2
+ export async function runLogin(tokenArg) {
3
+ const token = tokenArg ?? process.env.PLANCKSPACE_TOKEN ?? null;
4
+ if (!token) {
5
+ console.error("No token provided.\n" +
6
+ " planck login <token>\n" +
7
+ " planck login --token pk_live_...\n" +
8
+ " PLANCKSPACE_TOKEN=pk_live_... planck login");
9
+ process.exit(1);
10
+ }
11
+ const config = readConfig();
12
+ const apiUrl = resolveApiUrl();
13
+ let workspaceId = null;
14
+ let workspaceName = null;
15
+ try {
16
+ const res = await fetch(`${apiUrl}/api/me`, {
17
+ headers: { Authorization: `Bearer ${token}` },
18
+ });
19
+ if (res.ok) {
20
+ const data = (await res.json());
21
+ workspaceId = data.workspaceId ?? null;
22
+ workspaceName = data.workspaceName ?? null;
23
+ }
24
+ else if (res.status === 401) {
25
+ console.error("Invalid token — check your PlanckSpace token and try again.");
26
+ process.exit(1);
27
+ }
28
+ else {
29
+ console.error(`API returned ${res.status}; token stored, workspace will resolve on first sync.`);
30
+ }
31
+ }
32
+ catch {
33
+ console.error("Could not reach API; token stored, workspace will resolve on first sync.");
34
+ }
35
+ // Persist the apiUrl we actually used (may come from PLANCKSPACE_API_URL),
36
+ // so later commands stay pointed at the same backend without the env var.
37
+ writeConfig({ ...config, apiUrl, token, workspaceId, workspaceName });
38
+ if (workspaceName) {
39
+ console.log(`Connected to ${workspaceName}.`);
40
+ }
41
+ else {
42
+ console.log("Token saved. Run `planck sync` to complete workspace setup.");
43
+ }
44
+ }
45
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOtE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAiB;IAC9C,MAAM,KAAK,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC;IAEhE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,sBAAsB;YACpB,0BAA0B;YAC1B,sCAAsC;YACtC,8CAA8C,CACjD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAE/B,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,aAAa,GAAkB,IAAI,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,SAAS,EAAE;YAC1C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAe,CAAC;YAC9C,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC;YACvC,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;QAC7C,CAAC;aAAM,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;YAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CACX,gBAAgB,GAAG,CAAC,MAAM,uDAAuD,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,0EAA0E,CAAC,CAAC;IAC5F,CAAC;IAED,2EAA2E;IAC3E,0EAA0E;IAC1E,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC;IAEtE,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,gBAAgB,aAAa,GAAG,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runLogout(): void;
2
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,IAAI,CAIhC"}
@@ -0,0 +1,7 @@
1
+ import { readConfig, writeConfig } from "../config.js";
2
+ export function runLogout() {
3
+ const config = readConfig();
4
+ writeConfig({ ...config, token: null, workspaceId: null, workspaceName: null });
5
+ console.log("Logged out. Local session data retained.");
6
+ }
7
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,5 @@
1
+ export type ScanOptions = {
2
+ sync?: boolean;
3
+ };
4
+ export declare function runScan(options?: ScanOptions): Promise<void>;
5
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7C,wBAAsB,OAAO,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDtE"}
@@ -0,0 +1,51 @@
1
+ import { scanClaudeCodeLogs } from "../scrapers/claudeCode.js";
2
+ import { scanCursorLogs } from "../scrapers/cursor.js";
3
+ import { scanWindsurfLogs } from "../scrapers/windsurf.js";
4
+ import { initDb, upsertSessions, setMeta } from "../db/store.js";
5
+ import { correlateSessions } from "../correlate.js";
6
+ import { getSyncDeps, syncAndReport } from "./sync.js";
7
+ export async function runScan(options = {}) {
8
+ initDb();
9
+ // Each scraper fails closed (returns []) when its tool isn't installed, so we can
10
+ // run them unconditionally and merge. Cursor & Windsurf are beta (see COVERAGE.md).
11
+ console.log("Scanning Claude Code, Cursor, and Windsurf logs ...");
12
+ const [claudeSessions, cursorSessions, windsurfSessions] = await Promise.all([
13
+ scanClaudeCodeLogs(),
14
+ Promise.resolve().then(() => scanCursorLogs()),
15
+ Promise.resolve().then(() => scanWindsurfLogs()),
16
+ ]);
17
+ const sessions = [
18
+ ...claudeSessions,
19
+ ...cursorSessions,
20
+ ...windsurfSessions,
21
+ ];
22
+ if (sessions.length === 0) {
23
+ console.log("No sessions found.");
24
+ }
25
+ else {
26
+ const { added, updated } = upsertSessions(sessions);
27
+ setMeta("last_scan_at", new Date().toISOString());
28
+ const totalCost = sessions.reduce((sum, s) => sum + s.costUsd, 0);
29
+ const byTool = (t) => sessions.filter((s) => s.tool === t).length;
30
+ console.log(`Scanned ${sessions.length} session(s) ` +
31
+ `(claude_code ${byTool("claude_code")}, cursor ${byTool("cursor")} [beta], ` +
32
+ `windsurf ${byTool("windsurf")} [beta]): ` +
33
+ `${added} added, ${updated} updated. ` +
34
+ `Total cost tracked: $${totalCost.toFixed(4)}`);
35
+ }
36
+ // Correlate against git every run — outcomes drift as branches merge or age out.
37
+ // Runs unconditionally (even with no new sessions) so prior verdicts stay current.
38
+ const { updated: correlated } = await correlateSessions();
39
+ if (correlated > 0) {
40
+ console.log(`Correlated git outcomes for ${correlated} session(s).`);
41
+ }
42
+ if (options.sync) {
43
+ const deps = await getSyncDeps();
44
+ if (!deps) {
45
+ console.log("Not connected — skipping sync. Run `planck login <token>` to enable.");
46
+ return;
47
+ }
48
+ await syncAndReport(deps);
49
+ }
50
+ }
51
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAKvD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,UAAuB,EAAE;IACrD,MAAM,EAAE,CAAC;IAET,kFAAkF;IAClF,oFAAoF;IACpF,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IACnE,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3E,kBAAkB,EAAE;QACpB,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC;QAC9C,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC;KACjD,CAAC,CAAC;IACH,MAAM,QAAQ,GAAoB;QAChC,GAAG,cAAc;QACjB,GAAG,cAAc;QACjB,GAAG,gBAAgB;KACpB,CAAC;IAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACpD,OAAO,CAAC,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAElD,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,CAAC,CAAwB,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAEzF,OAAO,CAAC,GAAG,CACT,WAAW,QAAQ,CAAC,MAAM,cAAc;YACxC,gBAAgB,MAAM,CAAC,aAAa,CAAC,YAAY,MAAM,CAAC,QAAQ,CAAC,WAAW;YAC5E,YAAY,MAAM,CAAC,UAAU,CAAC,YAAY;YAC1C,GAAG,KAAK,WAAW,OAAO,YAAY;YACtC,wBAAwB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAC/C,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,mFAAmF;IACnF,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC1D,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,+BAA+B,UAAU,cAAc,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;YACpF,OAAO;QACT,CAAC;QACD,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runStatus(): void;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAGA,wBAAgB,SAAS,IAAI,IAAI,CA8BhC"}
@@ -0,0 +1,31 @@
1
+ import { readConfig } from "../config.js";
2
+ import { initDb, getSessions, getUnsyncedSessions, getMeta } from "../db/store.js";
3
+ export function runStatus() {
4
+ initDb();
5
+ const config = readConfig();
6
+ const workspace = config.workspaceName ?? "not connected";
7
+ const sessions = getSessions();
8
+ const unsynced = getUnsyncedSessions();
9
+ const lastScan = getMeta("last_scan_at");
10
+ const totalCost = sessions.reduce((sum, r) => sum + r.costUsd, 0);
11
+ const syncedCount = sessions.length - unsynced.length;
12
+ // Per-tool breakdown. Cursor & Windsurf are beta: Cursor does not persist token
13
+ // usage locally (so cost reads $0), and Windsurf parsing is unverified — see
14
+ // docs/COVERAGE.md for exactly what each tool captures.
15
+ const BETA_TOOLS = new Set(["cursor", "windsurf"]);
16
+ const counts = new Map();
17
+ for (const r of sessions)
18
+ counts.set(r.tool, (counts.get(r.tool) ?? 0) + 1);
19
+ console.log("PlanckSpace Status");
20
+ console.log("─────────────────────────────────────");
21
+ console.log(`Workspace : ${workspace}`);
22
+ console.log(`Sessions : ${sessions.length}`);
23
+ for (const tool of [...counts.keys()].sort()) {
24
+ const label = BETA_TOOLS.has(tool) ? `${tool} (beta)` : tool;
25
+ console.log(` ${label.padEnd(18)}: ${counts.get(tool)}`);
26
+ }
27
+ console.log(`Last scan : ${lastScan ? new Date(lastScan).toLocaleString() : "never"}`);
28
+ console.log(`Cost : $${totalCost.toFixed(4)}`);
29
+ console.log(`Sync : ${syncedCount} synced / ${unsynced.length} pending`);
30
+ }
31
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEnF,MAAM,UAAU,SAAS;IACvB,MAAM,EAAE,CAAC;IAET,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,IAAI,eAAe,CAAC;IAC1D,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEzC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAClE,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEtD,gFAAgF;IAChF,6EAA6E;IAC7E,wDAAwD;IACxD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAE5E,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,iBAAiB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,gBAAgB,WAAW,aAAa,QAAQ,CAAC,MAAM,UAAU,CAAC,CAAC;AACjF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type SyncDeps } from "../sync/syncEngine.js";
2
+ export type SyncOptions = {
3
+ watch?: boolean;
4
+ /** Watch interval in seconds (default 60). */
5
+ interval?: number;
6
+ };
7
+ /** Run one sync pass and print the standard summary line. */
8
+ export declare function syncAndReport(deps: SyncDeps): Promise<void>;
9
+ /**
10
+ * Build sync deps for callers that have already confirmed connection
11
+ * (e.g. `scan --sync`). Returns null if not connected.
12
+ */
13
+ export declare function getSyncDeps(): Promise<SyncDeps | null>;
14
+ export declare function runSync(options?: SyncOptions): Promise<void>;
15
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AA+CF,6DAA6D;AAC7D,wBAAsB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjE;AAED;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAE5D;AAED,wBAAsB,OAAO,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE"}