starling-ai 0.0.2 → 0.0.4

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
@@ -10,7 +10,7 @@ Agent session manager for Claude Code and OpenAI Codex. Starling discovers local
10
10
 
11
11
  - Discover Claude Code and Codex sessions from local session files.
12
12
  - Browse sessions by catalog, project, or recent activity.
13
- - Create hierarchical catalogs such as `work/research/paper`.
13
+ - Create catalogs such as `paper-review`, with optional hierarchical paths when needed.
14
14
  - Add session metadata, titles, tags, notes, and catalog assignments.
15
15
  - Resume Claude Code and Codex sessions from one command.
16
16
  - Track token usage when it is available in the session file.
@@ -31,6 +31,19 @@ The npm package is named `starling-ai`, but the installed command is:
31
31
  starling --help
32
32
  ```
33
33
 
34
+ The npm install step also installs the bundled Starling skill to:
35
+
36
+ ```text
37
+ ~/.codex/skills/starling/SKILL.md
38
+ ~/.claude/skills/starling/SKILL.md
39
+ ```
40
+
41
+ If npm lifecycle scripts were disabled with `--ignore-scripts`, install the skill manually from the package directory:
42
+
43
+ ```bash
44
+ npm explore -g starling-ai -- npm run install:skill
45
+ ```
46
+
34
47
  Starling requires Node.js 20 or newer.
35
48
 
36
49
  ## Quick Start
@@ -56,27 +69,27 @@ starling resume <session-id>
56
69
  Create a catalog and add a session:
57
70
 
58
71
  ```bash
59
- starling catalog create research/paper
60
- starling catalog add research/paper <session-id> --title "Figure review"
72
+ starling catalog create paper-review
73
+ starling catalog add paper-review <session-id> --title "Figure review"
61
74
  ```
62
75
 
63
76
  Launch Codex and assign the new session to a catalog:
64
77
 
65
78
  ```bash
66
- starling run --catalog research/paper codex
79
+ starling run --catalog paper-review codex
67
80
  ```
68
81
 
69
82
  Launch Claude Code with a Starling config profile:
70
83
 
71
84
  ```bash
72
- starling run --config ds --catalog research/paper claude
85
+ starling run --config ds --catalog paper-review claude
73
86
  ```
74
87
 
75
88
  Starling options must be placed before the agent name. Everything after `claude` or `codex` is passed directly to that agent:
76
89
 
77
90
  ```bash
78
- starling run --catalog research/paper codex exec "summarize this repo"
79
- starling run --catalog research/paper claude --dangerously-skip-permissions
91
+ starling run --catalog paper-review codex exec "summarize this repo"
92
+ starling run --catalog paper-review claude --dangerously-skip-permissions
80
93
  ```
81
94
 
82
95
  ## Commands
@@ -88,7 +101,7 @@ starling session ls
88
101
  starling session ls --all
89
102
  starling session ls --agent claude
90
103
  starling session ls --cataloged
91
- starling session ls --catalog research/paper
104
+ starling session ls --catalog paper-review
92
105
  starling session show <session-id>
93
106
  starling session resume <session-id>
94
107
  starling session meta <session-id> --title "New title" --tags review,important
@@ -100,8 +113,8 @@ starling session delete <session-id> --yes
100
113
  Catalog assignment can also be managed from the session namespace:
101
114
 
102
115
  ```bash
103
- starling session catalog add <session-id> research/paper --title "Important run"
104
- starling session catalog remove <session-id> research/paper
116
+ starling session catalog add <session-id> paper-review --title "Important run"
117
+ starling session catalog remove <session-id> paper-review
105
118
  starling session catalog clear <session-id>
106
119
  ```
107
120
 
@@ -113,6 +126,7 @@ starling catalog create parent/child/grandchild
113
126
  starling catalog create child --parent parent
114
127
  starling catalog ls
115
128
  starling catalog tree
129
+ starling catalog tree --sessions
116
130
  starling catalog show <catalog>
117
131
  starling catalog add <catalog> <session-id>
118
132
  starling catalog detach <catalog> <session-id>
@@ -189,8 +203,8 @@ starling model add demo --agent codex \
189
203
  Use a profile when launching an agent:
190
204
 
191
205
  ```bash
192
- starling run --config demo --catalog research/paper codex
193
- starling run --config ds --catalog research/paper claude
206
+ starling run --config demo --catalog paper-review codex
207
+ starling run --config ds --catalog paper-review claude
194
208
  ```
195
209
 
196
210
  If `--config` is not provided, Starling uses the agent's normal default configuration.
@@ -243,7 +257,7 @@ The repository includes a VS Code extension in `vscode-extension/`.
243
257
 
244
258
  The Starling sidebar contains three views:
245
259
 
246
- - Catalog: hierarchical catalog tree with sessions.
260
+ - Catalog: hierarchical catalog tree, with sessions shown on request.
247
261
  - Projects: project directory tree with session counts.
248
262
  - Sessions: recent sessions with incremental loading.
249
263
 
package/dist/index.js CHANGED
@@ -683,15 +683,21 @@ function removeSpace(id) {
683
683
  const idx = store.spaces.findIndex((s) => s.id === id || s.name === id);
684
684
  if (idx === -1) return false;
685
685
  const space = store.spaces[idx];
686
- for (const b of store.bookmarks) {
687
- b.space_ids = b.space_ids.filter((sid) => sid !== space.id);
688
- }
689
- for (const s of store.spaces) {
690
- if (s.parent_id === space.id) {
691
- s.parent_id = space.parent_id;
686
+ const idsToRemove = /* @__PURE__ */ new Set([space.id]);
687
+ let changed = true;
688
+ while (changed) {
689
+ changed = false;
690
+ for (const candidate of store.spaces) {
691
+ if (candidate.parent_id && idsToRemove.has(candidate.parent_id) && !idsToRemove.has(candidate.id)) {
692
+ idsToRemove.add(candidate.id);
693
+ changed = true;
694
+ }
692
695
  }
693
696
  }
694
- store.spaces.splice(idx, 1);
697
+ for (const b of store.bookmarks) {
698
+ b.space_ids = b.space_ids.filter((sid) => !idsToRemove.has(sid));
699
+ }
700
+ store.spaces = store.spaces.filter((s) => !idsToRemove.has(s.id));
695
701
  saveStore(store);
696
702
  return true;
697
703
  }
@@ -1546,9 +1552,9 @@ ${chalk4.yellow(`Pins in ${row.name} (${row.id})`)}`);
1546
1552
  }
1547
1553
  }
1548
1554
  });
1549
- space.command("tree").description("Display catalogs as a hierarchical tree").action(() => {
1555
+ space.command("tree").description("Display catalogs as a hierarchical tree").option("--sessions", "show sessions assigned to each catalog").action((opts) => {
1550
1556
  const spaces = listSpaces();
1551
- const bookmarks = listBookmarks();
1557
+ const bookmarks = opts.sessions ? listBookmarks() : [];
1552
1558
  console.log(formatSpaceTree(spaces, bookmarks));
1553
1559
  });
1554
1560
  space.command("add <catalog> <session-id>").description("Add a session to a catalog").option("-t, --title <title>", "pin title when creating a new pin").option("--tags <tags>", "comma-separated tags when creating a new pin").action(async (catalog, sessionId, opts) => {
@@ -2982,6 +2988,7 @@ function registerRunCommand(program2) {
2982
2988
  const beforeRun = hookRun ? /* @__PURE__ */ new Map() : await snapshotSessions(provider);
2983
2989
  const beforeRunProjectFiles = provider === "claude" && !hookRun ? snapshotProjectSessions(normalizedCwd) : /* @__PURE__ */ new Map();
2984
2990
  const cleanupRunState = async () => {
2991
+ syncClaudeProfileSettingsFromRunSettings(resolvedConfig, hookRun?.settingsPath ?? null);
2985
2992
  cleanupClaudeRunHookSettings(hookRun);
2986
2993
  await cleanupCodexRunConfig(codexConfig);
2987
2994
  restoreCodexDefaultConfig(codexDefaultSnapshot);
@@ -3207,6 +3214,38 @@ function cleanupClaudeRunHookSettings(hookRun) {
3207
3214
  }
3208
3215
  }
3209
3216
  }
3217
+ var CLAUDE_SETTINGS_SYNC_KEYS = [
3218
+ "permissions",
3219
+ "projects",
3220
+ "trust",
3221
+ "trustedProjects",
3222
+ "enableAllProjectMcpServers",
3223
+ "enabledMcpjsonServers",
3224
+ "disabledMcpjsonServers"
3225
+ ];
3226
+ function syncClaudeProfileSettingsFromRunSettings(sourceConfigPath, runSettingsPath) {
3227
+ if (!sourceConfigPath || !runSettingsPath || !existsSync6(runSettingsPath)) return false;
3228
+ const sourceExt = extname2(sourceConfigPath).toLowerCase();
3229
+ if (sourceExt !== ".json" && sourceExt !== ".jsonc") return false;
3230
+ try {
3231
+ const sourceSettings = readSettingsJsonObject(sourceConfigPath, sourceExt === ".jsonc");
3232
+ const runSettings = readSettingsJsonObject(runSettingsPath, false);
3233
+ if (!sourceSettings || !runSettings) return false;
3234
+ let changed = false;
3235
+ for (const key of CLAUDE_SETTINGS_SYNC_KEYS) {
3236
+ if (!Object.prototype.hasOwnProperty.call(runSettings, key)) continue;
3237
+ if (jsonStable(sourceSettings[key]) === jsonStable(runSettings[key])) continue;
3238
+ sourceSettings[key] = cloneJsonValue(runSettings[key]);
3239
+ changed = true;
3240
+ }
3241
+ if (!changed) return false;
3242
+ atomicWriteJSON(sourceConfigPath, sourceSettings);
3243
+ return true;
3244
+ } catch (error) {
3245
+ console.error(chalk6.yellow(`Could not sync Claude settings to ${sourceConfigPath}: ${String(error)}`));
3246
+ return false;
3247
+ }
3248
+ }
3210
3249
  async function createCodexRunConfig(configPath) {
3211
3250
  if (!configPath) {
3212
3251
  return null;
@@ -3658,14 +3697,24 @@ function readSessionIdFromHookEntry(value) {
3658
3697
  function readClaudeSettingsObject(configPath) {
3659
3698
  if (!configPath) return {};
3660
3699
  try {
3661
- const raw = readFileSync5(configPath, "utf-8");
3662
- const parsed = JSON.parse(raw);
3663
- if (isRecord4(parsed)) return parsed;
3700
+ const parsed = readSettingsJsonObject(configPath, extname2(configPath).toLowerCase() === ".jsonc");
3701
+ if (parsed) return parsed;
3664
3702
  } catch {
3665
3703
  console.log(chalk6.yellow("Could not add Claude SessionStart hook because settings is not parseable JSON."));
3666
3704
  }
3667
3705
  return null;
3668
3706
  }
3707
+ function readSettingsJsonObject(filePath, allowComments) {
3708
+ const raw = readFileSync5(filePath, "utf-8");
3709
+ const parsed = JSON.parse(allowComments ? stripJsonComments(raw) : raw);
3710
+ return isRecord4(parsed) ? parsed : null;
3711
+ }
3712
+ function jsonStable(value) {
3713
+ return JSON.stringify(value);
3714
+ }
3715
+ function cloneJsonValue(value) {
3716
+ return value === void 0 ? void 0 : JSON.parse(JSON.stringify(value));
3717
+ }
3669
3718
  function isRecord4(value) {
3670
3719
  return typeof value === "object" && value !== null && !Array.isArray(value);
3671
3720
  }
@@ -4694,7 +4743,7 @@ function escapeRegex(value) {
4694
4743
  // src/index.ts
4695
4744
  var program = new Command7();
4696
4745
  program.enablePositionalOptions();
4697
- program.name("starling").description("Agent session manager \u2014 discover, pin, and organize AI coding sessions").version("0.1.0");
4746
+ program.name("starling").description("Agent session manager \u2014 discover, pin, and organize AI coding sessions").version("0.0.4");
4698
4747
  registerSessionCommand(program);
4699
4748
  registerPinCommand(program);
4700
4749
  registerSpaceCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starling-ai",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Agent session manager — discover, bookmark, and organize AI coding sessions",
5
5
  "type": "module",
6
6
  "repository": {
@@ -12,6 +12,8 @@
12
12
  },
13
13
  "files": [
14
14
  "dist",
15
+ "skills",
16
+ "scripts/install-agent-skills.js",
15
17
  "package.json",
16
18
  "README.md",
17
19
  "LICENSE"
@@ -19,6 +21,8 @@
19
21
  "scripts": {
20
22
  "build": "tsup",
21
23
  "dev": "tsup --watch",
24
+ "postinstall": "node scripts/install-agent-skills.js",
25
+ "install:skill": "node scripts/install-agent-skills.js",
22
26
  "prepack": "npm run build",
23
27
  "test": "vitest run",
24
28
  "lint": "tsc --noEmit"
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { copyFileSync, existsSync, mkdirSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
8
+ const source = join(packageRoot, "skills", "starling", "SKILL.md");
9
+ const targets = [
10
+ join(homedir(), ".codex", "skills", "starling", "SKILL.md"),
11
+ join(homedir(), ".claude", "skills", "starling", "SKILL.md"),
12
+ ];
13
+
14
+ try {
15
+ if (!existsSync(source)) {
16
+ console.warn(`[starling] Codex skill not found in package: ${source}`);
17
+ process.exit(0);
18
+ }
19
+
20
+ for (const target of targets) {
21
+ mkdirSync(dirname(target), { recursive: true });
22
+ copyFileSync(source, target);
23
+ console.log(`[starling] Installed skill: ${target}`);
24
+ }
25
+ } catch (error) {
26
+ const message = error instanceof Error ? error.message : String(error);
27
+ console.warn(`[starling] Could not install skills: ${message}`);
28
+ }
@@ -0,0 +1,200 @@
1
+ ---
2
+ name: starling-agent-session
3
+ description: Use when working with Starling, the local agent session manager for Claude Code and Codex: organizing sessions into catalogs, managing projects/session, launching agents with catalog assignment, configuring Claude/Codex profiles.
4
+ ---
5
+
6
+ # Starling
7
+
8
+ Starling is a local session manager for Claude Code and Codex. It discovers session files, groups sessions by project, organizes them into catalogs, stores metadata under `~/.starling`, and provides a VS Code sidebar.
9
+
10
+
11
+ ## Catalogs
12
+
13
+ Use one plain catalog name in examples unless explaining hierarchy:
14
+
15
+ ```bash
16
+ starling catalog create paper-review
17
+ starling catalog add paper-review <session-id> --title "Figure review"
18
+ starling catalog tree
19
+ starling catalog show paper-review
20
+ ```
21
+
22
+ Hierarchy is path-based:
23
+
24
+ ```bash
25
+ starling catalog create research/paper
26
+ starling catalog create child --parent research
27
+ ```
28
+
29
+ `research/paper` means catalog `paper` under parent catalog `research`; it is not a single catalog name.
30
+
31
+ Useful catalog operations:
32
+
33
+ ```bash
34
+ starling catalog ls
35
+ starling catalog show <catalog>
36
+ starling catalog detach <catalog> <session-id>
37
+ starling catalog clear <catalog>
38
+ starling catalog rename <catalog> <new-name>
39
+ starling catalog delete <catalog>
40
+ ```
41
+
42
+ Deleting a catalog recursively deletes child catalogs from Starling metadata. It does not delete real session files.
43
+
44
+ ## Sessions
45
+
46
+ Common session commands:
47
+
48
+ ```bash
49
+ starling session ls
50
+ starling session ls --all
51
+ starling session ls --cataloged
52
+ starling session ls --catalog paper-review
53
+ starling session show <session-id>
54
+ starling resume <session-id>
55
+ ```
56
+
57
+ Manage catalog assignment from the session namespace:
58
+
59
+ ```bash
60
+ starling session catalog add <session-id> paper-review --title "Important run"
61
+ starling session catalog remove <session-id> paper-review
62
+ starling session catalog clear <session-id>
63
+ ```
64
+
65
+ Use 13-character session ID display when changing UI or tables, unless full IDs are required.
66
+
67
+ ## Projects And Index
68
+
69
+ Project views are built from the local session index by default:
70
+
71
+ ```bash
72
+ starling project ls
73
+ starling project ls --all
74
+ starling project show /path/to/project
75
+ starling session index status
76
+ starling session index rebuild
77
+ starling session index clear
78
+ ```
79
+
80
+ If project output is stale, rebuild the index. If performance is being investigated, compare indexed and scan modes:
81
+
82
+ ```bash
83
+ starling project ls --refresh-index
84
+ starling project ls --no-index
85
+ ```
86
+
87
+ ## Running Agents
88
+
89
+ Starling arguments go before the agent name. Agent arguments go after the agent name and should be passed through unchanged:
90
+
91
+ ```bash
92
+ starling run --catalog paper-review codex
93
+ starling run --catalog paper-review codex exec "summarize this repo"
94
+ starling run --config ds --catalog paper-review claude
95
+ starling run --catalog paper-review claude --dangerously-skip-permissions
96
+ ```
97
+
98
+ If `--config` is omitted, Starling should use the agent's normal default configuration and must not overwrite default Codex or Claude config files.
99
+
100
+ ## Model Profiles
101
+
102
+ Profiles live under:
103
+
104
+ ```text
105
+ ~/.starling/settings/claude/<name>.json
106
+ ~/.starling/settings/codex/<name>.json
107
+ ```
108
+
109
+ List profiles:
110
+
111
+ ```bash
112
+ starling model ls
113
+ starling model ls --agent claude
114
+ starling model ls --agent codex
115
+ ```
116
+
117
+ Create profiles:
118
+
119
+ ```bash
120
+ starling model add ds --agent claude --model deepseek-v4-pro --base-url https://api.example.com --api-key "$API_KEY"
121
+ starling model add demo --agent codex --model gpt-5.2 --base-url https://api.example.com/v1 --api-key "$OPENAI_API_KEY" --reasoning high --wire-api responses
122
+ ```
123
+
124
+ Codex profiles use JSON with `auth` and `config`. Starling converts them into temporary Codex config for a run.
125
+
126
+ ## VS Code Extension
127
+
128
+ Extension source is in:
129
+
130
+ ```text
131
+ vscode-extension/
132
+ ```
133
+
134
+ Compile before claiming extension changes work:
135
+
136
+ ```bash
137
+ cd /data20T/dev/Starling/vscode-extension
138
+ npm run compile
139
+ ```
140
+
141
+ The sidebar has three views in this order:
142
+
143
+ ```text
144
+ Catalog
145
+ Projects
146
+ Sessions
147
+ ```
148
+
149
+ The extension calls the `starling` CLI. If VS Code cannot find it, use the install prompt or set `starling.cliPath` to an absolute path.
150
+
151
+ ## Development And Release
152
+
153
+ For local development:
154
+
155
+ ```bash
156
+ cd /data20T/dev/Starling
157
+ npm install
158
+ npm run build
159
+ npm run lint
160
+ npm test
161
+ npm link
162
+ ```
163
+
164
+ For testing the published package:
165
+
166
+ ```bash
167
+ npm uninstall -g starling-ai
168
+ npm install -g starling-ai
169
+ starling --version
170
+ ```
171
+
172
+ Publishing uses tags:
173
+
174
+ ```bash
175
+ git tag vX.Y.Z
176
+ git tag vsx-vX.Y.Z
177
+ git push origin vX.Y.Z vsx-vX.Y.Z
178
+ ```
179
+
180
+ `vX.Y.Z` triggers npm publish. `vsx-vX.Y.Z` triggers VS Code Marketplace publish. A GitHub Release can include both assets:
181
+
182
+ ```bash
183
+ npm pack --pack-destination .
184
+ cd vscode-extension && npx @vscode/vsce package
185
+ gh release create vX.Y.Z ../starling-ai-X.Y.Z.tgz starling-ai-X.Y.Z.vsix --title "vX.Y.Z" --generate-notes
186
+ ```
187
+
188
+ If `gh release create` fails with a 403 while `GITHUB_TOKEN` is set, try:
189
+
190
+ ```bash
191
+ env -u GITHUB_TOKEN gh release create ...
192
+ ```
193
+
194
+ ## Guardrails
195
+
196
+ - Do not remove or rewrite user data in `~/.starling`, `~/.claude`, or `~/.codex` unless explicitly requested.
197
+ - Do not let `starling run --config <name> codex` mutate the user's default `~/.codex/config.toml`.
198
+ - Keep examples with a single catalog name unless the task is specifically about hierarchy.
199
+ - When changing CLI behavior, update README, tests, and `dist/index.js`.
200
+ - When changing extension behavior, update `vscode-extension/package.json` contributions if needed and run `npm run compile`.