studiograph 1.0.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.
- package/README.md +18 -0
- package/dist/agent/orchestrator.d.ts +69 -0
- package/dist/agent/orchestrator.js +211 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/tools/graph-tools.d.ts +30 -0
- package/dist/agent/tools/graph-tools.js +536 -0
- package/dist/agent/tools/graph-tools.js.map +1 -0
- package/dist/auth/github.d.ts +53 -0
- package/dist/auth/github.js +180 -0
- package/dist/auth/github.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +10 -0
- package/dist/cli/commands/auth.js +63 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.js +299 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/join.d.ts +14 -0
- package/dist/cli/commands/join.js +230 -0
- package/dist/cli/commands/join.js.map +1 -0
- package/dist/cli/commands/members.d.ts +11 -0
- package/dist/cli/commands/members.js +230 -0
- package/dist/cli/commands/members.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +17 -0
- package/dist/cli/commands/serve.js +90 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/start.d.ts +7 -0
- package/dist/cli/commands/start.js +381 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +10 -0
- package/dist/cli/commands/sync.js +121 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +31 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/graph.d.ts +169 -0
- package/dist/core/graph.js +558 -0
- package/dist/core/graph.js.map +1 -0
- package/dist/core/types.d.ts +216 -0
- package/dist/core/types.js +71 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/user-config.d.ts +31 -0
- package/dist/core/user-config.js +50 -0
- package/dist/core/user-config.js.map +1 -0
- package/dist/core/validation.d.ts +2371 -0
- package/dist/core/validation.js +432 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/core/workspace-manager.d.ts +104 -0
- package/dist/core/workspace-manager.js +432 -0
- package/dist/core/workspace-manager.js.map +1 -0
- package/dist/core/workspace.d.ts +103 -0
- package/dist/core/workspace.js +306 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.js +84 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/plugin-loader.d.ts +31 -0
- package/dist/server/plugin-loader.js +81 -0
- package/dist/server/plugin-loader.js.map +1 -0
- package/dist/server/routes/chat.d.ts +11 -0
- package/dist/server/routes/chat.js +66 -0
- package/dist/server/routes/chat.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +9 -0
- package/dist/server/routes/graph-api.js +72 -0
- package/dist/server/routes/graph-api.js.map +1 -0
- package/dist/server/routes/webhook.d.ts +14 -0
- package/dist/server/routes/webhook.js +69 -0
- package/dist/server/routes/webhook.js.map +1 -0
- package/dist/services/assets/base.d.ts +69 -0
- package/dist/services/assets/base.js +113 -0
- package/dist/services/assets/base.js.map +1 -0
- package/dist/services/assets/index.d.ts +36 -0
- package/dist/services/assets/index.js +89 -0
- package/dist/services/assets/index.js.map +1 -0
- package/dist/services/assets/local.d.ts +42 -0
- package/dist/services/assets/local.js +161 -0
- package/dist/services/assets/local.js.map +1 -0
- package/dist/services/assets/r2.d.ts +36 -0
- package/dist/services/assets/r2.js +182 -0
- package/dist/services/assets/r2.js.map +1 -0
- package/dist/services/csv-service.d.ts +36 -0
- package/dist/services/csv-service.js +143 -0
- package/dist/services/csv-service.js.map +1 -0
- package/dist/services/git.d.ts +99 -0
- package/dist/services/git.js +306 -0
- package/dist/services/git.js.map +1 -0
- package/dist/services/github-provisioner.d.ts +30 -0
- package/dist/services/github-provisioner.js +89 -0
- package/dist/services/github-provisioner.js.map +1 -0
- package/dist/services/markdown.d.ts +82 -0
- package/dist/services/markdown.js +338 -0
- package/dist/services/markdown.js.map +1 -0
- package/dist/services/memory-service.d.ts +74 -0
- package/dist/services/memory-service.js +183 -0
- package/dist/services/memory-service.js.map +1 -0
- package/dist/utils/git.d.ts +28 -0
- package/dist/utils/git.js +55 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/preflight.d.ts +44 -0
- package/dist/utils/preflight.js +95 -0
- package/dist/utils/preflight.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* studiograph join command
|
|
3
|
+
*
|
|
4
|
+
* Joins an existing Studiograph workspace by cloning the .studiograph
|
|
5
|
+
* config repo, detecting the user's role, and cloning all accessible repos.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { intro, select, confirm, outro, spinner, log } from '@clack/prompts';
|
|
9
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
10
|
+
import { join, resolve } from 'path';
|
|
11
|
+
import { Workspace } from '../../core/workspace.js';
|
|
12
|
+
import { gitClone, getGitConfig } from '../../utils/git.js';
|
|
13
|
+
import { loadToken, getGitHubUser } from '../../auth/github.js';
|
|
14
|
+
import { runPreflight } from '../../utils/preflight.js';
|
|
15
|
+
/**
|
|
16
|
+
* Attempt to identify a workspace member using the stored GitHub token.
|
|
17
|
+
* Returns the matching TeamMember, or undefined if not identified.
|
|
18
|
+
*/
|
|
19
|
+
export async function resolveIdentityFromToken(members) {
|
|
20
|
+
const stored = loadToken();
|
|
21
|
+
if (!stored)
|
|
22
|
+
return undefined;
|
|
23
|
+
try {
|
|
24
|
+
const ghUser = await getGitHubUser(stored.token);
|
|
25
|
+
return members.find(m => m.github_username === ghUser.login && m.active !== false);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Determine if a role can access a repo with the given access level.
|
|
33
|
+
* Mirrors the logic in WorkspaceManager.canAccessRepo().
|
|
34
|
+
*/
|
|
35
|
+
function canAccess(role, access) {
|
|
36
|
+
if (role === 'admin')
|
|
37
|
+
return true;
|
|
38
|
+
switch (access) {
|
|
39
|
+
case 'public': return true;
|
|
40
|
+
case 'team': return role === 'member';
|
|
41
|
+
case 'admin': return false;
|
|
42
|
+
case 'restricted': return false;
|
|
43
|
+
default: return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export const joinCommand = new Command('join')
|
|
47
|
+
.description('Join an existing Studiograph workspace')
|
|
48
|
+
.argument('<workspace-url>', 'GitHub URL to the .studiograph config repo')
|
|
49
|
+
.option('--dir <path>', 'Target directory for the workspace (default: current directory)')
|
|
50
|
+
.option('--github-username <username>', 'Your GitHub username (used to detect your role)')
|
|
51
|
+
.action(async (workspaceUrl, options) => {
|
|
52
|
+
intro('Join Studiograph Workspace');
|
|
53
|
+
const ready = runPreflight();
|
|
54
|
+
if (!ready) {
|
|
55
|
+
process.exit(1);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Step 1: Resolve target directory
|
|
60
|
+
const targetDir = resolve(options.dir ?? process.cwd());
|
|
61
|
+
const studiographDir = join(targetDir, '.studiograph');
|
|
62
|
+
if (existsSync(studiographDir)) {
|
|
63
|
+
outro('❌ A .studiograph directory already exists here. Choose a different directory with --dir or remove the existing one.');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
mkdirSync(targetDir, { recursive: true });
|
|
68
|
+
// Step 2: Clone the .studiograph config repo
|
|
69
|
+
const cloneSpinner = spinner();
|
|
70
|
+
cloneSpinner.start('Cloning workspace configuration...');
|
|
71
|
+
try {
|
|
72
|
+
gitClone(workspaceUrl, studiographDir);
|
|
73
|
+
cloneSpinner.stop('Workspace configuration cloned');
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
cloneSpinner.stop('Failed');
|
|
77
|
+
outro(`❌ Could not clone ${workspaceUrl}. Check the URL and your access permissions.`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Step 3: Load workspace config and team roster
|
|
82
|
+
const workspace = new Workspace(targetDir);
|
|
83
|
+
if (!workspace.isWorkspace()) {
|
|
84
|
+
outro('❌ The cloned repo does not appear to be a valid Studiograph workspace (missing workspace.json).');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const config = workspace.loadConfig();
|
|
89
|
+
const members = workspace.loadMembers();
|
|
90
|
+
log.info(`Workspace: ${config.team_name}`);
|
|
91
|
+
log.info(`${config.repos.length} repositor${config.repos.length === 1 ? 'y' : 'ies'} in workspace`);
|
|
92
|
+
// Step 4: Identify the user
|
|
93
|
+
const githubUsernameFromOption = options.githubUsername;
|
|
94
|
+
let userMember;
|
|
95
|
+
// Try stored GitHub token (skip if --github-username was passed explicitly)
|
|
96
|
+
if (!githubUsernameFromOption) {
|
|
97
|
+
userMember = await resolveIdentityFromToken(members);
|
|
98
|
+
if (userMember) {
|
|
99
|
+
log.success(`Identified as ${userMember.name} (${userMember.role})`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Fall back to --github-username option or git config
|
|
103
|
+
if (!userMember) {
|
|
104
|
+
const githubUsername = githubUsernameFromOption ?? getGitConfig('github.user');
|
|
105
|
+
if (githubUsername) {
|
|
106
|
+
userMember = members.find(m => m.github_username === githubUsername && m.active !== false);
|
|
107
|
+
if (userMember) {
|
|
108
|
+
log.success(`Identified as ${userMember.name} (${userMember.role})`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!userMember) {
|
|
113
|
+
const activeMembers = members.filter(m => m.active !== false);
|
|
114
|
+
if (activeMembers.length > 0) {
|
|
115
|
+
const memberOptions = [
|
|
116
|
+
...activeMembers.map(m => ({
|
|
117
|
+
value: m.id,
|
|
118
|
+
label: `${m.name}`,
|
|
119
|
+
hint: m.role,
|
|
120
|
+
})),
|
|
121
|
+
{ value: '__guest__', label: "I'm not on the team yet", hint: 'guest access' },
|
|
122
|
+
];
|
|
123
|
+
const selectedId = await select({
|
|
124
|
+
message: 'Who are you? (used to determine which repos to clone)',
|
|
125
|
+
options: memberOptions,
|
|
126
|
+
});
|
|
127
|
+
if (typeof selectedId === 'symbol') {
|
|
128
|
+
outro('Cancelled');
|
|
129
|
+
process.exit(0);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (selectedId !== '__guest__') {
|
|
133
|
+
userMember = activeMembers.find(m => m.id === selectedId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// No members defined yet — ask what role to assume
|
|
138
|
+
log.warn('No team roster found. Selecting a role here only determines which repos to attempt cloning — GitHub access controls what you can actually clone.');
|
|
139
|
+
const roleChoice = await select({
|
|
140
|
+
message: 'Which repos should we attempt to clone?',
|
|
141
|
+
options: [
|
|
142
|
+
{ value: 'admin', label: 'Admin', hint: 'attempt all repos (GitHub auth still applies)' },
|
|
143
|
+
{ value: 'member', label: 'Member', hint: 'attempt public + team repos' },
|
|
144
|
+
{ value: 'guest', label: 'Guest', hint: 'public repos only' },
|
|
145
|
+
],
|
|
146
|
+
});
|
|
147
|
+
if (typeof roleChoice === 'symbol') {
|
|
148
|
+
outro('Cancelled');
|
|
149
|
+
process.exit(0);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Synthesize a temporary member with the chosen role
|
|
153
|
+
userMember = { id: 'local', name: 'Local User', email: '', role: roleChoice };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const userRole = userMember?.role ?? 'guest';
|
|
157
|
+
// Step 5: Determine accessible vs inaccessible repos
|
|
158
|
+
const accessibleRepos = config.repos.filter(r => canAccess(userRole, r.access));
|
|
159
|
+
const blockedRepos = config.repos.filter(r => !canAccess(userRole, r.access));
|
|
160
|
+
log.info(`${accessibleRepos.length} repositor${accessibleRepos.length === 1 ? 'y' : 'ies'} accessible with your role (${userRole})`);
|
|
161
|
+
if (blockedRepos.length > 0) {
|
|
162
|
+
log.warn(`${blockedRepos.length} repositor${blockedRepos.length === 1 ? 'y' : 'ies'} require higher access: ${blockedRepos.map(r => r.name).join(', ')}`);
|
|
163
|
+
}
|
|
164
|
+
if (accessibleRepos.length === 0) {
|
|
165
|
+
outro('No accessible repositories to clone. Contact a workspace admin to update your role.');
|
|
166
|
+
process.exit(0);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// Confirm before cloning
|
|
170
|
+
const repoList = accessibleRepos.map(r => ` • ${r.name} (${r.access})`).join('\n');
|
|
171
|
+
const shouldProceed = await confirm({
|
|
172
|
+
message: `Clone these repos into ${targetDir}?\n${repoList}`,
|
|
173
|
+
});
|
|
174
|
+
if (!shouldProceed || typeof shouldProceed === 'symbol') {
|
|
175
|
+
outro('Cancelled');
|
|
176
|
+
process.exit(0);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Step 6: Clone accessible repos
|
|
180
|
+
let cloned = 0;
|
|
181
|
+
let skipped = 0;
|
|
182
|
+
let failed = 0;
|
|
183
|
+
for (const repo of accessibleRepos) {
|
|
184
|
+
if (!repo.github_url) {
|
|
185
|
+
log.warn(`Skipping ${repo.name}: no GitHub URL configured in workspace.json`);
|
|
186
|
+
skipped++;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const repoPath = join(targetDir, repo.path);
|
|
190
|
+
if (existsSync(repoPath)) {
|
|
191
|
+
log.warn(`Skipping ${repo.name}: directory already exists at ${repo.path}`);
|
|
192
|
+
skipped++;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const repoSpinner = spinner();
|
|
196
|
+
repoSpinner.start(`Cloning ${repo.name}...`);
|
|
197
|
+
try {
|
|
198
|
+
gitClone(repo.github_url, repoPath);
|
|
199
|
+
repoSpinner.stop(`Cloned ${repo.name}`);
|
|
200
|
+
cloned++;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
repoSpinner.stop(`Failed to clone ${repo.name}`);
|
|
204
|
+
log.warn(`Could not clone ${repo.name}: check your GitHub access permissions`);
|
|
205
|
+
failed++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Step 7: Summary
|
|
209
|
+
const parts = [];
|
|
210
|
+
if (cloned > 0)
|
|
211
|
+
parts.push(`${cloned} cloned`);
|
|
212
|
+
if (skipped > 0)
|
|
213
|
+
parts.push(`${skipped} skipped`);
|
|
214
|
+
if (failed > 0)
|
|
215
|
+
parts.push(`${failed} failed`);
|
|
216
|
+
const summary = parts.join(', ');
|
|
217
|
+
const nextStep = `\ncd ${targetDir}\nstudiograph start`;
|
|
218
|
+
if (failed > 0) {
|
|
219
|
+
outro(`⚠️ Joined ${config.team_name} with issues (${summary}). Ask a workspace admin to verify your repo access.\n${nextStep}`);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
outro(`✨ Joined ${config.team_name} workspace (${summary})${nextStep}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
outro(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
//# sourceMappingURL=join.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"join.js","sourceRoot":"","sources":["../../../src/cli/commands/join.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* studiograph members command
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* studiograph members list — list all team members
|
|
6
|
+
* studiograph members add <github-username> --role <> — add a member (admin only)
|
|
7
|
+
* studiograph members remove <github-username> — deactivate a member (admin only)
|
|
8
|
+
* studiograph members role <github-username> <role> — change a member's role (admin only)
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
export declare const membersCommand: Command;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* studiograph members command
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* studiograph members list — list all team members
|
|
6
|
+
* studiograph members add <github-username> --role <> — add a member (admin only)
|
|
7
|
+
* studiograph members remove <github-username> — deactivate a member (admin only)
|
|
8
|
+
* studiograph members role <github-username> <role> — change a member's role (admin only)
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { outro, log, text } from '@clack/prompts';
|
|
12
|
+
import { Workspace } from '../../core/workspace.js';
|
|
13
|
+
import { loadToken, getGitHubUser } from '../../auth/github.js';
|
|
14
|
+
const VALID_ROLES = ['admin', 'member', 'guest'];
|
|
15
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
16
|
+
function requireWorkspace() {
|
|
17
|
+
const workspace = new Workspace();
|
|
18
|
+
if (!workspace.isWorkspace()) {
|
|
19
|
+
console.error('❌ Not a Studiograph workspace. Run `studiograph init` first.');
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return workspace;
|
|
23
|
+
}
|
|
24
|
+
async function resolveCurrentUser(members) {
|
|
25
|
+
const stored = loadToken();
|
|
26
|
+
if (!stored)
|
|
27
|
+
return undefined;
|
|
28
|
+
try {
|
|
29
|
+
const ghUser = await getGitHubUser(stored.token);
|
|
30
|
+
return members.find(m => m.github_username === ghUser.login && m.active !== false);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function requireAdmin(currentUser) {
|
|
37
|
+
if (!currentUser) {
|
|
38
|
+
log.error('Could not identify you as a workspace member. Run `studiograph auth github` to authenticate.');
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (currentUser.role !== 'admin') {
|
|
42
|
+
log.error(`Only admins can manage team members. Your role is: ${currentUser.role}`);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
function formatRole(role) {
|
|
48
|
+
const widths = { admin: 'admin ', member: 'member', guest: 'guest ' };
|
|
49
|
+
return widths[role] ?? role.padEnd(6);
|
|
50
|
+
}
|
|
51
|
+
// ─── list ────────────────────────────────────────────────────────────────────
|
|
52
|
+
const listCommand = new Command('list')
|
|
53
|
+
.description('List all team members')
|
|
54
|
+
.action(async () => {
|
|
55
|
+
const workspace = requireWorkspace();
|
|
56
|
+
if (!workspace) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const members = workspace.loadMembers();
|
|
61
|
+
if (members.length === 0) {
|
|
62
|
+
log.info('No team members found.');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const active = members.filter(m => m.active !== false);
|
|
66
|
+
const inactive = members.filter(m => m.active === false);
|
|
67
|
+
console.log('\nTeam Members\n');
|
|
68
|
+
console.log(' Name Role GitHub Username Joined');
|
|
69
|
+
console.log(' ' + '─'.repeat(72));
|
|
70
|
+
for (const m of active) {
|
|
71
|
+
const name = m.name.padEnd(30);
|
|
72
|
+
const role = formatRole(m.role);
|
|
73
|
+
const gh = (m.github_username ?? '—').padEnd(18);
|
|
74
|
+
const joined = m.joined_at ? m.joined_at.slice(0, 10) : '—';
|
|
75
|
+
console.log(` ${name} ${role} ${gh} ${joined}`);
|
|
76
|
+
}
|
|
77
|
+
if (inactive.length > 0) {
|
|
78
|
+
console.log(`\n (${inactive.length} inactive member${inactive.length === 1 ? '' : 's'} not shown)`);
|
|
79
|
+
}
|
|
80
|
+
console.log('');
|
|
81
|
+
});
|
|
82
|
+
// ─── add ─────────────────────────────────────────────────────────────────────
|
|
83
|
+
const addCommand = new Command('add')
|
|
84
|
+
.description('Add a new team member (admin only)')
|
|
85
|
+
.argument('<github-username>', "The new member's GitHub username")
|
|
86
|
+
.option('--role <role>', 'Role: admin, member, or guest (default: member)', 'member')
|
|
87
|
+
.option('--name <name>', 'Display name (prompted if omitted)')
|
|
88
|
+
.option('--email <email>', 'Email address (prompted if omitted)')
|
|
89
|
+
.action(async (githubUsername, options) => {
|
|
90
|
+
const workspace = requireWorkspace();
|
|
91
|
+
if (!workspace) {
|
|
92
|
+
process.exit(1);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const members = workspace.loadMembers();
|
|
96
|
+
const currentUser = await resolveCurrentUser(members);
|
|
97
|
+
if (!requireAdmin(currentUser)) {
|
|
98
|
+
process.exit(1);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Validate role
|
|
102
|
+
const role = options.role;
|
|
103
|
+
if (!VALID_ROLES.includes(role)) {
|
|
104
|
+
log.error(`Invalid role "${role}". Must be one of: admin, member, guest`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Check for duplicate
|
|
109
|
+
if (members.find(m => m.github_username === githubUsername)) {
|
|
110
|
+
log.error(`Member with GitHub username "${githubUsername}" already exists.`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Resolve name
|
|
115
|
+
let name = options.name;
|
|
116
|
+
if (!name) {
|
|
117
|
+
const nameInput = await text({
|
|
118
|
+
message: 'Display name:',
|
|
119
|
+
placeholder: 'Alex Rivera',
|
|
120
|
+
validate: (v) => { if (!v?.trim())
|
|
121
|
+
return 'Name is required'; },
|
|
122
|
+
});
|
|
123
|
+
if (typeof nameInput !== 'string') {
|
|
124
|
+
outro('Cancelled');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
name = nameInput;
|
|
129
|
+
}
|
|
130
|
+
// Resolve email (optional)
|
|
131
|
+
let email = options.email;
|
|
132
|
+
if (!email) {
|
|
133
|
+
const emailInput = await text({
|
|
134
|
+
message: 'Email address (optional):',
|
|
135
|
+
placeholder: 'alex@example.com',
|
|
136
|
+
});
|
|
137
|
+
if (typeof emailInput === 'symbol') {
|
|
138
|
+
outro('Cancelled');
|
|
139
|
+
process.exit(0);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
email = emailInput ?? '';
|
|
143
|
+
}
|
|
144
|
+
const newMember = {
|
|
145
|
+
id: githubUsername,
|
|
146
|
+
name,
|
|
147
|
+
email,
|
|
148
|
+
role: role,
|
|
149
|
+
github_username: githubUsername,
|
|
150
|
+
joined_at: new Date().toISOString(),
|
|
151
|
+
active: true,
|
|
152
|
+
};
|
|
153
|
+
workspace.writeMembers([...members, newMember]);
|
|
154
|
+
log.success(`Added ${name} (@${githubUsername}) as ${role}`);
|
|
155
|
+
});
|
|
156
|
+
// ─── remove ──────────────────────────────────────────────────────────────────
|
|
157
|
+
const removeCommand = new Command('remove')
|
|
158
|
+
.description('Remove a team member (admin only)')
|
|
159
|
+
.argument('<github-username>', "The member's GitHub username")
|
|
160
|
+
.action(async (githubUsername) => {
|
|
161
|
+
const workspace = requireWorkspace();
|
|
162
|
+
if (!workspace) {
|
|
163
|
+
process.exit(1);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const members = workspace.loadMembers();
|
|
167
|
+
const currentUser = await resolveCurrentUser(members);
|
|
168
|
+
if (!requireAdmin(currentUser)) {
|
|
169
|
+
process.exit(1);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const target = members.find(m => m.github_username === githubUsername);
|
|
173
|
+
if (!target) {
|
|
174
|
+
log.error(`No member found with GitHub username "${githubUsername}".`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (target.active === false) {
|
|
179
|
+
log.warn(`${target.name} (@${githubUsername}) is already inactive.`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Soft-delete: set active: false
|
|
183
|
+
const updated = members.map(m => m.github_username === githubUsername ? { ...m, active: false } : m);
|
|
184
|
+
workspace.writeMembers(updated);
|
|
185
|
+
log.success(`Removed ${target.name} (@${githubUsername}) from the team`);
|
|
186
|
+
});
|
|
187
|
+
// ─── role ─────────────────────────────────────────────────────────────────────
|
|
188
|
+
const roleCommand = new Command('role')
|
|
189
|
+
.description("Change a member's role (admin only)")
|
|
190
|
+
.argument('<github-username>', "The member's GitHub username")
|
|
191
|
+
.argument('<role>', 'New role: admin, member, or guest')
|
|
192
|
+
.action(async (githubUsername, newRole) => {
|
|
193
|
+
const workspace = requireWorkspace();
|
|
194
|
+
if (!workspace) {
|
|
195
|
+
process.exit(1);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const members = workspace.loadMembers();
|
|
199
|
+
const currentUser = await resolveCurrentUser(members);
|
|
200
|
+
if (!requireAdmin(currentUser)) {
|
|
201
|
+
process.exit(1);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!VALID_ROLES.includes(newRole)) {
|
|
205
|
+
log.error(`Invalid role "${newRole}". Must be one of: admin, member, guest`);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const target = members.find(m => m.github_username === githubUsername && m.active !== false);
|
|
210
|
+
if (!target) {
|
|
211
|
+
log.error(`No active member found with GitHub username "${githubUsername}".`);
|
|
212
|
+
process.exit(1);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (target.role === newRole) {
|
|
216
|
+
log.info(`${target.name} (@${githubUsername}) already has role: ${newRole}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const updated = members.map(m => m.github_username === githubUsername ? { ...m, role: newRole } : m);
|
|
220
|
+
workspace.writeMembers(updated);
|
|
221
|
+
log.success(`Updated ${target.name} (@${githubUsername}): ${target.role} → ${newRole}`);
|
|
222
|
+
});
|
|
223
|
+
// ─── Export ──────────────────────────────────────────────────────────────────
|
|
224
|
+
export const membersCommand = new Command('members')
|
|
225
|
+
.description('Manage team members')
|
|
226
|
+
.addCommand(listCommand)
|
|
227
|
+
.addCommand(addCommand)
|
|
228
|
+
.addCommand(removeCommand)
|
|
229
|
+
.addCommand(roleCommand);
|
|
230
|
+
//# sourceMappingURL=members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.js","sourceRoot":"","sources":["../../../src/cli/commands/members.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* studiograph serve command
|
|
3
|
+
*
|
|
4
|
+
* Starts the Studiograph HTTP server, hosting:
|
|
5
|
+
* - Graph API (read-only REST)
|
|
6
|
+
* - Agent chat (POST /api/chat, GET /api/chat/stream)
|
|
7
|
+
* - GitHub webhook (POST /webhooks/github)
|
|
8
|
+
* - Installed app plugins (from .studiograph/apps/)
|
|
9
|
+
*
|
|
10
|
+
* Environment variables:
|
|
11
|
+
* API_KEYS — semicolon-separated bearer tokens (e.g. "key1;key2")
|
|
12
|
+
* WEBHOOK_SECRET — GitHub HMAC-SHA256 secret (optional)
|
|
13
|
+
* PORT — HTTP port (default 3000)
|
|
14
|
+
* HOST — Bind address (default 0.0.0.0)
|
|
15
|
+
*/
|
|
16
|
+
import { Command } from 'commander';
|
|
17
|
+
export declare const serveCommand: Command;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* studiograph serve command
|
|
3
|
+
*
|
|
4
|
+
* Starts the Studiograph HTTP server, hosting:
|
|
5
|
+
* - Graph API (read-only REST)
|
|
6
|
+
* - Agent chat (POST /api/chat, GET /api/chat/stream)
|
|
7
|
+
* - GitHub webhook (POST /webhooks/github)
|
|
8
|
+
* - Installed app plugins (from .studiograph/apps/)
|
|
9
|
+
*
|
|
10
|
+
* Environment variables:
|
|
11
|
+
* API_KEYS — semicolon-separated bearer tokens (e.g. "key1;key2")
|
|
12
|
+
* WEBHOOK_SECRET — GitHub HMAC-SHA256 secret (optional)
|
|
13
|
+
* PORT — HTTP port (default 3000)
|
|
14
|
+
* HOST — Bind address (default 0.0.0.0)
|
|
15
|
+
*/
|
|
16
|
+
import { Command } from 'commander';
|
|
17
|
+
import { join } from 'path';
|
|
18
|
+
import { Workspace } from '../../core/workspace.js';
|
|
19
|
+
import { WorkspaceManager } from '../../core/workspace-manager.js';
|
|
20
|
+
import { loadUserConfig } from '../../core/user-config.js';
|
|
21
|
+
import { runPreflight } from '../../utils/preflight.js';
|
|
22
|
+
import { createServer } from '../../server/index.js';
|
|
23
|
+
export const serveCommand = new Command('serve')
|
|
24
|
+
.description('Start the Studiograph HTTP server')
|
|
25
|
+
.option('-p, --port <port>', 'Port to listen on', '3000')
|
|
26
|
+
.option('-H, --host <host>', 'Host to bind to', '0.0.0.0')
|
|
27
|
+
.action(async (opts) => {
|
|
28
|
+
const workspace = new Workspace();
|
|
29
|
+
if (!workspace.isWorkspace()) {
|
|
30
|
+
console.error('Not a Studiograph workspace. Run `studiograph init` first.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const ready = runPreflight();
|
|
34
|
+
if (!ready) {
|
|
35
|
+
process.exit(1);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const config = workspace.loadConfig();
|
|
39
|
+
// Propagate API key from user config to env (orchestrator reads ANTHROPIC_API_KEY)
|
|
40
|
+
const userConfig = loadUserConfig();
|
|
41
|
+
if (userConfig.api_key && !process.env.ANTHROPIC_API_KEY) {
|
|
42
|
+
process.env.ANTHROPIC_API_KEY = userConfig.api_key;
|
|
43
|
+
}
|
|
44
|
+
// Build GitUser from workspace config
|
|
45
|
+
const gitUser = {
|
|
46
|
+
id: 'serve',
|
|
47
|
+
name: config.team_name || 'Studiograph Server',
|
|
48
|
+
email: 'noreply@studiograph.local',
|
|
49
|
+
};
|
|
50
|
+
// Admin user for WorkspaceManager (server has full access)
|
|
51
|
+
const serverUser = { ...gitUser, role: 'admin' };
|
|
52
|
+
const workspaceManager = new WorkspaceManager(process.cwd(), config, gitUser, serverUser);
|
|
53
|
+
// Read API keys from environment (semicolon-separated)
|
|
54
|
+
const apiKeysEnv = process.env.API_KEYS || '';
|
|
55
|
+
const apiKeys = apiKeysEnv
|
|
56
|
+
.split(';')
|
|
57
|
+
.map(k => k.trim())
|
|
58
|
+
.filter(k => k.length > 0);
|
|
59
|
+
if (apiKeys.length === 0) {
|
|
60
|
+
console.warn('Warning: No API_KEYS configured — server is open (dev mode)');
|
|
61
|
+
}
|
|
62
|
+
const webhookSecret = process.env.WEBHOOK_SECRET;
|
|
63
|
+
const port = parseInt(process.env.PORT || opts.port, 10);
|
|
64
|
+
const host = process.env.HOST || opts.host;
|
|
65
|
+
const appsDir = join(process.cwd(), '.studiograph', 'apps');
|
|
66
|
+
const server = await createServer({
|
|
67
|
+
workspaceManager,
|
|
68
|
+
workspacePath: process.cwd(),
|
|
69
|
+
workspaceConfig: config,
|
|
70
|
+
gitUser,
|
|
71
|
+
appsDir,
|
|
72
|
+
port,
|
|
73
|
+
host,
|
|
74
|
+
apiKeys,
|
|
75
|
+
webhookSecret,
|
|
76
|
+
});
|
|
77
|
+
await server.listen({ port, host });
|
|
78
|
+
console.log(`\nStudiograph server running at http://${host}:${port}`);
|
|
79
|
+
console.log('\nRoutes:');
|
|
80
|
+
console.log(' GET /api/repos');
|
|
81
|
+
console.log(' GET /api/repos/:repo/entities/:type');
|
|
82
|
+
console.log(' GET /api/repos/:repo/entities/:type/:id');
|
|
83
|
+
console.log(' GET /api/repos/:repo/search');
|
|
84
|
+
console.log(' GET /api/search');
|
|
85
|
+
console.log(' POST /api/chat');
|
|
86
|
+
console.log(' GET /api/chat/stream');
|
|
87
|
+
console.log(' POST /webhooks/github');
|
|
88
|
+
console.log('\nApp plugins loaded from:', appsDir);
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,CAAC;KACxD,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,EAAE,SAAS,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,IAAoC,EAAE,EAAE;IACrD,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;IAElC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAExC,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;IAEtC,mFAAmF;IACnF,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,IAAI,UAAU,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,UAAU,CAAC,OAAO,CAAC;IACrD,CAAC;IAED,sCAAsC;IACtC,MAAM,OAAO,GAAG;QACd,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,MAAM,CAAC,SAAS,IAAI,oBAAoB;QAC9C,KAAK,EAAE,2BAA2B;KACnC,CAAC;IAEF,2DAA2D;IAC3D,MAAM,UAAU,GAAG,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC;IAE1D,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,CAC3C,OAAO,CAAC,GAAG,EAAE,EACb,MAAM,EACN,OAAO,EACP,UAAU,CACX,CAAC;IAEF,uDAAuD;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,UAAU;SACvB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC;IAE3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;IAE5D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;QAChC,gBAAgB;QAChB,aAAa,EAAE,OAAO,CAAC,GAAG,EAAE;QAC5B,eAAe,EAAE,MAAM;QACvB,OAAO;QACP,OAAO;QACP,IAAI;QACJ,IAAI;QACJ,OAAO;QACP,aAAa;KACd,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpC,OAAO,CAAC,GAAG,CAAC,0CAA0C,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
|