gbos 1.4.16 → 1.4.18
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/package.json +13 -6
- package/src/cli.js +12 -1
- package/src/commands/auth-token.js +216 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gbos",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "GBOS
|
|
3
|
+
"version": "1.4.18",
|
|
4
|
+
"description": "CLI and orchestrator for the Generative Business Operating System (GBOS) — connect AI coding agents (Claude, Gemini, Codex) to managed development workflows with task automation, GitLab sync, and NDJSON event streaming for thin client integration",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"gbos": "src/cli.js"
|
|
@@ -17,11 +17,18 @@
|
|
|
17
17
|
"keywords": [
|
|
18
18
|
"gbos",
|
|
19
19
|
"cli",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
20
|
+
"orchestrator",
|
|
21
|
+
"ai-agent",
|
|
22
|
+
"ai-coding",
|
|
23
|
+
"claude",
|
|
24
|
+
"gemini",
|
|
25
|
+
"codex",
|
|
26
|
+
"task-automation",
|
|
22
27
|
"devtools",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
28
|
+
"gitlab",
|
|
29
|
+
"mcp",
|
|
30
|
+
"ndjson",
|
|
31
|
+
"thin-client"
|
|
25
32
|
],
|
|
26
33
|
"author": "Mystro Analytics",
|
|
27
34
|
"license": "MIT",
|
package/src/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ const { Command } = require('commander');
|
|
|
4
4
|
const program = new Command();
|
|
5
5
|
|
|
6
6
|
const authCommand = require('./commands/auth');
|
|
7
|
+
const authTokenCommand = require('./commands/auth-token');
|
|
7
8
|
const connectCommand = require('./commands/connect');
|
|
8
9
|
const logoutCommand = require('./commands/logout');
|
|
9
10
|
const { tasksCommand, nextTaskCommand, continueCommand, fallbackCommand, addTaskCommand, completedCommand } = require('./commands/tasks');
|
|
@@ -27,6 +28,16 @@ program
|
|
|
27
28
|
.option('-f, --force', 'Force re-authentication even if already authenticated')
|
|
28
29
|
.action(authCommand);
|
|
29
30
|
|
|
31
|
+
program
|
|
32
|
+
.command('auth-token')
|
|
33
|
+
.description('Authenticate with a pre-obtained access token (for thin clients and programmatic use)')
|
|
34
|
+
.requiredOption('-t, --token <token>', 'GBOS access token obtained from UI authentication')
|
|
35
|
+
.option('--node-id <nodeId>', 'Auto-connect to a specific node after authentication')
|
|
36
|
+
.option('-d, --dir <directory>', 'Working directory (defaults to current directory)')
|
|
37
|
+
.option('-a, --agent <agent>', 'Agent CLI being used (default: claude-code)')
|
|
38
|
+
.option('--json', 'Output result as JSON (for programmatic consumption)')
|
|
39
|
+
.action(authTokenCommand);
|
|
40
|
+
|
|
30
41
|
program
|
|
31
42
|
.command('connect')
|
|
32
43
|
.description('Connect to a GBOS development node')
|
|
@@ -313,7 +324,7 @@ program
|
|
|
313
324
|
cmd.outputHelp();
|
|
314
325
|
} else {
|
|
315
326
|
console.log(`Unknown command: ${command}`);
|
|
316
|
-
console.log('Available commands: auth, connect, disconnect, status, tasks, next, continue, completed, fallback, add_task, start, resume, stop, runs, auto, logout, gitlab, registry, help');
|
|
327
|
+
console.log('Available commands: auth, auth-token, connect, disconnect, status, tasks, next, continue, completed, fallback, add_task, start, resume, stop, runs, auto, logout, gitlab, registry, help');
|
|
317
328
|
}
|
|
318
329
|
} else {
|
|
319
330
|
program.outputHelp();
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auth-token command
|
|
3
|
+
* Programmatic authentication for thin clients.
|
|
4
|
+
* Accepts an access token directly (obtained from UI-based login),
|
|
5
|
+
* validates it against the GBOS API, saves the session,
|
|
6
|
+
* and optionally auto-connects to a specific node.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* gbos auth-token --token <access_token>
|
|
10
|
+
* gbos auth-token --token <access_token> --node-id <id>
|
|
11
|
+
* gbos auth-token --token <access_token> --node-id <id> --dir /path/to/project
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const api = require('../lib/api');
|
|
15
|
+
const config = require('../lib/config');
|
|
16
|
+
const { registerMCPServer } = require('../lib/skills');
|
|
17
|
+
const { setupProjectSkills } = require('../lib/skills');
|
|
18
|
+
|
|
19
|
+
async function authTokenCommand(options) {
|
|
20
|
+
const token = options.token;
|
|
21
|
+
|
|
22
|
+
if (!token) {
|
|
23
|
+
const result = { success: false, error: 'Missing --token flag. Provide an access token.' };
|
|
24
|
+
if (options.json) {
|
|
25
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
26
|
+
} else {
|
|
27
|
+
console.error('\nError: --token is required.\n');
|
|
28
|
+
console.error('Usage: gbos auth-token --token <access_token> [--node-id <id>] [--dir <path>]\n');
|
|
29
|
+
}
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Step 1: Temporarily save the token so the API client can use it
|
|
35
|
+
config.saveSession({ access_token: token });
|
|
36
|
+
|
|
37
|
+
// Step 2: Validate the token by calling the session endpoint
|
|
38
|
+
let sessionInfo;
|
|
39
|
+
try {
|
|
40
|
+
sessionInfo = await api.getSession();
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// Token is invalid — clear and fail
|
|
43
|
+
config.clearSession();
|
|
44
|
+
const result = { success: false, error: 'Invalid or expired token', details: err.message };
|
|
45
|
+
if (options.json) {
|
|
46
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
47
|
+
} else {
|
|
48
|
+
console.error('\nError: Token validation failed —', err.message, '\n');
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const userData = sessionInfo.data || sessionInfo;
|
|
54
|
+
const user = userData.user || userData;
|
|
55
|
+
const account = userData.account || {};
|
|
56
|
+
|
|
57
|
+
// Step 3: Build and save the full session
|
|
58
|
+
const userId = user.id || user.user_id;
|
|
59
|
+
const userName = user.first_name && user.last_name
|
|
60
|
+
? `${user.first_name} ${user.last_name}`
|
|
61
|
+
: user.name || user.user_name || `User ${userId}`;
|
|
62
|
+
const accountId = account.id || user.account_id;
|
|
63
|
+
const accountName = account.name || `Account ${accountId}`;
|
|
64
|
+
|
|
65
|
+
// Calculate token expiration — default 24 hours
|
|
66
|
+
const expiresInSeconds = userData.expires_in && userData.expires_in > 60
|
|
67
|
+
? userData.expires_in : 86400;
|
|
68
|
+
const tokenExpiresAt = new Date(Date.now() + expiresInSeconds * 1000).toISOString();
|
|
69
|
+
|
|
70
|
+
const session = {
|
|
71
|
+
access_token: token,
|
|
72
|
+
refresh_token: userData.refresh_token || null,
|
|
73
|
+
token_expires_at: tokenExpiresAt,
|
|
74
|
+
user_id: userId,
|
|
75
|
+
user_name: userName,
|
|
76
|
+
user_first_name: user.first_name || null,
|
|
77
|
+
user_last_name: user.last_name || null,
|
|
78
|
+
user_email: user.email || null,
|
|
79
|
+
account_id: accountId,
|
|
80
|
+
account_name: accountName,
|
|
81
|
+
session_id: userData.session_id || null,
|
|
82
|
+
authenticated_at: new Date().toISOString(),
|
|
83
|
+
auth_method: 'token',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
config.saveSession(session);
|
|
87
|
+
|
|
88
|
+
// Register MCP server
|
|
89
|
+
try {
|
|
90
|
+
registerMCPServer();
|
|
91
|
+
} catch (e) {
|
|
92
|
+
// Non-fatal
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Step 4: Optionally auto-connect to a node
|
|
96
|
+
let connectionResult = null;
|
|
97
|
+
|
|
98
|
+
if (options.nodeId) {
|
|
99
|
+
try {
|
|
100
|
+
const workingDirectory = options.dir || process.cwd();
|
|
101
|
+
|
|
102
|
+
// Get git info
|
|
103
|
+
let gitRepoUrl = null;
|
|
104
|
+
let gitBranch = null;
|
|
105
|
+
try {
|
|
106
|
+
const { execSync } = require('child_process');
|
|
107
|
+
gitRepoUrl = execSync('git config --get remote.origin.url', { encoding: 'utf8' }).trim();
|
|
108
|
+
gitBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
|
109
|
+
} catch (e) {
|
|
110
|
+
// Not a git repo — fine
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const agentCli = options.agent || 'claude-code';
|
|
114
|
+
|
|
115
|
+
const connectResponse = await api.connectToNode(options.nodeId, {
|
|
116
|
+
working_directory: workingDirectory,
|
|
117
|
+
git_repo_url: gitRepoUrl,
|
|
118
|
+
git_branch: gitBranch,
|
|
119
|
+
agent_cli: agentCli,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const { connection_id, node } = connectResponse.data;
|
|
123
|
+
const applicationName = node.application?.name || 'N/A';
|
|
124
|
+
|
|
125
|
+
// Save connection to session
|
|
126
|
+
config.saveConnection({
|
|
127
|
+
connection_id,
|
|
128
|
+
node: {
|
|
129
|
+
id: node.id,
|
|
130
|
+
uuid: node.uuid,
|
|
131
|
+
name: node.name,
|
|
132
|
+
node_type: node.node_type,
|
|
133
|
+
system_prompt: node.system_prompt,
|
|
134
|
+
application_id: node.application_id,
|
|
135
|
+
},
|
|
136
|
+
application: {
|
|
137
|
+
id: node.application?.id || node.application_id,
|
|
138
|
+
name: applicationName,
|
|
139
|
+
},
|
|
140
|
+
connected_at: new Date().toISOString(),
|
|
141
|
+
working_directory: workingDirectory,
|
|
142
|
+
git_repo_url: gitRepoUrl,
|
|
143
|
+
git_branch: gitBranch,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Setup project skills
|
|
147
|
+
try {
|
|
148
|
+
setupProjectSkills(workingDirectory);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
// Non-fatal
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
connectionResult = {
|
|
154
|
+
connection_id,
|
|
155
|
+
node_id: node.id,
|
|
156
|
+
node_name: node.name,
|
|
157
|
+
application_id: node.application?.id || node.application_id,
|
|
158
|
+
application_name: applicationName,
|
|
159
|
+
};
|
|
160
|
+
} catch (err) {
|
|
161
|
+
// Auth succeeded but connect failed
|
|
162
|
+
connectionResult = { error: err.message };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Step 5: Output result
|
|
167
|
+
const result = {
|
|
168
|
+
success: true,
|
|
169
|
+
user: {
|
|
170
|
+
id: userId,
|
|
171
|
+
name: userName,
|
|
172
|
+
email: user.email || null,
|
|
173
|
+
},
|
|
174
|
+
account: {
|
|
175
|
+
id: accountId,
|
|
176
|
+
name: accountName,
|
|
177
|
+
},
|
|
178
|
+
authenticated_at: session.authenticated_at,
|
|
179
|
+
token_expires_at: tokenExpiresAt,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
if (connectionResult) {
|
|
183
|
+
result.connection = connectionResult;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (options.json) {
|
|
187
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
188
|
+
} else {
|
|
189
|
+
console.log('\n ✓ Authentication successful!\n');
|
|
190
|
+
console.log(` User: ${userName}`);
|
|
191
|
+
console.log(` Account: ${accountName}`);
|
|
192
|
+
console.log(` Expires: ${new Date(tokenExpiresAt).toLocaleString()}\n`);
|
|
193
|
+
|
|
194
|
+
if (connectionResult && !connectionResult.error) {
|
|
195
|
+
console.log(' ✓ Connected to node!\n');
|
|
196
|
+
console.log(` Node: ${connectionResult.node_name}`);
|
|
197
|
+
console.log(` Application: ${connectionResult.application_name}`);
|
|
198
|
+
console.log(` Session: ${connectionResult.connection_id}\n`);
|
|
199
|
+
} else if (connectionResult && connectionResult.error) {
|
|
200
|
+
console.log(` ✗ Connection failed: ${connectionResult.error}\n`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(' You can now run "gbos connect", "gbos tasks", or "gbos auto".\n');
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
const result = { success: false, error: error.message };
|
|
207
|
+
if (options.json) {
|
|
208
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
209
|
+
} else {
|
|
210
|
+
console.error(`\nError: ${error.message}\n`);
|
|
211
|
+
}
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = authTokenCommand;
|