mindvest-atlas 0.100.1 → 0.100.2

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.100.1",
3
+ "version": "0.100.2",
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": {
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.100.1';
5
+ export const VERSION = '0.100.2';
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';
@@ -416,26 +416,51 @@ export async function mcpTools({ server = "", search = "" } = {}) {
416
416
  * the payload (see phonePress()). `done: true` finishes a card that is up. At
417
417
  * most 30 new ones an hour, so say what matters, not every step.
418
418
  *
419
+ * A tap on it opens this project in Local Mode, on this computer. `view` picks
420
+ * its tab (files, checks, dashboard, chats, computer). `open` sends the tap
421
+ * anywhere else on the dashboard instead: a name such as notifications,
422
+ * alerts, workflow:<id>:performance or project:<folder>:checks, or a path
423
+ * starting /atlas/dashboard?. The answer's `opens` says where it will go.
424
+ *
419
425
  * await notify("Backtest done", { body: "SPY: 61% win\n214 trades", key: "backtest" });
420
426
  * await notify("Backtest running", { key: "backtest", progress: 0.4 });
421
427
  * await notify("Backtest done", { key: "backtest", button: "Run on QQQ" });
428
+ * await notify("Charts ready", { key: "charts", view: "dashboard" });
429
+ * await notify("Alert fired", { open: "alerts" });
422
430
  *
423
431
  * Returns the tool's answer. `sent` is 0 when the owner switched these off
424
432
  * (Profile, Manage notifications, Studio); that is their choice, not an error.
425
433
  */
426
- export async function notify(title, { body = "", key = "", progress = null, button = "", done = false } = {}) {
434
+ export async function notify(title, { body = "", key = "", progress = null, button = "", done = false, open = "", view = "" } = {}) {
427
435
  const params = { title, body: body || "" };
428
436
  if (key) params.key = key;
429
437
  if (progress !== null && progress !== undefined) params.progress = progress;
430
- if (button) {
431
- params.button = button;
432
- // The project the button starts: this one.
433
- params.project = process.env.ATLAS_JOB || "";
434
- }
438
+ if (button) params.button = button;
435
439
  if (done) params.done = true;
440
+ // This project: the one the button starts, and where a tap opens.
441
+ const job = process.env.ATLAS_JOB || "";
442
+ if (job || button) params.project = job;
443
+ if (job) {
444
+ const machine = machineHere();
445
+ if (machine) params.machine = machine;
446
+ if (view) params.view = view;
447
+ }
448
+ if (open) params.open = open;
436
449
  return atlas("phone-notify", params);
437
450
  }
438
451
 
452
+ /** This computer's id, as the atlas command line keeps it ("" if none). */
453
+ function machineHere() {
454
+ let found = (process.env.ATLAS_MACHINE || "").trim();
455
+ if (!found) {
456
+ const dir = process.env.ATLAS_CONFIG_DIR
457
+ || (process.env.XDG_CONFIG_HOME ? path.join(process.env.XDG_CONFIG_HOME, "atlas") : path.join(os_.homedir(), ".config", "atlas"));
458
+ try { found = fs.readFileSync(path.join(dir, "machine-id"), "utf8").trim(); } catch { found = ""; }
459
+ }
460
+ found = found.slice(0, 64);
461
+ return /^[\w-]+$/.test(found) ? found : "";
462
+ }
463
+
439
464
  /**
440
465
  * The button press this is about, or null.
441
466
  *
@@ -568,7 +568,24 @@ def mcp_tools(server="", search=""):
568
568
  return atlas("mcp-tools", server=server or "", search=search or "")
569
569
 
570
570
 
571
- def notify(title, body="", key="", progress=None, button="", done=False):
571
+ def _machine_here():
572
+ """This computer's id, as the atlas command line keeps it ('' if none)."""
573
+ if os.environ.get("ATLAS_MACHINE"):
574
+ found = os.environ["ATLAS_MACHINE"].strip()
575
+ else:
576
+ base = os.environ.get("ATLAS_CONFIG_DIR") or (
577
+ os.path.join(os.environ["XDG_CONFIG_HOME"], "atlas") if os.environ.get("XDG_CONFIG_HOME")
578
+ else os.path.join(os.path.expanduser("~"), ".config", "atlas"))
579
+ try:
580
+ with open(os.path.join(base, "machine-id"), encoding="utf-8") as f:
581
+ found = f.read().strip()
582
+ except Exception:
583
+ found = ""
584
+ found = found[:64]
585
+ return found if found and all(c.isascii() and (c.isalnum() or c in "_-") for c in found) else ""
586
+
587
+
588
+ def notify(title, body="", key="", progress=None, button="", done=False, open="", view=""):
572
589
  """Tell the owner's PHONE (the MindVest Atlas app). A fixed layout you fill in.
573
590
 
574
591
  A title (cut at 40 characters) and up to two short lines; plain words. The
@@ -578,9 +595,17 @@ def notify(title, body="", key="", progress=None, button="", done=False):
578
595
  in the payload (see phone_press()). `done=True` finishes a card that is up.
579
596
  At most 30 new ones an hour, so say what matters, not every step.
580
597
 
598
+ A tap on it opens this project in Local Mode, on this computer. `view`
599
+ picks its tab (files, checks, dashboard, chats, computer). `open` sends the
600
+ tap anywhere else on the dashboard instead: a name such as notifications,
601
+ alerts, workflow:<id>:performance or project:<folder>:checks, or a path
602
+ starting /atlas/dashboard?. The answer's `opens` says where it will go.
603
+
581
604
  notify("Backtest done", "SPY: 61% win\n214 trades", key="backtest")
582
605
  notify("Backtest running", key="backtest", progress=0.4)
583
606
  notify("Backtest done", "Run it on QQQ too?", key="backtest", button="Run on QQQ")
607
+ notify("Charts ready", key="charts", view="dashboard")
608
+ notify("Alert fired", open="alerts")
584
609
 
585
610
  Returns the tool's answer. `sent` is 0 when the owner switched these off
586
611
  (Profile, Manage notifications, Studio); that is their choice, not an error.
@@ -592,10 +617,20 @@ def notify(title, body="", key="", progress=None, button="", done=False):
592
617
  params["progress"] = progress
593
618
  if button:
594
619
  params["button"] = button
595
- # The project the button starts: this one.
596
- params["project"] = os.environ.get("ATLAS_JOB", "")
597
620
  if done:
598
621
  params["done"] = True
622
+ # This project: the one the button starts, and where a tap opens.
623
+ job = os.environ.get("ATLAS_JOB", "")
624
+ if job or button:
625
+ params["project"] = job
626
+ if job:
627
+ machine = _machine_here()
628
+ if machine:
629
+ params["machine"] = machine
630
+ if view:
631
+ params["view"] = view
632
+ if open:
633
+ params["open"] = open
599
634
  return atlas("phone-notify", **params)
600
635
 
601
636
 
@@ -1517,7 +1552,8 @@ def _checks_notify(conf, told, line, why, project):
1517
1552
  title = template.replace("{project}", project).replace("{count}", str(len(told))).replace("{what}", what)
1518
1553
  when = "%s, %s" % (_WHY_WORDS.get(why, "Ran"), _time.strftime("%H:%M"))
1519
1554
  try:
1520
- notify(title[:40], "%s\n%s" % (line, when), key="checks-%s" % project)
1555
+ # A tap opens this project's Checks, on this computer.
1556
+ notify(title[:40], "%s\n%s" % (line, when), key="checks-%s" % project, view="checks")
1521
1557
  except Exception:
1522
1558
  pass
1523
1559