claude-code-session-manager 0.47.1 → 0.49.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.
@@ -313,7 +313,7 @@ const schedulerCreatePrd = z.object({
313
313
  originClaudeSessionId: z.string().min(1).max(128).regex(NO_NEWLINE_RE, 'must not contain newlines').optional(),
314
314
  // User-selected Feature/Bug tag (PRD 774) carried from the originating
315
315
  // PromptTicket — deterministic, never LLM-classified.
316
- tag: z.enum(['feature', 'bug', 'discussion']).optional(),
316
+ tag: z.enum(['feature', 'bug', 'discussion', 'build']).optional(),
317
317
  });
318
318
 
319
319
  // Bulk archive: slug list, capped to limit unbounded retag/archive payloads.
@@ -687,6 +687,12 @@ const appGitBranch = z.object({
687
687
  cwd: z.string().min(1).max(4096),
688
688
  }).passthrough();
689
689
 
690
+ // build:resolve-target — see src/main/lib/buildTarget.cjs. cwd is a trusted
691
+ // TAB cwd, not validatePath'd here (same invariant as appGitBranch above).
692
+ const buildResolveTarget = z.object({
693
+ cwd: z.string().min(1).max(4096),
694
+ }).passthrough();
695
+
690
696
  // git:status / git:file-status — see src/main/git.cjs. cwd is validatePath'd
691
697
  // inside the handler (allowedRoots = home), so the schema only enforces shape.
692
698
  const gitStatus = z.object({
@@ -857,6 +863,7 @@ module.exports = {
857
863
  voiceSetRecording,
858
864
  appTestFireHook,
859
865
  appGitBranch,
866
+ buildResolveTarget,
860
867
  gitStatus,
861
868
  gitFileStatus,
862
869
  repoAnalyze,
@@ -0,0 +1,52 @@
1
+ // buildTarget.cjs — resolves a project's publish destination for 'build'-tagged Epics.
2
+ // vitest globals (test/beforeEach/afterEach) — same convention as the other .cjs tests.
3
+ const assert = require('node:assert');
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const { resolveBuildTarget } = require('../buildTarget.cjs');
8
+
9
+ let tmpDir;
10
+
11
+ beforeEach(() => {
12
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-build-target-'));
13
+ });
14
+ afterEach(() => {
15
+ fs.rmSync(tmpDir, { recursive: true, force: true });
16
+ });
17
+
18
+ test('explicit config file present is returned verbatim', () => {
19
+ const archDir = path.join(tmpDir, 'session-manager-operations', 'architecture');
20
+ fs.mkdirSync(archDir, { recursive: true });
21
+ const config = {
22
+ registry: 'npm',
23
+ packageName: 'my-pkg',
24
+ versionBumpPolicy: 'conventional-commits',
25
+ gates: ['typecheck'],
26
+ };
27
+ fs.writeFileSync(path.join(archDir, 'build-target.json'), JSON.stringify(config));
28
+
29
+ assert.deepEqual(resolveBuildTarget(tmpDir), config);
30
+ });
31
+
32
+ test('no config but package.json has name and is not private auto-discovers', () => {
33
+ fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'auto-pkg' }));
34
+
35
+ assert.deepEqual(resolveBuildTarget(tmpDir), {
36
+ registry: 'npm',
37
+ packageName: 'auto-pkg',
38
+ versionBumpPolicy: 'conventional-commits',
39
+ gates: [],
40
+ discovered: true,
41
+ });
42
+ });
43
+
44
+ test('no config and package.json is private returns null', () => {
45
+ fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'priv-pkg', private: true }));
46
+
47
+ assert.equal(resolveBuildTarget(tmpDir), null);
48
+ });
49
+
50
+ test('no config and no package.json returns null', () => {
51
+ assert.equal(resolveBuildTarget(tmpDir), null);
52
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * buildTarget.cjs — resolves a project's publish destination for
3
+ * 'build'-tagged Epics.
4
+ *
5
+ * Reads `<cwd>/session-manager-operations/architecture/build-target.json`
6
+ * when present (a skill-authored doc, not an OWNERS-governed runtime-write
7
+ * namespace — see this repo's CLAUDE.md). Falls back to auto-discovery from
8
+ * `<cwd>/package.json` when no explicit config exists. Pure local-file read;
9
+ * no npm-registry network call here. `cwd` is not validated against
10
+ * `config.cjs`'s `validatePath` allowedRoots — callers must pass a trusted
11
+ * TAB cwd (the same invariant `prdLocations.cjs` relies on), not a raw
12
+ * renderer-supplied string.
13
+ */
14
+ 'use strict';
15
+
16
+ const fs = require('node:fs');
17
+ const path = require('node:path');
18
+
19
+ const BUILD_TARGET_SUBPATH = ['session-manager-operations', 'architecture', 'build-target.json'];
20
+
21
+ function readJson(filePath) {
22
+ try {
23
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * resolveBuildTarget(cwd) → the project's build target config, or null if
31
+ * neither an explicit config nor an auto-discoverable package.json exists.
32
+ */
33
+ function resolveBuildTarget(cwd) {
34
+ if (!cwd || typeof cwd !== 'string') return null;
35
+
36
+ const configPath = path.join(cwd, ...BUILD_TARGET_SUBPATH);
37
+ const explicit = readJson(configPath);
38
+ if (explicit && typeof explicit === 'object' && !Array.isArray(explicit) && typeof explicit.packageName === 'string') {
39
+ return explicit;
40
+ }
41
+
42
+ const pkg = readJson(path.join(cwd, 'package.json'));
43
+ if (pkg && typeof pkg.name === 'string' && pkg.name.length > 0 && pkg.private !== true) {
44
+ return {
45
+ registry: 'npm',
46
+ packageName: pkg.name,
47
+ versionBumpPolicy: 'conventional-commits',
48
+ gates: [],
49
+ discovered: true,
50
+ };
51
+ }
52
+
53
+ return null;
54
+ }
55
+
56
+ module.exports = { resolveBuildTarget };
@@ -1,3 +1,11 @@
1
+ export interface BuildTarget {
2
+ registry: string;
3
+ packageName: string;
4
+ versionBumpPolicy: string;
5
+ gates: string[];
6
+ discovered?: boolean;
7
+ }
8
+
1
9
  export interface ActionOutcome {
2
10
  ok: boolean;
3
11
  kind?: 'info' | 'warn' | 'error';
@@ -250,6 +258,17 @@ export interface McpStatusResult {
250
258
  checkedAt: number;
251
259
  }
252
260
 
261
+ /** One global `~/.claude/agents/<name>.md` persona, per the Agent Library nav page. */
262
+ export interface AgentPersona {
263
+ name: string;
264
+ description: string | null;
265
+ tools: string[];
266
+ path: string;
267
+ body: string;
268
+ /** Project names (basename of cwd) whose currently-open tab overlays this agent. */
269
+ overridingProjects: string[];
270
+ }
271
+
253
272
  export interface VoiceHotkeyConfig {
254
273
  accelerator: string;
255
274
  mode: 'hold' | 'toggle';
@@ -1090,7 +1109,7 @@ export interface ChatCreatePrdPayload {
1090
1109
  /** Originating tab id — used at job completion to route a status prompt back into the tab. */
1091
1110
  sourceTabId?: string;
1092
1111
  /** User-selected Feature/Bug tag (PRD 774) carried from the originating PromptTicket. */
1093
- tag?: 'feature' | 'bug' | 'discussion';
1112
+ tag?: 'feature' | 'bug' | 'discussion' | 'build';
1094
1113
  }
1095
1114
 
1096
1115
  export type ChatCreatePrdResult =
@@ -1170,6 +1189,8 @@ export interface SessionManagerAPI {
1170
1189
  engageRulesPath: () => Promise<string | null>;
1171
1190
  pickDirectory: () => Promise<string | null>;
1172
1191
  gitBranch: (cwd: string) => Promise<string | null>;
1192
+ /** Publish target for 'build'-tagged Epics — null disables the Build toolbar button. */
1193
+ resolveBuildTarget: (cwd: string) => Promise<BuildTarget | null>;
1173
1194
  rebootApp: () => void;
1174
1195
  testFireHook: (args: TestFireHookArgs) => Promise<TestFireHookResult>;
1175
1196
  /** F7 — true under SM_E2E=1; renderer uses this to suppress wizard auto-trigger. */
@@ -1284,6 +1305,9 @@ export interface SessionManagerAPI {
1284
1305
  mcp: {
1285
1306
  status: () => Promise<McpStatusResult>;
1286
1307
  };
1308
+ agents: {
1309
+ listPersonas: () => Promise<AgentPersona[]>;
1310
+ };
1287
1311
  logs: {
1288
1312
  write: (
1289
1313
  scope: string,
@@ -8,6 +8,7 @@ contextBridge.exposeInMainWorld('api', {
8
8
  engageRulesPath: () => ipcRenderer.invoke('app:engage-rules-path'),
9
9
  pickDirectory: () => ipcRenderer.invoke('app:pick-directory'),
10
10
  gitBranch: (cwd) => ipcRenderer.invoke('app:git-branch', { cwd }),
11
+ resolveBuildTarget: (cwd) => ipcRenderer.invoke('build:resolve-target', { cwd }),
11
12
  rebootApp: () => ipcRenderer.send('app:reboot-app'),
12
13
  archiveProject: (encoded) => ipcRenderer.invoke('app:archive-project', { encoded }),
13
14
  testFireHook: (args) => ipcRenderer.invoke('app:test-fire-hook', args),
@@ -145,6 +146,9 @@ contextBridge.exposeInMainWorld('api', {
145
146
  mcp: {
146
147
  status: () => ipcRenderer.invoke('mcp:status'),
147
148
  },
149
+ agents: {
150
+ listPersonas: () => ipcRenderer.invoke('agents:list-personas'),
151
+ },
148
152
  logs: {
149
153
  // ctx is optional: { cwd, tabId, epicId, tags } — when present and
150
154
  // level is 'error', main also appends a tagged line to that project's