@ours.network/install 0.17.0-nightly.10 → 0.17.0-nightly.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/lib/effects.mjs +32 -14
- package/package.json +1 -1
package/lib/effects.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
18
18
|
import { atomicWriteConfig, snapshotConfig, restoreConfig } from './config.mjs';
|
|
19
19
|
import { askYesNo, askLine as askLineOnTty } from './prompt.mjs';
|
|
20
20
|
import { classifyHarnessProbe } from './logic.mjs';
|
|
21
|
+
import { classifyStateDir } from './detect.mjs';
|
|
21
22
|
|
|
22
23
|
/** GET http://127.0.0.1:<port>/state-dir — the unauthenticated identity probe. */
|
|
23
24
|
async function probePort(port, { timeoutMs = 1500 } = {}) {
|
|
@@ -156,24 +157,41 @@ function copyToClipboard(text) {
|
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
/**
|
|
159
|
-
* Every state directory on this machine
|
|
160
|
+
* Every DAEMON state directory on this machine.
|
|
160
161
|
*
|
|
161
|
-
*
|
|
162
|
-
* GLOBAL packages still needed by somebody else? Getting it wrong the optimistic
|
|
163
|
-
* way (reporting none) uninstalls the CLI out from under a second daemon that is
|
|
164
|
-
* still running, so the search is deliberately conservative — it looks only where
|
|
165
|
-
* a state directory can actually be, and an unreadable home means "there might be
|
|
166
|
-
* others", not "there are none".
|
|
162
|
+
* ONE DEFINITION OF WHAT A DAEMON IS, and this function is why that matters.
|
|
167
163
|
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
164
|
+
* It used to count any `~/.ours*` directory containing a config.json. Two of those
|
|
165
|
+
* are not daemons on a perfectly normal machine: `~/.ours-telegram/config.json` is
|
|
166
|
+
* the Telegram connector's and `~/.ours-cowork/config.json` is cowork's. So the
|
|
167
|
+
* uninstaller reported "@ours.network/cli kept — still used by the daemon at
|
|
168
|
+
* ~/.ours-telegram", and two things followed silently:
|
|
169
|
+
*
|
|
170
|
+
* · planGlobalPackages kept cli, mcp and the plugin packages FOREVER on any
|
|
171
|
+
* machine with the connector installed, naming a connector's config directory
|
|
172
|
+
* as a daemon;
|
|
173
|
+
* · worse, planPluginRemoval's `lastDaemon` went false, so the whole harness
|
|
174
|
+
* plugin phase was skipped — with a reason that was not true. A plain
|
|
175
|
+
* interactive `ours-uninstall` on a machine with the connector removed no
|
|
176
|
+
* plugins at all.
|
|
177
|
+
*
|
|
178
|
+
* The selection screen had already closed exactly this: config.json is the one
|
|
179
|
+
* piece of evidence that is AMBIGUOUS, so it cannot be the test. That predicate
|
|
180
|
+
* lives in lib/detect.mjs and this now calls it rather than keeping a second,
|
|
181
|
+
* naive copy that drifted. A daemon is identified by an artefact only a daemon
|
|
182
|
+
* writes, or by a config whose SHAPE is a daemon's.
|
|
183
|
+
*
|
|
184
|
+
* Still deliberately conservative about WHERE it looks: only `~/.ours` and its
|
|
185
|
+
* `~/.ours*` siblings. A state directory somewhere else is not found, and an
|
|
186
|
+
* unreadable home means "there might be others", not "there are none" — because
|
|
187
|
+
* the caller uses this to decide whether a GLOBAL package is still needed, and
|
|
188
|
+
* being wrong the optimistic way uninstalls the CLI out from under a running
|
|
189
|
+
* daemon.
|
|
173
190
|
*/
|
|
174
191
|
function knownStateDirsIn(home) {
|
|
175
192
|
const found = [];
|
|
176
|
-
const
|
|
193
|
+
const io = { exists: existsSync, readJson: readJsonFile };
|
|
194
|
+
const consider = (dir) => { if (classifyStateDir(dir, io).isDaemon) found.push(dir); };
|
|
177
195
|
consider(join(home, '.ours'));
|
|
178
196
|
try {
|
|
179
197
|
for (const entry of readdirSync(home, { withFileTypes: true })) {
|
|
@@ -278,7 +296,7 @@ export function realEffects({ write, ttyFd, env = process.env, home = homedir(),
|
|
|
278
296
|
};
|
|
279
297
|
}
|
|
280
298
|
|
|
281
|
-
export const __testables = { probePort, portTakenSync, readJsonFile, readTextFile, installedVersionOf };
|
|
299
|
+
export const __testables = { probePort, portTakenSync, readJsonFile, readTextFile, installedVersionOf, knownStateDirsIn };
|
|
282
300
|
|
|
283
301
|
// -----------------------------------------------------------------------------
|
|
284
302
|
// THE PAIR
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/install",
|
|
3
|
-
"version": "0.17.0-nightly.
|
|
3
|
+
"version": "0.17.0-nightly.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The unified ours.network stack installer (ours-install): one guided ~3-minute flow for ours core (the daemon) + the harness plugins (Claude Code / Codex) + ours-fleet + the Telegram connector, then a single copy-paste hand-off prompt. Self-contained (Node built-ins only); run as `ours-install` or via curl|bash (install.sh).",
|
|
6
6
|
"type": "module",
|