uc-config 0.2.1 → 0.2.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/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ npx uc-config init --refresh-docs
9
9
  npx uc-config compile && npx uc-config plan # must show 0 operations
10
10
  ```
11
11
 
12
+ ## 0.2.2
13
+
14
+ Action required: optional. Run `npx uc-config init --refresh-docs` to get the
15
+ new AGENTS.md sections.
16
+
17
+ - Multiple remotes: documented as one folder per remote. `init` refuses to add
18
+ a second remote to a folder, and commands that can't pick a target list the
19
+ targets the folder has.
20
+ - `init` ends by suggesting the prompt "Set up my Remote 3" (the address is
21
+ already saved).
22
+ - Docs: dock or wake the remote during setup; AGENTS.md says what to do when the
23
+ remote stops responding.
24
+
12
25
  ## 0.2.1
13
26
 
14
27
  Action required: run `npx uc-config init --refresh-docs`. It updates the
package/README.md CHANGED
@@ -24,7 +24,12 @@ hardware. Humans can use it directly too.
24
24
  - On the remote, enable the web configurator: **Settings → Profile → Web
25
25
  configurator**. Note the **PIN** it shows.
26
26
  - Find the remote's **IP address**. It's shown in the remote's network
27
- settings, or in your router's device list. The computer you use must be on the same network as the remote.
27
+ settings, or in your router's device list. The computer you use must be on
28
+ the same network as the remote.
29
+ - **Dock the remote** (or keep picking it up) during setup. It doesn't need the
30
+ dock to work, but it goes to sleep when idle and drops off Wi-Fi, which
31
+ interrupts setup. The Integration Manager's web page is also only available
32
+ while docked.
28
33
 
29
34
  ### 2. Create your config folder
30
35
 
@@ -51,7 +56,10 @@ repo.
51
56
  Start your coding agent (Claude Code, Codex, Cursor, etc.) in that folder and
52
57
  prompt:
53
58
 
54
- > Set up my Remote 3 at `<IP>`
59
+ > Set up my Remote 3
60
+
61
+ `init` already saved the remote's address, so you don't need to repeat it. (If
62
+ you skipped the IP prompt, include it: "Set up my Remote 3 at 192.168.1.50".)
55
63
 
56
64
  The agent imports your current setup into `remote.config.ts` and records which
57
65
  resources it manages. This writes nothing to the remote.
@@ -82,6 +90,24 @@ Ask your agent for changes in plain language, for example:
82
90
  The agent shows a plan of what will change before applying it. After you update
83
91
  an integration in the Integration Manager, ask the agent to run diagnostics.
84
92
 
93
+ ## Multiple remotes
94
+
95
+ Use **one folder per remote**:
96
+
97
+ ```sh
98
+ mkdir -p remotes/living-room && cd remotes/living-room && npx uc-config init
99
+ mkdir -p remotes/bedroom && cd remotes/bedroom && npx uc-config init
100
+ ```
101
+
102
+ Each folder has its own `remote.config.ts`, state and API key, and an agent
103
+ working in one folder can't touch the other remote. The folders can share one
104
+ private git repo. Two remotes rarely have identical configs, because entity IDs
105
+ include each remote's integration IDs; to share a macro or layout, put it in a
106
+ common `.ts` file and import it, using each folder's own `generated/devices.ts`
107
+ for the IDs.
108
+
109
+ `init` refuses to add a second remote to a folder that already has one.
110
+
85
111
  ## Updating
86
112
 
87
113
  Ask your agent to "update uc-config", or run in your config folder:
package/dist/cli.js CHANGED
@@ -23,23 +23,27 @@ const program = new Command()
23
23
  .description("TypeScript configuration and provisioning for Unfolded Circle Remote 3")
24
24
  .version(pkgVersion)
25
25
  .option("--workspace <path>", "project directory", process.cwd());
26
- // UC_TARGET, else the workspace's only target, else "home".
27
- function implicitTarget() {
28
- if (process.env.UC_TARGET)
29
- return process.env.UC_TARGET;
30
- const ws = process.argv.indexOf("--workspace");
31
- const dir = resolve(ws > 0 ? process.argv[ws + 1] : process.cwd());
26
+ function workspaceTargets(dir) {
27
+ if (!dir) {
28
+ const ws = process.argv.indexOf("--workspace");
29
+ dir = resolve(ws > 0 ? process.argv[ws + 1] : process.cwd());
30
+ }
32
31
  try {
33
- const names = readdirSync(join(dir, ".uc", "targets"))
32
+ return readdirSync(join(dir, ".uc", "targets"))
34
33
  .filter((f) => f.endsWith(".json"))
35
- .map((f) => f.slice(0, -5));
36
- if (names.length === 1)
37
- return names[0];
34
+ .map((f) => f.slice(0, -5))
35
+ .sort();
38
36
  }
39
37
  catch {
40
- // no targets yet
38
+ return []; // no targets yet
41
39
  }
42
- return "home";
40
+ }
41
+ // UC_TARGET, else the workspace's only target, else "home".
42
+ function implicitTarget() {
43
+ if (process.env.UC_TARGET)
44
+ return process.env.UC_TARGET;
45
+ const names = workspaceTargets();
46
+ return names.length === 1 ? names[0] : "home";
43
47
  }
44
48
  const defaultTarget = implicitTarget();
45
49
  const root = () => resolve(program.opts().workspace);
@@ -58,8 +62,12 @@ async function load(name) {
58
62
  target = await readJson(targetFile(name));
59
63
  }
60
64
  catch (e) {
61
- if (e.code === "ENOENT")
62
- throw new Error(`No target "${name}" in this workspace. Run: uc-config connect ${name} --host http://<REMOTE_IP>`);
65
+ if (e.code === "ENOENT") {
66
+ const names = workspaceTargets(root());
67
+ throw new Error(names.length
68
+ ? `No target "${name}" in this workspace. It has: ${names.join(", ")}. Pass --target <name> or set UC_TARGET.`
69
+ : `No target "${name}" in this workspace. Run: uc-config connect ${name} --host http://<REMOTE_IP>`);
70
+ }
63
71
  throw e;
64
72
  }
65
73
  let token = process.env[target.tokenEnv];
@@ -147,7 +155,7 @@ async function connectTarget(name, host, tokenEnv = "UC_API_KEY") {
147
155
  try {
148
156
  const old = await readJson(targetFile(name));
149
157
  if (old.identity !== target.identity)
150
- throw new Error("Target name already refers to another remote; use a new name");
158
+ throw new Error("This folder is already connected to a different remote. Use one folder per remote (mkdir ../other-remote && cd ../other-remote && npx uc-config init).");
151
159
  }
152
160
  catch (e) {
153
161
  if (e.code !== "ENOENT")
@@ -565,7 +573,7 @@ program
565
573
  .command("init")
566
574
  .description("Scaffold a private config workspace (package.json, tsconfig, .gitignore, AGENTS.md)")
567
575
  .option("--host <ip>", "remote IP address (skips the prompt)")
568
- .option("--target <name>", "target name", "home")
576
+ .option("--target <name>", "target name (default: the folder's existing target, else home)")
569
577
  .option("--no-connect", "only create files; don't connect or authenticate")
570
578
  .option("--refresh-docs", "update AGENTS.md/CLAUDE.md to this version (edited files get a .new copy)")
571
579
  .action(async (o) => {
@@ -586,15 +594,24 @@ program
586
594
  return;
587
595
  }
588
596
  const interactive = Boolean(process.stdin.isTTY);
589
- const next = "Next: npm install, then start your coding agent here and ask it to set up your Remote 3.";
597
+ const next = 'Next: npm install, then start your coding agent here and ask it to "Set up my Remote 3".';
590
598
  if (!o.connect)
591
599
  return console.log(next);
592
- const name = o.target;
600
+ const existing = workspaceTargets(root());
601
+ const name = o.target ?? (existing.length === 1 ? existing[0] : "home");
602
+ if (existing.length && !existing.includes(name)) {
603
+ console.log(`This folder already manages ${existing.join(", ")}. Use one folder per remote:\n` +
604
+ " mkdir ../other-remote && cd ../other-remote && npx uc-config init");
605
+ process.exitCode = 1;
606
+ return;
607
+ }
593
608
  // 1. Connect (unless already connected).
594
609
  let target;
595
610
  try {
596
611
  target = await readJson(targetFile(name));
597
612
  console.log(`Already connected to ${target.host} as "${name}".`);
613
+ if (o.host)
614
+ console.log(`Ignoring --host: this folder already manages "${name}". For another remote, use a new folder.`);
598
615
  }
599
616
  catch (e) {
600
617
  if (e.code !== "ENOENT")
package/dist/init.js CHANGED
@@ -71,6 +71,19 @@ Re-adding a dropped entity the integration still offers is safe to do
71
71
  directly. Ask before anything else. Integration installs and updates belong to
72
72
  the UC Integration Manager (http://<remote>:9999); run diagnose after any update.
73
73
 
74
+ ## Multiple remotes
75
+
76
+ This folder manages exactly one remote (one target in \`.uc/targets/\`). For
77
+ another remote, create a sibling folder and run \`npx uc-config init\` there.
78
+ Never connect a second remote here, and never copy \`.uc/\` between folders.
79
+ Shared pieces can be imported from a common .ts file, but entity IDs must come
80
+ from each folder's own generated/devices.ts.
81
+
82
+ ## If the remote doesn't respond
83
+
84
+ \`transport failed\` or timeouts usually mean the remote went to sleep. Ask the
85
+ user to pick it up or dock it, then retry. Don't change the host.
86
+
74
87
  ## Upgrading the tool
75
88
 
76
89
  1. \`npm install uc-config@latest\` (not \`npm update\`: it won't cross 0.x minor versions).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uc-config",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "description": "Configuration-as-code for the Unfolded Circle Remote 3, designed to be driven by coding agents",
6
6
  "license": "MIT",