teamshare-bridge 0.1.0 → 0.2.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 (60) hide show
  1. package/dist/bridge/daemon.js +239 -8
  2. package/dist/bridge/daemon.js.map +1 -1
  3. package/dist/bridge/index.js +10 -0
  4. package/dist/bridge/index.js.map +1 -1
  5. package/dist/bridge/local-server.d.ts +6 -1
  6. package/dist/bridge/local-server.js +24 -0
  7. package/dist/bridge/local-server.js.map +1 -1
  8. package/dist/bridge/protocol.js +33 -4
  9. package/dist/bridge/protocol.js.map +1 -1
  10. package/dist/bridge/spawn.d.ts +20 -4
  11. package/dist/bridge/spawn.js +93 -29
  12. package/dist/bridge/spawn.js.map +1 -1
  13. package/dist/cli/index.js +1102 -64
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/lib/api.d.ts +203 -5
  16. package/dist/lib/api.js +144 -3
  17. package/dist/lib/api.js.map +1 -1
  18. package/dist/lib/chat-reply.d.ts +22 -2
  19. package/dist/lib/chat-reply.js +139 -67
  20. package/dist/lib/chat-reply.js.map +1 -1
  21. package/dist/lib/config.d.ts +103 -0
  22. package/dist/lib/config.js +272 -0
  23. package/dist/lib/config.js.map +1 -1
  24. package/dist/lib/doc-reply.d.ts +11 -0
  25. package/dist/lib/doc-reply.js +18 -34
  26. package/dist/lib/doc-reply.js.map +1 -1
  27. package/dist/lib/harness.d.ts +38 -0
  28. package/dist/lib/harness.js +139 -0
  29. package/dist/lib/harness.js.map +1 -0
  30. package/dist/lib/llm.d.ts +30 -2
  31. package/dist/lib/llm.js +284 -30
  32. package/dist/lib/llm.js.map +1 -1
  33. package/dist/lib/lock.d.ts +1 -1
  34. package/dist/lib/models.d.ts +11 -0
  35. package/dist/lib/models.js +30 -1
  36. package/dist/lib/models.js.map +1 -1
  37. package/dist/lib/orchestrator/client.d.ts +27 -0
  38. package/dist/lib/orchestrator/client.js +135 -0
  39. package/dist/lib/orchestrator/client.js.map +1 -0
  40. package/dist/lib/orchestrator/index.d.ts +5 -0
  41. package/dist/lib/orchestrator/index.js +17 -0
  42. package/dist/lib/orchestrator/index.js.map +1 -0
  43. package/dist/lib/orchestrator/runner.d.ts +18 -0
  44. package/dist/lib/orchestrator/runner.js +177 -0
  45. package/dist/lib/orchestrator/runner.js.map +1 -0
  46. package/dist/lib/orchestrator/worktree.d.ts +43 -0
  47. package/dist/lib/orchestrator/worktree.js +243 -0
  48. package/dist/lib/orchestrator/worktree.js.map +1 -0
  49. package/dist/lib/session-stream.d.ts +1 -1
  50. package/dist/lib/skills.d.ts +21 -0
  51. package/dist/lib/skills.js +80 -0
  52. package/dist/lib/skills.js.map +1 -0
  53. package/dist/lib/usage.d.ts +52 -0
  54. package/dist/lib/usage.js +69 -0
  55. package/dist/lib/usage.js.map +1 -0
  56. package/package.json +3 -1
  57. package/skills/teamshare-auth-rbac/SKILL.md +79 -0
  58. package/skills/teamshare-cdd/SKILL.md +145 -0
  59. package/skills/teamshare-modularity/SKILL.md +92 -0
  60. package/tools/usage_report.py +223 -0
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorktreeRoot = getWorktreeRoot;
4
+ exports.createWorktree = createWorktree;
5
+ exports.removeWorktree = removeWorktree;
6
+ exports.gitStatus = gitStatus;
7
+ exports.gitCommit = gitCommit;
8
+ exports.gitMerge = gitMerge;
9
+ exports.gitDiff = gitDiff;
10
+ /**
11
+ * Git Worktree Manager: creates, manages, and removes Git worktrees
12
+ * for orchestrator tasks. All git operations use native CLI.
13
+ */
14
+ const child_process_1 = require("child_process");
15
+ const fs_1 = require("fs");
16
+ const path_1 = require("path");
17
+ const log = {
18
+ info: (msg) => console.log(`[worktree] ${msg}`),
19
+ warn: (msg) => console.warn(`[worktree] ${msg}`),
20
+ error: (msg) => console.error(`[worktree] ${msg}`),
21
+ };
22
+ /**
23
+ * Validate that a path is safe (no traversal, no network drives).
24
+ * Returns true if the path is safe to use.
25
+ */
26
+ function validatePath(p) {
27
+ const resolved = (0, path_1.resolve)(p);
28
+ // Block UNC paths (\\server\share)
29
+ if (resolved.startsWith('\\\\'))
30
+ return false;
31
+ // Block paths with ..
32
+ if (p.includes('..'))
33
+ return false;
34
+ // Block absolute paths that escape the user profile (basic check)
35
+ const home = process.env.USERPROFILE ?? process.env.HOME ?? '';
36
+ if (home && !resolved.startsWith(home) && !resolved.startsWith('/tmp')) {
37
+ return false;
38
+ }
39
+ return true;
40
+ }
41
+ /**
42
+ * Get the worktree root directory for a project.
43
+ * Derived from the project's linked path.
44
+ */
45
+ function getWorktreeRoot(projectPath) {
46
+ return (0, path_1.join)((0, path_1.resolve)(projectPath, '..'), '.teamshare-worktrees');
47
+ }
48
+ /**
49
+ * Create a new Git worktree for an orchestrator task.
50
+ */
51
+ function createWorktree(repoPath, branch, baseBranch, taskId) {
52
+ // Validate paths
53
+ if (!validatePath(repoPath)) {
54
+ throw new Error(`Invalid repository path: ${repoPath}`);
55
+ }
56
+ const worktreeRoot = getWorktreeRoot(repoPath);
57
+ const worktreePath = (0, path_1.join)(worktreeRoot, `task-${taskId}`);
58
+ // Ensure worktree root exists
59
+ if (!(0, fs_1.existsSync)(worktreeRoot)) {
60
+ (0, fs_1.mkdirSync)(worktreeRoot, { recursive: true });
61
+ }
62
+ // Check if worktree already exists
63
+ if ((0, fs_1.existsSync)(worktreePath)) {
64
+ log.warn(`Worktree already exists at ${worktreePath}, removing`);
65
+ removeWorktree(repoPath, worktreePath);
66
+ }
67
+ // Create the worktree
68
+ try {
69
+ (0, child_process_1.execSync)(`git worktree add "${worktreePath}" -b ${branch} ${baseBranch}`, { cwd: repoPath, encoding: 'utf-8', timeout: 30_000 });
70
+ }
71
+ catch (err) {
72
+ // If branch already exists, try without -b
73
+ const msg = err instanceof Error ? err.message : String(err);
74
+ if (msg.includes('already exists')) {
75
+ (0, child_process_1.execSync)(`git worktree add "${worktreePath}" ${branch}`, { cwd: repoPath, encoding: 'utf-8', timeout: 30_000 });
76
+ }
77
+ else {
78
+ throw err;
79
+ }
80
+ }
81
+ // Get the current commit hash
82
+ const commitHash = (0, child_process_1.execSync)('git rev-parse HEAD', {
83
+ cwd: worktreePath,
84
+ encoding: 'utf-8',
85
+ timeout: 5_000,
86
+ }).trim();
87
+ log.info(`Created worktree at ${worktreePath} (branch: ${branch}, commit: ${commitHash})`);
88
+ return { path: worktreePath, branch, commitHash };
89
+ }
90
+ /**
91
+ * Remove a Git worktree.
92
+ */
93
+ function removeWorktree(repoPath, worktreePath) {
94
+ try {
95
+ // Discard any uncommitted changes
96
+ (0, child_process_1.execSync)('git checkout -- .', {
97
+ cwd: worktreePath,
98
+ encoding: 'utf-8',
99
+ timeout: 10_000,
100
+ });
101
+ (0, child_process_1.execSync)('git clean -fd', {
102
+ cwd: worktreePath,
103
+ encoding: 'utf-8',
104
+ timeout: 10_000,
105
+ });
106
+ // Remove the worktree
107
+ (0, child_process_1.execSync)(`git worktree remove "${worktreePath}" --force`, {
108
+ cwd: repoPath,
109
+ encoding: 'utf-8',
110
+ timeout: 30_000,
111
+ });
112
+ log.info(`Removed worktree at ${worktreePath}`);
113
+ }
114
+ catch (err) {
115
+ log.error(`Failed to remove worktree: ${err instanceof Error ? err.message : String(err)}`);
116
+ }
117
+ }
118
+ /**
119
+ * Get git status for a worktree.
120
+ */
121
+ function gitStatus(worktreePath) {
122
+ try {
123
+ const branch = (0, child_process_1.execSync)('git branch --show-current', {
124
+ cwd: worktreePath,
125
+ encoding: 'utf-8',
126
+ timeout: 5_000,
127
+ }).trim();
128
+ const statusOutput = (0, child_process_1.execSync)('git status --porcelain', {
129
+ cwd: worktreePath,
130
+ encoding: 'utf-8',
131
+ timeout: 5_000,
132
+ });
133
+ const files = statusOutput
134
+ .split('\n')
135
+ .filter((line) => line.trim())
136
+ .map((line) => line.slice(3));
137
+ const aheadOutput = (0, child_process_1.execSync)('git rev-list --count HEAD @{u}..HEAD 2>/dev/null || echo 0', {
138
+ cwd: worktreePath,
139
+ encoding: 'utf-8',
140
+ timeout: 5_000,
141
+ }).trim();
142
+ return {
143
+ branch,
144
+ dirty: files.length > 0,
145
+ ahead: parseInt(aheadOutput, 10) || 0,
146
+ files,
147
+ };
148
+ }
149
+ catch (err) {
150
+ log.error(`git status failed: ${err instanceof Error ? err.message : String(err)}`);
151
+ return { branch: 'unknown', dirty: false, ahead: 0, files: [] };
152
+ }
153
+ }
154
+ /**
155
+ * Commit changes in a worktree.
156
+ */
157
+ function gitCommit(worktreePath, message, files) {
158
+ try {
159
+ if (files && files.length > 0) {
160
+ (0, child_process_1.execSync)(`git add ${files.join(' ')}`, {
161
+ cwd: worktreePath,
162
+ encoding: 'utf-8',
163
+ timeout: 10_000,
164
+ });
165
+ }
166
+ else {
167
+ (0, child_process_1.execSync)('git add -A', {
168
+ cwd: worktreePath,
169
+ encoding: 'utf-8',
170
+ timeout: 10_000,
171
+ });
172
+ }
173
+ (0, child_process_1.execSync)(`git commit -m "${message}"`, {
174
+ cwd: worktreePath,
175
+ encoding: 'utf-8',
176
+ timeout: 10_000,
177
+ });
178
+ const hash = (0, child_process_1.execSync)('git rev-parse HEAD', {
179
+ cwd: worktreePath,
180
+ encoding: 'utf-8',
181
+ timeout: 5_000,
182
+ }).trim();
183
+ log.info(`Committed: ${hash} - ${message}`);
184
+ return hash;
185
+ }
186
+ catch (err) {
187
+ log.error(`git commit failed: ${err instanceof Error ? err.message : String(err)}`);
188
+ throw err;
189
+ }
190
+ }
191
+ /**
192
+ * Merge a branch into the integration branch.
193
+ */
194
+ function gitMerge(repoPath, sourceBranch, targetBranch) {
195
+ try {
196
+ // Checkout target branch
197
+ (0, child_process_1.execSync)(`git checkout ${targetBranch}`, {
198
+ cwd: repoPath,
199
+ encoding: 'utf-8',
200
+ timeout: 10_000,
201
+ });
202
+ // Merge source branch
203
+ (0, child_process_1.execSync)(`git merge ${sourceBranch} --no-edit`, {
204
+ cwd: repoPath,
205
+ encoding: 'utf-8',
206
+ timeout: 30_000,
207
+ });
208
+ log.info(`Merged ${sourceBranch} into ${targetBranch}`);
209
+ return { success: true };
210
+ }
211
+ catch (err) {
212
+ // Check for merge conflicts
213
+ try {
214
+ const conflictOutput = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', {
215
+ cwd: repoPath,
216
+ encoding: 'utf-8',
217
+ timeout: 5_000,
218
+ });
219
+ const conflictFiles = conflictOutput.split('\n').filter((f) => f.trim());
220
+ return { success: false, conflictFiles };
221
+ }
222
+ catch {
223
+ return { success: false };
224
+ }
225
+ }
226
+ }
227
+ /**
228
+ * Get the diff for a worktree.
229
+ */
230
+ function gitDiff(worktreePath) {
231
+ try {
232
+ return (0, child_process_1.execSync)('git diff --stat', {
233
+ cwd: worktreePath,
234
+ encoding: 'utf-8',
235
+ timeout: 10_000,
236
+ });
237
+ }
238
+ catch (err) {
239
+ log.error(`git diff failed: ${err instanceof Error ? err.message : String(err)}`);
240
+ return '';
241
+ }
242
+ }
243
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../../src/lib/orchestrator/worktree.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ export interface SessionMeta {
8
8
  agentId: string;
9
9
  projectId?: string;
10
10
  taskId?: string;
11
- mode: 'run' | 'chat';
11
+ mode: 'run' | 'chat' | 'build';
12
12
  model?: string | null;
13
13
  }
14
14
  export declare function sessionsDir(): string;
@@ -0,0 +1,21 @@
1
+ /** The three skills shipped with the bridge (source of truth: ./skills). */
2
+ export declare const SHIPPED_SKILLS: readonly ["teamshare-cdd", "teamshare-modularity", "teamshare-auth-rbac"];
3
+ /** Source: <package>/skills (ships in the npm tarball via package.json files). */
4
+ export declare function skillsSourceDir(): string;
5
+ /** Target: ~/.agents/skills (opencode convention) unless overridden. */
6
+ export declare function skillsTargetDir(): string;
7
+ export declare function listSkills(): {
8
+ available: string[];
9
+ installed: string[];
10
+ target: string;
11
+ };
12
+ /** Idempotently copies every shipped skill into the target skills directory. */
13
+ export declare function installSkills(): {
14
+ copied: string[];
15
+ target: string;
16
+ };
17
+ /** Removes the shipped skills from the target directory (leaves others). */
18
+ export declare function uninstallSkills(): {
19
+ removed: string[];
20
+ target: string;
21
+ };
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SHIPPED_SKILLS = void 0;
4
+ exports.skillsSourceDir = skillsSourceDir;
5
+ exports.skillsTargetDir = skillsTargetDir;
6
+ exports.listSkills = listSkills;
7
+ exports.installSkills = installSkills;
8
+ exports.uninstallSkills = uninstallSkills;
9
+ /**
10
+ * TeamShare agent skills (IMP-603): ships the opencode skills that enforce
11
+ * documents-driven development, modular architecture and auth/RBAC inside
12
+ * TeamShare repos. The bridge installs them into the user's opencode skills
13
+ * directory (~/.agents/skills by default) so every harness session can load
14
+ * them via their SKILL.md frontmatter.
15
+ */
16
+ const node_fs_1 = require("node:fs");
17
+ const node_os_1 = require("node:os");
18
+ const node_path_1 = require("node:path");
19
+ /** The three skills shipped with the bridge (source of truth: ./skills). */
20
+ exports.SHIPPED_SKILLS = [
21
+ 'teamshare-cdd',
22
+ 'teamshare-modularity',
23
+ 'teamshare-auth-rbac',
24
+ ];
25
+ /** Source: <package>/skills (ships in the npm tarball via package.json files). */
26
+ function skillsSourceDir() {
27
+ return (0, node_path_1.join)(__dirname, '..', '..', 'skills');
28
+ }
29
+ /** Target: ~/.agents/skills (opencode convention) unless overridden. */
30
+ function skillsTargetDir() {
31
+ return process.env.TEAMSHARE_SKILLS_DIR ?? (0, node_path_1.join)((0, node_os_1.homedir)(), '.agents', 'skills');
32
+ }
33
+ function skillDirs(root) {
34
+ if (!(0, node_fs_1.existsSync)(root))
35
+ return [];
36
+ return (0, node_fs_1.readdirSync)(root, { withFileTypes: true })
37
+ .filter((entry) => entry.isDirectory() && (0, node_fs_1.existsSync)((0, node_path_1.join)(root, entry.name, 'SKILL.md')))
38
+ .map((entry) => entry.name)
39
+ .sort();
40
+ }
41
+ function listSkills() {
42
+ return {
43
+ available: skillDirs(skillsSourceDir()),
44
+ installed: skillDirs(skillsTargetDir()),
45
+ target: skillsTargetDir(),
46
+ };
47
+ }
48
+ /** Idempotently copies every shipped skill into the target skills directory. */
49
+ function installSkills() {
50
+ const source = skillsSourceDir();
51
+ if (!(0, node_fs_1.existsSync)(source)) {
52
+ throw new Error(`[skills] source not found in this installation: ${source} (skills ship with the npm package; running from a source checkout also works)`);
53
+ }
54
+ const target = skillsTargetDir();
55
+ (0, node_fs_1.mkdirSync)(target, { recursive: true });
56
+ const copied = [];
57
+ for (const name of skillDirs(source)) {
58
+ const dest = (0, node_path_1.join)(target, name);
59
+ (0, node_fs_1.mkdirSync)(dest, { recursive: true });
60
+ for (const file of (0, node_fs_1.readdirSync)((0, node_path_1.join)(source, name))) {
61
+ (0, node_fs_1.copyFileSync)((0, node_path_1.join)(source, name, file), (0, node_path_1.join)(dest, file));
62
+ }
63
+ copied.push(name);
64
+ }
65
+ return { copied, target };
66
+ }
67
+ /** Removes the shipped skills from the target directory (leaves others). */
68
+ function uninstallSkills() {
69
+ const target = skillsTargetDir();
70
+ const removed = [];
71
+ for (const name of exports.SHIPPED_SKILLS) {
72
+ const dir = (0, node_path_1.join)(target, name);
73
+ if ((0, node_fs_1.existsSync)(dir)) {
74
+ (0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
75
+ removed.push(name);
76
+ }
77
+ }
78
+ return { removed, target };
79
+ }
80
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ export interface UsageSession {
2
+ title: string;
3
+ model: string;
4
+ providerID: string;
5
+ cost: number;
6
+ tokensInput: number;
7
+ tokensOutput: number;
8
+ tokensReasoning: number;
9
+ tokensCacheRead: number;
10
+ tokensCacheWrite: number;
11
+ timeCreated: number;
12
+ timeUpdated: number;
13
+ durationMin: number;
14
+ /** 'user' = the user's own opencode windows; 'agent' = agent sessions. */
15
+ attribution: 'user' | 'agent';
16
+ /** True when the title starts with "TeamShare " (bridge/TeamShare work). */
17
+ teamshare: boolean;
18
+ }
19
+ export interface UsageReport {
20
+ day: string;
21
+ dbPath: string;
22
+ totalCost: number;
23
+ sessionCount: number;
24
+ userCost: number;
25
+ agentCost: number;
26
+ teamshareCost: number;
27
+ tokens: {
28
+ input: number;
29
+ output: number;
30
+ reasoning: number;
31
+ cacheRead: number;
32
+ cacheWrite: number;
33
+ };
34
+ sessions: UsageSession[];
35
+ }
36
+ export interface UsageOptions {
37
+ /** YYYY-MM-DD (default: today, local time). */
38
+ day?: string;
39
+ /** Filter to sessions whose title carries `agent <id>`. */
40
+ agent?: string;
41
+ }
42
+ /** Resolves the python binary: TEAMSHARE_PYTHON > known 3.14 > PATH python. */
43
+ export declare function pythonBinary(): string;
44
+ /** Absolute path to tools/usage_report.py (package root, whatever the cwd). */
45
+ export declare function usageScriptPath(): string;
46
+ export declare class UsageError extends Error {
47
+ }
48
+ /**
49
+ * Runs the read-only spend report. Throws UsageError when the script or the
50
+ * db is unavailable (the caller decides how loudly to fail).
51
+ */
52
+ export declare function runUsageReport(opts?: UsageOptions): UsageReport;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UsageError = void 0;
4
+ exports.pythonBinary = pythonBinary;
5
+ exports.usageScriptPath = usageScriptPath;
6
+ exports.runUsageReport = runUsageReport;
7
+ /**
8
+ * Agent spend reporting - typed wrapper around tools/usage_report.py.
9
+ *
10
+ * Node has no built-in sqlite, so the CLI (and the local-server /usage
11
+ * endpoint) shells out to the Python script, which opens opencode.db with a
12
+ * READ-ONLY sqlite uri. Never writes, never copies - the db is the source
13
+ * of truth. Works fully offline; needs neither the backend nor the daemon.
14
+ */
15
+ const node_fs_1 = require("node:fs");
16
+ const node_child_process_1 = require("node:child_process");
17
+ const node_path_1 = require("node:path");
18
+ /** Python 3.14 on this machine - has sqlite3 in stdlib and pip (unlike the
19
+ * undocumented PATH python 3.11). env TEAMSHARE_PYTHON overrides. */
20
+ const KNOWN_PYTHON = 'C:\\Users\\Dominion Banjo\\AppData\\Local\\Python\\bin\\python.exe';
21
+ /** Resolves the python binary: TEAMSHARE_PYTHON > known 3.14 > PATH python. */
22
+ function pythonBinary() {
23
+ if (process.env.TEAMSHARE_PYTHON)
24
+ return process.env.TEAMSHARE_PYTHON;
25
+ if ((0, node_fs_1.existsSync)(KNOWN_PYTHON))
26
+ return KNOWN_PYTHON;
27
+ return 'python';
28
+ }
29
+ /** Absolute path to tools/usage_report.py (package root, whatever the cwd). */
30
+ function usageScriptPath() {
31
+ return (0, node_path_1.join)(__dirname, '..', '..', 'tools', 'usage_report.py');
32
+ }
33
+ class UsageError extends Error {
34
+ }
35
+ exports.UsageError = UsageError;
36
+ /**
37
+ * Runs the read-only spend report. Throws UsageError when the script or the
38
+ * db is unavailable (the caller decides how loudly to fail).
39
+ */
40
+ function runUsageReport(opts = {}) {
41
+ const script = usageScriptPath();
42
+ if (!(0, node_fs_1.existsSync)(script)) {
43
+ throw new UsageError(`usage script not found: ${script} (reinstall teamshare-bridge)`);
44
+ }
45
+ const args = [script, '--json'];
46
+ if (opts.day)
47
+ args.push('--day', opts.day);
48
+ if (opts.agent)
49
+ args.push('--agent', opts.agent);
50
+ const res = (0, node_child_process_1.spawnSync)(pythonBinary(), args, { encoding: 'utf8' });
51
+ if (res.error) {
52
+ throw new UsageError(`could not run ${pythonBinary()} - is Python installed? (${res.error.message})`);
53
+ }
54
+ if (res.status !== 0) {
55
+ const detail = (res.stderr || res.stdout || '').trim();
56
+ throw new UsageError(detail || `usage report failed with exit code ${res.status}`);
57
+ }
58
+ try {
59
+ const parsed = JSON.parse(res.stdout);
60
+ if (typeof parsed.totalCost !== 'number' || !Array.isArray(parsed.sessions)) {
61
+ throw new Error('unexpected report shape');
62
+ }
63
+ return parsed;
64
+ }
65
+ catch (err) {
66
+ throw new UsageError(`could not parse usage report output: ${err instanceof Error ? err.message : String(err)}`);
67
+ }
68
+ }
69
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/lib/usage.ts"],"names":[],"mappings":";;;AA6DA,oCAIC;AAGD,0CAEC;AAQD,wCA6BC;AA3GD;;;;;;;GAOG;AACH,qCAAqC;AACrC,2DAA+C;AAC/C,yCAAiC;AA8CjC;qEACqE;AACrE,MAAM,YAAY,GAAG,oEAAoE,CAAC;AAE1F,+EAA+E;AAC/E,SAAgB,YAAY;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,IAAI,IAAA,oBAAU,EAAC,YAAY,CAAC;QAAE,OAAO,YAAY,CAAC;IAClD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+EAA+E;AAC/E,SAAgB,eAAe;IAC7B,OAAO,IAAA,gBAAI,EAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;AACjE,CAAC;AAED,MAAa,UAAW,SAAQ,KAAK;CAAG;AAAxC,gCAAwC;AAExC;;;GAGG;AACH,SAAgB,cAAc,CAAC,OAAqB,EAAE;IACpD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,CAAC,IAAA,oBAAU,EAAC,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,2BAA2B,MAAM,+BAA+B,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,GAAG;QAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,IAAI,CAAC,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,IAAA,8BAAS,EAAC,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAClB,iBAAiB,YAAY,EAAE,4BAA4B,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,CAChF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,MAAM,IAAI,UAAU,CAAC,MAAM,IAAI,sCAAsC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAgB,CAAC;QACrD,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,UAAU,CAClB,wCAAwC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamshare-bridge",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Local bridge for TeamShare agents - CLI session runner, auto-wake WebSocket daemon, and teamshare:// protocol handler.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
@@ -18,6 +18,8 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
+ "skills",
22
+ "tools",
21
23
  "README.md"
22
24
  ],
23
25
  "bin": {
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: teamshare-auth-rbac
3
+ description: TeamShare auth & authorization rules for every endpoint you write or change. Pick the correct guard stack (@Permissions for human-only, @Public + AgentsDualAuthGuard + @ApiKeyScopes for agent+human surfaces, @Public for truly public, ApiKeyGuard + canUseTool for MCP). Enforce capability + key scope + project access (never less than two layers). Use envelope + zod validation + UPPER_SNAKE error codes, and write AgentLog rows for every agent action.
4
+ ---
5
+
6
+ # TeamShare Auth & Authorization (RBAC)
7
+
8
+ Every endpoint in `teamshare-backend` must declare its access story. Use this
9
+ decision table; never leave an endpoint with default guards and no metadata.
10
+
11
+ ## 1. Choose the guard stack
12
+
13
+ | Who calls it | What to use on the route |
14
+ |---|---|
15
+ | Human JWT only (company/team/env-var/roles/webhooks/invitations/attachments) | Leave global guards, add `@Permissions('<entity>.<action>')` (e.g. `document.create`) |
16
+ | Agents AND humans (tasks, comments, chat, documents, search, projects, agents self-service) | Class-level `@Public()` + `@UseGuards(AgentsDualAuthGuard)` + per-route `@ApiKeyScopes('<entity>:read' \| '<entity>:write')` |
17
+ | Truly public (auth, verify, reset, billing webhook, run-token redeem) | `@Public()` only |
18
+ | MCP tools (`/api/mcp`) | `ApiKeyGuard` + per-tool `canUseTool(capabilities, keyScopes, required)` |
19
+
20
+ `AgentsDualAuthGuard` accepts `X-Api-Key` (enforces `@ApiKeyScopes`) OR a
21
+ `Bearer` JWT. **Do not combine `@Permissions` with `AgentsDualAuthGuard` on the
22
+ same route** — global RbacGuard runs before the route guard can set
23
+ `request.user` for key callers. Dual-auth routes delegate access to the
24
+ service layer.
25
+
26
+ ## 2. The three enforcement layers (never less than two)
27
+
28
+ For every agent action: **capability** (`Agent.capabilities`) + **API-key
29
+ scope** (`@ApiKeyScopes`, minted by `scopesForCapabilities`) + **project
30
+ access** (`assertProjectAccess`). Never gate access on env vars.
31
+
32
+ - MCP tool → `ctx.canUse('<capability>')` (capability + scope) then the shared
33
+ service runs `assertProjectAccess` as the agent user.
34
+ - Agent REST → `@ApiKeyScopes` (scope) then the service runs
35
+ `assertProjectAccess` (project role).
36
+ - Service layer helpers: `assertProjectAccess(prisma, projectId, userId,
37
+ minRole)`, `assertCompanyMembership`, `isCompanyOwnerOrAdmin`.
38
+
39
+ ## 3. Permission vocabulary (CRUDL)
40
+
41
+ - `src/common/constants/rbac.ts`: `ENTITIES` (17) × `ACTIONS`
42
+ (`create | read | list | update | delete`) → `Permission = entity.action`
43
+ plus `SPECIAL_PERMISSIONS` (`env_var.reveal`, `env_var.export`, ...).
44
+ - Static role matrices: `COMPANY_ROLE_PERMISSIONS`
45
+ (owner/admin/member/secret_manager/viewer) and `PROJECT_ROLE_PERMISSIONS`
46
+ (owner/member/viewer). Dynamic roles add `companyPermissions` claims.
47
+ - Agent capabilities live in `src/common/constants/enums.ts`
48
+ (`AGENT_CAPABILITIES`, `CAPABILITY_SCOPES`). A key never exceeds its
49
+ agent's capabilities and a capability never exceeds the key's scopes.
50
+ - Add a new capability → add its scope in `API_KEY_SCOPES` + a mapping in
51
+ `CAPABILITY_SCOPES`, so `scopesForCapabilities` mints the right key.
52
+
53
+ ## 4. Error codes & envelope
54
+
55
+ - Throw `new XxxException({ code: 'UPPER_SNAKE', message, details? })`
56
+ (`VALIDATION_ERROR`, `PROJECT_NOT_FOUND`, `INSUFFICIENT_PROJECT_ROLE`,
57
+ `API_KEY_SCOPE_MISSING`, `DOCUMENT_UPDATE_DENIED`, ...). Secrets never
58
+ appear in messages/logs.
59
+ - Responses: `{ success: true, data, pagination? }` /
60
+ `{ success: false, error: { code, message, details? } }` (global
61
+ interceptor/filter — your handler returns raw data).
62
+
63
+ ## 5. AgentLog — never bypass
64
+
65
+ Every agent mutation logs an `AgentLog` row via the shared services:
66
+ `logAgentActionIfAgent(prisma, userId, { action, taskId?, detail })`
67
+ (best-effort; humans skipped). Actions are in `AGENT_LOG_ACTIONS`
68
+ (`task_created`, `comment_created`, `document_created`, `document_updated`,
69
+ `subtask_updated`, `wake_sent`, ...). If you add an agent-facing mutation,
70
+ wire the log in the service — never in the controller.
71
+
72
+ ## 6. Checklist for a new endpoint
73
+
74
+ - [ ] Guard stack chosen from the table; metadata declared on the route.
75
+ - [ ] zod `ZodValidationPipe` on body/query/param; generated zod for enums.
76
+ - [ ] Service re-checks project/company access (guards are a first filter).
77
+ - [ ] Envelope-compliant return; UPPER_SNAKE error codes.
78
+ - [ ] Agent actions write `AgentLog` via `logAgentActionIfAgent`.
79
+ - [ ] Swagger `@ApiOperation` mentions the RBAC; `@errs(...)` lists the codes.