@intentic/machine 1.344.0 → 1.346.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/README.md +185 -154
- package/dist/autostart/autostart.d.ts +0 -1
- package/dist/autostart/autostart.d.ts.map +1 -1
- package/dist/autostart/autostart.js +3 -9
- package/dist/autostart/autostart.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -21
- package/dist/commands.js.map +1 -1
- package/dist/device/commands.d.ts +8 -2
- package/dist/device/commands.d.ts.map +1 -1
- package/dist/device/commands.js +23 -9
- package/dist/device/commands.js.map +1 -1
- package/dist/device/connection.d.ts.map +1 -1
- package/dist/device/connection.js +27 -9
- package/dist/device/connection.js.map +1 -1
- package/dist/device/grant.d.ts +244 -1
- package/dist/device/grant.d.ts.map +1 -1
- package/dist/device/mcp.d.ts.map +1 -1
- package/dist/device/mcp.js +25 -8
- package/dist/device/mcp.js.map +1 -1
- package/dist/device/router.d.ts +469 -226
- package/dist/device/router.d.ts.map +1 -1
- package/dist/device/router.js +18 -10
- package/dist/device/router.js.map +1 -1
- package/dist/device/sandbox-rounds/keeper.d.ts +4 -1
- package/dist/device/sandbox-rounds/keeper.d.ts.map +1 -1
- package/dist/device/sandbox-rounds/keeper.js +13 -7
- package/dist/device/sandbox-rounds/keeper.js.map +1 -1
- package/dist/device/sandbox-rounds/sleep.d.ts +15 -2
- package/dist/device/sandbox-rounds/sleep.d.ts.map +1 -1
- package/dist/device/sandbox-rounds/sleep.js +68 -13
- package/dist/device/sandbox-rounds/sleep.js.map +1 -1
- package/dist/device/tools/agent.d.ts +15 -0
- package/dist/device/tools/agent.d.ts.map +1 -1
- package/dist/device/tools/agent.js +75 -19
- package/dist/device/tools/agent.js.map +1 -1
- package/dist/device/tools/android.d.ts +1 -1
- package/dist/device/tools/android.d.ts.map +1 -1
- package/dist/device/tools/android.js +17 -8
- package/dist/device/tools/android.js.map +1 -1
- package/dist/device/tools/browser.d.ts.map +1 -1
- package/dist/device/tools/browser.js +3 -5
- package/dist/device/tools/browser.js.map +1 -1
- package/dist/device/tools/ic-binary.d.ts +2 -1
- package/dist/device/tools/ic-binary.d.ts.map +1 -1
- package/dist/device/tools/ic-binary.js +34 -4
- package/dist/device/tools/ic-binary.js.map +1 -1
- package/dist/device/tools/os/settings.js +3 -3
- package/dist/device/tools/os/settings.js.map +1 -1
- package/dist/device/tools/programs/app-wait-tools.d.ts +12 -0
- package/dist/device/tools/programs/app-wait-tools.d.ts.map +1 -0
- package/dist/device/tools/programs/app-wait-tools.js +60 -0
- package/dist/device/tools/programs/app-wait-tools.js.map +1 -0
- package/dist/device/tools/programs/app-wait.d.ts +19 -0
- package/dist/device/tools/programs/app-wait.d.ts.map +1 -0
- package/dist/device/tools/programs/app-wait.js +89 -0
- package/dist/device/tools/programs/app-wait.js.map +1 -0
- package/dist/device/tools/programs/file-changes.d.ts +2 -0
- package/dist/device/tools/programs/file-changes.d.ts.map +1 -0
- package/dist/device/tools/programs/file-changes.js +19 -0
- package/dist/device/tools/programs/file-changes.js.map +1 -0
- package/dist/device/tools/programs/programs.d.ts +12 -0
- package/dist/device/tools/programs/programs.d.ts.map +1 -1
- package/dist/device/tools/programs/programs.js +13 -12
- package/dist/device/tools/programs/programs.js.map +1 -1
- package/dist/device/tools/programs/stop-all.d.ts +10 -0
- package/dist/device/tools/programs/stop-all.d.ts.map +1 -0
- package/dist/device/tools/programs/stop-all.js +52 -0
- package/dist/device/tools/programs/stop-all.js.map +1 -0
- package/dist/device/tools/sandboxes.d.ts +2 -0
- package/dist/device/tools/sandboxes.d.ts.map +1 -1
- package/dist/device/tools/sandboxes.js +11 -3
- package/dist/device/tools/sandboxes.js.map +1 -1
- package/dist/device/tools/shell.d.ts +1 -1
- package/dist/device/tools/shell.d.ts.map +1 -1
- package/dist/install.d.ts +15 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +35 -6
- package/dist/install.js.map +1 -1
- package/dist/keyring/app-commands.d.ts +15 -0
- package/dist/keyring/app-commands.d.ts.map +1 -0
- package/dist/keyring/app-commands.js +247 -0
- package/dist/keyring/app-commands.js.map +1 -0
- package/dist/keyring/commands.d.ts +1 -1
- package/dist/keyring/commands.d.ts.map +1 -1
- package/dist/keyring/commands.js +26 -32
- package/dist/keyring/commands.js.map +1 -1
- package/dist/keyring/git-helper.d.ts +8 -0
- package/dist/keyring/git-helper.d.ts.map +1 -0
- package/dist/keyring/git-helper.js +60 -0
- package/dist/keyring/git-helper.js.map +1 -0
- package/dist/keyring/keyring-status.d.ts +8 -1
- package/dist/keyring/keyring-status.d.ts.map +1 -1
- package/dist/keyring/keyring-status.js +39 -4
- package/dist/keyring/keyring-status.js.map +1 -1
- package/dist/keyring/native-host-install.d.ts +28 -0
- package/dist/keyring/native-host-install.d.ts.map +1 -0
- package/dist/keyring/native-host-install.js +99 -0
- package/dist/keyring/native-host-install.js.map +1 -0
- package/dist/keyring/relay.d.ts +5 -1
- package/dist/keyring/relay.d.ts.map +1 -1
- package/dist/keyring/relay.js +16 -0
- package/dist/keyring/relay.js.map +1 -1
- package/dist/keyring/sandbox-push.d.ts +4 -0
- package/dist/keyring/sandbox-push.d.ts.map +1 -0
- package/dist/keyring/sandbox-push.js +21 -0
- package/dist/keyring/sandbox-push.js.map +1 -0
- package/dist/keyring/service.d.ts +11 -5
- package/dist/keyring/service.d.ts.map +1 -1
- package/dist/keyring/service.js +34 -51
- package/dist/keyring/service.js.map +1 -1
- package/dist/resident/resident.d.ts +1 -0
- package/dist/resident/resident.d.ts.map +1 -1
- package/dist/resident/resident.js +9 -1
- package/dist/resident/resident.js.map +1 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +1 -8
- package/dist/status.js.map +1 -1
- package/dist/sync/binary/mutagen-binary.d.ts +4 -0
- package/dist/sync/binary/mutagen-binary.d.ts.map +1 -0
- package/dist/sync/binary/mutagen-binary.js +65 -0
- package/dist/sync/binary/mutagen-binary.js.map +1 -0
- package/dist/sync/commands.d.ts +1 -9
- package/dist/sync/commands.d.ts.map +1 -1
- package/dist/sync/commands.js +49 -84
- package/dist/sync/commands.js.map +1 -1
- package/dist/sync/config.d.ts +21 -25
- package/dist/sync/config.d.ts.map +1 -1
- package/dist/sync/config.js +76 -35
- package/dist/sync/config.js.map +1 -1
- package/dist/sync/endpoint.d.ts +1 -1
- package/dist/sync/endpoint.d.ts.map +1 -1
- package/dist/sync/endpoint.js +2 -3
- package/dist/sync/endpoint.js.map +1 -1
- package/dist/sync/folders.d.ts.map +1 -1
- package/dist/sync/folders.js.map +1 -1
- package/dist/sync/forget-command.js +1 -1
- package/dist/sync/forget-command.js.map +1 -1
- package/dist/sync/gone-watch.d.ts +1 -1
- package/dist/sync/gone-watch.d.ts.map +1 -1
- package/dist/sync/gone-watch.js +16 -40
- package/dist/sync/gone-watch.js.map +1 -1
- package/dist/sync/holds.d.ts +30 -0
- package/dist/sync/holds.d.ts.map +1 -0
- package/dist/sync/holds.js +117 -0
- package/dist/sync/holds.js.map +1 -0
- package/dist/sync/low-disk.d.ts +2 -9
- package/dist/sync/low-disk.d.ts.map +1 -1
- package/dist/sync/low-disk.js +10 -45
- package/dist/sync/low-disk.js.map +1 -1
- package/dist/sync/mirror.d.ts +2 -3
- package/dist/sync/mirror.d.ts.map +1 -1
- package/dist/sync/mirror.js +61 -160
- package/dist/sync/mirror.js.map +1 -1
- package/dist/sync/mutagen-env.d.ts +1 -3
- package/dist/sync/mutagen-env.d.ts.map +1 -1
- package/dist/sync/mutagen-env.js +2 -12
- package/dist/sync/mutagen-env.js.map +1 -1
- package/dist/sync/mutagen-move.d.ts +3 -1
- package/dist/sync/mutagen-move.d.ts.map +1 -1
- package/dist/sync/mutagen-move.js +31 -22
- package/dist/sync/mutagen-move.js.map +1 -1
- package/dist/sync/mutagen.d.ts +6 -12
- package/dist/sync/mutagen.d.ts.map +1 -1
- package/dist/sync/mutagen.js +17 -144
- package/dist/sync/mutagen.js.map +1 -1
- package/dist/sync/project/project-commands.d.ts +0 -3
- package/dist/sync/project/project-commands.d.ts.map +1 -1
- package/dist/sync/project/project-commands.js +5 -3
- package/dist/sync/project/project-commands.js.map +1 -1
- package/dist/sync/project/project-delivery.d.ts.map +1 -1
- package/dist/sync/project/project-delivery.js +5 -4
- package/dist/sync/project/project-delivery.js.map +1 -1
- package/dist/sync/project/project-transfer.d.ts +4 -0
- package/dist/sync/project/project-transfer.d.ts.map +1 -1
- package/dist/sync/project/project-transfer.js +9 -2
- package/dist/sync/project/project-transfer.js.map +1 -1
- package/dist/sync/report.d.ts.map +1 -1
- package/dist/sync/report.js +18 -11
- package/dist/sync/report.js.map +1 -1
- package/dist/sync/retire.d.ts.map +1 -1
- package/dist/sync/retire.js +1 -2
- package/dist/sync/retire.js.map +1 -1
- package/dist/sync/tunnel.d.ts +4 -3
- package/dist/sync/tunnel.d.ts.map +1 -1
- package/dist/sync/tunnel.js +107 -42
- package/dist/sync/tunnel.js.map +1 -1
- package/dist/sync/uninstall.d.ts.map +1 -1
- package/dist/sync/uninstall.js +4 -3
- package/dist/sync/uninstall.js.map +1 -1
- package/dist/sync/wake.d.ts +3 -0
- package/dist/sync/wake.d.ts.map +1 -0
- package/dist/sync/wake.js +43 -0
- package/dist/sync/wake.js.map +1 -0
- package/dist/uninstall/command.d.ts +3 -0
- package/dist/uninstall/command.d.ts.map +1 -0
- package/dist/uninstall/command.js +40 -0
- package/dist/uninstall/command.js.map +1 -0
- package/dist/uninstall/distros.d.ts +8 -0
- package/dist/uninstall/distros.d.ts.map +1 -0
- package/dist/uninstall/distros.js +103 -0
- package/dist/uninstall/distros.js.map +1 -0
- package/dist/uninstall/plan.d.ts +23 -0
- package/dist/uninstall/plan.d.ts.map +1 -0
- package/dist/uninstall/plan.js +71 -0
- package/dist/uninstall/plan.js.map +1 -0
- package/dist/uninstall/purge.d.ts +3 -0
- package/dist/uninstall/purge.d.ts.map +1 -0
- package/dist/uninstall/purge.js +79 -0
- package/dist/uninstall/purge.js.map +1 -0
- package/dist/uninstall/steps.d.ts +12 -0
- package/dist/uninstall/steps.d.ts.map +1 -0
- package/dist/uninstall/steps.js +200 -0
- package/dist/uninstall/steps.js.map +1 -0
- package/dist/uninstall/sweep.d.ts +12 -0
- package/dist/uninstall/sweep.d.ts.map +1 -0
- package/dist/uninstall/sweep.js +90 -0
- package/dist/uninstall/sweep.js.map +1 -0
- package/dist/uninstall/tally.d.ts +14 -0
- package/dist/uninstall/tally.d.ts.map +1 -0
- package/dist/uninstall/tally.js +25 -0
- package/dist/uninstall/tally.js.map +1 -0
- package/package.json +9 -9
- package/dist/sync/attach-commands.d.ts +0 -39
- package/dist/sync/attach-commands.d.ts.map +0 -1
- package/dist/sync/attach-commands.js +0 -163
- package/dist/sync/attach-commands.js.map +0 -1
- package/dist/sync/swap-pause.d.ts +0 -10
- package/dist/sync/swap-pause.d.ts.map +0 -1
- package/dist/sync/swap-pause.js +0 -29
- package/dist/sync/swap-pause.js.map +0 -1
package/README.md
CHANGED
|
@@ -108,8 +108,12 @@ flowchart LR
|
|
|
108
108
|
sandbox's, in this environment or another of this PC's (see [What folder sync owns](#what-folder-sync-owns)), and a
|
|
109
109
|
set-up-again that would change where a paired sandbox's folder syncs. It is **copy-first** unless
|
|
110
110
|
its owner opted into two-way: see [Copy-first projects](#copy-first-projects).
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
Setting the same folder up again keeps its session and every fact that holds its sync (see
|
|
112
|
+
[File sync runs or holds still by one rule](#file-sync-runs-or-holds-still-by-one-rule)). A project folder also takes
|
|
113
|
+
its agents' landed work by itself (`deliver: "auto"`, see [Delivering landed work](#delivering-landed-work)), and is
|
|
114
|
+
refused where it is a whole disk, a home folder or one holding it, or the system's own (`folderRefusal` in
|
|
115
|
+
[`sync/folders.ts`](src/sync/folders.ts), as the desktop app refuses them). `setup` wakes the resident watcher
|
|
116
|
+
(`sync/wake.ts`) once it has recorded the pairing, so the session is made at once rather than at the next poll.
|
|
113
117
|
- **Through Docker** ([`sync/endpoint.ts`](src/sync/endpoint.ts)): with `setup --transport auto`, the default, a
|
|
114
118
|
project's sandbox is reached through this machine's own Docker engine when the container `ic` named after the
|
|
115
119
|
pairing URL's slug is running there with that URL as its `SANDBOX_PUBLIC_URL`. Anything else stays on ssh: a hosted
|
|
@@ -124,10 +128,10 @@ flowchart LR
|
|
|
124
128
|
- (2026-10-05) The transport is no longer decided once: the container is asked after on every prepare and every
|
|
125
129
|
minute (`checkContainers` in [`sync/gone-watch.ts`](src/sync/gone-watch.ts)). A stopped container, or an engine that
|
|
126
130
|
does not answer, changes nothing. A container the engine no longer holds is looked up in ic: still listed (a swap
|
|
127
|
-
moving it) changes nothing; in ic's trash
|
|
128
|
-
at its address, whether ic holds it nowhere or cannot say, it lives elsewhere now and the
|
|
129
|
-
(
|
|
130
|
-
sync
|
|
131
|
+
moving it) changes nothing; in ic's trash holds the folder's sync still (`containerAway: "trashed"`). When the
|
|
132
|
+
sandbox still answers at its address, whether ic holds it nowhere or cannot say, it lives elsewhere now and the
|
|
133
|
+
pairing moves onto ssh (held instead without an enrollment to ride); in neither and silent, the sandbox is gone
|
|
134
|
+
(below); otherwise its sync holds still until the container is back (`containerAway: "missing"`).
|
|
131
135
|
|
|
132
136
|
(2026-10-01) Measured on Docker Desktop from Windows and from WSL: a session was up in 2–4 s, against up to 90 s
|
|
133
137
|
through the tunnel. Bind-mounting the folder into the container was rejected: a land or an agent's `rm -rf` would
|
|
@@ -141,10 +145,11 @@ flowchart LR
|
|
|
141
145
|
(`settlesFirst` in [`sync/mutagen.ts`](src/sync/mutagen.ts) says why for each). Every session and forward is created
|
|
142
146
|
with three Mutagen labels, `intentic-owner=<machineId>-<environment>`, `intentic-sandbox=<sanitized id>` and
|
|
143
147
|
`intentic-kind=sync|state|forward`; see [What folder sync owns](#what-folder-sync-owns).
|
|
144
|
-
- **
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
(`
|
|
148
|
+
- **Each folder has a sandbox of its own** (`sync setup --project`, see [Copy-first projects](#copy-first-projects)):
|
|
149
|
+
copied one way into its `/work/<name>`, with the land of a conversation written back into it by itself
|
|
150
|
+
(`deliverProject`, see [Delivering landed work](#delivering-landed-work)). _(2026-10-21) Folders used to attach to one
|
|
151
|
+
sandbox per computer (`sync setup --projects-host`, `sync attach`); that went, see
|
|
152
|
+
[One sandbox per computer, retired](#one-sandbox-per-computer-retired)._
|
|
148
153
|
- **What file sync costs this device is cycles, and the sandbox's side decides how many.** Mutagen's agent in the
|
|
149
154
|
sandbox has no recursive watcher, and both sessions force it to poll (`--watch-mode-<side> force-poll`): every 2 s
|
|
150
155
|
for the workspace, which is how late an agent's edit reaches the folder, and every 60 s for the state backup, which
|
|
@@ -170,21 +175,25 @@ flowchart LR
|
|
|
170
175
|
host key the enrollment carries when it carries one (a sandbox reads its sshd's public key off its history volume and
|
|
171
176
|
answers with it, `SyncEnrollmentAnswerSchema` in the contract), else with nothing, so `accept-new` records the key
|
|
172
177
|
the sandbox presents now, as it does for an older sandbox. Outside an enrollment a changed key is still refused. A sandbox whose ports poll has failed for ten
|
|
173
|
-
minutes has its forwards taken off localhost, and they come back with its first answer; after an hour its
|
|
174
|
-
|
|
175
|
-
restarted more often than hourly never
|
|
178
|
+
minutes has its forwards taken off localhost, and they come back with its first answer; after an hour its sync holds
|
|
179
|
+
still, an hour counted from `unreachableSince` in `sync.json` (2026-10-05: it was counted in memory, so an agent
|
|
180
|
+
restarted more often than hourly never held a dead sandbox's sessions). A sandbox that no longer exists is another
|
|
176
181
|
matter: see [Sandboxes that are gone](#sandboxes-that-are-gone). `sync uninstall` ends every session and forward of
|
|
177
182
|
this agent's and stops its Mutagen daemon, which serves this agent alone (below), starting it first if it was down so
|
|
178
|
-
every session is really ended; the synced folders keep their files.
|
|
179
|
-
|
|
180
|
-
their ports and their
|
|
183
|
+
every session is really ended; the synced folders keep their files. It runs the agent's own Mutagen in `bin/` and
|
|
184
|
+
downloads none: without that copy the session steps are skipped (2026-10-18). `sync uninstall --folders` (what the desktop app's
|
|
185
|
+
uninstaller runs) unpairs only the pairings that sync a folder here: mirror-only pairings keep their ports and their
|
|
186
|
+
enrollments.
|
|
181
187
|
- Symbolic links travel only where the device can create them ([`sync/symlinks.ts`](src/sync/symlinks.ts)). A
|
|
182
188
|
Windows PC without Developer Mode refuses every link, and Mutagen would try again on every cycle, so its sessions
|
|
183
189
|
use `--symlink-mode ignore`. Turning Developer Mode on brings them back at the agent's next start.
|
|
184
190
|
- **Which computer this is** ([`machine-id.ts`](src/machine-id.ts)): a `machineId` minted once at install and kept
|
|
185
|
-
in `~/.intentic/machine/machine-id`, sent in the connect-time facts, the sync report
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
in `~/.intentic/machine/machine-id`, sent in the connect-time facts, the sync report, the sync enrollment and the
|
|
192
|
+
device enrollment (`device setup` sends it with the environment when it redeems the pairing). The Windows side hands
|
|
193
|
+
its own to the agent it starts in each distro, so every OS install of one PC answers with one id; a sandbox joins
|
|
194
|
+
enrollments, sync enrollments and device rows on it, never on a hostname. (2026-10-20: `device setup` used to redeem
|
|
195
|
+
with no body, so the sandbox learned the id only once the agent connected, and the PC showed as two machine cards
|
|
196
|
+
until then.)
|
|
188
197
|
- The features a device advertises (`set-shape`, `reshape-later`, `rollback-to`, `background-prepare`) are read off
|
|
189
198
|
the `ic` under it, from that `ic`'s own help (`ic sandbox shape --set` for the first two, `ic sandbox rollback --to`
|
|
190
199
|
for the third, `ic sandbox prepare --auto` for the fourth), rather than listed beside the code. The agent's own two,
|
|
@@ -356,97 +365,35 @@ folded where the platform folds it). With `--json` each prints exactly one JSON
|
|
|
356
365
|
back included. Copy-first then carries the restored files to the sandbox, as it does any edit here, so the agent's
|
|
357
366
|
versions they replace are gone from there too.
|
|
358
367
|
- One bring-back, restore or delivery runs per folder at a time (`restore/<pairing key>/.operation.pid`, a pid of this
|
|
359
|
-
boot, checked alive).
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
- `attach` finds the projects host whose URL has the same host as `--sandbox-url`. Without one it answers "this
|
|
390
|
-
computer's sandbox is not set up for folders yet".
|
|
391
|
-
- It refuses:
|
|
392
|
-
- a name `isProjectDirName` refuses (the sandbox's reserved names included);
|
|
393
|
-
- a folder that is not there;
|
|
394
|
-
- a whole disk, the home folder or one holding it, `/var/home` or a whole home in it, and the system's folders (on
|
|
395
|
-
Windows, on whichever drive), as the desktop app does ([`folderRefusal`](src/sync/folders.ts)). (2026-10-06) A WSL
|
|
396
|
-
distro's folder named from Windows (`\\wsl.localhost\<distro>\…`, `\\wsl$\…`) is held to the distro's rules: its
|
|
397
|
-
`/home`, a whole home in it, `/root`, a mounted disk (`/mnt/c`) and its system's folders;
|
|
398
|
-
- a folder that is, holds or sits inside any other pairing's, this environment's or (2026-10-05) another environment
|
|
399
|
-
of this PC's ([`sync/siblings.ts`](src/sync/siblings.ts), as `setup` does);
|
|
400
|
-
- a name already attached for another folder.
|
|
401
|
-
- It records `{ key: "<sandboxId>~<name>", sandboxId, sandboxUrl, syncToken (the host's), mode: "sync", localDir,
|
|
402
|
-
remoteDir: "/work/<name>", project: true, direction: "to-sandbox", deliver: "auto", transport?, container? }`.
|
|
403
|
-
Docker is preferred, as for the host. Attaching the same folder under the same name again keeps the direction its
|
|
404
|
-
owner chose. `localDir` is the folder as given, made absolute, as `setup` records one; links are resolved only to
|
|
405
|
-
compare folders (2026-10-05: the desktop app finds its folder in `status --json` by the path it passed, and on Fedora
|
|
406
|
-
Atomic `/home` is itself a link to `/var/home`, so a link-resolved path would never be found).
|
|
407
|
-
- It returns once the pairing is recorded and the resident agent is running. The agent creates the session on its next
|
|
408
|
-
pass, and `status --json` lists the folder with its `localDir`, `remoteDir`, `deliver` and `mutagenStatus`.
|
|
409
|
-
`mutagenStatus` is absent until the session exists, then Mutagen's own words: `connecting-beta`, `scanning`,
|
|
410
|
-
`reconciling`, `staging-beta`, `transitioning`, `saving` while the first copy runs, and `watching` once a whole cycle
|
|
411
|
-
has finished. Read the first `watching` as "first copy done": later edits pass through the same words again.
|
|
412
|
-
- `detach` removes the pairing first, so the agent recreates nothing, then ends its session and drops its listing record.
|
|
413
|
-
Its restore points stay. A folder with a sandbox of its own is refused, with the `sync uninstall` that unpairs it.
|
|
414
|
-
- `changes`, `bring-back`, `restore-points`, `restore` and `direction` work on an attached folder as on any project, by
|
|
415
|
-
`--dir`.
|
|
416
|
-
|
|
417
|
-
**A pairing key.** Every pairing is filed under `pairingKey` = `key ?? sandboxId`. Every pairing made before folders could
|
|
418
|
-
attach has no `key`, so its key is its sandbox id and nothing of it moves: its session names, its restore points, its
|
|
419
|
-
listing record, its lock. The key names what is a folder's own: the `upsertPairing`/`removePairing`/`set*` writes, the
|
|
420
|
-
Mutagen session (`sessionName`), `restore/<key>/` with its lock and pause marker, and `hashes/<key>.json`. The sandbox
|
|
421
|
-
id still names what is the sandbox's: the enrollment and its token, the ssh alias and tunnel (one block per sandbox),
|
|
422
|
-
the container, the forwards, the swap pause, the report's `sandboxId`. `sync.json` is refused whole for:
|
|
423
|
-
|
|
424
|
-
- two pairings under one key;
|
|
425
|
-
- an attached key that is not `<sandboxId>~<name>` for its `/work/<name>`;
|
|
426
|
-
- a projects host with a folder, remote dir, project flag or key.
|
|
427
|
-
|
|
428
|
-
`--sandbox` (pause, resume, mirror, autoheal, uninstall) selects every pairing of the sandbox it names.
|
|
429
|
-
|
|
430
|
-
**One poll, one mirror, one report per sandbox** ([`sync/mirror.ts`](src/sync/mirror.ts)):
|
|
431
|
-
|
|
432
|
-
- The sandbox's own pairing polls its ports; with no host, the first folder attached to it does. The poll is also how the
|
|
433
|
-
sandbox's liveness and a revoked enrollment are noticed. Every other folder follows that answer
|
|
434
|
-
(`followSandbox`): paused after an hour of no answer, resumed on the first. A folder never mirrors a port, whatever
|
|
435
|
-
`mirrorOff` says. It carries the sandbox's switch only so the report says the same of it.
|
|
436
|
-
- A revoked enrollment drops every pairing of the sandbox, since they share its token.
|
|
437
|
-
- The report goes to each sandbox once (`reportCarriers`), and `scopedReport` carries all of its pairings, host and
|
|
438
|
-
folders, each with `remoteDir`, `projectsHost` and `deliver`: the daemon keeps one report per machine.
|
|
439
|
-
- **A folder's first copy waits for its report** (`readyToPrepare`). The daemon makes `/work/<name>` a repository of its
|
|
440
|
-
own once a report names it. So a folder whose session does not exist yet gets one only after a report naming it was
|
|
441
|
-
taken, tried again each pass otherwise. A daemon with no report route (404) is not waited for.
|
|
442
|
-
|
|
443
|
-
(2026-10-05) An attached folder's session is `intentic-<sandbox>--<name>-<8 hex of sha256(name)>`. A sanitized id never
|
|
444
|
-
holds `--`, so the name can be no sandbox's session nor its `-state` backup (a folder called `state` included). The hash
|
|
445
|
-
keeps `my.app` and `my_app` apart, which sanitize alike. Letting every folder poll was rejected: ten folders would cost
|
|
446
|
-
the daemon eleven polls every five seconds, and three rejected polls counted per sandbox would revoke after one tick.
|
|
447
|
-
|
|
448
|
-
**Delivering landed work** ([`sync/project/project-delivery.ts`](src/sync/project/project-delivery.ts)). When a conversation's work
|
|
449
|
-
lands in `/work/<name>`, the daemon calls `deliverProject` on the device link (`ProjectDeliverySchema` in the contract),
|
|
368
|
+
boot, checked alive). Its pause is a hold like any other (`transferSince`, below): recorded on the pairing before
|
|
369
|
+
the session is paused and lifted as the operation lets go, so the watcher's pass keeps the session paused while it
|
|
370
|
+
writes. (2026-10-21: recorded nowhere, it read as a pause nothing explained, and the next pass resumed the session in
|
|
371
|
+
the middle of the write.) A pause an operation made and never lifted (the process killed in between) is recorded in
|
|
372
|
+
`restore/<pairing key>/.paused`, and the next command about that folder resumes the session; the watcher lets go of
|
|
373
|
+
its hold by itself once the folder's lock names no live process.
|
|
374
|
+
|
|
375
|
+
### One sandbox per computer, retired
|
|
376
|
+
|
|
377
|
+
(2026-10-21) Each computer used to have one always-available sandbox that every folder attached to as `/work/<name>`:
|
|
378
|
+
`sync setup --projects-host` enrolled it with no folder of its own, and `sync attach` / `sync detach` filed each
|
|
379
|
+
folder under a key of its own (`<sandboxId>~<name>`), polled and reported once per sandbox and announced to the daemon
|
|
380
|
+
before its first copy. The owner retired it: a central sandbox for everything was the wrong shape, and each folder now
|
|
381
|
+
gets a sandbox of its own, made for it (`sync setup --project`, [Copy-first projects](#copy-first-projects)), which
|
|
382
|
+
takes landed work by itself. So there is one pairing per sandbox again, filed under its sandbox id, and `sync.json` is
|
|
383
|
+
refused whole for two pairings of one sandbox, as before.
|
|
384
|
+
|
|
385
|
+
A `sync.json` an older agent wrote is never refused for what that design left in it. Reading leaves out its folderless
|
|
386
|
+
pairing (`projectsHost: true`) and every attached folder (`key`), so nothing syncs them; the watcher's start writes
|
|
387
|
+
the file without them and says each in one line (`retireLegacyPairings` in [`sync/config.ts`](src/sync/config.ts)),
|
|
388
|
+
and the orphan sweep ends their Mutagen sessions and forwards. Nothing is deleted on either side: each folder keeps its
|
|
389
|
+
files, and that sandbox keeps its copies and its agents' history, carrying on as an ordinary sandbox. The sync scripts
|
|
390
|
+
refuse `SYNC_PROJECTS_HOST` from a desktop app older than this, rather than reading it as a folder for that
|
|
391
|
+
sandbox's whole `/work`.
|
|
392
|
+
|
|
393
|
+
### Delivering landed work
|
|
394
|
+
|
|
395
|
+
([`sync/project/project-delivery.ts`](src/sync/project/project-delivery.ts)) When a conversation's work lands in a
|
|
396
|
+
project sandbox's `/work/<name>`, the daemon calls `deliverProject` on the device link (`ProjectDeliverySchema` in the contract),
|
|
450
397
|
and this agent writes the change into the folder. It is a procedure of the link, not an MCP tool, so no agent can call
|
|
451
398
|
it, and it sits behind no switch of the grant: the folder's own `deliver: "auto"` is the permission. It is logged and
|
|
452
399
|
appended to the audit file like every call.
|
|
@@ -506,11 +453,11 @@ Two witnesses can say a sandbox is gone ([`sync/gone.ts`](src/sync/gone.ts)); ab
|
|
|
506
453
|
What follows is the same for both ([`sync/gone-watch.ts`](src/sync/gone-watch.ts)):
|
|
507
454
|
|
|
508
455
|
- **Marked.** Every pairing of the sandbox gets `goneSince` (first heard), `goneCheckedAt` and `goneBy` (`edge` or
|
|
509
|
-
`local`) in `sync.json
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
- **Asked again** at most hourly (one ports poll), whatever the outcome. An answer clears all three fields,
|
|
513
|
-
|
|
456
|
+
`local`) in `sync.json`, which is what holds its file sync still. Its ports come off localhost, its tunnel listener
|
|
457
|
+
closes, no report is posted to it, nothing is created for it, and its folders do nothing more. One line says so, with
|
|
458
|
+
the day it will be retired.
|
|
459
|
+
- **Asked again** at most hourly (one ports poll), whatever the outcome. An answer clears all three fields, which lets
|
|
460
|
+
its sync go, and the next pass puts the ports back. A sandbox ic listed again (restored from its trash) is cleared at once
|
|
514
461
|
when ic was the witness; the edge's word is withdrawn only by the sandbox answering.
|
|
515
462
|
- **Retired** once seven days (the trash window) have passed since it was first said to be gone, on a verdict asked
|
|
516
463
|
within the last hour, so an agent that was off for a week asks once first. Retiring ([`sync/retire.ts`](src/sync/retire.ts))
|
|
@@ -561,11 +508,16 @@ whose it is.
|
|
|
561
508
|
environment the watcher (and `sync uninstall`) moves off the old directory
|
|
562
509
|
([`sync/mutagen-move.ts`](src/sync/mutagen-move.ts)): each of this agent's sync sessions there is carried, not made
|
|
563
510
|
again. It is paused, its state files (`sessions/<id>` and `archives/<id>`, the last state both sides agreed on) are
|
|
564
|
-
copied into the new directory, it is terminated in the old one, and this agent's daemon, started again, loads it
|
|
565
|
-
|
|
511
|
+
copied into the new directory, it is terminated in the old one, and this agent's daemon, started again, loads it. A
|
|
512
|
+
session that was paused there is the owner's pause (`ownerPausedAt`), and the watcher's next pass resumes the rest.
|
|
513
|
+
_(2026-10-20)_ Which sessions were paused is written down at the move's first look (`mutagen-move-paused.json`, gone
|
|
514
|
+
once the move is recorded done) and declared before the move pauses anything; a later try reads that record, not a
|
|
515
|
+
listing in which the move's own pauses look like the owner's. Declared after the terminate instead, a move cut short
|
|
516
|
+
in between left nothing saying whose the pauses were, and its retry declared every session the owner's, so folders
|
|
517
|
+
nobody paused stayed paused. Made again from nothing, a two-way session would bring back what one side deleted while it
|
|
566
518
|
could not sync and read a one-sided edit as a conflict; nothing could be flushed first, since the move runs before the
|
|
567
519
|
transport is up. Forwards are terminated and made again. A session that cannot be carried is terminated and made again
|
|
568
|
-
by the watcher, paused if it was
|
|
520
|
+
by the watcher, paused if it was, since its pause was declared the same way. The old daemon is stopped only
|
|
569
521
|
when nothing else is left in it or the move started it; one of another Mutagen version is stopped and started with
|
|
570
522
|
this agent's copy for the move, then started again with the owner's own Mutagen where one is on PATH. Mutagen's own
|
|
571
523
|
sign-in registration is removed only where it starts this agent's copy.
|
|
@@ -594,11 +546,10 @@ whose it is.
|
|
|
594
546
|
up to a week. A clone the bridge started, or one already shallow, takes the sandbox's shallow boundary
|
|
595
547
|
(`--update-shallow`), so a shallow sandbox repo no longer leaves a whole refused pack behind on every pass. Leftovers
|
|
596
548
|
older than an hour from an earlier agent are cleared once per process. Holds are in `status` and the report.
|
|
597
|
-
- **A nearly full drive
|
|
598
|
-
measures the drive holding each folder whose session writes there (not a copy-first project, which only sends).
|
|
599
|
-
Under 2% of the drive, clamped to 5–20 GiB, the pairing's
|
|
600
|
-
|
|
601
|
-
put back once a minute in case one did. `status` and the device card say why, with the numbers.
|
|
549
|
+
- **A nearly full drive holds folder sync still** (2026-10-18, [`sync/low-disk.ts`](src/sync/low-disk.ts)). Every
|
|
550
|
+
pass measures the drive holding each folder whose session writes there (not a copy-first project, which only sends).
|
|
551
|
+
Under 2% of the drive, clamped to 5–20 GiB, the pairing's sync and git bridge hold still (`lowDisk`); they carry on
|
|
552
|
+
once the floor and 2 GiB more are free. `status` and the device card say why, with the numbers.
|
|
602
553
|
- **Keys and enrollments per environment.** A newly made key is commented `<hostname>-<environment>`, so the sandbox
|
|
603
554
|
files a new enrollment under that name. An existing key keeps its comment (a sandbox older than this agent would read
|
|
604
555
|
a changed comment on the same key as a second machine holding sync); the sandbox tells existing ones apart by machine
|
|
@@ -606,7 +557,7 @@ whose it is.
|
|
|
606
557
|
- **Tunnel ports per environment.** Under WSL's mirrored networking a distro's loopback is the Windows side's, so both
|
|
607
558
|
sides pairing one sandbox derived one port twice. A distro now derives its ports in 20000-23999 from its name and the
|
|
608
559
|
sandbox id; every native environment keeps 24000-27999 exactly as before, so nothing outside WSL moves.
|
|
609
|
-
- **One folder, one sync, across the PC.** `setup`
|
|
560
|
+
- **One folder, one sync, across the PC.** `setup` reads the other environments' `sync.json` (from the
|
|
610
561
|
Windows side each supervised distro's through `wsl.exe -d <distro> cat`; from a distro the Windows side's beside its
|
|
611
562
|
agent) and compare after one spelling: `C:\code\app` and `/mnt/c/code/app` are `drive:c/code/app`, and
|
|
612
563
|
`\\wsl.localhost\Ubuntu\home\ada\app` and Ubuntu's `/home/ada/app` are `wsl:ubuntu/home/ada/app`. An overlap is refused
|
|
@@ -641,12 +592,33 @@ whose it is.
|
|
|
641
592
|
each side's sandboxes to that side, a sandbox made from WSL had nobody backing it up, preparing its update or tidying
|
|
642
593
|
after it, so each environment now runs them for its own. Both back off from a slug that keeps failing, as auto-prepare does, and each has its switch
|
|
643
594
|
beside the update ones (`intentic-machine updates --backups off`, `--tidy off`).
|
|
644
|
-
- **File sync holds still while its sandbox is swapped here** ([`sync/
|
|
595
|
+
- **File sync holds still while its sandbox is swapped here** ([`sync/holds.ts`](src/sync/holds.ts) `holdsSync`). A
|
|
645
596
|
pairing's local slug is the first label of its sandbox's public hostname (what ic names a sandbox with one) or the
|
|
646
|
-
id in it (what ic names one from its connect token), so the mapping is exact. Its
|
|
647
|
-
cutover and the first quarter hour
|
|
648
|
-
|
|
649
|
-
|
|
597
|
+
id in it (what ic names one from its connect token), so the mapping is exact. Its sync holds still through the
|
|
598
|
+
cutover and the first quarter hour after the cutover began, and past that while ic still watches the swap and the
|
|
599
|
+
sandbox does not answer. The quarter hour is measured from the pairing's own `swapSince`, the cutover's start as ic
|
|
600
|
+
recorded it, so it lasts after ic lets its record of the swap go. (2026-10-20: a swap with no probation, such as the dev
|
|
601
|
+
loop, leaves no record seconds after its cutover, and a hold read off the record alone let go after about thirty
|
|
602
|
+
seconds. Giving ic's record a longer life was rejected: the hold is the agent's fact, and ic's record answers whether a
|
|
603
|
+
swap is going on.) A later swap of the same sandbox starts the quarter hour again. Only this environment's records
|
|
604
|
+
count: a distro syncing a sandbox the Windows side swaps is not held.
|
|
605
|
+
- **File sync runs or holds still by one rule** (2026-10-20, [`sync/holds.ts`](src/sync/holds.ts)). Eight facts on a
|
|
606
|
+
pairing hold its sync still: the owner's `sync pause` (`ownerPausedAt`), the sandbox said to be gone (`goneSince`),
|
|
607
|
+
its container away or in ic's trash (`containerAway`), a swap (`swapSince`), an hour without an answer
|
|
608
|
+
(`unreachableSince`), a nearly full drive (`lowDisk`), and a bring-back, restore or delivery writing into the folder
|
|
609
|
+
(`transferSince`, 2026-10-21; that operation also pauses its session itself, at once, before it writes). Each is kept
|
|
610
|
+
by the one rule that observes it, and none of
|
|
611
|
+
them touches Mutagen. Every pass, after the rules have run, `holdSessions` reads every session in one listing and
|
|
612
|
+
makes Mutagen agree: what runs while anything holds it is paused, and what is paused while nothing does is resumed,
|
|
613
|
+
one session per call and read back (`resumeSessions`), tried again each pass until Mutagen took it. A session is made
|
|
614
|
+
paused while its pairing is held. `sync resume` lifts the owner's pause alone and says what else still holds it; the
|
|
615
|
+
report carries the holds as `heldBy`, so a page offers Resume only for the owner's pause. Before this, each reason
|
|
616
|
+
paused and resumed Mutagen itself behind a marker of its own (`fileSyncAutoPaused`, `fileSyncSwapPaused`,
|
|
617
|
+
`fileSyncPausedFor`, `fileSyncLowDisk`, translated on read into the facts above), set only when it found the session
|
|
618
|
+
running, and a person's pause had no record at all. A marker cleared before the resume took (fair-moth, 2026-10-19),
|
|
619
|
+
one a reattach dropped (swift-cedar, 2026-10-17), or a pause another reason found in place left sync paused with
|
|
620
|
+
nothing to lift it, or lifted one somebody still meant. The first pass of this build takes every paused session no
|
|
621
|
+
fact explains as the owner's, once (`sync-owner-pauses-adopted`).
|
|
650
622
|
- (2026-10-15) **Nothing downloaded replaces a binary until the release vouches for it**
|
|
651
623
|
([`release-verify.ts`](src/release/release-verify.ts)). Before an upgrade runs the new agent (and the Windows launcher
|
|
652
624
|
beside it), before ic is put in place ([`tools/ic-binary.ts`](src/device/tools/ic-binary.ts)), and before setup
|
|
@@ -766,10 +738,19 @@ The keeper now puts an unneeded sandbox to sleep and wakes it when somebody open
|
|
|
766
738
|
- **Wake.** The platform never calls a machine. A browser that finds the sandbox asleep asks the platform to wake it,
|
|
767
739
|
and this agent's wake round asks the platform for such requests (`ic sandbox wakes --json --source agent`, one request
|
|
768
740
|
for every sleeper on this side, each under its own report key), starting each one asked for through `ic sandbox
|
|
769
|
-
start`.
|
|
770
|
-
|
|
741
|
+
start`. While anything sleeps the ask is held (2026-10-19): `--wait 25` has the platform answer the moment somebody
|
|
742
|
+
asks for a wake, or after 25 s, and the next ask follows at once, so a wake no longer waits up to fifteen seconds for
|
|
743
|
+
the next poll. An ic or a platform from before the held ask is asked every fifteen seconds as before; an ic that
|
|
744
|
+
refuses the flag (clap's exit 2, no JSON) is asked again at once without it, and plainly for an hour. With nothing
|
|
745
|
+
asleep it asks every five minutes, to catch a sleep made by hand. It runs whatever the keeper's switch says, so a
|
|
746
|
+
sandbox asleep when the keeper was switched off still wakes.
|
|
771
747
|
The desktop app on the same computer runs the same command the moment its workspace page has asked
|
|
772
748
|
(`--source app`, the app's `sandbox_wakes.rs`), so a sandbox opened there need not wait for this round.
|
|
749
|
+
- **The link comes back with it** (2026-10-19). A sleep leaves this agent's link to the sandbox on its dial ladder,
|
|
750
|
+
which after twenty failures rests a quarter of an hour between tries: on rog a sandbox woken at 16:48 had its device
|
|
751
|
+
tools back at 17:12. Each start is acted on as ic prints it, and every link naming the slug is dialled at once and put
|
|
752
|
+
back on the ladder's first rung (peer-dial's `retryNow`); so is a sandbox somebody else woke, once ic counts nothing
|
|
753
|
+
asleep or the keeper's next listing shows it running.
|
|
773
754
|
- **The setting** is this environment's `sandboxSleepMinutes` in `machine.json`: absent means 30, `0` means never. Set
|
|
774
755
|
it with `intentic-machine sandbox sleep-after <minutes|off>` and read it with `sleep-after status`. One sandbox can
|
|
775
756
|
be kept awake from its own editor instead (Overview, "Sleep when unused", settings `sleepWhenUnused`, 2026-10-18):
|
|
@@ -869,16 +850,28 @@ version, file time) and the `IC_*`/`INTENTIC_*` variables in the agent's environ
|
|
|
869
850
|
|
|
870
851
|
### The keyring
|
|
871
852
|
|
|
872
|
-
[intentic-keyring](../keyring) is a process of its own beside this agent (2026-10-16):
|
|
873
|
-
it running and relays to it, and holds no vault key and no value.
|
|
874
|
-
|
|
875
|
-
the
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
`keyring
|
|
881
|
-
|
|
853
|
+
[intentic-keyring](../keyring), the vault behind Passwords, is a process of its own beside this agent (2026-10-16):
|
|
854
|
+
the agent installs it, keeps it running and relays to it, and holds no vault key and no value. Since 2026-10-19 it has
|
|
855
|
+
one mode, the protected service: the vault is held by a system account of its own (`LOCAL SERVICE` from a startup task
|
|
856
|
+
on Windows, the `intentic-keyring` user from the systemd unit `intentic-keyring@<uid>` on Linux), and what starts at
|
|
857
|
+
sign-in is its session helper. `intentic-machine keyring setup` puts the `intentic-keyring` asset of this agent's own
|
|
858
|
+
release into `bin/` (checked against the release's signed `SHA256SUMS`, as the launcher is; a from-source agent copies
|
|
859
|
+
`_devices/keyring/dist-bin`'s build instead), makes `intentic-askpass` a hard link beside it, asks for an
|
|
860
|
+
administrator's yes once (UAC on Windows, `pkexec` on Linux) to run `intentic-keyring service install`, registers the
|
|
861
|
+
helper's login entry (`keyring`, `IntenticKeyring` on Windows, running `intentic-keyring session`), starts it, and sets
|
|
862
|
+
up the vault: it generates a recovery key (six groups of five Crockford base32 characters, 150 bits), sends it as the
|
|
863
|
+
setup op's `passphrase`, and prints it once; it is never stored. Windows Hello is enrolled through the helper unless
|
|
864
|
+
`--no-hello`; on Linux the daily unlock is a polkit yes. Without the administrator's yes setup stops with `declined`
|
|
865
|
+
and "Passwords needs an administrator's approval once…", having changed nothing; on macOS, or a Linux without
|
|
866
|
+
systemd, polkit or setfacl, it stops with `unavailable` before installing anything. A computer still on the per-user
|
|
867
|
+
keyring from before (`intentic-keyring serve`, retired) is moved by `setup` or `upgrade`: the old keyring is stopped,
|
|
868
|
+
`service install` carries `~/.intentic/keyring/vault.json` and its files into the service's folder, and the login entry
|
|
869
|
+
becomes the helper's. Its old passphrase still opens it where the recovery key would.
|
|
870
|
+
|
|
871
|
+
Nothing in the agent's own upgrade, its `bin/` sweep or its rollback touches the keyring's files: it moves to a new
|
|
872
|
+
release only through `keyring upgrade`, which downloads and checks the new binary, asks the running keyring (which asks
|
|
873
|
+
the person), and only then swaps it, keeping `.previous` and putting it back if the new one does not answer; the new
|
|
874
|
+
binary's `service install` then runs as an administrator, so the service's own copy follows.
|
|
882
875
|
|
|
883
876
|
- **Relayed for the sandbox** ([`keyring/relay.ts`](src/keyring/relay.ts)): the contract's `keyring*` procedures go
|
|
884
877
|
to the keyring's pipe and back, with the sandbox named from the link the call came in on (`shares`, `copies`) and an
|
|
@@ -890,12 +883,9 @@ then swaps it, keeping `.previous` and putting it back if the new one does not a
|
|
|
890
883
|
1.5 s, the answer kept for 30 s ([`keyring/feature.ts`](src/keyring/feature.ts)).
|
|
891
884
|
- **Marked**: what `run_command` and `app_start` start carries `INTENTIC_AGENT_COMMAND=1`, for the keyring's record
|
|
892
885
|
and prompts. A hint, not a boundary: the agent's command can unset it.
|
|
893
|
-
- **
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
the login entry becomes `intentic-keyring session`. Hardened mode is read from the marker the install writes for this
|
|
897
|
-
user (`%ProgramData%\Intentic\Keyring\<SID>.hardened`). `keyring upgrade` on a hardened keyring also runs the new
|
|
898
|
-
binary's `service install`, elevated, so the service's own copy follows.
|
|
886
|
+
- **Installed** is read from the marker `service install` writes for this user, which every user may read:
|
|
887
|
+
`%ProgramData%\Intentic\Keyring\<SID>.hardened` on Windows (named from when the service was an optional "hardened
|
|
888
|
+
mode"), `/var/lib/intentic-keyring/<uid>.installed` on Linux ([`keyring/service.ts`](src/keyring/service.ts)).
|
|
899
889
|
- `status` and `doctor` show one keyring row (not installed, not running, not set up, locked or unlocked), and
|
|
900
890
|
`status --json` and `doctor --json` carry it as `keyring: { installed, running, setUp, locked?, unlockedUntil?, version? }`.
|
|
901
891
|
|
|
@@ -906,8 +896,8 @@ it reaches the pipe.
|
|
|
906
896
|
|
|
907
897
|
| Command | Success output |
|
|
908
898
|
|---|---|
|
|
909
|
-
| `keyring setup [--
|
|
910
|
-
| `keyring status` | `{ "ok": true, "installed", "running", "setUp", "state"?, "askpass": { "installed", "path"? }, "
|
|
899
|
+
| `keyring setup [--no-hello]` | `{ "ok": true, "path", "askpass": { "installed", "path"? }, "autostart", "setUp": true, "alreadySetUp", "recoveryKey"?, "state"? }` (`recoveryKey` only when this run made the vault) |
|
|
900
|
+
| `keyring status` | `{ "ok": true, "installed", "running", "setUp", "state"?, "askpass": { "installed", "path"? }, "support": { "canSetUp", "why"?, "hello", "platform" } }` |
|
|
911
901
|
| `keyring unlock [--minutes N]` / `keyring lock` | `{ "ok": true, "unlockedUntil" }` / `{ "ok": true }` |
|
|
912
902
|
| `keyring list` | `{ "ok": true, "entries": [EntryInfo], "backends" }` |
|
|
913
903
|
| `keyring add NAME [--stdin] [rules] [--backend B --ref R [--field F] [--attribute A]] [--replace]` | `{ "ok": true, "name" }` |
|
|
@@ -919,8 +909,7 @@ it reaches the pipe.
|
|
|
919
909
|
| `keyring askpass install\|uninstall\|status` | `{ "ok": true, "installed", "path"?, "variables", "file"?, "profile"? }` |
|
|
920
910
|
| `keyring sync status` | `{ "ok": true, "sync": { "key", "peers", "revision" } }` |
|
|
921
911
|
| `keyring upgrade` | `{ "ok": true, "upgraded", "from", "to" }` |
|
|
922
|
-
| `keyring
|
|
923
|
-
| `keyring uninstall` | `{ "ok": true, "removed", "vault", "hardened" }` |
|
|
912
|
+
| `keyring uninstall` | `{ "ok": true, "removed", "vault", "service" }` |
|
|
924
913
|
|
|
925
914
|
The rule flags are `--kind password|text`, `--program P`, `--package P`, `--host H`, `--askpass M` (each repeatable;
|
|
926
915
|
on `edit` a list flag replaces the whole list, and a lone `""` empties it), `--username U`, `--remember-minutes N`, and
|
|
@@ -928,17 +917,59 @@ on `edit` a list flag replaces the whole list, and a lone `""` empties it), `--u
|
|
|
928
917
|
value. `askpass install` sets `SSH_ASKPASS`, `SSH_ASKPASS_REQUIRE=prefer`, `SUDO_ASKPASS` and `GIT_ASKPASS` for the
|
|
929
918
|
user: through `[Environment]::SetEnvironmentVariable` on Windows, and on Linux and macOS in
|
|
930
919
|
`~/.config/environment.d/intentic-askpass.conf`, printing the `export` lines a shell profile needs. `keyring
|
|
931
|
-
uninstall`
|
|
920
|
+
uninstall` removes the service (an administrator's yes) and puts the vault back in `~/.intentic/keyring`, where it
|
|
921
|
+
stays; set up again, the same recovery key opens it.
|
|
922
|
+
|
|
923
|
+
### Uninstall
|
|
924
|
+
|
|
925
|
+
`intentic-machine uninstall [--purge] [--delete-data]` ([`src/uninstall/`](src/uninstall/)). `ic uninstall` is the one
|
|
926
|
+
orchestrator of a whole-device uninstall and runs `--purge` here; the agent's own command is the same removal for a
|
|
927
|
+
person who runs it alone, and either way it never downloads anything.
|
|
928
|
+
|
|
929
|
+
- **No flag**: every sandbox link, every sync pairing and the login entry go, as they always have. The agent goes even
|
|
930
|
+
from a device that hosts sandboxes; on Windows it keeps running while WSL distros are attached, to keep them running.
|
|
931
|
+
- **`--purge`**: everything of the agent leaves this environment, in this order:
|
|
932
|
+
1. On Windows, each WSL distro in `machine.json` is purged through its own agent (`wsl.exe`, five minutes at most
|
|
933
|
+
each; an agent older than `--purge` takes the plain uninstall, and the warning says how to finish), and the list
|
|
934
|
+
is emptied, so nothing is left for the Windows side's agent to keep running for.
|
|
935
|
+
2. On Linux and macOS the binary is renamed to `bin/intentic-machine.uninstalling` before anything stops the agent.
|
|
936
|
+
The Windows side restarts a stopped distro agent a second later through a script that exits 64 when the binary is
|
|
937
|
+
missing, and then drops that distro from its list, so a purged distro does not come back.
|
|
938
|
+
3. The programs sandboxes started with `app_start` are stopped, from every sandbox's `runs/<sandbox>/apps.json`.
|
|
939
|
+
4. The plain uninstall runs (links, pairings, the login entry). Mutagen is the agent's own copy in `bin/` or none: a
|
|
940
|
+
missing copy skips the session steps instead of downloading one.
|
|
941
|
+
5. Windows' start before sign-in is removed (Windows asks for permission), and the resident agent is stopped with its
|
|
942
|
+
login entry whatever it still served.
|
|
943
|
+
6. The agent's Mutagen daemon is stopped and the ssh include removed, in case the sync step stopped early.
|
|
944
|
+
7. The keyring goes with askpass (`keyring uninstall`). Its protected service needs an administrator's yes. If it is
|
|
945
|
+
declined, the service stays, and so do `bin/` and the PATH entry, so the purge can be run again to finish it.
|
|
946
|
+
8. What the agents before this one left goes: the `intentic-host` and `intentic-sync-mirror` login entries,
|
|
947
|
+
`~/.intentic/host` and `~/.intentic/sync`, their `~/.local/bin` links, and the `intentic-link-watch` timer.
|
|
948
|
+
9. The PATH entry goes: `bin` out of the per-user PATH on Windows (`removeFromWindowsPathValue`, written back under
|
|
949
|
+
the value's own kind), and the `~/.local/bin/intentic-machine` link where it points into `bin`.
|
|
950
|
+
10. Lingering is turned off only where the agent turned it on. local-agent writes `linger-enabled` beside the agent's
|
|
951
|
+
log the one time `loginctl enable-linger` changes it from off to on. Lingering the user had already stays.
|
|
952
|
+
11. The files go: `~/.intentic/machine` and `~/.intentic/keyring` except the person's data, then each folder once
|
|
953
|
+
empty, and `~/.intentic` once nothing is left in it. Everything else under `~/.intentic` is ic's and is never
|
|
954
|
+
touched. On Windows the running agent is moved to `%TEMP%` first, and a hidden PowerShell removes what was still
|
|
955
|
+
in use once this process has exited.
|
|
956
|
+
- **The data that stays** without `--delete-data`: the keyring's `vault.json`, `keys.json` and `audit.jsonl*`;
|
|
957
|
+
`machine/restore`; `machine/audit.jsonl*`; and in `machine/trash` the folders `trash_file` made for files a sandbox
|
|
958
|
+
moved aside on this device (named for the moment alone; the upkeep's own trash entries go). The narration says what
|
|
959
|
+
stayed and why.
|
|
960
|
+
- **`--delete-data`** implies `--purge` and removes the data too.
|
|
961
|
+
- A step that does not finish is a warning with the command that finishes it by hand (`fix:` on its own line), and the
|
|
962
|
+
verdict counts them. The run fails, exit 1, only when the agent is still running or its files could not be removed.
|
|
932
963
|
|
|
933
964
|
## Key files
|
|
934
965
|
|
|
935
966
|
- [src/commands.ts](src/commands.ts) — the CLI: `device`, `sync`, `keyring`, `sandbox`, `run`, `status`, `doctor`, `upgrade`, `updates`, `uninstall`.
|
|
967
|
+
- [src/uninstall/purge.ts](src/uninstall/purge.ts) — `uninstall --purge`: the steps in `steps.ts`, the distros in `distros.ts`, the files in `sweep.ts`, every decision pure in `plan.ts`.
|
|
936
968
|
- [src/resident/resident.ts](src/resident/resident.ts) — the resident process that holds links, pairings and WSL distros; `supervision.ts` beside it starts and stops it through whatever restarts this environment's agent.
|
|
937
969
|
- [src/device/mcp.ts](src/device/mcp.ts) — every tool a sandbox can call on this device.
|
|
938
970
|
- [src/device/policy.ts](src/device/policy.ts) — scope checks and the file-root boundary.
|
|
939
971
|
- [src/sync/endpoint.ts](src/sync/endpoint.ts) — how a pairing reaches its sandbox: the tunnelled sshd (`tunnel.ts`), or Docker for a project on this machine.
|
|
940
|
-
- [src/sync/
|
|
941
|
-
- [src/sync/project/project-delivery.ts](src/sync/project/project-delivery.ts) — landed work written into an attached folder (`deliverProject`).
|
|
972
|
+
- [src/sync/project/project-delivery.ts](src/sync/project/project-delivery.ts) — landed work written into a project folder (`deliverProject`).
|
|
942
973
|
- [src/sync/gone.ts](src/sync/gone.ts) — when a paired sandbox counts as gone; `gone-watch.ts` acts on it, `retire.ts` retires its pairings, `forget-command.ts` is `sync forget`.
|
|
943
974
|
- [src/environments/machine.ts](src/environments/machine.ts) — the Windows root and its WSL children.
|
|
944
975
|
- [src/upkeep/manifest.ts](src/upkeep/manifest.ts) — what the device upkeep finds and puts right; `reconcile.ts` runs it.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AutostartSpec } from "@intentic/local-agent";
|
|
2
2
|
export declare const MACHINE_AUTOSTART: AutostartSpec;
|
|
3
3
|
export declare const KEYRING_AUTOSTART: AutostartSpec;
|
|
4
|
-
export declare const KEYRING_SESSION_AUTOSTART: AutostartSpec;
|
|
5
4
|
//# sourceMappingURL=autostart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostart.d.ts","sourceRoot":"","sources":["../../src/autostart/autostart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAM3D,eAAO,MAAM,iBAAiB,EAAE,aAc/B,CAAC;
|
|
1
|
+
{"version":3,"file":"autostart.d.ts","sourceRoot":"","sources":["../../src/autostart/autostart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAM3D,eAAO,MAAM,iBAAiB,EAAE,aAc/B,CAAC;AASF,eAAO,MAAM,iBAAiB,EAAE,aAW/B,CAAC"}
|
|
@@ -16,18 +16,12 @@ const keyringLog = keyringPaths().log;
|
|
|
16
16
|
export const KEYRING_AUTOSTART = {
|
|
17
17
|
id: "keyring",
|
|
18
18
|
windowsRunValue: "IntenticKeyring",
|
|
19
|
-
desktopName: "Intentic
|
|
20
|
-
desktopComment: "
|
|
19
|
+
desktopName: "Intentic Passwords",
|
|
20
|
+
desktopComment: "Passwords on this computer: its prompts and typing on this desktop, for the protected service that holds the vault",
|
|
21
21
|
logPath: keyringLog,
|
|
22
22
|
launchAgent: { label: "dev.intentic.keyring" },
|
|
23
|
-
detachedArgs: ["serve"],
|
|
24
|
-
foregroundArgs: ["serve"],
|
|
25
|
-
failureNote: (reason) => `Couldn't register the keyring to start at login (${reason}); it runs until this computer restarts, and \`intentic-machine keyring setup\` starts it again. Its log is ${keyringLog}.`,
|
|
26
|
-
};
|
|
27
|
-
export const KEYRING_SESSION_AUTOSTART = {
|
|
28
|
-
...KEYRING_AUTOSTART,
|
|
29
|
-
desktopComment: "The intentic keyring's prompts and typing on this desktop, for the IntenticKeyring service that holds the vault",
|
|
30
23
|
detachedArgs: ["session"],
|
|
31
24
|
foregroundArgs: ["session"],
|
|
25
|
+
failureNote: (reason) => `Couldn't register Passwords to start at login (${reason}); it runs until this computer restarts, and \`intentic-machine keyring setup\` starts it again. Its log is ${keyringLog}.`,
|
|
32
26
|
};
|
|
33
27
|
//# sourceMappingURL=autostart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostart.js","sourceRoot":"","sources":["../../src/autostart/autostart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,MAAM,CAAC,MAAM,iBAAiB,GAAkB;IAC5C,EAAE,EAAE,kBAAkB;IACtB,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,wBAAwB;IACrC,cAAc,EAAE,yFAAyF;IAEzG,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC9C,YAAY,EAAE,CAAC,KAAK,CAAC;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC;IAEvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,kBAAkB,CAAC;IAC7D,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CACpB,4DAA4D,MAAM,iGAAiG,UAAU,GAAG;CACvL,CAAC;
|
|
1
|
+
{"version":3,"file":"autostart.js","sourceRoot":"","sources":["../../src/autostart/autostart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,MAAM,CAAC,MAAM,iBAAiB,GAAkB;IAC5C,EAAE,EAAE,kBAAkB;IACtB,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,wBAAwB;IACrC,cAAc,EAAE,yFAAyF;IAEzG,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC9C,YAAY,EAAE,CAAC,KAAK,CAAC;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC;IAEvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,kBAAkB,CAAC;IAC7D,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CACpB,4DAA4D,MAAM,iGAAiG,UAAU,GAAG;CACvL,CAAC;AAOF,MAAM,UAAU,GAAG,YAAY,EAAE,CAAC,GAAG,CAAC;AAEtC,MAAM,CAAC,MAAM,iBAAiB,GAAkB;IAC5C,EAAE,EAAE,SAAS;IACb,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,oBAAoB;IACjC,cAAc,EAAE,oHAAoH;IACpI,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC9C,YAAY,EAAE,CAAC,SAAS,CAAC;IACzB,cAAc,EAAE,CAAC,SAAS,CAAC;IAC3B,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CACpB,kDAAkD,MAAM,+GAA+G,UAAU,GAAG;CAC3L,CAAC"}
|
package/dist/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAsInE,eAAO,MAAM,QAAQ,kDA4BnB,CAAC"}
|