@keepgoingdev/cli 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +117 -79
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,10 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/storage.ts
4
- import fs from "fs";
5
- import path from "path";
6
- import { randomUUID as randomUUID2 } from "crypto";
7
-
8
3
  // ../../packages/shared/src/session.ts
9
4
  import { randomUUID } from "crypto";
10
5
  function generateCheckpointId() {
@@ -59,6 +54,18 @@ function formatRelativeTime(timestamp) {
59
54
  import { execFileSync, execFile } from "child_process";
60
55
  import { promisify } from "util";
61
56
  var execFileAsync = promisify(execFile);
57
+ function findGitRoot(startPath) {
58
+ try {
59
+ const result = execFileSync("git", ["rev-parse", "--show-toplevel"], {
60
+ cwd: startPath,
61
+ encoding: "utf-8",
62
+ timeout: 5e3
63
+ });
64
+ return result.trim() || startPath;
65
+ } catch {
66
+ return startPath;
67
+ }
68
+ }
62
69
  function getCurrentBranch(workspacePath) {
63
70
  try {
64
71
  const result = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
@@ -93,69 +100,14 @@ function getRecentSessions(allSessions, count = RECENT_SESSION_COUNT) {
93
100
  return allSessions.slice(-count).reverse();
94
101
  }
95
102
 
96
- // src/storage.ts
103
+ // ../../packages/shared/src/storage.ts
104
+ import fs from "fs";
105
+ import path from "path";
106
+ import { randomUUID as randomUUID2 } from "crypto";
97
107
  var STORAGE_DIR = ".keepgoing";
98
108
  var META_FILE = "meta.json";
99
109
  var SESSIONS_FILE = "sessions.json";
100
110
  var STATE_FILE = "state.json";
101
- var KeepGoingReader = class {
102
- storagePath;
103
- metaFilePath;
104
- sessionsFilePath;
105
- stateFilePath;
106
- constructor(workspacePath) {
107
- this.storagePath = path.join(workspacePath, STORAGE_DIR);
108
- this.metaFilePath = path.join(this.storagePath, META_FILE);
109
- this.sessionsFilePath = path.join(this.storagePath, SESSIONS_FILE);
110
- this.stateFilePath = path.join(this.storagePath, STATE_FILE);
111
- }
112
- exists() {
113
- return fs.existsSync(this.storagePath);
114
- }
115
- getState() {
116
- return this.readJsonFile(this.stateFilePath);
117
- }
118
- getMeta() {
119
- return this.readJsonFile(this.metaFilePath);
120
- }
121
- getSessions() {
122
- return this.parseSessions().sessions;
123
- }
124
- getLastSession() {
125
- const { sessions, wrapperLastSessionId } = this.parseSessions();
126
- if (sessions.length === 0) {
127
- return void 0;
128
- }
129
- const state = this.getState();
130
- if (state?.lastSessionId) {
131
- const found = sessions.find((s) => s.id === state.lastSessionId);
132
- if (found) return found;
133
- }
134
- if (wrapperLastSessionId) {
135
- const found = sessions.find((s) => s.id === wrapperLastSessionId);
136
- if (found) return found;
137
- }
138
- return sessions[sessions.length - 1];
139
- }
140
- getRecentSessions(count) {
141
- return getRecentSessions(this.getSessions(), count);
142
- }
143
- parseSessions() {
144
- const raw = this.readJsonFile(this.sessionsFilePath);
145
- if (!raw) return { sessions: [] };
146
- if (Array.isArray(raw)) return { sessions: raw };
147
- return { sessions: raw.sessions ?? [], wrapperLastSessionId: raw.lastSessionId };
148
- }
149
- readJsonFile(filePath) {
150
- try {
151
- if (!fs.existsSync(filePath)) return void 0;
152
- const raw = fs.readFileSync(filePath, "utf-8");
153
- return JSON.parse(raw);
154
- } catch {
155
- return void 0;
156
- }
157
- }
158
- };
159
111
  var KeepGoingWriter = class {
160
112
  storagePath;
161
113
  sessionsFilePath;
@@ -191,6 +143,10 @@ var KeepGoingWriter = class {
191
143
  }
192
144
  sessionsData.sessions.push(checkpoint);
193
145
  sessionsData.lastSessionId = checkpoint.id;
146
+ const MAX_SESSIONS = 200;
147
+ if (sessionsData.sessions.length > MAX_SESSIONS) {
148
+ sessionsData.sessions = sessionsData.sessions.slice(-MAX_SESSIONS);
149
+ }
194
150
  fs.writeFileSync(this.sessionsFilePath, JSON.stringify(sessionsData, null, 2), "utf-8");
195
151
  const state = {
196
152
  lastSessionId: checkpoint.id,
@@ -198,29 +154,110 @@ var KeepGoingWriter = class {
198
154
  lastActivityAt: checkpoint.timestamp
199
155
  };
200
156
  fs.writeFileSync(this.stateFilePath, JSON.stringify(state, null, 2), "utf-8");
157
+ this.updateMeta(checkpoint.timestamp);
158
+ }
159
+ updateMeta(timestamp) {
201
160
  let meta;
202
161
  try {
203
162
  if (fs.existsSync(this.metaFilePath)) {
204
163
  meta = JSON.parse(fs.readFileSync(this.metaFilePath, "utf-8"));
205
- meta.lastUpdated = checkpoint.timestamp;
164
+ meta.lastUpdated = timestamp;
206
165
  } else {
207
166
  meta = {
208
167
  projectId: randomUUID2(),
209
- createdAt: checkpoint.timestamp,
210
- lastUpdated: checkpoint.timestamp
168
+ createdAt: timestamp,
169
+ lastUpdated: timestamp
211
170
  };
212
171
  }
213
172
  } catch {
214
173
  meta = {
215
174
  projectId: randomUUID2(),
216
- createdAt: checkpoint.timestamp,
217
- lastUpdated: checkpoint.timestamp
175
+ createdAt: timestamp,
176
+ lastUpdated: timestamp
218
177
  };
219
178
  }
220
179
  fs.writeFileSync(this.metaFilePath, JSON.stringify(meta, null, 2), "utf-8");
221
180
  }
222
181
  };
223
182
 
183
+ // ../../packages/shared/src/decisionStorage.ts
184
+ import fs2 from "fs";
185
+ import path2 from "path";
186
+
187
+ // ../../packages/shared/src/featureGate.ts
188
+ var DefaultFeatureGate = class {
189
+ isEnabled(_feature) {
190
+ return true;
191
+ }
192
+ };
193
+ var currentGate = new DefaultFeatureGate();
194
+
195
+ // src/storage.ts
196
+ import fs3 from "fs";
197
+ import path3 from "path";
198
+ var STORAGE_DIR2 = ".keepgoing";
199
+ var META_FILE2 = "meta.json";
200
+ var SESSIONS_FILE2 = "sessions.json";
201
+ var STATE_FILE2 = "state.json";
202
+ var KeepGoingReader = class {
203
+ storagePath;
204
+ metaFilePath;
205
+ sessionsFilePath;
206
+ stateFilePath;
207
+ constructor(workspacePath) {
208
+ this.storagePath = path3.join(workspacePath, STORAGE_DIR2);
209
+ this.metaFilePath = path3.join(this.storagePath, META_FILE2);
210
+ this.sessionsFilePath = path3.join(this.storagePath, SESSIONS_FILE2);
211
+ this.stateFilePath = path3.join(this.storagePath, STATE_FILE2);
212
+ }
213
+ exists() {
214
+ return fs3.existsSync(this.storagePath);
215
+ }
216
+ getState() {
217
+ return this.readJsonFile(this.stateFilePath);
218
+ }
219
+ getMeta() {
220
+ return this.readJsonFile(this.metaFilePath);
221
+ }
222
+ getSessions() {
223
+ return this.parseSessions().sessions;
224
+ }
225
+ getLastSession() {
226
+ const { sessions, wrapperLastSessionId } = this.parseSessions();
227
+ if (sessions.length === 0) {
228
+ return void 0;
229
+ }
230
+ const state = this.getState();
231
+ if (state?.lastSessionId) {
232
+ const found = sessions.find((s) => s.id === state.lastSessionId);
233
+ if (found) return found;
234
+ }
235
+ if (wrapperLastSessionId) {
236
+ const found = sessions.find((s) => s.id === wrapperLastSessionId);
237
+ if (found) return found;
238
+ }
239
+ return sessions[sessions.length - 1];
240
+ }
241
+ getRecentSessions(count) {
242
+ return getRecentSessions(this.getSessions(), count);
243
+ }
244
+ parseSessions() {
245
+ const raw = this.readJsonFile(this.sessionsFilePath);
246
+ if (!raw) return { sessions: [] };
247
+ if (Array.isArray(raw)) return { sessions: raw };
248
+ return { sessions: raw.sessions ?? [], wrapperLastSessionId: raw.lastSessionId };
249
+ }
250
+ readJsonFile(filePath) {
251
+ try {
252
+ if (!fs3.existsSync(filePath)) return void 0;
253
+ const raw = fs3.readFileSync(filePath, "utf-8");
254
+ return JSON.parse(raw);
255
+ } catch {
256
+ return void 0;
257
+ }
258
+ }
259
+ };
260
+
224
261
  // src/render.ts
225
262
  var RESET = "\x1B[0m";
226
263
  var BOLD = "\x1B[1m";
@@ -300,7 +337,7 @@ async function statusCommand(opts) {
300
337
 
301
338
  // src/commands/save.ts
302
339
  import readline from "readline";
303
- import path2 from "path";
340
+ import path4 from "path";
304
341
  function prompt(rl, question) {
305
342
  return new Promise((resolve) => {
306
343
  rl.question(question, (answer) => {
@@ -344,15 +381,15 @@ async function saveCommand(opts) {
344
381
  workspaceRoot: opts.cwd,
345
382
  source: "manual"
346
383
  });
347
- const projectName = path2.basename(opts.cwd);
384
+ const projectName = path4.basename(opts.cwd);
348
385
  const writer = new KeepGoingWriter(opts.cwd);
349
386
  writer.saveCheckpoint(checkpoint, projectName);
350
387
  console.log("Checkpoint saved.");
351
388
  }
352
389
 
353
390
  // src/commands/hook.ts
354
- import fs2 from "fs";
355
- import path3 from "path";
391
+ import fs4 from "fs";
392
+ import path5 from "path";
356
393
  import os from "os";
357
394
  var HOOK_MARKER_START = "# keepgoing-hook-start";
358
395
  var HOOK_MARKER_END = "# keepgoing-hook-end";
@@ -381,10 +418,10 @@ function detectShellRcFile() {
381
418
  const shellEnv = process.env["SHELL"] ?? "";
382
419
  const home = os.homedir();
383
420
  if (shellEnv.endsWith("zsh")) {
384
- return { shell: "zsh", rcFile: path3.join(home, ".zshrc") };
421
+ return { shell: "zsh", rcFile: path5.join(home, ".zshrc") };
385
422
  }
386
423
  if (shellEnv.endsWith("bash")) {
387
- return { shell: "bash", rcFile: path3.join(home, ".bashrc") };
424
+ return { shell: "bash", rcFile: path5.join(home, ".bashrc") };
388
425
  }
389
426
  return void 0;
390
427
  }
@@ -400,14 +437,14 @@ function hookInstallCommand() {
400
437
  const hookBlock = shell === "zsh" ? ZSH_HOOK : BASH_HOOK;
401
438
  let existing = "";
402
439
  try {
403
- existing = fs2.readFileSync(rcFile, "utf-8");
440
+ existing = fs4.readFileSync(rcFile, "utf-8");
404
441
  } catch {
405
442
  }
406
443
  if (existing.includes(HOOK_MARKER_START)) {
407
444
  console.log(`KeepGoing hook is already installed in ${rcFile}.`);
408
445
  return;
409
446
  }
410
- fs2.appendFileSync(rcFile, `
447
+ fs4.appendFileSync(rcFile, `
411
448
  ${hookBlock}
412
449
  `, "utf-8");
413
450
  console.log(`KeepGoing hook installed in ${rcFile}.`);
@@ -426,7 +463,7 @@ function hookUninstallCommand() {
426
463
  const { rcFile } = detected;
427
464
  let existing = "";
428
465
  try {
429
- existing = fs2.readFileSync(rcFile, "utf-8");
466
+ existing = fs4.readFileSync(rcFile, "utf-8");
430
467
  } catch {
431
468
  console.log(`${rcFile} not found \u2014 nothing to remove.`);
432
469
  return;
@@ -442,7 +479,7 @@ function hookUninstallCommand() {
442
479
  "g"
443
480
  );
444
481
  const updated = existing.replace(pattern, "").replace(/\n{3,}/g, "\n\n");
445
- fs2.writeFileSync(rcFile, updated, "utf-8");
482
+ fs4.writeFileSync(rcFile, updated, "utf-8");
446
483
  console.log(`KeepGoing hook removed from ${rcFile}.`);
447
484
  console.log(`Reload your shell config to deactivate it:
448
485
  `);
@@ -491,6 +528,7 @@ function parseArgs(argv) {
491
528
  subcommand = arg;
492
529
  }
493
530
  }
531
+ cwd = findGitRoot(cwd);
494
532
  return { command, subcommand, cwd, json, quiet };
495
533
  }
496
534
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keepgoingdev/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Terminal CLI for KeepGoing. Resume side projects without the mental friction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",