mindvest-atlas 0.63.0 → 0.65.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 +1 -1
- package/src/commands/computer-use.js +9 -1
- package/src/commands/dashboard.js +9 -1
- package/src/commands/run.js +11 -4
- package/src/commands/screenshot.js +9 -5
- package/src/commands/tools.js +1 -1
- package/src/config.js +1 -1
- package/src/helpers/atlas_env.js +6 -0
- package/src/helpers/atlas_env.py +30 -0
- package/src/remote-control.js +28 -0
package/package.json
CHANGED
|
@@ -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.
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
// IT IS NOT THE COMPUTER. This drives the project's own window, so the real
|
|
9
9
|
// pointer never moves, nothing is claimed, no switch is needed, and a click at
|
|
10
10
|
// the wrong coordinates lands somewhere else in your own page rather than in
|
|
11
|
-
// whatever was behind it.
|
|
11
|
+
// whatever was behind it. That is the FIRST pass (styling, measured). `expand`
|
|
12
|
+
// opens the SECOND: the dashboard in its own window on the real screen, in front
|
|
13
|
+
// and in the picture, to be pressed with `atlas computer-use` so every tab and
|
|
14
|
+
// button is seen to react (owner, 2026-09-10). `collapse` takes it down.
|
|
12
15
|
import { color, println, eprintln } from '../util/ui.js';
|
|
13
16
|
import { runInProject } from './computer-use.js';
|
|
14
17
|
|
|
@@ -24,6 +27,8 @@ const OPS = {
|
|
|
24
27
|
shot: ['shot', 0],
|
|
25
28
|
check: ['check', 0],
|
|
26
29
|
close: ['close', 0],
|
|
30
|
+
expand: ['expand', 0],
|
|
31
|
+
collapse: ['collapse', 0],
|
|
27
32
|
};
|
|
28
33
|
const NUMERIC = new Set(['click', 'double-click', 'move', 'scroll']);
|
|
29
34
|
|
|
@@ -39,6 +44,9 @@ const HELP = `atlas dashboard <command>
|
|
|
39
44
|
shot a picture, AND what is wrong with it in words
|
|
40
45
|
check all four views, each measured
|
|
41
46
|
close
|
|
47
|
+
expand its own window ON the screen, in front: then
|
|
48
|
+
press it with \`atlas computer-use\`
|
|
49
|
+
collapse take that window down
|
|
42
50
|
|
|
43
51
|
--job <project> which project (defaults to $ATLAS_JOB, which a chat sets)
|
|
44
52
|
|
package/src/commands/run.js
CHANGED
|
@@ -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:
|
|
92
|
-
+ '
|
|
93
|
-
+ '
|
|
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
|
-
|
|
29
|
-
|
|
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('
|
|
37
|
-
eprintln(color.dim('
|
|
38
|
-
+ '
|
|
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/commands/tools.js
CHANGED
|
@@ -42,7 +42,7 @@ const HELPER_FUNCTIONS = {
|
|
|
42
42
|
atlas: 'atlas(tool, params) any cloud tool, as a call instead of a process',
|
|
43
43
|
ask: 'ask(prompt) the model on this computer, with its own tools',
|
|
44
44
|
mcp: 'mcp(server, tool, args) a connected MCP server',
|
|
45
|
-
dashboard: "dashboard.open/find/click/
|
|
45
|
+
dashboard: "dashboard.open/find/click/shot/expand work this project's own page; expand = on the real screen",
|
|
46
46
|
computer: 'computer: screen, click, type, key see and use the whole machine',
|
|
47
47
|
screen: 'screen(), click(x,y), type(text) see and use the whole machine',
|
|
48
48
|
click: 'click(x, y), double_click, drag use the mouse on this computer',
|
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.
|
|
5
|
+
export const VERSION = '0.65.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';
|
package/src/helpers/atlas_env.js
CHANGED
|
@@ -324,6 +324,12 @@ export const dashboard = {
|
|
|
324
324
|
/** All four views, each measured: computer and phone, dark and light. */
|
|
325
325
|
check: async () => (await driveDashboard("check")).views || [],
|
|
326
326
|
close: () => driveDashboard("close"),
|
|
327
|
+
/** The second pass: the dashboard in its own full-screen window ON the screen,
|
|
328
|
+
* in front and in the picture, so it can be pressed with the real pointer
|
|
329
|
+
* (computer.screen / computer.click). Answers with its bounds and whether
|
|
330
|
+
* computer use is on. collapse() takes it down again. */
|
|
331
|
+
expand: () => driveDashboard("expand"),
|
|
332
|
+
collapse: () => driveDashboard("collapse"),
|
|
327
333
|
};
|
|
328
334
|
|
|
329
335
|
/**
|
package/src/helpers/atlas_env.py
CHANGED
|
@@ -395,6 +395,14 @@ class _Dashboard(object):
|
|
|
395
395
|
atlas.dashboard.close()
|
|
396
396
|
|
|
397
397
|
Coordinates are inside the dashboard, from its top left, not the screen's.
|
|
398
|
+
|
|
399
|
+
THAT IS THE FIRST PASS: styling, offscreen, measured. The second pass is
|
|
400
|
+
the real screen (owner, 2026-09-10: "use the user's computer and navigate
|
|
401
|
+
and press the buttons ... test the sensitivity"): once check() is clean,
|
|
402
|
+
expand() puts the dashboard in its own full-screen window IN FRONT and in
|
|
403
|
+
the picture, and you press its tabs and buttons with the real pointer
|
|
404
|
+
through screen()/click()/do(), reading `changed` after each. Then
|
|
405
|
+
collapse(). Computer view only; the phone reacts the same way.
|
|
398
406
|
"""
|
|
399
407
|
|
|
400
408
|
@staticmethod
|
|
@@ -526,6 +534,28 @@ class _Dashboard(object):
|
|
|
526
534
|
_log_action("dashboard_close")
|
|
527
535
|
return out
|
|
528
536
|
|
|
537
|
+
def expand(self):
|
|
538
|
+
"""The dashboard in its own full-screen window, ON THE SCREEN, in front.
|
|
539
|
+
|
|
540
|
+
For the second pass: pressing it with the real pointer. This is the one
|
|
541
|
+
Atlas window a run may photograph, so `screen()` will show it and
|
|
542
|
+
`windows(title)` will find it under this project's name. Answers with
|
|
543
|
+
where it sits (`bounds`, in desktop points, and that display's `scale`)
|
|
544
|
+
and `computer_use_on`, which says whether the real-screen pass is open
|
|
545
|
+
to you at all. LOOK before you click: the bounds are where to look, not
|
|
546
|
+
a coordinate to press.
|
|
547
|
+
"""
|
|
548
|
+
out = self._call("expand", timeout=90)
|
|
549
|
+
_log_action("dashboard_expand", {"bounds": out.get("bounds"),
|
|
550
|
+
"computer_use_on": bool(out.get("computer_use_on"))})
|
|
551
|
+
return out
|
|
552
|
+
|
|
553
|
+
def collapse(self):
|
|
554
|
+
"""Take the expanded window down again. Do this when the pass is done."""
|
|
555
|
+
out = self._call("collapse")
|
|
556
|
+
_log_action("dashboard_collapse")
|
|
557
|
+
return out
|
|
558
|
+
|
|
529
559
|
|
|
530
560
|
dashboard = _Dashboard()
|
|
531
561
|
|
package/src/remote-control.js
CHANGED
|
@@ -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
|