@lanes-sh/link 0.5.2 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lanes-sh/link",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "A self-hostable MCP gateway for all your connections, memory, tasks, files, and secrets",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://lanes.sh/link",
@@ -1,6 +1,7 @@
1
1
  import { homedir } from 'node:os';
2
2
  import { join, sep } from 'node:path';
3
- import { installRoot } from '#profile';
3
+ import { installRoot, resolveWorkspaceRoot } from '#profile';
4
+ import { repairOwnerLayer } from '../config-repair.ts';
4
5
  import { emit, fail, ok, print, printErr, progress, style, warn } from '../output.ts';
5
6
  import { PACKAGE, release, type ReleaseState } from '../release.ts';
6
7
  import { version } from '../version.ts';
@@ -152,6 +153,27 @@ export async function update(flags: UpdateFlags): Promise<void> {
152
153
  // was down would make this the flakiest check in it.
153
154
  if (flags.check === true && decision.action === 'install') process.exitCode = 1;
154
155
 
156
+ // Whatever the registry said, and before the branch that returns early.
157
+ //
158
+ // `start`, `connect` and `deploy` already repair a profile that is missing
159
+ // part of the owner layer, and for months that was enough. It is not: a
160
+ // release that adds a surface — `tasks` and `assets` in 0.5.0 — leaves every
161
+ // existing profile without it until one of those three next runs, and someone
162
+ // who serves their endpoint from elsewhere may run none of them for weeks. The
163
+ // page they look at meanwhile offers to *add* what they already have,
164
+ // which is where this was reported from.
165
+ //
166
+ // `update` is the command that means "bring me current", so it is the honest
167
+ // place for the other half of current. Not on `--check`, which is a question
168
+ // and must not write, and not conditional on an install having happened: the
169
+ // profile of someone already on the latest version is exactly the one this was
170
+ // reported against.
171
+ if (flags.check !== true) {
172
+ await repairOwnerLayer(resolveWorkspaceRoot(), undefined, {
173
+ ...(flags.json === true ? { report: progress } : {}),
174
+ });
175
+ }
176
+
155
177
  const report = {
156
178
  installed: current.installed,
157
179
  latest: current.latest,
@@ -261,7 +261,14 @@ export function ensureIdentityConnection(document: ConfigDocument): SurfaceRepai
261
261
  export async function repairOwnerLayer(
262
262
  workspaceRoot: string,
263
263
  profiles: readonly string[] | undefined,
264
+ options: { report?: (line: string) => void } = {},
264
265
  ): Promise<void> {
266
+ // stdout by default, because every caller but one is printing a report a
267
+ // person reads. `update --json` passes `progress` instead: what it produces is
268
+ // a document, and a line of prose in front of it corrupts whatever is parsing.
269
+ // Routed rather than silenced — nothing else here widens a policy without
270
+ // saying so, and this must not be the exception.
271
+ const say = options.report ?? print;
265
272
  const wanted = profiles === undefined ? undefined : new Set(profiles);
266
273
 
267
274
  for (const name of await listProfiles(workspaceRoot)) {
@@ -274,13 +281,13 @@ export async function repairOwnerLayer(
274
281
 
275
282
  await document.save();
276
283
 
277
- print(ok(`gave ${style.bold(name)} its own owner layer`));
278
- for (const change of repairLines(repair)) print(` ${style.dim(change)}`);
279
- print(
284
+ say(ok(`gave ${style.bold(name)} its own owner layer`));
285
+ for (const change of repairLines(repair)) say(` ${style.dim(change)}`);
286
+ say(
280
287
  ` ${style.dim('memory, tasks, assets, skills, vault and setup — your own material, no account behind any of them')}`,
281
288
  );
282
289
  } catch (error) {
283
- print(
290
+ say(
284
291
  warn(
285
292
  `could not give ${name} its owner layer: ${error instanceof Error ? error.message.split('\n')[0] : String(error)}`,
286
293
  ),