@struere/cli 0.2.2 → 0.2.4

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 (2) hide show
  1. package/dist/index.js +15 -107
  2. package/package.json +12 -4
package/dist/index.js CHANGED
@@ -76,11 +76,13 @@ function getSyncUrl() {
76
76
 
77
77
  class ApiClient {
78
78
  baseUrl;
79
- constructor(baseUrl) {
79
+ tokenOverride;
80
+ constructor(baseUrl, token) {
80
81
  this.baseUrl = baseUrl || getApiUrl();
82
+ this.tokenOverride = token;
81
83
  }
82
84
  async request(path, options = {}) {
83
- const token = getToken();
85
+ const token = this.tokenOverride || getToken();
84
86
  const apiKey = getApiKey();
85
87
  const headers = {
86
88
  "Content-Type": "application/json",
@@ -165,7 +167,7 @@ class ApiError extends Error {
165
167
 
166
168
  // src/commands/login.ts
167
169
  var AUTH_CALLBACK_PORT = 9876;
168
- var loginCommand = new Command("login").description("Log in to Struere").option("--headless", "Login with email/password (no browser)").action(async (options) => {
170
+ var loginCommand = new Command("login").description("Log in to Struere").action(async () => {
169
171
  const spinner = ora();
170
172
  console.log();
171
173
  console.log(chalk.bold("Struere Login"));
@@ -177,22 +179,14 @@ var loginCommand = new Command("login").description("Log in to Struere").option(
177
179
  console.log();
178
180
  return;
179
181
  }
180
- if (options.headless) {
181
- await headlessLogin(spinner);
182
- } else {
183
- await browserLogin(spinner);
184
- }
182
+ await browserLogin(spinner);
185
183
  });
186
- async function performLogin(options = {}) {
184
+ async function performLogin() {
187
185
  const spinner = ora();
188
186
  console.log();
189
187
  console.log(chalk.bold("Struere Login"));
190
188
  console.log();
191
- if (options.headless) {
192
- return headlessLoginInternal(spinner);
193
- } else {
194
- return browserLoginInternal(spinner);
195
- }
189
+ return browserLoginInternal(spinner);
196
190
  }
197
191
  async function browserLogin(spinner) {
198
192
  const result = await browserLoginInternal(spinner);
@@ -212,6 +206,7 @@ async function browserLoginInternal(spinner) {
212
206
  const sessionId = url.searchParams.get("session_id");
213
207
  if (token && sessionId) {
214
208
  resolve({ token, sessionId });
209
+ setTimeout(() => server.stop(), 1000);
215
210
  return new Response(getSuccessHtml(), {
216
211
  headers: { "Content-Type": "text/html" }
217
212
  });
@@ -250,7 +245,7 @@ async function browserLoginInternal(spinner) {
250
245
  try {
251
246
  const { token } = await authPromise;
252
247
  spinner.text = "Fetching user info";
253
- const api = new ApiClient;
248
+ const api = new ApiClient(undefined, token);
254
249
  const { user, organization } = await api.getMe();
255
250
  const credentials = {
256
251
  token,
@@ -279,60 +274,6 @@ async function browserLoginInternal(spinner) {
279
274
  console.log();
280
275
  console.log(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
281
276
  console.log();
282
- console.log(chalk.gray("Try"), chalk.cyan("struere login --headless"), chalk.gray("for email/password login"));
283
- console.log();
284
- return null;
285
- }
286
- }
287
- async function headlessLogin(spinner) {
288
- const result = await headlessLoginInternal(spinner);
289
- if (result) {
290
- printNextSteps();
291
- }
292
- }
293
- async function headlessLoginInternal(spinner) {
294
- const email = await prompt("Email: ");
295
- const password = await prompt("Password: ", true);
296
- if (!email || !password) {
297
- console.log(chalk.red("Email and password are required"));
298
- return null;
299
- }
300
- spinner.start("Logging in");
301
- try {
302
- const api = new ApiClient;
303
- const { token, user } = await api.login(email, password);
304
- const { organization } = await api.getMe();
305
- const credentials = {
306
- token,
307
- user: {
308
- id: user.id,
309
- email: user.email,
310
- name: user.name,
311
- organizationId: user.organizationId
312
- },
313
- organization: {
314
- id: organization.id,
315
- name: organization.name,
316
- slug: organization.slug
317
- },
318
- expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
319
- };
320
- saveCredentials(credentials);
321
- spinner.succeed("Logged in successfully");
322
- console.log();
323
- console.log(chalk.green("Welcome,"), chalk.cyan(user.name));
324
- console.log(chalk.gray("Organization:"), organization.name);
325
- console.log();
326
- return credentials;
327
- } catch (error) {
328
- spinner.fail("Login failed");
329
- console.log();
330
- if (error instanceof ApiError) {
331
- console.log(chalk.red("Error:"), error.message);
332
- } else {
333
- console.log(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
334
- }
335
- console.log();
336
277
  return null;
337
278
  }
338
279
  }
@@ -344,9 +285,9 @@ function printNextSteps() {
344
285
  console.log();
345
286
  }
346
287
  function getAuthUrl() {
347
- const baseUrl = process.env.STRUERE_AUTH_URL || "https://struere.dev";
288
+ const baseUrl = process.env.STRUERE_AUTH_URL || "https://app.struere.dev";
348
289
  const callbackUrl = `http://localhost:${AUTH_CALLBACK_PORT}/callback`;
349
- return `${baseUrl}/cli-auth?callback=${encodeURIComponent(callbackUrl)}`;
290
+ return `${baseUrl}/authorize?callback=${encodeURIComponent(callbackUrl)}`;
350
291
  }
351
292
  function getSuccessHtml() {
352
293
  return `<!DOCTYPE html>
@@ -389,39 +330,6 @@ function getErrorHtml(message) {
389
330
  </body>
390
331
  </html>`;
391
332
  }
392
- async function prompt(message, hidden = false) {
393
- process.stdout.write(chalk.gray(message));
394
- return new Promise((resolve) => {
395
- let input = "";
396
- if (hidden) {
397
- process.stdin.setRawMode(true);
398
- }
399
- process.stdin.resume();
400
- process.stdin.setEncoding("utf8");
401
- const onData = (char) => {
402
- if (char === `
403
- ` || char === "\r") {
404
- process.stdin.removeListener("data", onData);
405
- process.stdin.pause();
406
- if (hidden) {
407
- process.stdin.setRawMode(false);
408
- console.log();
409
- }
410
- resolve(input);
411
- } else if (char === "\x03") {
412
- process.exit();
413
- } else if (char === "\x7F") {
414
- input = input.slice(0, -1);
415
- } else {
416
- input += char;
417
- if (!hidden) {
418
- process.stdout.write(char);
419
- }
420
- }
421
- };
422
- process.stdin.on("data", onData);
423
- });
424
- }
425
333
 
426
334
  // src/utils/project.ts
427
335
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
@@ -774,7 +682,7 @@ function hasAgentFiles(cwd) {
774
682
  }
775
683
 
776
684
  // src/commands/init.ts
777
- var initCommand = new Command2("init").description("Initialize a new Struere project").argument("[project-name]", "Project name").option("-y, --yes", "Skip prompts and use defaults").option("--headless", "Use headless login if authentication is needed").action(async (projectNameArg, options) => {
685
+ var initCommand = new Command2("init").description("Initialize a new Struere project").argument("[project-name]", "Project name").option("-y, --yes", "Skip prompts and use defaults").action(async (projectNameArg, options) => {
778
686
  const cwd = process.cwd();
779
687
  const spinner = ora2();
780
688
  console.log();
@@ -802,7 +710,7 @@ var initCommand = new Command2("init").description("Initialize a new Struere pro
802
710
  if (!credentials) {
803
711
  console.log(chalk2.gray("Authentication required"));
804
712
  console.log();
805
- credentials = await performLogin({ headless: options.headless });
713
+ credentials = await performLogin();
806
714
  if (!credentials) {
807
715
  console.log(chalk2.red("Authentication failed"));
808
716
  process.exit(1);
@@ -2208,7 +2116,7 @@ var whoamiCommand = new Command11("whoami").description("Show current logged in
2208
2116
  });
2209
2117
 
2210
2118
  // src/index.ts
2211
- program.name("struere").description("Struere CLI - Build, test, and deploy AI agents").version("0.2.2");
2119
+ program.name("struere").description("Struere CLI - Build, test, and deploy AI agents").version("0.2.4");
2212
2120
  program.addCommand(initCommand);
2213
2121
  program.addCommand(loginCommand);
2214
2122
  program.addCommand(logoutCommand);
package/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "@struere/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "CLI tool for developing, testing, and deploying AI agents",
5
- "keywords": ["ai", "agents", "cli", "developer-tools", "llm"],
5
+ "keywords": [
6
+ "ai",
7
+ "agents",
8
+ "cli",
9
+ "developer-tools",
10
+ "llm"
11
+ ],
6
12
  "author": "struere",
7
13
  "license": "MIT",
8
14
  "publishConfig": {
@@ -22,13 +28,15 @@
22
28
  "struere": "./dist/index.js"
23
29
  },
24
30
  "main": "./dist/index.js",
25
- "files": ["dist"],
31
+ "files": [
32
+ "dist"
33
+ ],
26
34
  "scripts": {
27
35
  "build": "bun build ./src/index.ts --outdir ./dist --target bun --external commander --external chalk --external ora --external chokidar --external yaml --external @struere/runtime && chmod +x ./dist/index.js",
28
36
  "dev": "tsc --watch",
29
37
  "test": "bun test",
30
38
  "prepublishOnly": "bun run build && bun run verify-build",
31
- "bump": "node scripts/bump-version.js",
39
+ "bump": "node scripts/bump-version.cjs",
32
40
  "verify-build": "node -e \"const pkg = require('./package.json'); const fs = require('fs'); const bundle = fs.readFileSync('./dist/index.js', 'utf8'); const match = bundle.match(/version\\(\\\"([^\\\"]+)\\\"\\)/); if (!match || match[1] !== pkg.version) { console.error('Version mismatch: package.json=' + pkg.version + ' bundle=' + (match ? match[1] : 'not found')); process.exit(1); } console.log('Build verified: v' + pkg.version);\""
33
41
  },
34
42
  "dependencies": {