atris 3.67.0 → 3.68.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 (2) hide show
  1. package/commands/signup.js +45 -2
  2. package/package.json +1 -1
@@ -11,8 +11,10 @@
11
11
  // Backend: backend/routers/agent_auth_router.py (POST /auth/agent/signup).
12
12
 
13
13
  const crypto = require('crypto');
14
+ const fs = require('fs');
14
15
  const { apiRequestJson, getApiBaseUrl } = require('../utils/api');
15
- const { saveCredentials } = require('../utils/auth');
16
+ const { saveCredentials, saveProfile, saveAgentClientCredentials, getCredentialsPath } = require('../utils/auth');
17
+ const agentClient = require('../utils/agent-client');
16
18
  const { argsWantHelp, isHelpToken } = require('../lib/noninteractive');
17
19
 
18
20
  // Mirror the server rule exactly (^[a-z0-9]{3,30}$) so we fail fast and friendly
@@ -45,6 +47,36 @@ function parseHandle(args = []) {
45
47
  return (positional || '').trim().toLowerCase();
46
48
  }
47
49
 
50
+ // Newer servers also hand back an agent client (id + secret) so the agent can
51
+ // renew its own login forever. Store it the way `atris login` does with the
52
+ // secret in ATRIS_CLIENT_SECRET: a private 0600 copy under
53
+ // ~/.atris/agent-clients/, then make the client the active login. The 30-day
54
+ // token just saved stays reachable as a profile named after the handle.
55
+ // Returns { ok: true } or { ok: false, secretFile, clientId }. Never throws,
56
+ // never prints the secret or a token.
57
+ async function adoptSignupClient(client, handle, deps = {}) {
58
+ const clientId = client && typeof client.client_id === 'string' ? client.client_id.trim() : '';
59
+ const secret = client && typeof client.client_secret === 'string' ? client.client_secret.trim() : '';
60
+ if (!clientId.startsWith(agentClient.CLIENT_ID_PREFIX) || !secret) return { ok: false };
61
+
62
+ let secretFile = null;
63
+ try {
64
+ const target = agentClient.managedSecretPath(clientId);
65
+ agentClient.writeFileAtomic(target, `${secret}\n`);
66
+ secretFile = target;
67
+ const entry = await agentClient.requestClientToken({ clientId, secret, scope: null }, deps);
68
+
69
+ // Keep the 30-day login as a profile named after the handle, then switch.
70
+ const fallback = JSON.parse(fs.readFileSync(getCredentialsPath(), 'utf8'));
71
+ saveProfile(handle, fallback);
72
+ saveAgentClientCredentials({ client_id: clientId, client_secret_file: secretFile, scope: null });
73
+ agentClient.writeTokenCache(clientId, entry);
74
+ return { ok: true, clientId };
75
+ } catch (error) {
76
+ return { ok: false, clientId, secretFile, reason: agentClient.scrub(error && error.message, [secret]) };
77
+ }
78
+ }
79
+
48
80
  function printSignupUsage() {
49
81
  console.error('Usage: atris signup <handle>');
50
82
  console.error(' handle: 3–30 characters, lowercase letters and digits only.');
@@ -79,9 +111,20 @@ async function signupCommand(args = []) {
79
111
  const { token, email, user_id: userId } = res.data;
80
112
  const identity = email || `${handle}@atrismail.com`;
81
113
  saveCredentials(token, null, identity, userId || null, 'atrisos');
114
+ const hasClient = Boolean(res.data.client);
115
+ const adopted = hasClient ? await adoptSignupClient(res.data.client, handle) : { ok: false };
82
116
  console.log(`\n✓ You're in: ${identity}`);
117
+ if (adopted.ok) console.log('This agent renews its own login; no human needed.');
83
118
  console.log(' Inert starter account (0 credits): identity is free, capability is earned.');
84
119
  console.log(' Saved to your active profile.');
120
+ if (adopted.ok) {
121
+ console.log(` The 30-day login is kept as a backup. switch to it: atris switch ${handle} --global`);
122
+ } else if (hasClient && adopted.secretFile) {
123
+ console.log(` Could not sign in with the agent client yet${adopted.reason ? ` (${adopted.reason})` : ''}. Using the 30-day login for now.`);
124
+ console.log(` Try again: atris login --client-id ${adopted.clientId} --client-secret-file ${adopted.secretFile}`);
125
+ } else if (hasClient || typeof res.data.client_error === 'string') {
126
+ console.log(' This login lasts 30 days; after that, renewing it will need a fresh signup login.');
127
+ }
85
128
  console.log('\nNext:');
86
129
  console.log(' atris play # claim a starter mission and earn your first proof-backed rep');
87
130
  console.log(' atris xp # see where you stand on the board');
@@ -107,4 +150,4 @@ async function signupCommand(args = []) {
107
150
  return 1;
108
151
  }
109
152
 
110
- module.exports = { signupCommand, parseHandle, HANDLE_RE };
153
+ module.exports = { signupCommand, parseHandle, HANDLE_RE, adoptSignupClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atris",
3
- "version": "3.67.0",
3
+ "version": "3.68.0",
4
4
  "description": "you say what you want in plain words. atris builds it, checks it, and shows you proof.",
5
5
  "main": "bin/atris.js",
6
6
  "bin": {