mindvest-atlas 0.63.0 → 0.64.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindvest-atlas",
3
- "version": "0.63.0",
3
+ "version": "0.64.0",
4
4
  "description": "Atlas CLI \u2014 OAuth login, tool calls, and live alert/flow streaming for the Atlas trading API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@ import fs from 'node:fs';
27
27
  import path from 'node:path';
28
28
  import {
29
29
  workspace, workspaceRoot, venvPython, ambientPython, jobEnv, ensureProjectFiles,
30
- computerUseAllowed, computerClaim, releaseComputerClaim,
30
+ computerUseAllowed, computerClaim, releaseComputerClaim, askAddress,
31
31
  } from '../remote-control.js';
32
32
  import { color, println, eprintln } from '../util/ui.js';
33
33
 
@@ -254,6 +254,14 @@ export function runInProject(job, code, root) {
254
254
  const venv = venvPython(dir);
255
255
  const python = venv ? [String(venv)] : [...ambientPython()];
256
256
  const env = { ...process.env, ...jobEnv(dir), ATLAS_JOB: path.basename(dir) };
257
+ // AND HOW TO REACH THE APP, when this shell was not started by it. Without
258
+ // these, ask(), screenshot() and every dashboard call inside the script refuse
259
+ // with "this has to run from inside Atlas" while Atlas is running (owner,
260
+ // 2026-09-10). Only filled when absent: a run Atlas started keeps its own.
261
+ if (!env.ATLAS_ASK_URL || !env.ATLAS_ASK_TOKEN) {
262
+ const at = askAddress(root);
263
+ if (at) { env.ATLAS_ASK_URL = at.url; env.ATLAS_ASK_TOKEN = at.token; }
264
+ }
257
265
  // BEFORE ANYTHING TRIES TO IMPORT THEM. Checked every time and installed only
258
266
  // when something is missing, so the cost is one python start on a machine
259
267
  // that is already set up.
@@ -24,7 +24,7 @@ import { spawnSync } from 'node:child_process';
24
24
  import fs from 'node:fs';
25
25
  import path from 'node:path';
26
26
  import {
27
- workspace, venvPython, ambientPython, jobEnv, ensureProjectFiles,
27
+ workspace, venvPython, ambientPython, jobEnv, ensureProjectFiles, askAddress,
28
28
  } from '../remote-control.js';
29
29
  import { color, println, eprintln } from '../util/ui.js';
30
30
  import { shellSession } from './computer-use.js';
@@ -86,11 +86,18 @@ export function runCommand(args) {
86
86
  // THE BRIDGE BACK TO ATLAS is inherited, never invented. These are handed to
87
87
  // a process Atlas starts, so an agent's own shell has them and a person's
88
88
  // ordinary terminal does not. Saying so beats a snippet that half works.
89
+ // FILLED IN WHEN THE APP IS RUNNING. It writes its loopback address down while
90
+ // it listens, so a shell Atlas did not start can still reach it. The note below
91
+ // is now only for the case that is actually true: Atlas is not running.
92
+ if (!env.ATLAS_ASK_URL || !env.ATLAS_ASK_TOKEN) {
93
+ const at = askAddress(flags.root);
94
+ if (at) { env.ATLAS_ASK_URL = at.url; env.ATLAS_ASK_TOKEN = at.token; }
95
+ }
89
96
  if (!env.ATLAS_ASK_URL || !env.ATLAS_ASK_TOKEN) {
90
97
  println(color.dim(
91
- ' Note: this shell was not started by Atlas, so ask(), dashboard and '
92
- + 'screenshot() will not work in it. Everything else will. Ask in a chat '
93
- + 'if you need those.'));
98
+ ' Note: Atlas Studio is not running, so ask(), dashboard and screenshot() '
99
+ + 'will not work in this shell. Everything else will. Start Atlas Studio if '
100
+ + 'you need those.'));
94
101
  }
95
102
  if (!env.ATLAS_JOB) env.ATLAS_JOB = path.basename(dir);
96
103
  // ONE SESSION FOR THE WHOLE SHELL, the same one `atlas computer-use` uses.
@@ -16,6 +16,7 @@
16
16
  // the project's own `screenshots/`, and prints the faults in words — because a
17
17
  // picture the agent cannot see is not a check.
18
18
  import { color, println, eprintln } from '../util/ui.js';
19
+ import { askAddress } from '../remote-control.js';
19
20
 
20
21
  export async function screenshotCommand(args) {
21
22
  const flags = args.flags || {};
@@ -25,17 +26,20 @@ export async function screenshotCommand(args) {
25
26
  return 1;
26
27
  }
27
28
 
28
- const url = process.env.ATLAS_ASK_URL;
29
- const token = process.env.ATLAS_ASK_TOKEN;
29
+ // Atlas hands these to what it starts, and writes them down while it is
30
+ // running so a terminal it did not start can find them too.
31
+ const at = askAddress(flags.root);
32
+ const url = at?.url;
33
+ const token = at?.token;
30
34
  if (!url || !token) {
31
35
  // NOT a Local Mode check, whatever it used to say. These variables are
32
36
  // handed to a process Atlas starts — a script it runs, or an agent it
33
37
  // spawned. Their absence means this command is running somewhere Atlas did
34
38
  // not start it, and saying "turn Local Mode on" sent people to a switch
35
39
  // that was already on (owner, 2026-09-05).
36
- eprintln(color.red('This has to run from inside Atlas. Atlas is what draws the page.'));
37
- eprintln(color.dim('Ask for it in a chat, or call screenshot() from the project\'s script. '
38
- + 'Run by hand in a terminal there is nothing to photograph.'));
40
+ eprintln(color.red('Atlas Studio is not running on this computer. Atlas is what draws the page.'));
41
+ eprintln(color.dim('Start Atlas Studio and try again, or ask for it in a chat. '
42
+ + 'With nothing running there is nothing to photograph.'));
39
43
  return 1;
40
44
  }
41
45
 
package/src/config.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import path from 'node:path';
3
3
  import os from 'node:os';
4
4
 
5
- export const VERSION = '0.63.0';
5
+ export const VERSION = '0.64.0';
6
6
  export const DEFAULT_BASE_URL = 'https://atlasmcp.finmanagerai.com';
7
7
  export const DEFAULT_SCOPE = 'atlas broker';
8
8
  export const CLIENT_NAME = 'Atlas CLI';
@@ -39,6 +39,34 @@ export const ENTRIES = ['main.py', 'main.js', 'main.mjs'];
39
39
  */
40
40
  export const DEFAULT_TIMEOUT_MS = 1_800_000;
41
41
 
42
+ /**
43
+ * HOW TO REACH A RUNNING ATLAS, from a shell it did not start.
44
+ *
45
+ * ATLAS_ASK_URL / ATLAS_ASK_TOKEN are handed to processes Atlas spawns. Anything
46
+ * else on the same machine had no way in at all: `atlas screenshot`, `atlas
47
+ * dashboard` and `atlas run --code` all refused with "this has to run from
48
+ * inside Atlas", with the app running the whole time and nothing the person
49
+ * could do about it (owner, 2026-09-10).
50
+ *
51
+ * The app writes its loopback address down while it is listening, so this is
52
+ * the same server those variables point at, on the same machine, for the same
53
+ * user. The environment still wins when it is set: a run Atlas started should
54
+ * talk to the Atlas that started it.
55
+ */
56
+ export function askAddress(root) {
57
+ const url = process.env.ATLAS_ASK_URL;
58
+ const token = process.env.ATLAS_ASK_TOKEN;
59
+ if (url && token) return { url, token };
60
+ try {
61
+ const file = path.join(workspaceRoot(root), '.studio', 'ask-server.json');
62
+ const saved = JSON.parse(fs.readFileSync(file, 'utf8'));
63
+ if (saved?.url && saved?.token) return { url: String(saved.url), token: String(saved.token) };
64
+ } catch {
65
+ // Not running, or a different machine's home. The caller says so in words.
66
+ }
67
+ return null;
68
+ }
69
+
42
70
  export function workspaceRoot(override) {
43
71
  const raw = override || process.env.ATLAS_LOCAL_DIR
44
72
  || process.env.ATLAS_LIBRARY_DIR // what Studio sets