macaw-ai 0.9.10 → 0.9.11

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/README.md CHANGED
@@ -42,8 +42,10 @@ because it has no path to the place approvals are given.
42
42
  Anthropic, LangChain, MCP, LiteLLM and Pydantic AI, with the examples ready to
43
43
  run.
44
44
 
45
- Both are free, and both create a workspace on first run: a link appears in
46
- your terminal, you approve it in a browser, and that is the account.
45
+ Both are free. The first install creates a workspace: a link appears in your
46
+ terminal, you approve it in a browser, and that is the account. Later installs
47
+ find that key and join the same workspace, so choosing both surfaces above
48
+ asks you once, not twice.
47
49
 
48
50
  ## Licence
49
51
 
package/bin/macaw.js CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  import { spawnSync } from "node:child_process";
10
10
  import { createInterface } from "node:readline/promises";
11
+ import fs from "node:fs";
12
+ import path from "node:path";
11
13
 
12
14
  const SURFACES = [
13
15
  {
@@ -28,12 +30,50 @@ const C = process.stdout.isTTY
28
30
  ? { b: "\x1b[1m", dim: "\x1b[2m", c: "\x1b[36m", x: "\x1b[0m" }
29
31
  : { b: "", dim: "", c: "", x: "" };
30
32
 
31
- function run(pkg, args) {
33
+ function run(pkg, args, env) {
32
34
  console.log(`\n${C.dim} → npx ${pkg} ${args.join(" ")}${C.x}\n`);
33
- const r = spawnSync("npx", ["-y", pkg, ...args], { stdio: "inherit" });
35
+ const r = spawnSync("npx", ["-y", pkg, ...args], {
36
+ stdio: "inherit",
37
+ env: { ...process.env, ...env },
38
+ });
34
39
  return r.status ?? 1;
35
40
  }
36
41
 
42
+ // The coding-agents installer writes its key here. Reading it back lets the
43
+ // second surface join that workspace without asking for a key the user
44
+ // approved thirty seconds earlier.
45
+ function keyFromThisDirectory() {
46
+ try {
47
+ const cfg = JSON.parse(fs.readFileSync(path.join(process.cwd(), ".macaw", "config.json"), "utf8"));
48
+ if (typeof cfg?.api_key === "string" && cfg.api_key.startsWith("mw_")) {
49
+ return { MACAW_API_KEY: cfg.api_key, MACAW_WORKSPACE: cfg.workspace || "" };
50
+ }
51
+ } catch {
52
+ // No install here, or not readable. The next installer asks, as it would.
53
+ }
54
+ return undefined;
55
+ }
56
+
57
+ // Both surfaces, in this order. Coding agents first because that install is
58
+ // the one that creates the workspace, and the key it writes is then handed to
59
+ // the client rather than asked for again.
60
+ //
61
+ // The order is load-bearing the other way too: coding-agents writes
62
+ // $PWD/.macaw/config.json, which the client's lookup reads. The client writes
63
+ // into a subdirectory it chooses, which nothing else can be expected to find.
64
+ function both(args) {
65
+ const steps = args.length ? args : ["install"];
66
+ for (const [i, s] of SURFACES.entries()) {
67
+ // Two installers each printing their own banner reads as the thing having
68
+ // restarted. Say which step this is.
69
+ console.log("");
70
+ console.log(`${C.b} ── ${i + 1} of ${SURFACES.length} · ${s.label} ──${C.x}`);
71
+ const code = run(s.pkg, steps, i === 0 ? undefined : keyFromThisDirectory());
72
+ if (code !== 0) return code;
73
+ }
74
+ return 0;
75
+ }
76
+
37
77
  async function main() {
38
78
  const args = process.argv.slice(2);
39
79
 
@@ -44,6 +84,13 @@ async function main() {
44
84
  process.exit(run(named.pkg, args.filter((a) => !a.startsWith("--macaw") && a !== `--${named.pkg.split("/")[1]}`)));
45
85
  }
46
86
 
87
+ // macaw-ai install --both
88
+ // The menu's third choice, as a flag. The other two already have one, and
89
+ // without this there is no way to ask for both without a terminal.
90
+ if (args.includes("--both")) {
91
+ process.exit(both(args.filter((a) => a !== "--both")));
92
+ }
93
+
47
94
  console.log("");
48
95
  console.log(`${C.b} MACAW${C.x}`);
49
96
  console.log("");
@@ -70,13 +117,7 @@ async function main() {
70
117
  rl.close();
71
118
 
72
119
  const rest = args.length ? args : ["install"];
73
- if (choice === "3") {
74
- for (const s of SURFACES) {
75
- const code = run(s.pkg, rest);
76
- if (code !== 0) process.exit(code);
77
- }
78
- process.exit(0);
79
- }
120
+ if (choice === "3") process.exit(both(rest));
80
121
 
81
122
  const picked = SURFACES.find((s) => s.key === choice);
82
123
  if (!picked) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "macaw-ai",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "description": "Deterministic controls for agents. Ask MACAW to govern your coding agent or your Python project, and it installs the right thing.",
5
5
  "type": "module",
6
6
  "bin": {