summer-engine 4.0.0 → 4.3.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 (216) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +3 -2
  3. package/.codex-plugin/plugin.json +15 -11
  4. package/.cursor-plugin/plugin.json +5 -3
  5. package/.factory-plugin/plugin.json +3 -2
  6. package/AGENTS.md +2 -2
  7. package/CHANGELOG.md +48 -0
  8. package/README.md +21 -10
  9. package/dist/cli/command-usage.d.ts +8 -0
  10. package/dist/cli/command-usage.js +22 -0
  11. package/dist/cli/commands/config.js +3 -2
  12. package/dist/cli/commands/create.js +12 -3
  13. package/dist/cli/commands/list.d.ts +5 -0
  14. package/dist/cli/commands/list.js +30 -13
  15. package/dist/cli/commands/login.js +1 -1
  16. package/dist/cli/commands/memory.js +6 -2
  17. package/dist/cli/commands/ops.d.ts +20 -3
  18. package/dist/cli/commands/ops.js +60 -27
  19. package/dist/cli/commands/setup.d.ts +2 -0
  20. package/dist/cli/commands/setup.js +219 -16
  21. package/dist/cli/commands/skills.js +20 -7
  22. package/dist/cli/commands/status.d.ts +26 -0
  23. package/dist/cli/commands/status.js +36 -21
  24. package/dist/cli/commands/tool.js +4 -0
  25. package/dist/cli/index.js +2 -0
  26. package/dist/core/agent-host.d.ts +3 -0
  27. package/dist/core/agent-host.js +8 -2
  28. package/dist/core/capabilities/apps.d.ts +10 -10
  29. package/dist/core/capabilities/audit/args.d.ts +6 -6
  30. package/dist/core/capabilities/fabricate-mesh.d.ts +2 -2
  31. package/dist/core/capabilities/game-task-plan.d.ts +2 -2
  32. package/dist/core/capabilities/hdri-import.d.ts +2 -2
  33. package/dist/core/capabilities/motion-generation.d.ts +2 -2
  34. package/dist/core/capabilities/placement.d.ts +23 -23
  35. package/dist/core/capabilities/runtime-control.d.ts +38 -38
  36. package/dist/core/capabilities/seeing/args.d.ts +16 -16
  37. package/dist/core/capabilities/ui-control.d.ts +2 -2
  38. package/dist/core/capabilities/world-snapshot.d.ts +4 -4
  39. package/dist/core/cli-usage-beacon.d.ts +1 -0
  40. package/dist/core/cli-usage-beacon.js +18 -0
  41. package/dist/core/cli-usage.d.ts +49 -0
  42. package/dist/core/cli-usage.js +108 -0
  43. package/dist/core/feedback/client.d.ts +1 -1
  44. package/dist/core/feedback/client.js +3 -2
  45. package/dist/core/hosted-mcp.d.ts +7 -1
  46. package/dist/core/hosted-mcp.js +6 -4
  47. package/dist/core/library-search.d.ts +2 -2
  48. package/dist/core/ops/areas.d.ts +11 -0
  49. package/dist/core/ops/areas.js +24 -0
  50. package/dist/core/ops/catalog.d.ts +11 -0
  51. package/dist/core/ops/catalog.js +24 -1
  52. package/dist/core/ops/cloud.d.ts +10 -2
  53. package/dist/core/ops/cloud.js +51 -28
  54. package/dist/core/ops/contract.d.ts +2 -1
  55. package/dist/core/ops/contract.js +2 -10
  56. package/dist/core/ops/public-catalog.d.ts +48 -0
  57. package/dist/core/ops/public-catalog.js +56 -0
  58. package/dist/core/ops/search.d.ts +0 -1
  59. package/dist/core/ops/search.js +169 -37
  60. package/dist/core/telemetry.d.ts +10 -0
  61. package/dist/core/telemetry.js +58 -29
  62. package/dist/installer/agent-config.js +5 -0
  63. package/dist/installer/agent-table.d.ts +9 -0
  64. package/dist/installer/agent-table.js +23 -2
  65. package/dist/installer/cli-permissions.d.ts +65 -0
  66. package/dist/installer/cli-permissions.js +182 -0
  67. package/dist/installer/setup.d.ts +2 -0
  68. package/dist/installer/setup.js +3 -0
  69. package/dist/installer/skills-refresh.d.ts +29 -0
  70. package/dist/installer/skills-refresh.js +261 -0
  71. package/dist/installer/version-check.d.ts +22 -2
  72. package/dist/installer/version-check.js +66 -9
  73. package/dist/mcp/ops-surface.js +16 -6
  74. package/dist/mcp/server.d.ts +10 -0
  75. package/dist/mcp/server.js +38 -8
  76. package/dist/project-memory/agent-instructions.d.ts +47 -0
  77. package/dist/project-memory/agent-instructions.js +226 -0
  78. package/gemini-extension.json +3 -2
  79. package/integrations/README.md +1 -1
  80. package/integrations/claude/README.md +6 -0
  81. package/integrations/claude/manifest-target.json +4 -0
  82. package/integrations/gemini/README.md +11 -0
  83. package/integrations/windsurf/README.md +1 -1
  84. package/library/skills/3d-lighting/SKILL.md +16 -0
  85. package/library/skills/README.md +5 -4
  86. package/library/skills/adaptive-music/SKILL.md +21 -0
  87. package/library/skills/agent-playtesting/SKILL.md +22 -0
  88. package/library/skills/ai-characters-in-games/SKILL.md +15 -0
  89. package/library/skills/ambient-bed/SKILL.md +16 -0
  90. package/library/skills/animated-loop/SKILL.md +19 -0
  91. package/library/skills/animation-tree/SKILL.md +26 -0
  92. package/library/skills/art-direction/SKILL.md +14 -0
  93. package/library/skills/asset-strategy/SKILL.md +30 -0
  94. package/library/skills/audio-direction/SKILL.md +16 -0
  95. package/library/skills/auto-fire-targeting/SKILL.md +14 -0
  96. package/library/skills/brainstorm-game/SKILL.md +13 -0
  97. package/library/skills/browse-templates/SKILL.md +10 -0
  98. package/library/skills/camera-rigs/SKILL.md +20 -0
  99. package/library/skills/character-animation-wiring/SKILL.md +24 -0
  100. package/library/skills/character-model/SKILL.md +28 -0
  101. package/library/skills/character-movement/SKILL.md +24 -0
  102. package/library/skills/character-portrait/SKILL.md +15 -0
  103. package/library/skills/cinematic-cutscene/SKILL.md +21 -0
  104. package/library/skills/combat-basics/SKILL.md +19 -0
  105. package/library/skills/compatibility-renderer-traps/SKILL.md +11 -0
  106. package/library/skills/concept-art/SKILL.md +13 -0
  107. package/library/skills/concept-to-level/SKILL.md +20 -1
  108. package/library/skills/concept-to-level/resource.yaml +2 -2
  109. package/library/skills/create-asset-sheet/SKILL.md +18 -0
  110. package/library/skills/debug/SKILL.md +32 -0
  111. package/library/skills/debugging-game-feel/SKILL.md +12 -0
  112. package/library/skills/design-level/SKILL.md +17 -0
  113. package/library/skills/design-mechanic/SKILL.md +17 -0
  114. package/library/skills/design-npc/SKILL.md +21 -0
  115. package/library/skills/diagnosing-perf-regressions/SKILL.md +12 -0
  116. package/library/skills/driving-the-editor-ui/SKILL.md +23 -0
  117. package/library/skills/environment-kit/SKILL.md +23 -0
  118. package/library/skills/export-and-ship/SKILL.md +23 -0
  119. package/library/skills/fabricating-assets/SKILL.md +23 -0
  120. package/library/skills/facial-and-lipsync/SKILL.md +22 -0
  121. package/library/skills/fps-controller/SKILL.md +17 -0
  122. package/library/skills/game-feel/SKILL.md +26 -0
  123. package/library/skills/gameskill/SKILL.md +11 -0
  124. package/library/skills/gdscript-patterns/SKILL.md +15 -0
  125. package/library/skills/generate-motion/SKILL.md +21 -0
  126. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +17 -0
  127. package/library/skills/grow-analytics/SKILL.md +10 -0
  128. package/library/skills/headless-scripting/SKILL.md +13 -0
  129. package/library/skills/in-game-purchases/SKILL.md +11 -0
  130. package/library/skills/instantiate-asset-pack/SKILL.md +17 -0
  131. package/library/skills/make-game/SKILL.md +29 -0
  132. package/library/skills/multiplayer/SKILL.md +12 -0
  133. package/library/skills/multiplayer-movement/SKILL.md +18 -0
  134. package/library/skills/multiplayer-project/SKILL.md +17 -0
  135. package/library/skills/multiplayer-publish/SKILL.md +17 -5
  136. package/library/skills/multiplayer-state/SKILL.md +16 -0
  137. package/library/skills/multiplayer-testing/SKILL.md +15 -0
  138. package/library/skills/music-track/SKILL.md +16 -0
  139. package/library/skills/navigate-summer/SKILL.md +15 -0
  140. package/library/skills/new-project/SKILL.md +11 -0
  141. package/library/skills/organic-model/SKILL.md +24 -0
  142. package/library/skills/pixel-art/SKILL.md +15 -0
  143. package/library/skills/play/SKILL.md +18 -0
  144. package/library/skills/playtesting-a-feature/SKILL.md +23 -0
  145. package/library/skills/procedural-animation/SKILL.md +18 -0
  146. package/library/skills/prop-model/SKILL.md +23 -0
  147. package/library/skills/publish-your-game/SKILL.md +27 -0
  148. package/library/skills/release-readiness/SKILL.md +12 -0
  149. package/library/skills/remote-deploy/SKILL.md +14 -0
  150. package/library/skills/retarget/SKILL.md +20 -0
  151. package/library/skills/running-in-the-cloud/SKILL.md +10 -0
  152. package/library/skills/save-load/SKILL.md +15 -0
  153. package/library/skills/scene-composition/SKILL.md +17 -0
  154. package/library/skills/scene-hierarchy-design/SKILL.md +24 -0
  155. package/library/skills/scene-scripting/SKILL.md +30 -0
  156. package/library/skills/scene-to-level/SKILL.md +22 -0
  157. package/library/skills/skill-test/SKILL.md +10 -0
  158. package/library/skills/skybox-panorama/SKILL.md +20 -0
  159. package/library/skills/sound-effect/SKILL.md +23 -0
  160. package/library/skills/spatial-placement/SKILL.md +30 -0
  161. package/library/skills/sprite-sheet/SKILL.md +23 -0
  162. package/library/skills/store-art/SKILL.md +11 -0
  163. package/library/skills/store-listing/SKILL.md +10 -0
  164. package/library/skills/summer-analytics/SKILL.md +15 -0
  165. package/library/skills/summer-apps/SKILL.md +29 -0
  166. package/library/skills/summer-assets/SKILL.md +31 -1
  167. package/library/skills/summer-assets/resource.yaml +2 -2
  168. package/library/skills/summer-cli/SKILL.md +133 -0
  169. package/library/skills/summer-cli/resource.yaml +31 -0
  170. package/library/skills/summer-friends/SKILL.md +14 -0
  171. package/library/skills/summer-leaderboards/SKILL.md +16 -0
  172. package/library/skills/summer-match-results/SKILL.md +17 -0
  173. package/library/skills/summer-matchmaking/SKILL.md +17 -0
  174. package/library/skills/summer-parties/SKILL.md +14 -0
  175. package/library/skills/summer-player-data/SKILL.md +14 -0
  176. package/library/skills/summer-store/SKILL.md +15 -0
  177. package/library/skills/summer-world-chat/SKILL.md +14 -0
  178. package/library/skills/summer-world-saves/SKILL.md +14 -0
  179. package/library/skills/text-to-motion/SKILL.md +15 -0
  180. package/library/skills/tileable-texture/SKILL.md +18 -0
  181. package/library/skills/trailer-shot/SKILL.md +18 -0
  182. package/library/skills/tune-performance/SKILL.md +26 -0
  183. package/library/skills/ui-basics/SKILL.md +14 -0
  184. package/library/skills/ui-graphics/SKILL.md +17 -0
  185. package/library/skills/use-widget-asset/SKILL.md +14 -0
  186. package/library/skills/using-summer/SKILL.md +26 -0
  187. package/library/skills/using-summer/resource.yaml +2 -1
  188. package/library/skills/vehicle-model/SKILL.md +27 -0
  189. package/library/skills/verifying-scenes/SKILL.md +29 -0
  190. package/library/skills/vfx-dissolve/SKILL.md +19 -0
  191. package/library/skills/vfx-fire/SKILL.md +26 -0
  192. package/library/skills/vfx-hit-spark/SKILL.md +23 -0
  193. package/library/skills/vfx-lightning/SKILL.md +23 -0
  194. package/library/skills/vfx-magic-glow/SKILL.md +23 -0
  195. package/library/skills/vfx-muzzle-flash/SKILL.md +23 -0
  196. package/library/skills/vfx-smoke/SKILL.md +26 -0
  197. package/library/skills/vfx-water-ripple/SKILL.md +23 -0
  198. package/library/skills/voice-line/SKILL.md +16 -0
  199. package/library/skills/web-and-touch-input/SKILL.md +19 -0
  200. package/library/skills/web-compatibility-look/SKILL.md +20 -0
  201. package/library/skills/world-building-3d/SKILL.md +28 -0
  202. package/package.json +3 -2
  203. package/registry/generated/counts.json +2 -2
  204. package/registry/generated/gemini-extension.json +3 -2
  205. package/registry/generated/index.json +157 -118
  206. package/registry/generated/marketplace.claude.json +2 -2
  207. package/registry/generated/plugin.claude-directory.json +168 -0
  208. package/registry/generated/plugin.claude.json +3 -2
  209. package/registry/generated/plugin.codex.json +15 -11
  210. package/registry/generated/plugin.cursor.json +5 -3
  211. package/registry/generated/plugin.factory.json +3 -2
  212. package/registry/generated/server.json +11 -2
  213. package/registry/generated/skills-index.md +5 -4
  214. package/registry/generated/skills-registry.json +16 -2
  215. package/registry/operations/legacy-names.json +35 -0
  216. package/registry/operations/public-catalog.json +33160 -0
@@ -98,12 +98,12 @@ export declare const searchLibraryInputSchema: z.ZodObject<{
98
98
  include_preview: z.ZodOptional<z.ZodBoolean>;
99
99
  }, "strict", z.ZodTypeAny, {
100
100
  query: string;
101
- kinds?: ("template" | "tool" | "reference" | "skill" | "example" | "collection")[] | undefined;
101
+ kinds?: ("template" | "tool" | "skill" | "reference" | "example" | "collection")[] | undefined;
102
102
  limit?: number | undefined;
103
103
  include_preview?: boolean | undefined;
104
104
  }, {
105
105
  query: string;
106
- kinds?: ("template" | "tool" | "reference" | "skill" | "example" | "collection")[] | undefined;
106
+ kinds?: ("template" | "tool" | "skill" | "reference" | "example" | "collection")[] | undefined;
107
107
  limit?: number | undefined;
108
108
  include_preview?: boolean | undefined;
109
109
  }>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Where operations live and run, the part scripts/ needs too. No imports:
3
+ * scripts/validate-library loads this file as plain TypeScript to write the
4
+ * shell command of each tool a skill names.
5
+ */
6
+ /**
7
+ * Areas with operations today: each is one `summer <area> <action>` command
8
+ * (src/cli/commands/ops.ts). CLI command words stay out of this list.
9
+ */
10
+ export declare const CLI_AREAS: readonly ["team", "profile", "docs", "assets", "makers", "jobs", "projects", "plans", "games", "store", "jams", "pricing", "analytics", "experiments", "marketing", "content", "players", "economy", "inbox", "apps", "studio", "chats", "stories", "plugins", "engine", "account"];
11
+ export declare function isLocalOp(op: string): boolean;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Where operations live and run, the part scripts/ needs too. No imports:
3
+ * scripts/validate-library loads this file as plain TypeScript to write the
4
+ * shell command of each tool a skill names.
5
+ */
6
+ /**
7
+ * Areas with operations today: each is one `summer <area> <action>` command
8
+ * (src/cli/commands/ops.ts). CLI command words stay out of this list.
9
+ */
10
+ export const CLI_AREAS = [
11
+ "team", "profile", "docs", "assets", "makers", "jobs", "projects", "plans", "games", "store", "jams", "pricing",
12
+ "analytics", "experiments", "marketing", "content", "players", "economy", "inbox", "apps", "studio", "chats", "stories",
13
+ "plugins", "engine", "account",
14
+ ];
15
+ /**
16
+ * Operations that run in this package: everything in `engine`, the library
17
+ * (`docs`, apart from the Studio workflows, which are cloud), opening a
18
+ * page or an editor surface, docking an App in the editor, and uploading a
19
+ * local export. Everything else runs on the hosted server.
20
+ */
21
+ const LOCAL_OPS = new Set(["docs.search", "docs.read", "docs.feedback", "docs.plan", "docs.engine_api", "studio.open", "apps.dock", "apps.publish_folder", "store.upload_file"]);
22
+ export function isLocalOp(op) {
23
+ return op.startsWith("engine.") || LOCAL_OPS.has(op);
24
+ }
@@ -18,6 +18,10 @@ export interface CatalogEntry {
18
18
  legacy?: string[];
19
19
  /** The exact input JSON Schema (search results and describe carry it). */
20
20
  input?: Record<string, unknown>;
21
+ /** A cloud operation listed from the shipped catalog while no one is signed in: it runs after `summer login`. */
22
+ needsSignIn?: true;
23
+ /** Search words only, never printed: the library's topics for docs.search ("add multiplayer" is a how-to). */
24
+ topics?: string[];
21
25
  }
22
26
  /**
23
27
  * The operations this package runs (engine and local), from the shipped
@@ -32,6 +36,13 @@ export declare function localInputSchema(op: string): Record<string, unknown> |
32
36
  * A local operation in the contract's wire form (registry/schemas/operation.schema.json):
33
37
  * what ops.describe answers and what the contract test validates.
34
38
  */
39
+ /**
40
+ * The operation when it is a real one (this package runs it, or the shipped
41
+ * catalog lists it), else null. Usage lines name an operation only through
42
+ * this, so a word someone typed (`summer engine my-secret-game`) never
43
+ * leaves the machine as an operation name.
44
+ */
45
+ export declare function knownOp(op: string | null | undefined): string | null;
35
46
  export declare function localWireForm(op: string): Record<string, unknown> | null;
36
47
  /**
37
48
  * The first problem a JSON Schema's top level finds in an input: a missing
@@ -5,6 +5,7 @@ import { loadLibraryIndex } from "../library-search.js";
5
5
  import { PACKAGE_ROOT } from "../package-root.js";
6
6
  import { CONTRACT_VERSION, isLocalOp, legacyNames, LOCAL_RUNNERS, mcpNameOf, MIN_APPROVAL } from "./contract.js";
7
7
  import { ENGINE_SPLIT_OPS, engineOpDef, isSplitOp, splitInputSchema } from "./engine.js";
8
+ import { shippedTitle } from "./public-catalog.js";
8
9
  /** A local tool's effect from its registry authority: scene edits and project files are writes. */
9
10
  function effectOf(authority) {
10
11
  if (authority?.publish)
@@ -26,7 +27,8 @@ function entryFor(op, toolName, tool, legacy) {
26
27
  const summary = def?.summary ?? (tool.summary ?? "").slice(0, 300);
27
28
  return {
28
29
  name: op,
29
- title: def?.title ?? titleOf(summary, op),
30
+ // The hosted catalog's title when it has the op too (docs.search: "Search Summer docs", not "Search").
31
+ title: def?.title ?? shippedTitle(op) ?? titleOf(summary, op),
30
32
  summary,
31
33
  effect,
32
34
  approval: MIN_APPROVAL[effect],
@@ -67,9 +69,19 @@ export function localEntries() {
67
69
  continue;
68
70
  out.set(row.op, entryFor(row.op, toolName, tool, name));
69
71
  }
72
+ const docsSearch = out.get("docs.search");
73
+ if (docsSearch)
74
+ out.set("docs.search", { ...docsSearch, topics: libraryTopics() });
70
75
  entriesCache = [...out.values()];
71
76
  return entriesCache;
72
77
  }
78
+ /** The words of every skill, template and example slug (multiplayer, fps, lighting...): what the library teaches. */
79
+ function libraryTopics() {
80
+ const slugs = loadLibraryIndex()
81
+ .filter((entry) => entry.kind !== "tool" && entry.kind !== "reference")
82
+ .flatMap((entry) => entry.id.replace(/^[a-z]+\//, "").split("-"));
83
+ return [...new Set(slugs)].filter((word) => word.length > 2 && !/^\d/.test(word));
84
+ }
73
85
  function descriptorSchema(toolName) {
74
86
  const record = loadLibraryIndex().find((candidate) => candidate.kind === "tool" && candidate.mcp_tool_name === toolName);
75
87
  const slug = record?.id.replace(/^tool\//, "");
@@ -95,6 +107,17 @@ export function localInputSchema(op) {
95
107
  * A local operation in the contract's wire form (registry/schemas/operation.schema.json):
96
108
  * what ops.describe answers and what the contract test validates.
97
109
  */
110
+ /**
111
+ * The operation when it is a real one (this package runs it, or the shipped
112
+ * catalog lists it), else null. Usage lines name an operation only through
113
+ * this, so a word someone typed (`summer engine my-secret-game`) never
114
+ * leaves the machine as an operation name.
115
+ */
116
+ export function knownOp(op) {
117
+ if (!op)
118
+ return null;
119
+ return localEntries().some((entry) => entry.name === op) || shippedTitle(op) !== undefined ? op : null;
120
+ }
98
121
  export function localWireForm(op) {
99
122
  const entry = localEntries().find((candidate) => candidate.name === op);
100
123
  if (!entry)
@@ -42,10 +42,18 @@ export declare function hostedCallFailure(error: unknown, call: {
42
42
  export declare function answerOfHosted(result: Record<string, unknown>): Answer;
43
43
  /** Runs a tool on the hosted v4 surface: the MCP's mounted client or the CLI's one-shot call. */
44
44
  export type HostedCall = (name: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
45
+ /**
46
+ * ops.describe of a cloud operation when Summer's server could not answer it
47
+ * (no sign-in, no network): the operation from the shipped catalog, with a
48
+ * warning. Null when the catalog has no such operation; the failure stands.
49
+ */
50
+ export declare function describeFromShipped(name: string, failure: Answer): Answer | null;
45
51
  /**
46
52
  * One ranked list of local and cloud operations for a plain-words query.
47
- * Local hits carry their input schema from the library descriptor. When the
48
- * hosted server cannot be asked, the local hits come back with a warning.
53
+ * Every cloud operation comes from the shipped catalog (public-catalog.ts),
54
+ * so search finds it signed out, marked needsSignIn; signed in, the server's
55
+ * own search lays its live rows over the shipped ones (and adds newer
56
+ * operations). Local hits carry their input schema from the library descriptor.
49
57
  */
50
58
  export declare function searchEverywhere(query: string, filters: {
51
59
  area?: string;
@@ -1,9 +1,10 @@
1
1
  import { defaultHostedConnectDependencies, hostedConnectFailure, HostedUnreachableError, httpStatusOf } from "../hosted-mcp.js";
2
2
  import { OAuthError, resolveMcpResourceUrl } from "../oauth.js";
3
3
  import { localEntries, localInputSchema } from "./catalog.js";
4
- import { errorAnswer, isLocalOp } from "./contract.js";
4
+ import { errorAnswer, isLocalOp, resolveOpName } from "./contract.js";
5
+ import { shippedCloudEntries, shippedWireForm } from "./public-catalog.js";
5
6
  import { withOutField } from "./save-files.js";
6
- import { scoreEntry, searchEntries } from "./search.js";
7
+ import { searchEntries } from "./search.js";
7
8
  /**
8
9
  * The hosted Summer server's v4 surface: the same address with `?surface=v4`
9
10
  * (it keeps serving 3.x tools to every request that does not ask). Cloud
@@ -139,37 +140,59 @@ export function answerOfHosted(result) {
139
140
  }
140
141
  return result.isError === true ? errorAnswer("unavailable", first.slice(0, 300) || "The Summer server did not answer.") : { ok: true, status: "done", result: { text: first } };
141
142
  }
143
+ /** Failures that mean Summer's server did not describe the operation, so the shipped catalog may. */
144
+ const DID_NOT_ANSWER = new Set(["not_signed_in", "forbidden", "rate_limited", "unavailable"]);
145
+ /**
146
+ * ops.describe of a cloud operation when Summer's server could not answer it
147
+ * (no sign-in, no network): the operation from the shipped catalog, with a
148
+ * warning. Null when the catalog has no such operation; the failure stands.
149
+ */
150
+ export function describeFromShipped(name, failure) {
151
+ // The server's own answer stands (not_found: it no longer has the operation).
152
+ if (failure.ok || !DID_NOT_ANSWER.has(failure.error.code))
153
+ return null;
154
+ const operation = shippedWireForm(resolveOpName(name));
155
+ if (!operation)
156
+ return null;
157
+ const warning = failure.error.code === "not_signed_in"
158
+ ? "Not signed in: this is the catalog in this version; the operation runs after `summer login`."
159
+ : `Summer's server did not answer (${failure.error.message}); this is the catalog in this version.`;
160
+ return { ok: true, status: "done", result: { operation }, warnings: [warning] };
161
+ }
162
+ /** The warning when cloud operations come from the shipped catalog, and whether that is because no one is signed in. */
163
+ function shippedReason(answer) {
164
+ if (!answer.ok && answer.error.code === "not_signed_in") {
165
+ return { warning: "Not signed in: cloud operations are listed from the catalog in this version and run after `summer login` (needsSignIn).", signedOut: true };
166
+ }
167
+ return { warning: `Cloud operations are listed from the catalog in this version; Summer's server did not search: ${answer.ok ? "no answer" : answer.error.message}`, signedOut: false };
168
+ }
142
169
  /**
143
170
  * One ranked list of local and cloud operations for a plain-words query.
144
- * Local hits carry their input schema from the library descriptor. When the
145
- * hosted server cannot be asked, the local hits come back with a warning.
171
+ * Every cloud operation comes from the shipped catalog (public-catalog.ts),
172
+ * so search finds it signed out, marked needsSignIn; signed in, the server's
173
+ * own search lays its live rows over the shipped ones (and adds newer
174
+ * operations). Local hits carry their input schema from the library descriptor.
146
175
  */
147
176
  export async function searchEverywhere(query, filters, call, isDirect = () => false) {
148
- const local = searchEntries(localEntries(), query, filters).map((entry) => ({
149
- ...entry,
150
- input: localInputSchema(entry.name) ?? { type: "object" },
151
- mcpTool: entry.mcpTool && isDirect(entry.mcpTool) ? entry.mcpTool : undefined,
152
- }));
153
- let cloud = [];
154
- let warning = null;
177
+ let live = [];
178
+ let reason = null;
155
179
  try {
156
- const answer = answerOfHosted(await call("summer_search", { query, ...(filters.area ? { area: filters.area } : {}), limit: filters.limit }));
157
- // The operations that save files take `out` here (save-files.ts), so their input shows it.
158
- if (answer.ok && answer.status === "done") {
159
- cloud = (answer.result.items ?? [])
160
- .filter((entry) => !isLocalOp(entry.name))
161
- .map((entry) => (entry.input ? { ...entry, input: withOutField(entry.name, entry.input) } : entry));
162
- }
163
- else if (!answer.ok)
164
- warning = `Cloud operations were not searched: ${answer.error.message}`;
180
+ const answer = answerOfHosted(await call("summer_search", { query, ...(filters.area ? { area: filters.area } : {}), limit: 20 }));
181
+ if (answer.ok && answer.status === "done")
182
+ live = (answer.result.items ?? []).filter((entry) => !isLocalOp(entry.name));
183
+ else
184
+ reason = shippedReason(answer);
165
185
  }
166
186
  catch (error) {
167
- warning = `Cloud operations were not searched: ${error instanceof Error ? error.message : String(error)}`;
168
- }
169
- const items = [...local, ...cloud]
170
- .map((entry) => ({ entry, score: scoreEntry(entry, query) }))
171
- .sort((a, b) => b.score - a.score)
172
- .slice(0, filters.limit)
173
- .map(({ entry }) => entry);
174
- return { items, warning };
187
+ reason = shippedReason(hostedCallFailure(error, { op: "ops.search", read: true }));
188
+ }
189
+ const cloud = new Map(shippedCloudEntries().map((entry) => [entry.name, reason?.signedOut ? { ...entry, needsSignIn: true } : entry]));
190
+ // The operations that save files take `out` here (save-files.ts), so their input shows it.
191
+ for (const entry of live) {
192
+ cloud.set(entry.name, { ...cloud.get(entry.name), ...entry, ...(entry.input ? { input: withOutField(entry.name, entry.input) } : {}) });
193
+ }
194
+ const items = searchEntries([...localEntries(), ...cloud.values()], query, filters).map(({ topics: _topics, ...entry }) => isLocalOp(entry.name)
195
+ ? { ...entry, input: localInputSchema(entry.name) ?? { type: "object" }, mcpTool: entry.mcpTool && isDirect(entry.mcpTool) ? entry.mcpTool : undefined }
196
+ : entry);
197
+ return { items, warning: reason?.warning ?? null };
175
198
  }
@@ -1,3 +1,4 @@
1
+ import { isLocalOp } from "./areas.js";
1
2
  /**
2
3
  * The Summer operation catalog, the part this package needs (contract 1).
3
4
  * Every Summer operation has one name (`area.action`), one effect, one
@@ -100,7 +101,7 @@ export declare function resolveOpName(name: string): string;
100
101
  * (apps.publish_folder reads a folder on disk; apps.publish takes files).
101
102
  */
102
103
  export declare const LOCAL_RUNNERS: Readonly<Record<string, string>>;
103
- export declare function isLocalOp(op: string): boolean;
104
+ export { isLocalOp };
104
105
  /**
105
106
  * The local 3.x tools that run an operation here, first choice first: the
106
107
  * tool the op was renamed from before the tools merged into it.
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { PACKAGE_ROOT } from "../package-root.js";
4
+ import { isLocalOp } from "./areas.js";
4
5
  /**
5
6
  * The Summer operation catalog, the part this package needs (contract 1).
6
7
  * Every Summer operation has one name (`area.action`), one effect, one
@@ -65,22 +66,13 @@ export function resolveOpName(name) {
65
66
  const trimmed = name.trim();
66
67
  return legacyNames()[trimmed]?.op ?? trimmed;
67
68
  }
68
- /**
69
- * Operations that run in this package: everything in `engine`, the library
70
- * (`docs`, apart from the Studio workflows, which are cloud), opening a
71
- * page or an editor surface, docking an App in the editor, and uploading a
72
- * local export. Everything else runs on the hosted server.
73
- */
74
- const LOCAL_OPS = new Set(["docs.search", "docs.read", "docs.feedback", "docs.plan", "docs.engine_api", "studio.open", "apps.dock", "apps.publish_folder", "store.upload_file"]);
75
69
  /**
76
70
  * Local operations a 3.x tool runs although legacy-names.json maps that
77
71
  * tool to a cloud operation: the local-only input is its own operation
78
72
  * (apps.publish_folder reads a folder on disk; apps.publish takes files).
79
73
  */
80
74
  export const LOCAL_RUNNERS = { "apps.publish_folder": "summer_app_publish" };
81
- export function isLocalOp(op) {
82
- return op.startsWith("engine.") || LOCAL_OPS.has(op);
83
- }
75
+ export { isLocalOp };
84
76
  /**
85
77
  * The local 3.x tools that run an operation here, first choice first: the
86
78
  * tool the op was renamed from before the tools merged into it.
@@ -0,0 +1,48 @@
1
+ import type { CatalogEntry } from "./catalog.js";
2
+ import { type Approval, type Effect } from "./contract.js";
3
+ export interface PublicOperation {
4
+ name: string;
5
+ title: string;
6
+ summary: string;
7
+ effect: Effect;
8
+ approval: Approval;
9
+ permission: string;
10
+ provider: "cloud";
11
+ auth: string;
12
+ status: "stable" | "preview" | "deprecated";
13
+ since: string;
14
+ mcpTool: string;
15
+ direct: string[];
16
+ idempotencyKey?: "required" | "optional";
17
+ job?: {
18
+ typicalSeconds: number;
19
+ };
20
+ input: Record<string, unknown>;
21
+ output: Record<string, unknown>;
22
+ legacy?: string[];
23
+ tags?: string[];
24
+ examples: Array<{
25
+ input: Record<string, unknown>;
26
+ note: string;
27
+ }>;
28
+ deprecated?: {
29
+ replacedBy: string;
30
+ after: string;
31
+ };
32
+ }
33
+ export interface PublicCatalog {
34
+ contract: number;
35
+ operations: PublicOperation[];
36
+ /** The operations the server leaves to this package (engine and local ones), with their 3.x names. */
37
+ localOperations: Array<{
38
+ name: string;
39
+ legacy: string[];
40
+ }>;
41
+ }
42
+ export declare function publicCatalog(): PublicCatalog;
43
+ /** The cloud operations as search rows; the ones that save files show `out` in their input. */
44
+ export declare function shippedCloudEntries(): CatalogEntry[];
45
+ /** The catalog's title of an operation, for the local ones it lists too. */
46
+ export declare function shippedTitle(op: string): string | undefined;
47
+ /** One cloud operation as ops.describe answers it, from the shipped catalog; null when it has no such row. */
48
+ export declare function shippedWireForm(op: string): Record<string, unknown> | null;
@@ -0,0 +1,56 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { PACKAGE_ROOT } from "../package-root.js";
4
+ import { CONTRACT_VERSION, isLocalOp } from "./contract.js";
5
+ import { withOutField } from "./save-files.js";
6
+ /**
7
+ * The hosted Summer server's public operation catalog, shipped in this
8
+ * package: registry/operations/public-catalog.json, a byte copy of the
9
+ * server's own file (`npm run sync:catalog`; `-- --check` fails when it is
10
+ * behind). Search and describe list every cloud operation from it with no
11
+ * sign-in; a signed-in search lays the server's live rows over it.
12
+ */
13
+ const PUBLIC_CATALOG_FILE = join("registry", "operations", "public-catalog.json");
14
+ let catalogCache = null;
15
+ export function publicCatalog() {
16
+ if (catalogCache)
17
+ return catalogCache;
18
+ try {
19
+ catalogCache = JSON.parse(readFileSync(join(PACKAGE_ROOT, PUBLIC_CATALOG_FILE), "utf8"));
20
+ }
21
+ catch {
22
+ catalogCache = { contract: CONTRACT_VERSION, operations: [], localOperations: [] };
23
+ }
24
+ return catalogCache;
25
+ }
26
+ /** The cloud operations as search rows; the ones that save files show `out` in their input. */
27
+ export function shippedCloudEntries() {
28
+ return publicCatalog()
29
+ .operations.filter((op) => !isLocalOp(op.name))
30
+ .map((op) => ({
31
+ name: op.name,
32
+ title: op.title,
33
+ summary: op.summary,
34
+ effect: op.effect,
35
+ approval: op.approval,
36
+ provider: "cloud",
37
+ status: op.status,
38
+ available: true,
39
+ ...(op.tags?.length ? { tags: op.tags } : {}),
40
+ ...(op.legacy?.length ? { legacy: op.legacy } : {}),
41
+ input: withOutField(op.name, op.input),
42
+ }));
43
+ }
44
+ /** The catalog's title of an operation, for the local ones it lists too. */
45
+ export function shippedTitle(op) {
46
+ return publicCatalog().operations.find((candidate) => candidate.name === op)?.title;
47
+ }
48
+ /** One cloud operation as ops.describe answers it, from the shipped catalog; null when it has no such row. */
49
+ export function shippedWireForm(op) {
50
+ const found = publicCatalog().operations.find((candidate) => candidate.name === op);
51
+ if (!found || isLocalOp(op))
52
+ return null;
53
+ // `direct` names the hosted profiles that list it as a tool; it says nothing here.
54
+ const { direct: _direct, ...wire } = found;
55
+ return { contract: CONTRACT_VERSION, ...wire, input: withOutField(op, found.input), needsSignIn: true };
56
+ }
@@ -1,7 +1,6 @@
1
1
  import type { CatalogEntry } from "./catalog.js";
2
2
  import type { Effect } from "./contract.js";
3
3
  export declare function words(text: string): string[];
4
- export declare function scoreEntry(entry: CatalogEntry, query: string): number;
5
4
  export declare function searchEntries(entries: readonly CatalogEntry[], query: string, filters: {
6
5
  area?: string;
7
6
  effect?: Effect;