uc-config 0.2.1 → 0.2.3
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 +24 -0
- package/README.md +50 -10
- package/dist/cli.js +35 -18
- package/dist/init.js +13 -0
- package/docs/snippets.md +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,30 @@ 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.3
|
|
13
|
+
|
|
14
|
+
Action required: none. Docs only.
|
|
15
|
+
|
|
16
|
+
- README: what to do when a plan contains operations you didn't make, how to
|
|
17
|
+
read full sequence changes from `.uc/plan.json`, telling a sleeping remote
|
|
18
|
+
from a machine without LAN access, and what `deferred` means.
|
|
19
|
+
- Snippets: corrected the entity-swap recipe. Swapped-in commands are deferred
|
|
20
|
+
until the `entity_ids` change is applied, rather than failing with
|
|
21
|
+
`Cannot verify command`.
|
|
22
|
+
|
|
23
|
+
## 0.2.2
|
|
24
|
+
|
|
25
|
+
Action required: optional. Run `npx uc-config init --refresh-docs` to get the
|
|
26
|
+
new AGENTS.md sections.
|
|
27
|
+
|
|
28
|
+
- Multiple remotes: documented as one folder per remote. `init` refuses to add
|
|
29
|
+
a second remote to a folder, and commands that can't pick a target list the
|
|
30
|
+
targets the folder has.
|
|
31
|
+
- `init` ends by suggesting the prompt "Set up my Remote 3" (the address is
|
|
32
|
+
already saved).
|
|
33
|
+
- Docs: dock or wake the remote during setup; AGENTS.md says what to do when the
|
|
34
|
+
remote stops responding.
|
|
35
|
+
|
|
12
36
|
## 0.2.1
|
|
13
37
|
|
|
14
38
|
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
|
|
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
|
|
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:
|
|
@@ -182,6 +208,19 @@ npm run uc -- check # must report 0 operations
|
|
|
182
208
|
remote identity, firmware and preconditions first. A plan with zero operations
|
|
183
209
|
needs no apply. See [docs/snippets.md](docs/snippets.md) for common edits.
|
|
184
210
|
|
|
211
|
+
**If the plan touches things you didn't edit, stop.** Those operations are
|
|
212
|
+
earlier source changes that were never applied, or edits made on the remote
|
|
213
|
+
since. Don't apply them along with your change: sync with the live remote first
|
|
214
|
+
(see [Pull changes made in the web configurator](docs/snippets.md#pull-changes-made-in-the-web-configurator)),
|
|
215
|
+
then replan until only your change is left.
|
|
216
|
+
|
|
217
|
+
**The plan output shortens long sequences.** To see the exact step-by-step
|
|
218
|
+
change, compare each operation's `before` with its `desired` in `.uc/plan.json`:
|
|
219
|
+
|
|
220
|
+
```sh
|
|
221
|
+
jq '.operations[] | {key, action, before, desired}' .uc/plan.json
|
|
222
|
+
```
|
|
223
|
+
|
|
185
224
|
## Diagnostics and fixing problems
|
|
186
225
|
|
|
187
226
|
Run `diagnose` whenever something looks wrong on the remote, after any
|
|
@@ -209,14 +248,15 @@ For each orphan it proposes a fix:
|
|
|
209
248
|
|
|
210
249
|
Plan/apply problems:
|
|
211
250
|
|
|
212
|
-
| Message
|
|
213
|
-
|
|
|
214
|
-
| `Drift at <fields>`
|
|
215
|
-
| `Managed resource disappeared`
|
|
216
|
-
| `Cannot verify command`
|
|
217
|
-
| `Remote firmware changed; reconnect and replan`
|
|
218
|
-
| `transport failed` / timeouts
|
|
219
|
-
|
|
|
251
|
+
| Message | Meaning and fix |
|
|
252
|
+
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
253
|
+
| `Drift at <fields>` | Someone (or a driver update) changed an owned field on the remote. Copy the live value into source, or rerun `plan --overwrite-drift` only if the user wants the source value restored. |
|
|
254
|
+
| `Managed resource disappeared` | Resource was deleted on the remote. Run `diagnose`; re-add or remove from source. |
|
|
255
|
+
| `Cannot verify command` | `cmd_id` isn't advertised by that entity, or the entity isn't in the activity's `entity_ids`. Check `generated/devices.ts`, refresh inventory. |
|
|
256
|
+
| `Remote firmware changed; reconnect and replan` | Remote auto-updated. Rerun `connect <name> --host ...` (keeps credentials), then plan. |
|
|
257
|
+
| `transport failed` / timeouts | Remote asleep, or this machine has no LAN access. Ping the router and another LAN device: if they fail too, it's this machine (on macOS, Local Network privacy), and waking the remote won't help. |
|
|
258
|
+
| `deferred ...: apply prerequisites, then replan` | The item depends on another change in the same plan (e.g. a new entity in `entity_ids`). Apply the plan, then plan again for the deferred items. |
|
|
259
|
+
| Uncertain writes after a crash | Run `resume`. Never blindly rerun apply; use `state adopt KEY ID` if a create actually succeeded. |
|
|
220
260
|
|
|
221
261
|
`npm run uc -- api GET <path>` makes a raw authenticated Core API read (output
|
|
222
262
|
redacted). Non-GET methods require `--write` and should only be used for the
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
32
|
+
return readdirSync(join(dir, ".uc", "targets"))
|
|
34
33
|
.filter((f) => f.endsWith(".json"))
|
|
35
|
-
.map((f) => f.slice(0, -5))
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
|
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 =
|
|
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
|
|
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/docs/snippets.md
CHANGED
|
@@ -254,9 +254,10 @@ npm run uc -- compile && npm run uc -- plan --out .uc/plan.json && npm run uc --
|
|
|
254
254
|
npm run uc -- diagnose
|
|
255
255
|
```
|
|
256
256
|
|
|
257
|
-
|
|
258
|
-
activity's
|
|
259
|
-
`
|
|
257
|
+
Buttons and sequences that use the new entity show up as **deferred** until the
|
|
258
|
+
activity's `entity_ids` change is on the remote. Apply the plan, then plan and
|
|
259
|
+
apply again for the deferred items. `check` must report 0 operations at the
|
|
260
|
+
end.
|
|
260
261
|
|
|
261
262
|
**Drift from a driver renaming something** (`Drift at data.name`): copy the
|
|
262
263
|
live value (shown in the plan) into source, then:
|