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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gbos",
3
- "version": "1.4.16",
4
- "description": "GBOS - Command line interface for GBOS services",
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
- "tui",
21
- "cloud",
20
+ "orchestrator",
21
+ "ai-agent",
22
+ "ai-coding",
23
+ "claude",
24
+ "gemini",
25
+ "codex",
26
+ "task-automation",
22
27
  "devtools",
23
- "development",
24
- "ai-agent"
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;