neuvikon 0.2.6 → 0.2.7

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 CHANGED
@@ -74,7 +74,7 @@ being used, add the block above by hand.
74
74
  | | |
75
75
  |---|---|
76
76
  | `~/.neuvikon/config.json` | Token and deployment URL, `0600` |
77
- | `.neuvikon-session` | Which ticket this directory is tracking. Git-ignored by `init` |
77
+ | `.neuvikon-session[.<id>]` | Which ticket this directory (or, under Claude Code, this agent) is tracking. Git-ignored by `init` |
78
78
  | `--dev` | Target the development deployment instead of production |
79
79
  | `NEUVIKON_URL` | Point at a self-hosted deployment. `--url` does the same per command |
80
80
  | `NEUVIKON_TOKEN` | Use this token instead of logging in — for CI and anywhere a browser cannot open |
package/dist/index.mjs CHANGED
@@ -156,17 +156,32 @@ function writeCursorRule(root) {
156
156
  action: existing ? "updated" : "created"
157
157
  };
158
158
  }
159
- /** Keeps the per-directory session file out of the user's commits. */
159
+ /**
160
+ * Keeps the per-directory session file(s) out of the user's commits. Globbed
161
+ * because each concurrent agent gets its own `.neuvikon-session.<id>` file
162
+ * now (see `session.ts`) — an exact-match `.neuvikon-session` line no longer
163
+ * covers them, so an older, already-ignored project is migrated in place.
164
+ */
160
165
  function ignoreSessionFile(root) {
161
166
  const path = join(root, ".gitignore");
162
167
  if (!existsSync(join(root, ".git")) && !existsSync(path)) return null;
163
168
  const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
164
- if (existing.split("\n").some((line) => line.trim() === ".neuvikon-session")) return {
169
+ const lines = existing.split("\n");
170
+ if (lines.some((line) => line.trim() === ".neuvikon-session*")) return {
165
171
  path: ".gitignore",
166
172
  action: "unchanged"
167
173
  };
174
+ const legacyIndex = lines.findIndex((line) => line.trim() === ".neuvikon-session");
175
+ if (legacyIndex !== -1) {
176
+ lines[legacyIndex] = ".neuvikon-session*";
177
+ writeFileSync(path, lines.join("\n"));
178
+ return {
179
+ path: ".gitignore",
180
+ action: "updated"
181
+ };
182
+ }
168
183
  const prefix = existing.length === 0 ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
169
- writeFileSync(path, `${existing}${prefix}# neuvikon CLI session state\n.neuvikon-session\n`);
184
+ writeFileSync(path, `${existing}${prefix}# neuvikon CLI session state\n.neuvikon-session*\n`);
170
185
  return {
171
186
  path: ".gitignore",
172
187
  action: existing ? "updated" : "created"
@@ -452,11 +467,25 @@ async function login(flags) {
452
467
  //#endregion
453
468
  //#region src/session.ts
454
469
  /**
470
+ * Distinguishes concurrent agents working in the *same* checkout — two Claude
471
+ * Code panes both running `claude` in this directory get two session files,
472
+ * because each one's process tree carries its own CLAUDE_CODE_SESSION_ID. A
473
+ * tool that doesn't set it (or a person typing the command by hand) falls
474
+ * back to the pre-multi-agent behavior of one session per directory.
475
+ */
476
+ function instanceKey() {
477
+ return process.env.CLAUDE_CODE_SESSION_ID?.trim() || null;
478
+ }
479
+ /**
455
480
  * Scoped to the working directory rather than the machine: two checkouts driven
456
- * in parallel are two sessions, which is what running two agents means.
481
+ * in parallel are two sessions, which is what running two agents means. Within
482
+ * one checkout, `instanceKey()` further scopes it per agent so two panes in the
483
+ * same directory don't stop each other's session out from under them.
457
484
  */
458
485
  function sessionPath() {
459
- return join(process.cwd(), ".neuvikon-session");
486
+ const key = instanceKey();
487
+ const filename = key ? `.neuvikon-session.${key}` : ".neuvikon-session";
488
+ return join(process.cwd(), filename);
460
489
  }
461
490
  function readSession() {
462
491
  let raw;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neuvikon",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Tell Neuvikon which ticket your coding agent is working on.",
5
5
  "keywords": [
6
6
  "neuvikon",