@intentic/extension-manifest 1.223.0 → 1.225.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 (66) hide show
  1. package/README.md +16 -16
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundle.js.map +1 -1
  4. package/dist/manifest.js +5 -5
  5. package/dist/manifest.js.map +1 -1
  6. package/dist/mark.js +3 -3
  7. package/dist/mark.js.map +1 -1
  8. package/dist/permissions.js +1 -1
  9. package/dist/permissions.js.map +1 -1
  10. package/dist/points/automation-templates.d.ts +1 -1
  11. package/dist/points/automation-templates.d.ts.map +1 -1
  12. package/dist/points/automation-templates.js +6 -6
  13. package/dist/points/automation-templates.js.map +1 -1
  14. package/dist/points/bin.d.ts +1 -1
  15. package/dist/points/bin.d.ts.map +1 -1
  16. package/dist/points/bin.js +1 -1
  17. package/dist/points/bin.js.map +1 -1
  18. package/dist/points/capabilities.d.ts +1 -1
  19. package/dist/points/capabilities.d.ts.map +1 -1
  20. package/dist/points/capabilities.js +13 -13
  21. package/dist/points/capabilities.js.map +1 -1
  22. package/dist/points/commands.js +1 -1
  23. package/dist/points/commands.js.map +1 -1
  24. package/dist/points/environment.d.ts +1 -1
  25. package/dist/points/environment.d.ts.map +1 -1
  26. package/dist/points/environment.js +2 -2
  27. package/dist/points/environment.js.map +1 -1
  28. package/dist/points/files.js +2 -2
  29. package/dist/points/files.js.map +1 -1
  30. package/dist/points/index.d.ts +7 -7
  31. package/dist/points/listener.d.ts +1 -1
  32. package/dist/points/listener.d.ts.map +1 -1
  33. package/dist/points/listener.js +3 -3
  34. package/dist/points/listener.js.map +1 -1
  35. package/dist/points/processes.d.ts +1 -1
  36. package/dist/points/processes.d.ts.map +1 -1
  37. package/dist/points/processes.js +1 -1
  38. package/dist/points/processes.js.map +1 -1
  39. package/dist/points/settings.js +1 -1
  40. package/dist/points/settings.js.map +1 -1
  41. package/dist/points/viewers.d.ts +1 -1
  42. package/dist/points/viewers.d.ts.map +1 -1
  43. package/dist/points/viewers.js +3 -3
  44. package/dist/points/viewers.js.map +1 -1
  45. package/intentic-extension.schema.json +73 -73
  46. package/package.json +3 -3
  47. package/src/bundle.ts +5 -5
  48. package/src/contribution-point.ts +5 -5
  49. package/src/json-schema.ts +6 -6
  50. package/src/manifest.ts +18 -18
  51. package/src/mark.ts +11 -11
  52. package/src/permissions.ts +2 -2
  53. package/src/points/agent.ts +1 -1
  54. package/src/points/automation-templates.ts +10 -10
  55. package/src/points/bin.ts +2 -2
  56. package/src/points/capabilities.ts +38 -38
  57. package/src/points/commands.ts +4 -4
  58. package/src/points/documents.ts +2 -2
  59. package/src/points/environment.ts +2 -2
  60. package/src/points/files.ts +9 -9
  61. package/src/points/index.ts +4 -4
  62. package/src/points/listener.ts +7 -7
  63. package/src/points/processes.ts +1 -1
  64. package/src/points/settings.ts +1 -1
  65. package/src/points/viewers.ts +8 -8
  66. package/src/powers-diff.ts +5 -5
@@ -13,7 +13,7 @@ export const CapabilityFieldSchema = z.object({
13
13
  secret: z.boolean().optional().describe("Mask it, and never echo it back."),
14
14
  optional: z.boolean().optional(),
15
15
  multiline: z.boolean().optional(),
16
- // An OPT-IN EXTRA rather than a decision — rendered as a switch, carried as the "on"/"off" the config
16
+ // An OPT-IN EXTRA rather than a decision, rendered as a switch, carried as the "on"/"off" the config
17
17
  // schemas already speak (the vpn's pfs/aggressive precedent). A two-option Segmented can express the same
18
18
  // value, and reads wrong for this: it presents a choice the user must make to proceed, sized like the
19
19
  // required fields around it. Something the capability works fine without wants the control that is quiet
@@ -32,9 +32,9 @@ export const CapabilityFieldSchema = z.object({
32
32
  .string()
33
33
  .optional()
34
34
  .describe(
35
- "A line under this control, for what the label alone cannot say — a host requirement, when a value takes effect. The card's own `hint` speaks for the whole card; this one is bound to the field it qualifies.",
35
+ "A line under this control, for what the label alone cannot say: a host requirement, when a value takes effect. The card's own `hint` speaks for the whole card; this one is bound to the field it qualifies.",
36
36
  ),
37
- /* This field's value only takes effect after the sandbox is REBUILT — it rides the environment overlay
37
+ /* This field's value only takes effect after the sandbox is REBUILT, it rides the environment overlay
38
38
  * rather than something the daemon can act on now. Rendered as a chip beside the label.
39
39
  *
40
40
  * The one fact a user needs before touching a control, and the one the form cannot infer: two switches
@@ -45,50 +45,50 @@ export const CapabilityFieldSchema = z.object({
45
45
  .boolean()
46
46
  .optional()
47
47
  .describe(
48
- "This value only takes effect after the sandbox is rebuilt, because it rides the image overlay. Shown as a chip beside the label — two switches side by side, identical in every visible way, can otherwise cost five seconds or five minutes with no way to tell which.",
48
+ "This value only takes effect after the sandbox is rebuilt, because it rides the image overlay. Shown as a chip beside the label: two switches side by side, identical in every visible way, can otherwise cost five seconds or five minutes with no way to tell which.",
49
49
  ),
50
50
  default: z.string().optional(),
51
51
  options: z
52
52
  .array(z.object({ value: z.string(), label: z.string() }))
53
53
  .optional()
54
54
  .describe("Turns the field into a select."),
55
- /* Gates this field on the answers already given — the SSH credential that only applies to the auth mode
55
+ /* Gates this field on the answers already given, the SSH credential that only applies to the auth mode
56
56
  * chosen, the gateway fields that belong to one VPN provider. A `when` condition (@intentic/base/when)
57
57
  * evaluated against the form's live values, so it re-reads as the user toggles.
58
58
  *
59
59
  * Refused at parse when it does not parse. A card is data an extension ships, and a condition nobody can
60
- * evaluate is not a field that is always shown or always hidden — it is a card whose author believes it
60
+ * evaluate is not a field that is always shown or always hidden, it is a card whose author believes it
61
61
  * asks something it never asks. Failing the manifest names the card; failing at render names nothing. */
62
62
  when: z
63
63
  .string()
64
64
  .refine(isWhenExpression, { message: "not a valid `when` condition" })
65
65
  .optional()
66
66
  .describe(
67
- "Only show this field while a condition over the answers already given holds — `auth == 'key'`, `provider in ['ipsec', 'fortinet']`, `!advanced`. Supports `&&`, `||`, `!`, comparisons and `in`.",
67
+ "Only show this field while a condition over the answers already given holds: `auth == 'key'`, `provider in ['ipsec', 'fortinet']`, `!advanced`. Supports `&&`, `||`, `!`, comparisons and `in`.",
68
68
  ),
69
- // A fixed value baked into the config rather than asked for — how a card pins a discriminator
69
+ // A fixed value baked into the config rather than asked for, how a card pins a discriminator
70
70
  // (platform="reddit", provider="stripe"). Rendered as nothing; sent as itself.
71
71
  value: z
72
72
  .string()
73
73
  .optional()
74
74
  .describe(
75
- 'A fixed value baked into the config rather than asked for — how a card pins its discriminator (platform="reddit", provider="stripe"). Renders as nothing.',
75
+ 'A fixed value baked into the config rather than asked for: how a card pins its discriminator (platform="reddit", provider="stripe"). Renders as nothing.',
76
76
  ),
77
- /* This field holds a TOTP seed — the base32 key (or otpauth:// URI) a service shows when enrolling an
77
+ /* This field holds a TOTP seed, the base32 key (or otpauth:// URI) a service shows when enrolling an
78
78
  * authenticator app. Declare it WITH `secret: true`: the seed is a durable second factor, so it is never
79
- * echoed and, unlike an ordinary secret, never enters the agent's environment either — the daemon mints the
79
+ * echoed and, unlike an ordinary secret, never enters the agent's environment either, the daemon mints the
80
80
  * six-digit codes on demand (`otp <name>` / GET /capabilities/<id>/otp) and only those cross, each dead
81
81
  * within its period. A cli entry whose env references a totp field therefore fails to parse (see below). */
82
82
  totp: z
83
83
  .boolean()
84
84
  .optional()
85
85
  .describe(
86
- "This field holds a TOTP seed — the base32 key or otpauth:// URI a service shows when enrolling an authenticator app. Declare it with `secret: true`. Unlike an ordinary secret it never enters the agent's environment: the daemon mints the six-digit codes on demand and only those cross.",
86
+ "This field holds a TOTP seed, the base32 key or otpauth:// URI a service shows when enrolling an authenticator app. Declare it with `secret: true`. Unlike an ordinary secret it never enters the agent's environment: the daemon mints the six-digit codes on demand and only those cross.",
87
87
  ),
88
88
  });
89
89
  export type CapabilityField = z.infer<typeof CapabilityFieldSchema>;
90
90
 
91
- /* WHETHER A FIELD IS IN PLAY, given what has been answered so far — and the only place that decides it.
91
+ /* WHETHER A FIELD IS IN PLAY, given what has been answered so far, and the only place that decides it.
92
92
  *
93
93
  * Two tiers ask this question about the same card. The web's form asks it to decide what to draw and what to
94
94
  * validate; the daemon asks it at install to decide which fields it may demand. They used to answer it with
@@ -98,7 +98,7 @@ export type CapabilityField = z.infer<typeof CapabilityFieldSchema>;
98
98
  * report about one card rather than as a broken rule.
99
99
  *
100
100
  * It lives beside the schema for the reason the description does: this is a fact about the shape, and the two
101
- * consumers are in different packages. Parsed per call rather than cached — a card has a handful of fields,
101
+ * consumers are in different packages. Parsed per call rather than cached, a card has a handful of fields,
102
102
  * this runs on a keystroke at worst, and a cache keyed by manifest strings is a map that outlives every
103
103
  * extension that ever declared one. */
104
104
  export const fieldApplies = (field: CapabilityField, values: Readonly<Record<string, unknown>>): boolean =>
@@ -109,7 +109,7 @@ export const fieldApplies = (field: CapabilityField, values: Readonly<Record<str
109
109
  const CatalogSchema = z.object({
110
110
  name: z.string().min(1),
111
111
  ...MARK_FIELDS,
112
- // ONE LINE — aim for 60 characters or fewer. The grid clamps this at two lines and a card sits beside two
112
+ // ONE LINE, aim for 60 characters or fewer. The grid clamps this at two lines and a card sits beside two
113
113
  // others in a pane the index column has already taken 16rem out of, so a paragraph here is a paragraph the
114
114
  // reader gets truncated. Everything longer belongs in `hint`, which the config form prints in full and the
115
115
  // catalog's search reads. Not capped in the schema: an extension published before this rule should still
@@ -118,16 +118,16 @@ const CatalogSchema = z.object({
118
118
  .string()
119
119
  .min(1)
120
120
  .describe(
121
- "ONE LINE — aim for 60 characters or fewer. The grid clamps it at two lines in a narrow pane, so a paragraph here is a paragraph the reader gets truncated. Everything longer belongs in `hint`.",
121
+ "ONE LINE: aim for 60 characters or fewer. The grid clamps it at two lines in a narrow pane, so a paragraph here is a paragraph the reader gets truncated. Everything longer belongs in `hint`.",
122
122
  ),
123
123
  category: z.string().min(1),
124
- // The paragraph. Shown under the add-form, and searched from the catalog — so the words that identify this
124
+ // The paragraph. Shown under the add-form, and searched from the catalog, so the words that identify this
125
125
  // card to someone hunting for it ("webauthn", "socket mode") belong here even when the tile can't show them.
126
126
  hint: z
127
127
  .string()
128
128
  .optional()
129
129
  .describe(
130
- 'The paragraph, shown under the add form and searched from the catalog — so the words that identify this card to someone hunting for it ("webauthn", "socket mode") belong here even when the tile cannot show them.',
130
+ 'The paragraph, shown under the add form and searched from the catalog, so the words that identify this card to someone hunting for it ("webauthn", "socket mode") belong here even when the tile cannot show them.',
131
131
  ),
132
132
  // The credential-creation walkthrough the install dialog renders (the platform catalog's guide shape).
133
133
  guide: z
@@ -151,24 +151,24 @@ const contributionBase = {
151
151
  fields: z.array(CapabilityFieldSchema),
152
152
  };
153
153
 
154
- /* A CAPABILITY CARD AS DATA. The catalog is the extensible layer; the HANDLERS are core — so an entry names one
154
+ /* A CAPABILITY CARD AS DATA. The catalog is the extensible layer; the HANDLERS are core, so an entry names one
155
155
  * of the kinds whose daemon-side machinery is fully generic over its data, and the machinery stays put. The
156
156
  * kinds NOT listed here are the ones whose card is one-to-one with a handler that owns real privilege (`docker`
157
157
  * bakes --privileged, `vpn` bakes NET_ADMIN, `extension` installs extensions, `devops` scaffolds repos): their
158
158
  * cards live in the platform catalog because separating card from handler would split one concept in two, and
159
159
  * because a manifest that could name them would be a manifest that grants itself privilege. That restriction is
160
- * this discriminated union, not a comment — a manifest naming any other kind fails to parse.
160
+ * this discriminated union, not a comment, a manifest naming any other kind fails to parse.
161
161
  *
162
162
  * `${id}` in a cli/host skill file is substituted with the instance name at apply time (so a host pack's tool
163
163
  * names read `mcp__my-laptop__run_command`), and, for `cli`, each `$ENVVAR` becomes its per-instance suffixed
164
- * name. A BROWSER pack's skill renders once per SITE rather than per instance — its seams are `${accounts}`
164
+ * name. A BROWSER pack's skill renders once per SITE rather than per instance, its seams are `${accounts}`
165
165
  * (the roster of connected accounts), `${tools}` (the core driving/connecting note) and `${site}` (the host,
166
166
  * for the generic card whose text can name no site of its own); `${id}` and per-field substitution do not
167
167
  * apply there (capabilities/account-skills.ts in the sandbox daemon). */
168
168
  export const CapabilityContributionSchema = z
169
169
  .discriminatedUnion("kind", [
170
170
  // A CLI tool the AGENT gets, authenticated: the env vars its shell receives (value templates over the
171
- // fields — `${field}` substitutes, `${field:uri}` percent-encodes), a SKILL.md cheatsheet, and an optional
171
+ // fields, `${field}` substitutes, `${field:uri}` percent-encodes), a SKILL.md cheatsheet, and an optional
172
172
  // image fragment holding the client binary (psql, mysql, whisper).
173
173
  z.object({
174
174
  ...contributionBase,
@@ -177,7 +177,7 @@ export const CapabilityContributionSchema = z
177
177
  env: z
178
178
  .record(z.string().regex(/^[A-Z][A-Z0-9_]*$/), z.string())
179
179
  .describe(
180
- "The environment the agent's shell gets, as value templates over the fields — `${field}` substitutes, `${field:uri}` percent-encodes. Each name is suffixed per instance.",
180
+ "The environment the agent's shell gets, as value templates over the fields: `${field}` substitutes, `${field:uri}` percent-encodes. Each name is suffixed per instance.",
181
181
  ),
182
182
  skill: z
183
183
  .string()
@@ -191,18 +191,18 @@ export const CapabilityContributionSchema = z
191
191
  }),
192
192
  /* A site the agent acts on AS THE OWNER, through the shared logged-in Chromium. `loginUrl` is what the
193
193
  * sign-in window opens; the profile it persists is the credential. `homeUrl` is where that same profile
194
- * opens once it HAS one — the owner's own hands on the connected browser, which a login page is the wrong
194
+ * opens once it HAS one, the owner's own hands on the connected browser, which a login page is the wrong
195
195
  * place to start (signed in, it only redirects). Two fields because for some platforms the login lives on
196
196
  * another site entirely (YouTube signs in at accounts.google.com), so one cannot be derived from the other.
197
197
  * No `env` and no `fragment`: the browser itself is core (one Chromium install serves every platform),
198
- * only the identity is per-entry. A card never declares the account's username/password either — those are
198
+ * only the identity is per-entry. A card never declares the account's username/password either, those are
199
199
  * CORE form fields on every browser card (the catalog appends them; the daemon's add validation accepts
200
200
  * them), because which box a login form wants filled is the same fact on every site.
201
201
  *
202
202
  * BOTH URLs ARE OPTIONAL, so that one card can be the GENERIC one: a site card pins them (Reddit knows
203
203
  * where Reddit signs in), and the generic "browser session" card asks for them on its form instead, which
204
- * is what lets a user connect a site nobody shipped a card for. A card must do one or the other — pin a
205
- * URL or declare a field that supplies it — and the daemon's apply says so on the form when neither does,
204
+ * is what lets a user connect a site nobody shipped a card for. A card must do one or the other, pin a
205
+ * URL or declare a field that supplies it, and the daemon's apply says so on the form when neither does,
206
206
  * because the alternative is a sign-in window that opens on nothing. */
207
207
  z.object({
208
208
  ...contributionBase,
@@ -211,22 +211,22 @@ export const CapabilityContributionSchema = z
211
211
  .url()
212
212
  .optional()
213
213
  .describe(
214
- "What the sign-in window opens; the profile it persists IS the credential. Optional so one card can be the generic one that asks for the URL on its form instead — but a card must either pin this or declare a field that supplies it, or the window opens on nothing.",
214
+ "What the sign-in window opens; the profile it persists IS the credential. Optional so one card can be the generic one that asks for the URL on its form instead, but a card must either pin this or declare a field that supplies it, or the window opens on nothing.",
215
215
  ),
216
216
  homeUrl: z
217
217
  .url()
218
218
  .optional()
219
219
  .describe(
220
- "Where that same profile opens once it HAS a session — the owner's own hands on the connected browser. Separate from loginUrl because for some platforms the login lives on another site entirely (YouTube signs in at accounts.google.com).",
220
+ "Where that same profile opens once it HAS a session: the owner's own hands on the connected browser. Separate from loginUrl because for some platforms the login lives on another site entirely (YouTube signs in at accounts.google.com).",
221
221
  ),
222
222
  skill: z
223
223
  .string()
224
224
  .min(1)
225
225
  .describe(
226
- "Checkout-relative SKILL.md teaching the agent this site's actions — rendered once per site, all its connected accounts on one roster (`${accounts}`), the core tool note at `${tools}`.",
226
+ "Checkout-relative SKILL.md teaching the agent this site's actions: rendered once per site, all its connected accounts on one roster (`${accounts}`), the core tool note at `${tools}`.",
227
227
  ),
228
228
  }),
229
- // An operating system a connected computer can run — the skill pack that teaches the agent THAT machine's
229
+ // An operating system a connected computer can run, the skill pack that teaches the agent THAT machine's
230
230
  // shell. The enrollment, the socket and the scope enforcement are core; only the pack varies.
231
231
  z.object({
232
232
  ...contributionBase,
@@ -234,13 +234,13 @@ export const CapabilityContributionSchema = z
234
234
  skill: z.string().min(1).describe("Checkout-relative SKILL.md teaching the agent that machine's shell."),
235
235
  }),
236
236
  /* A PRESET over a core kind: no payload at all, just a named card whose `fields` carry the defaults. What an
237
- * ACP agent needs is a command, so "OpenCode" is entirely a name, a logo and a filled-in form — which is
237
+ * ACP agent needs is a command, so "OpenCode" is entirely a name, a logo and a filled-in form, which is
238
238
  * exactly what a catalog row is. */
239
239
  z.object({ ...contributionBase, kind: z.literal("agent") }),
240
240
  ])
241
241
  .superRefine((spec, ctx) => {
242
242
  // The totp flag's one invariant, enforced where the manifest is parsed rather than trusted to authors: a
243
- // seed the daemon mints codes from must never ride the env into the agent's shell — that would hand the
243
+ // seed the daemon mints codes from must never ride the env into the agent's shell, that would hand the
244
244
  // agent the second factor itself instead of one expiring code at a time.
245
245
  if (spec.kind !== "cli") {
246
246
  return;
@@ -249,21 +249,21 @@ export const CapabilityContributionSchema = z
249
249
  if (Object.values(spec.env).some((template) => template.includes(`\${${field.key}}`) || template.includes(`\${${field.key}:uri}`))) {
250
250
  ctx.addIssue({
251
251
  code: "custom",
252
- message: `env must not reference the totp field "${field.key}" — the daemon mints codes from it instead`,
252
+ message: `env must not reference the totp field "${field.key}", the daemon mints codes from it instead`,
253
253
  });
254
254
  }
255
255
  }
256
256
  });
257
257
  export type CapabilityContribution = z.infer<typeof CapabilityContributionSchema>;
258
- // The arms carrying a per-instance SKILL.md — the daemon templates and installs these identically.
258
+ // The arms carrying a per-instance SKILL.md, the daemon templates and installs these identically.
259
259
  export type SkillContribution = Extract<CapabilityContribution, { skill: string }>;
260
260
 
261
261
  /* The config key a kind's cards PIN to their own id, so a stored capability can be traced back to the card that
262
- * made it — the daemon resolves the entry's handler data through it, and the web tells one card's instances from
262
+ * made it, the daemon resolves the entry's handler data through it, and the web tells one card's instances from
263
263
  * another's. `agent` has none on purpose: its cards are presets over one config shape, differing only in their
264
264
  * defaults, so every agent instance belongs to every agent card equally.
265
265
  *
266
- * Here, beside the schema, because it is a fact about the contribution shape — the daemon, the catalog and the
266
+ * Here, beside the schema, because it is a fact about the contribution shape, the daemon, the catalog and the
267
267
  * web all need it, and three copies of it is three chances for a card's instances to go missing. `satisfies`
268
268
  * rather than a lookup table so a new arm above is a compile error until this answers for it. */
269
269
  const DISCRIMINATOR = { cli: "provider", browser: "platform", host: "platform", agent: undefined } satisfies Record<
@@ -275,6 +275,6 @@ export const contributionDiscriminator = (kind: string): string | undefined => D
275
275
  export const capabilitiesPoint = {
276
276
  name: "capabilities",
277
277
  description:
278
- 'Capability cards this pack adds to the "+" grid — a connected CLI tool, a site the agent acts on as the owner through the shared browser, an operating system pack, or a preset over a core kind. The card and its form are data here; the machinery that acts on them is core, which is why a card may only name one of these four kinds.',
278
+ 'Capability cards this pack adds to the "+" grid: a connected CLI tool, a site the agent acts on as the owner through the shared browser, an operating system pack, or a preset over a core kind. The card and its form are data here; the machinery that acts on them is core, which is why a card may only name one of these four kinds.',
279
279
  schema: z.array(CapabilityContributionSchema),
280
280
  } as const satisfies ContributionPoint;
@@ -9,7 +9,7 @@ export const CommandContributionSchema = z.object({
9
9
  icon: z.string().optional().describe("A name from the host's icon set, drawn beside the title."),
10
10
  // An optional global keyboard shortcut, in the host's chord notation (`Mod`/`Ctrl`/`Shift`/`Alt` + key, e.g.
11
11
  // "Mod+Shift+K"; `Mod` = ⌘ on Apple, Ctrl elsewhere). It is DECLARED here so it rides the install dialog's
12
- // approval surface — a global shortcut is consequential, so like title/icon the manifest value is authoritative
12
+ // approval surface, a global shortcut is consequential, so like title/icon the manifest value is authoritative
13
13
  // and the host binds only what was approved. Whitespace-free; an unparseable chord simply never fires.
14
14
  keybinding: z
15
15
  .string()
@@ -18,12 +18,12 @@ export const CommandContributionSchema = z.object({
18
18
  .describe(
19
19
  'A global keyboard shortcut, e.g. "Mod+Shift+K" — `Mod` is ⌘ on Apple and Ctrl elsewhere. Declared here because a global shortcut is consequential: the owner approves it at install, and the host binds only what was approved.',
20
20
  ),
21
- /* When the KEYBINDING applies — a condition over the shell's context keys (`tabSurface == 'chat'`,
21
+ /* When the KEYBINDING applies, a condition over the shell's context keys (`tabSurface == 'chat'`,
22
22
  * `!editableTarget`; see @intentic/base/when). The palette ignores it: a command is always runnable by
23
23
  * name, and what a condition decides is whether the chord is claimed from whatever else would have had it.
24
24
  *
25
25
  * Declared here because it could not be declared anywhere. The shell's own commands used to gate on a
26
- * JavaScript predicate, which an extension has no way to ship — so every extension command took its chord
26
+ * JavaScript predicate, which an extension has no way to ship, so every extension command took its chord
27
27
  * globally, from every surface, including terminals where a bare key belongs to the program on the other
28
28
  * end. A condition an extension can write is what makes a contributed shortcut safe to grant. */
29
29
  when: z
@@ -31,7 +31,7 @@ export const CommandContributionSchema = z.object({
31
31
  .refine(isWhenExpression, { message: "not a valid `when` condition" })
32
32
  .optional()
33
33
  .describe(
34
- "When the shortcut applies, as a condition over the shell's context keys — `tabSurface == 'chat'`, `!editableTarget`. Without one the chord is claimed everywhere, including inside a terminal where a bare key belongs to the program running in it. The command palette ignores this: a command is always runnable by name.",
34
+ "When the shortcut applies, as a condition over the shell's context keys, `tabSurface == 'chat'`, `!editableTarget`. Without one the chord is claimed everywhere, including inside a terminal where a bare key belongs to the program running in it. The command palette ignores this: a command is always runnable by name.",
35
35
  ),
36
36
  });
37
37
  export type CommandContribution = z.infer<typeof CommandContributionSchema>;
@@ -2,11 +2,11 @@ import { z } from "zod";
2
2
  import type { ContributionPoint } from "../contribution-point.js";
3
3
 
4
4
  /* A per-directory document family the extension may register at runtime (api.documents.register): the provider
5
- * marks the directory rows it can explain in the Workspace tree, and the host opens its component as a tab —
5
+ * marks the directory rows it can explain in the Workspace tree, and the host opens its component as a tab,
6
6
  * see DocumentProviderRegistration.
7
7
  *
8
8
  * Only the id and the label are declared, deliberately. The consequential part of a viewer is which FILES it
9
- * takes over, and of a command its global shortcut — both are decided in the manifest because the owner must see
9
+ * takes over, and of a command its global shortcut, both are decided in the manifest because the owner must see
10
10
  * them. A document provider takes nothing over: it adds an icon to rows it has something for, and every one of
11
11
  * those rows is evidence the owner can see for themselves. So the manifest gates WHETHER the extension may mark
12
12
  * up the tree at all, and the per-row wording stays with the provider, which is the only thing that knows what
@@ -11,7 +11,7 @@ export const EnvironmentContributionSchema = z.object({
11
11
  .min(1)
12
12
  .refine((value) => !value.split("/").includes(".."), { message: "fragment must stay inside the checkout" })
13
13
  .describe(
14
- "Checkout-relative path to a file holding ONLY RUN and ENV instructions. FROM and privileged directives are rejected — those stay daemon-owned.",
14
+ "Checkout-relative path to a file holding ONLY RUN and ENV instructions. FROM and privileged directives are rejected: those stay daemon-owned.",
15
15
  ),
16
16
  });
17
17
  export type EnvironmentContribution = z.infer<typeof EnvironmentContributionSchema>;
@@ -19,6 +19,6 @@ export type EnvironmentContribution = z.infer<typeof EnvironmentContributionSche
19
19
  export const environmentPoint = {
20
20
  name: "environment",
21
21
  description:
22
- "A Dockerfile fragment baked into the sandbox image so your tools are actually installed at runtime — a whisper binary, a psql client. The owner approves the composed overlay and rebuilds out of band, so this does not take effect immediately.",
22
+ "A Dockerfile fragment baked into the sandbox image so your tools are actually installed at runtime: a whisper binary, a psql client. The owner approves the composed overlay and rebuilds out of band, so this does not take effect immediately.",
23
23
  schema: EnvironmentContributionSchema,
24
24
  } as const satisfies ContributionPoint;
@@ -1,24 +1,24 @@
1
1
  import { z } from "zod";
2
2
  import type { ContributionPoint } from "../contribution-point.js";
3
3
 
4
- /* WHICH WORKSPACE FILE MAKES THIS EXTENSION'S VIEW STALE — the extension's half of the core's
4
+ /* WHICH WORKSPACE FILE MAKES THIS EXTENSION'S VIEW STALE, the extension's half of the core's
5
5
  * WORKSPACE_STATE_FILES table (@intentic/sandbox-contract), in the same two fields so the browser can union them
6
6
  * without translating.
7
7
  *
8
8
  * An intentic workspace is file-first: the agent edits /work with its own file tools, out of band from every
9
9
  * HTTP route, and the daemon's filesystem watcher is the ONLY thing that can tell a browser its view went stale.
10
- * Before this contribution point existed an extension had no way into that push, so every one of them polled —
10
+ * Before this contribution point existed an extension had no way into that push, so every one of them polled,
11
11
  * and the core's table had to hardcode `automations`/`automation-approvals`, query keys owned by an extension,
12
12
  * because the extension itself couldn't declare them. Declaring is now the extension's job and unioning is the
13
13
  * host's.
14
14
  *
15
15
  * It rides the manifest rather than a runtime api.workspace.onDidChangeFiles for two reasons: the owner sees at
16
- * install which of their files an extension reads, and there is nothing imperative left to get wrong — no
16
+ * install which of their files an extension reads, and there is nothing imperative left to get wrong, no
17
17
  * subscribe, no unsubscribe, no listener that quietly stops firing. */
18
18
  export const FileContributionSchema = z.object({
19
- /* Workspace-root-relative, forward-slash — the space the watcher's changed paths arrive in. Matched by
19
+ /* Workspace-root-relative, forward-slash, the space the watcher's changed paths arrive in. Matched by
20
20
  * PREFIX, so one entry covers an exact file (`.intentic/config/automations.json`), a directory (`.intentic/config/drafts/`
21
- * — keep the trailing slash so it cannot match a sibling file) or a name family (`.intentic/environment.`).
21
+ *, keep the trailing slash so it cannot match a sibling file) or a name family (`.intentic/environment.`).
22
22
  * Deliberately not a glob: prefix is the whole matching rule on both sides of this union. */
23
23
  path: z
24
24
  .string()
@@ -27,21 +27,21 @@ export const FileContributionSchema = z.object({
27
27
  message: "path must be workspace-root-relative and stay inside the workspace",
28
28
  })
29
29
  .describe(
30
- "Workspace-root-relative, forward-slash, matched by prefix — so one entry covers an exact file (`.intentic/config/automations.json`), a directory (`.intentic/config/drafts/`, with the trailing slash so it cannot match a sibling file) or a name family (`.intentic/environment.`). Not a glob.",
30
+ "Workspace-root-relative, forward-slash, matched by prefix, so one entry covers an exact file (`.intentic/config/automations.json`), a directory (`.intentic/config/drafts/`, with the trailing slash so it cannot match a sibling file) or a name family (`.intentic/environment.`). Not a glob.",
31
31
  ),
32
- /* The browser query keys those contents feed — the first element of the extension's own
32
+ /* The browser query keys those contents feed, the first element of the extension's own
33
33
  * `api.sandbox.key(...)` keys, which is what makes them match (the sandbox id is a SUFFIX). Empty is not
34
34
  * allowed: a path that makes nothing stale is a declaration with no effect, and saying so at install beats
35
35
  * discovering it as a view that never refreshes.
36
36
  *
37
37
  * Keep the paths as narrow as the view actually needs. A broad prefix costs every connected browser a
38
38
  * refetch per matching write, and a write-heavy path (an index, a transcript, a log) turns that into a
39
- * request storm — the reason the core table leaves the daemon's own machine state off the push entirely. */
39
+ * request storm, the reason the core table leaves the daemon's own machine state off the push entirely. */
40
40
  invalidates: z
41
41
  .array(z.string().min(1))
42
42
  .min(1)
43
43
  .describe(
44
- "The query keys this path makes stale — the first element of your own api.sandbox.key(...) keys. Keep both this and the path as narrow as the view actually needs: a broad prefix costs every connected browser a refetch on every matching write.",
44
+ "The query keys this path makes stale, the first element of your own api.sandbox.key(...) keys. Keep both this and the path as narrow as the view actually needs: a broad prefix costs every connected browser a refetch on every matching write.",
45
45
  ),
46
46
  });
47
47
  export type FileContribution = z.infer<typeof FileContributionSchema>;
@@ -30,14 +30,14 @@ export * from "./views.js";
30
30
 
31
31
  /* EVERYTHING A MANIFEST MAY DECLARE. `contributes` is assembled from this list (manifest.ts), the authoring
32
32
  * JSON Schema is generated from it (json-schema.ts), and the SDK's surface guard reads the point names back out
33
- * of it — so the three cannot disagree about what this build supports.
33
+ * of it, so the three cannot disagree about what this build supports.
34
34
  *
35
35
  * Collected explicitly rather than by a module-load side effect, because two readers need the answer to be the
36
36
  * same every time it is asked: the wire contract's lock file, which is a committed document a diff has to be
37
37
  * able to guard, and the generated schema, which is committed too. A registry that filled itself as modules
38
38
  * happened to load would make both of those depend on import order.
39
39
  *
40
- * Adding a point is a file in this directory and a line here — points.test.ts fails when a file appears without
40
+ * Adding a point is a file in this directory and a line here, points.test.ts fails when a file appears without
41
41
  * the line, so the pair cannot come apart. */
42
42
  export const CONTRIBUTION_POINTS = [
43
43
  viewsPoint,
@@ -56,13 +56,13 @@ export const CONTRIBUTION_POINTS = [
56
56
  ] as const satisfies readonly ContributionPoint[];
57
57
 
58
58
  // The `contributes` shape those points assemble to: each point's key, its schema, optional. A mapped type
59
- // rather than a widened record so `manifest.contributes.views` keeps its exact type at every call site — the
59
+ // rather than a widened record so `manifest.contributes.views` keeps its exact type at every call site, the
60
60
  // whole point of the schema being typed at all.
61
61
  type ContributesShape = {
62
62
  [Point in (typeof CONTRIBUTION_POINTS)[number] as Point["name"]]: z.ZodOptional<Point["schema"]>;
63
63
  };
64
64
 
65
- /* The `contributes` object, assembled rather than hand-written — which is what makes adding a point a file plus
65
+ /* The `contributes` object, assembled rather than hand-written, which is what makes adding a point a file plus
66
66
  * a line above, instead of an edit to a schema thirteen unrelated features share.
67
67
  *
68
68
  * Each point's description rides `z.describe` onto its own key, so it survives into the generated authoring
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ContributionPoint } from "../contribution-point.js";
3
3
 
4
- // One narrowing field the generic automation editor draws for a source — a channel, a branch. `hint` is the
4
+ // One narrowing field the generic automation editor draws for a source, a channel, a branch. `hint` is the
5
5
  // sentence under the input, for a filter whose empty case is easy to get wrong.
6
6
  const TriggerFieldContributionSchema = z.object({
7
7
  label: z.string().min(1),
@@ -15,12 +15,12 @@ const TriggerFieldContributionSchema = z.object({
15
15
  * the provider extension is what lets a newly installed listener become configurable without a matching app
16
16
  * release.
17
17
  *
18
- * The daemon serves a provider-scoped control surface — GET /listeners/<provider>/state to reconcile, POST
18
+ * The daemon serves a provider-scoped control surface. GET /listeners/<provider>/state to reconcile, POST
19
19
  * …/dispatch to wake an automation (optionally holding a turn-stream), …/failure + …/status to report. The
20
20
  * daemon holds no provider connection itself.
21
21
  *
22
22
  * WHAT DISPATCHES IT IS OPEN. A gateway process (contributes.processes) is the usual answer and the one the
23
- * reconcile feed is shaped for — it holds a live connection the daemon must not. But an extension BACKEND can
23
+ * reconcile feed is shaped for, it holds a live connection the daemon must not. But an extension BACKEND can
24
24
  * dispatch through the same route by declaring the dispatch path in `permissions.daemon`, which is
25
25
  * how an area that learns things on its own schedule (an estate poller noticing a container died) contributes
26
26
  * a trigger without running a gateway at all. Declaring this with neither is legal and inert: the source is
@@ -54,12 +54,12 @@ export const ListenerContributionSchema = z.object({
54
54
  .describe(
55
55
  "Only for a source whose message events distinguish being addressed. Absent ⇒ the editor offers no mention-only filter, rather than inventing semantics you did not promise.",
56
56
  ),
57
- channel: TriggerFieldContributionSchema.describe("The primary narrowing filter — a channel, a room, a repo."),
58
- // A SECOND narrowing axis, for a source whose events carry one — a pipeline's git ref, so a trigger can
57
+ channel: TriggerFieldContributionSchema.describe("The primary narrowing filter, a channel, a room, a repo."),
58
+ // A SECOND narrowing axis, for a source whose events carry one, a pipeline's git ref, so a trigger can
59
59
  // say "the branch that ships" rather than "every agent's every failure". Absent ⇒ the editor offers
60
60
  // only the channel filter.
61
61
  branchField: TriggerFieldContributionSchema.optional().describe(
62
- 'A second narrowing axis, for a source whose events carry one — a pipeline\'s git ref, so a trigger can say "the branch that ships" rather than "every agent\'s every failure".',
62
+ 'A second narrowing axis, for a source whose events carry one: a pipeline\'s git ref, so a trigger can say "the branch that ships" rather than "every agent\'s every failure".',
63
63
  ),
64
64
  // The provider owns the payload vocabulary, so it also owns the first prompt that explains that payload.
65
65
  starterPrompt: z
@@ -76,6 +76,6 @@ export type ListenerContribution = z.infer<typeof ListenerContributionSchema>;
76
76
  export const listenerPoint = {
77
77
  name: "listener",
78
78
  description:
79
- "A realtime event source this extension supplies, so automations can trigger on it. One declaration feeds both halves: the daemon accepts these event types and serves this provider's control surface, and the automation editor derives its source picker, filters and starter prompt from it — so a newly installed listener is configurable without a matching app release.",
79
+ "A realtime event source this extension supplies, so automations can trigger on it. One declaration feeds both halves: the daemon accepts these event types and serves this provider's control surface, and the automation editor derives its source picker, filters and starter prompt from it, so a newly installed listener is configurable without a matching app release.",
80
80
  schema: ListenerContributionSchema,
81
81
  } as const satisfies ContributionPoint;
@@ -15,6 +15,6 @@ export type ProcessContribution = z.infer<typeof ProcessContributionSchema>;
15
15
  export const processesPoint = {
16
16
  name: "processes",
17
17
  description:
18
- "Long-lived background processes the daemon runs for this extension — a gateway holding a connection the daemon must not, a dev server. Managed the same way panel dev servers are, and startable and stoppable from the Extensions tab.",
18
+ "Long-lived background processes the daemon runs for this extension: a gateway holding a connection the daemon must not, a dev server. Managed the same way panel dev servers are, and startable and stoppable from the Extensions tab.",
19
19
  schema: z.array(ProcessContributionSchema),
20
20
  } as const satisfies ContributionPoint;
@@ -12,7 +12,7 @@ export const SettingContributionSchema = z.object({
12
12
  secret: z
13
13
  .boolean()
14
14
  .optional()
15
- .describe("Mask the value in the UI and strip it from reads — a set secret round-trips as “still set”, never as its value."),
15
+ .describe("Mask the value in the UI and strip it from reads: a set secret round-trips as 'still set', never as its value."),
16
16
  env: z
17
17
  .string()
18
18
  .regex(/^[A-Z][A-Z0-9_]*$/)
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import type { ContributionPoint } from "../contribution-point.js";
3
3
 
4
4
  /* A custom file viewer the extension may register at runtime (api.viewers.register): the host resolves an open
5
- * file to this viewer by extension, gets its content, and renders the registered component with it — the host
5
+ * file to this viewer by extension, gets its content, and renders the registered component with it, the host
6
6
  * keeps the fetch + open-file lifecycle and the daemon credentials; the extension only renders. This is the
7
7
  * non-sidebar contribution point. */
8
8
  export const ViewerContributionSchema = z.object({
@@ -10,20 +10,20 @@ export const ViewerContributionSchema = z.object({
10
10
  extensions: z
11
11
  .array(z.string().regex(/^[a-z0-9]+$/))
12
12
  .min(1)
13
- .describe('Bare file extensions, no dot — e.g. ["docx", "xlsx"].'),
13
+ .describe('Bare file extensions, no dot: e.g. ["docx", "xlsx"].'),
14
14
  /* `fetch` is how much of the file the host puts in the extension's hands, and it is a real choice:
15
- * text — decoded utf8 (`text` prop). For a format that IS text: svg, a subtitle track, a notebook.
16
- * blob — the whole file in memory (`blob` prop). For a format that must be parsed end to end before any of
15
+ * text, decoded utf8 (`text` prop). For a format that IS text: svg, a subtitle track, a notebook.
16
+ * blob, the whole file in memory (`blob` prop). For a format that must be parsed end to end before any of
17
17
  * it can be shown: a .docx, a spreadsheet. Bounded by the daemon's raw-read cap.
18
- * url — a streaming URL the component points an element at (`src` prop), never the bytes. For anything
18
+ * url , a streaming URL the component points an element at (`src` prop), never the bytes. For anything
19
19
  * RANGE-READ rather than parsed: audio and video, where the file may be gigabytes and the player
20
- * wants the header, the index and the seconds around the playhead — not the file. The host mints
20
+ * wants the header, the index and the seconds around the playhead, not the file. The host mints
21
21
  * the credential on that URL and keeps it out of the extension.
22
22
  */
23
23
  fetch: z
24
24
  .enum(["text", "blob", "url"])
25
25
  .describe(
26
- "How much of the file the host hands you. `text` for a format that is text (svg, a subtitle track). `blob` for one that must be parsed end to end before any of it shows (a .docx, a spreadsheet) — bounded by the daemon's raw-read cap. `url` for anything range-read rather than parsed (audio, video): your component gets a streaming URL to point an element at, never the bytes.",
26
+ "How much of the file the host hands you. `text` for a format that is text (svg, a subtitle track). `blob` for one that must be parsed end to end before any of it shows (a .docx, a spreadsheet), bounded by the daemon's raw-read cap. `url` for anything range-read rather than parsed (audio, video): your component gets a streaming URL to point an element at, never the bytes.",
27
27
  ),
28
28
  });
29
29
  export type ViewerContribution = z.infer<typeof ViewerContributionSchema>;
@@ -31,6 +31,6 @@ export type ViewerContribution = z.infer<typeof ViewerContributionSchema>;
31
31
  export const viewersPoint = {
32
32
  name: "viewers",
33
33
  description:
34
- "File formats this extension can render. The host resolves an opened file to your viewer by its extension, fetches the content, and renders your component with it — you keep none of the fetch lifecycle and none of the daemon credentials.",
34
+ "File formats this extension can render. The host resolves an opened file to your viewer by its extension, fetches the content, and renders your component with it: you keep none of the fetch lifecycle and none of the daemon credentials.",
35
35
  schema: z.array(ViewerContributionSchema),
36
36
  } as const satisfies ContributionPoint;
@@ -2,18 +2,18 @@ import type { ExtensionManifest } from "./manifest.js";
2
2
 
3
3
  /* WHAT AN UPDATE ASKS FOR, MECHANICALLY. The install dialog renders a manifest's contributions once; an update
4
4
  * is judged on what sits BETWEEN two manifests, and "read both and compare" is exactly the job a person will
5
- * skip on the fifth update. So each manifest is folded to a set of POWERS — the consequential facts an owner
5
+ * skip on the fifth update. So each manifest is folded to a set of POWERS, the consequential facts an owner
6
6
  * approved: which daemon routes it may call, which processes the daemon runs for it, what lands on the agent's
7
- * PATH, what may interrupt from another screen — each under a stable key (the identity compared) with a plain
7
+ * PATH, what may interrupt from another screen, each under a stable key (the identity compared) with a plain
8
8
  * sentence (what the reader sees). The diff is set arithmetic over the keys.
9
9
  *
10
10
  * Deliberately NOT here: plain settings (a new knob is config surface, not reach), display marks, category,
11
- * version. A power's INTERNALS moving (a process's command line, a fragment's contents) keeps its key — the
11
+ * version. A power's INTERNALS moving (a process's command line, a fragment's contents) keeps its key, the
12
12
  * code changed, which is what the sha pin and the agent diff-read answer for; this diff answers only "did the
13
13
  * set of things I approved grow". An empty `added` is what makes an update one click. */
14
14
 
15
15
  export interface PowersDiff {
16
- // Powers the new manifest declares that the installed one didn't — the reason an update re-asks.
16
+ // Powers the new manifest declares that the installed one didn't, the reason an update re-asks.
17
17
  readonly added: string[];
18
18
  readonly removed: string[];
19
19
  readonly unchanged: string[];
@@ -81,7 +81,7 @@ const powersOf = (manifest: ExtensionManifest): Map<string, string> => {
81
81
  };
82
82
 
83
83
  // `before` absent covers a first install: everything the manifest declares is `added`, which is exactly what
84
- // the install dialog already renders — one vocabulary for both moments.
84
+ // the install dialog already renders, one vocabulary for both moments.
85
85
  export const diffPowers = (before: ExtensionManifest | undefined, after: ExtensionManifest): PowersDiff => {
86
86
  const from = before === undefined ? new Map<string, string>() : powersOf(before);
87
87
  const to = powersOf(after);