@lanes-sh/link 0.4.0 → 0.5.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.
Files changed (48) hide show
  1. package/README.md +20 -9
  2. package/instructions/agents/lanes-link-scout.md +14 -3
  3. package/instructions/skills/lanes-link/SKILL.md +80 -3
  4. package/package.json +2 -2
  5. package/src/cli/argv.ts +7 -0
  6. package/src/cli/commands/connect/index.ts +9 -6
  7. package/src/cli/commands/connection.ts +298 -0
  8. package/src/cli/commands/mcp/list.ts +123 -29
  9. package/src/cli/commands/operate/inspect.ts +37 -20
  10. package/src/cli/commands/operate/serve.ts +21 -0
  11. package/src/cli/commands/owner/assets.ts +132 -0
  12. package/src/cli/commands/owner/shared.ts +28 -4
  13. package/src/cli/commands/owner/tasks.ts +194 -0
  14. package/src/cli/commands/owner.ts +9 -4
  15. package/src/cli/config-edit.ts +33 -7
  16. package/src/cli/config-repair.ts +115 -11
  17. package/src/cli/dispatch-owner.ts +49 -8
  18. package/src/cli/lanes.ts +1 -1
  19. package/src/cli/main.ts +26 -3
  20. package/src/cli/provider-marks.ts +1 -1
  21. package/src/cli/runtime/registry.ts +10 -2
  22. package/src/cli/selection.ts +14 -0
  23. package/src/cli/usage.ts +18 -2
  24. package/src/connectivity/mail/attachments.ts +5 -1
  25. package/src/connectivity/mail/index.ts +6 -1
  26. package/src/connectivity/manifest/provider.ts +15 -2
  27. package/src/deployments/deploy.ts +3 -2
  28. package/src/deployments/prepare.ts +1 -1
  29. package/src/deployments/servable.ts +1 -1
  30. package/src/deployments/upload.ts +0 -53
  31. package/src/profile/load.ts +46 -0
  32. package/src/providers/assets/provider.ts +337 -0
  33. package/src/providers/assets/store.ts +167 -0
  34. package/src/providers/bunq/hints.ts +3 -1
  35. package/src/providers/bunq/redact.ts +13 -2
  36. package/src/providers/bunq/specs/bunq.v1.json +20 -1
  37. package/src/providers/bunq/specs/vendor.ts +59 -1
  38. package/src/providers/google/index.ts +1 -1
  39. package/src/providers/google/tasks/index.ts +3 -3
  40. package/src/providers/google/tasks/redact.ts +21 -11
  41. package/src/providers/index.ts +3 -3
  42. package/src/providers/owner.ts +39 -19
  43. package/src/providers/setup/plan.ts +17 -1
  44. package/src/providers/shared/vendor-operations.ts +81 -0
  45. package/src/providers/tasks/provider.ts +370 -0
  46. package/src/providers/tasks/store.ts +248 -0
  47. package/src/server/mcp/build.ts +1 -1
  48. package/src/server/mcp/instructions.ts +67 -8
@@ -64,6 +64,29 @@ about this person or their work, search it. Writing to memory is a separate
64
64
  grant, and what you write is served back to every later session — including to
65
65
  a different agent — so write when asked to remember something, not by habit.`;
66
66
 
67
+ const TASKS = `**Tasks are what the owner has to do**, each with a status. "Remember to…" and
68
+ "add a todo" belong here. Closing one is an update, not a delete, and a listing
69
+ shows outstanding work unless you ask for more.`;
70
+
71
+ /**
72
+ * The pair, when both are reachable — which after ADR-050 is the ordinary case.
73
+ *
74
+ * Not the two paragraphs above concatenated. The mistake this is here to prevent
75
+ * is a routing one — a thing to *do* written into memory, where nothing can ever
76
+ * close it — and a routing rule is shorter and clearer said once, in one
77
+ * sentence naming both stores, than implied by two paragraphs that each describe
78
+ * only themselves. It also very nearly pays for itself: this replaces `MEMORY`
79
+ * rather than joining it, so the pair costs about what the single one did.
80
+ */
81
+ const MEMORY_AND_TASKS = `**Memory and tasks are different stores.** Search memory before concluding you do
82
+ not know something about this person or their work. A thing to *do* goes in
83
+ tasks, not memory — "remember to…" is a task, and it has a status. Both are
84
+ served back to every later session, so write when asked, not by habit.`;
85
+
86
+ const ASSETS = `**Assets are the owner's own files**, kept by name in this profile. Storing one
87
+ names a source, exactly as an attachment does; a text asset reads back as text
88
+ and anything else is described rather than encoded.`;
89
+
67
90
  const SKILLS = `**Skills are the owner's procedures**, surfaced as prompts rather than tools.
68
91
  That is deliberate: a procedure is selected by the person, not chosen by the
69
92
  model, and you cannot read one's body. They belong to one profile, so a skill
@@ -133,15 +156,39 @@ runs, and a client can report it unreachable while it is up. That is ordinary
133
156
  not a fault to diagnose, and not authorization you have lost. Say the call did
134
157
  not land, do not redo what already succeeded, and offer to retry.`;
135
158
 
136
- /** Which paragraph each owner-layer provider brings, when it is reachable. */
159
+ /** Which paragraph each owner-layer provider brings, when it is reachable alone. */
137
160
  const OWNER_HABITS: Record<string, string> = {
138
161
  memory: MEMORY,
162
+ tasks: TASKS,
163
+ assets: ASSETS,
139
164
  skills: SKILLS,
140
165
  vault: VAULT,
141
166
  setup: SETUP,
142
167
  identity: IDENTITY,
143
168
  };
144
169
 
170
+ /**
171
+ * The paragraphs this principal should be told, in `RESERVED_PROVIDER_IDS` order.
172
+ *
173
+ * A lookup per provider would be enough if every paragraph described exactly one
174
+ * provider, and one does not: memory and tasks are only worth distinguishing
175
+ * from each other, so when both are reachable they collapse into one. The
176
+ * substitution is conditional rather than unconditional for the reason the
177
+ * docstring at the top of this file gives — prose describing a tool that is not
178
+ * there is worse than absent prose, and a profile carrying `deny: [tasks.*]` is
179
+ * exactly the case that would produce it.
180
+ */
181
+ function habitsFor(reachable: readonly string[]): string[] {
182
+ const present = new Set(reachable);
183
+ const paired = present.has('memory') && present.has('tasks');
184
+
185
+ return reachable.flatMap((id) => {
186
+ if (paired && id === 'memory') return [MEMORY_AND_TASKS];
187
+ if (paired && id === 'tasks') return [];
188
+ return OWNER_HABITS[id] ? [OWNER_HABITS[id]!] : [];
189
+ });
190
+ }
191
+
145
192
  /**
146
193
  * The whole string's ceiling, and the only budget there is.
147
194
  *
@@ -158,11 +205,23 @@ const OWNER_HABITS: Record<string, string> = {
158
205
  * Raised a second time, to 2500, for `IDENTITY`, and the same answer for the
159
206
  * same reason: an agent signing as the wrong person has already sent the
160
207
  * message, and a skill loaded only when relevant is not loaded at the moment
161
- * that happens. The measured worst case — twenty profiles, twenty connections
162
- * each, every owner provider reachable, remote clients — is 2474, so this is
163
- * the measurement plus a little, not a round number picked first. Two things
164
- * hold it there: the paragraph names no identity, and it is spent only by a
165
- * profile that declared one.
208
+ * that happens.
209
+ *
210
+ * Raised a third time, to 2700, for tasks and assets (ADR-051), and the answer
211
+ * is the same shape a third time. The memory/tasks distinction is a routing rule
212
+ * applied at the instant of a write: an agent that files "remember to chase the
213
+ * invoice" as a memory entry has put it somewhere nothing can ever close, and it
214
+ * has already done so by the time a skill would have been loaded. The client
215
+ * that most needs the rule is the one holding no skills directory.
216
+ *
217
+ * The arithmetic, because the number is a measurement and not a round figure:
218
+ * twenty profiles, twenty connections each, every owner provider reachable,
219
+ * remote clients, is **2686**. That is the *unpaired* case — memory reachable
220
+ * and tasks denied — which runs three characters longer than the ordinary one
221
+ * (2683), because `MEMORY_AND_TASKS` is slightly shorter than `MEMORY` and
222
+ * `TASKS` apart. Worth stating, because the last two raises were both certified
223
+ * against a case an endpoint does not actually serve, and the widest case here
224
+ * is the one that looks like the narrower configuration.
166
225
  *
167
226
  * Exported because the test asserted `2000` as a literal while the code
168
227
  * reserved room against a second, differently-derived number — so the two could
@@ -171,7 +230,7 @@ const OWNER_HABITS: Record<string, string> = {
171
230
  * exactly the final length, because `join` adds the same two characters the
172
231
  * reduce already counted.
173
232
  */
174
- export const MAX_INSTRUCTIONS = 2500;
233
+ export const MAX_INSTRUCTIONS = 2700;
175
234
 
176
235
  /** Which of the owner-layer providers this principal can actually reach. */
177
236
  function ownerProviders(merged: ReadonlyMap<string, MergedCapability>): string[] {
@@ -238,7 +297,7 @@ export function serverInstructions(
238
297
  const sections = [
239
298
  OPENING,
240
299
  ROUTING,
241
- ...owner.map((id) => OWNER_HABITS[id]).filter((habit): habit is string => habit !== undefined),
300
+ ...habitsFor(owner),
242
301
  FILES,
243
302
  REFUSAL,
244
303
  ...(remoteClients ? [AVAILABILITY] : []),