paseo-prompt-kit 0.5.2

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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/client/actions/enabled.ts +30 -0
  4. package/client/commands/rewrite-command.ts +54 -0
  5. package/client/composer-bridge/adapter.ts +15 -0
  6. package/client/composer-bridge/dom.ts +101 -0
  7. package/client/composer-bridge/effect.ts +64 -0
  8. package/client/composer-bridge/fiber.ts +97 -0
  9. package/client/composer-bridge/web.ts +58 -0
  10. package/client/icon.ts +13 -0
  11. package/client/pills/agent-pills.ts +207 -0
  12. package/client/pills/rewrite-runner.ts +123 -0
  13. package/client/settings/action-samples.ts +102 -0
  14. package/client/settings/api-endpoints.ts +156 -0
  15. package/client/settings/custom-actions.ts +79 -0
  16. package/client/settings/draft.ts +82 -0
  17. package/client/settings/model-filter.ts +33 -0
  18. package/client/settings/read-settings.ts +45 -0
  19. package/client/settings/readiness.ts +84 -0
  20. package/client/settings/sections/actions-section.tsx +75 -0
  21. package/client/settings/sections/advanced-section.tsx +127 -0
  22. package/client/settings/sections/api-endpoint-section.tsx +388 -0
  23. package/client/settings/sections/custom-actions-section.tsx +163 -0
  24. package/client/settings/sections/dedicated-model-section.tsx +136 -0
  25. package/client/settings/sections/engine-section.tsx +101 -0
  26. package/client/settings/sections/provider-map-card.tsx +89 -0
  27. package/client/settings/sections/stored-key-rows.tsx +106 -0
  28. package/client/settings/selection.ts +46 -0
  29. package/client/settings/settings-saved.ts +17 -0
  30. package/client/settings/settings-screen.tsx +197 -0
  31. package/client/settings/ui/button.tsx +56 -0
  32. package/client/settings/ui/notice.tsx +61 -0
  33. package/client/settings/ui/split-select.tsx +26 -0
  34. package/client/settings/ui/status-bar.tsx +89 -0
  35. package/client/settings/ui/tokens.ts +38 -0
  36. package/client/settings/validation.ts +50 -0
  37. package/client/sheet/rewrite-sheet.tsx +249 -0
  38. package/index.client.tsx +71 -0
  39. package/index.server.ts +98 -0
  40. package/package.json +53 -0
  41. package/paseo-plugin.json +6 -0
  42. package/server/log.ts +20 -0
  43. package/server/model-resolver/provider-catalog.ts +37 -0
  44. package/server/model-resolver/resolver.ts +196 -0
  45. package/server/paseo-types.ts +13 -0
  46. package/server/rewrite-engine/engine.ts +88 -0
  47. package/server/rewrite-engine/handler.ts +94 -0
  48. package/server/rewrite-engine/output-validator.ts +130 -0
  49. package/server/transports/api/anthropic.ts +61 -0
  50. package/server/transports/api/cloudflare.ts +52 -0
  51. package/server/transports/api/gemini.ts +62 -0
  52. package/server/transports/api/key.ts +95 -0
  53. package/server/transports/api/openai.ts +52 -0
  54. package/server/transports/api/protocol.ts +96 -0
  55. package/server/transports/api/runner.ts +284 -0
  56. package/server/transports/api/secrets-store.ts +90 -0
  57. package/server/transports/cli/family.ts +216 -0
  58. package/server/transports/cli/process.ts +118 -0
  59. package/server/transports/cli/runner.ts +89 -0
  60. package/shared/action-registry/loader.ts +63 -0
  61. package/shared/action-registry/registry.ts +47 -0
  62. package/shared/action-registry/rewrite-contract.ts +31 -0
  63. package/shared/action-registry/schema.ts +65 -0
  64. package/shared/action-registry/wrapper.ts +30 -0
  65. package/shared/api-protocol.ts +56 -0
  66. package/shared/cli-families.ts +29 -0
  67. package/shared/language-registry/loader.ts +53 -0
  68. package/shared/language-registry/registry.ts +20 -0
  69. package/shared/language-registry/schema.ts +21 -0
  70. package/shared/languages/en.json +6 -0
  71. package/shared/languages/index.ts +5 -0
  72. package/shared/languages/vi.json +6 -0
  73. package/shared/packs/general.json +17 -0
  74. package/shared/packs/index.ts +12 -0
  75. package/shared/protected-literals.ts +550 -0
  76. package/shared/rpc.ts +187 -0
  77. package/shared/settings.ts +90 -0
package/shared/rpc.ts ADDED
@@ -0,0 +1,187 @@
1
+ import { defineRpc } from "@getpaseo/plugin";
2
+ import { z } from "zod";
3
+ import { ACTION_ID_PATTERN, actionPackSchema } from "./action-registry/schema.js";
4
+ import { apiEndpointSchema } from "./api-protocol.js";
5
+ import { promptKitSettingsSchema } from "./settings.js";
6
+
7
+ export const rewriteErrorCodeSchema = z.enum([
8
+ "invalid_model",
9
+ "invalid_selection",
10
+ "unknown_action",
11
+ "timeout",
12
+ "empty_output",
13
+ "unsupported_provider",
14
+ "spawn_failed",
15
+ "missing_api_key",
16
+ "api_endpoint_unknown",
17
+ "api_http_error",
18
+ "api_bad_response",
19
+ "protected_literal_loss",
20
+ "generation_failed",
21
+ ]);
22
+
23
+ export const rewriteErrorSchema = z.object({
24
+ code: rewriteErrorCodeSchema,
25
+ message: z.string().min(1),
26
+ });
27
+
28
+ export const rewriteModelSchema = z.object({
29
+ provider: z.string().min(1),
30
+ model: z.string().min(1).nullable(),
31
+ thinkingOptionId: z.string().min(1).nullable(),
32
+ });
33
+
34
+ /**
35
+ * Paseo 0.8.0's `registerSettings` returns void, so the daemon-side handler
36
+ * cannot read its own settings document; the caller's persisted settings
37
+ * snapshot travels with the request and the handler re-validates every field.
38
+ */
39
+ export const rewriteRpc = defineRpc({
40
+ name: "prompt-kit.rewrite",
41
+ input: z.object({
42
+ actionId: z.string().regex(ACTION_ID_PATTERN),
43
+ /** Null for a draft Composer with no agent yet. */
44
+ agentId: z.string().min(1).nullable(),
45
+ workspaceId: z.string().min(1),
46
+ originalPrompt: z.string().min(1).max(50_000),
47
+ settings: promptKitSettingsSchema,
48
+ }),
49
+ output: z.discriminatedUnion("status", [
50
+ z.object({
51
+ status: z.literal("ok"),
52
+ rewrittenPrompt: z.string().min(1),
53
+ model: rewriteModelSchema,
54
+ durationMs: z.number().nonnegative(),
55
+ }),
56
+ z.object({
57
+ status: z.literal("error"),
58
+ error: rewriteErrorSchema,
59
+ }),
60
+ ]),
61
+ });
62
+
63
+ export const actionSummarySchema = z.object({
64
+ id: z.string().min(1),
65
+ version: z.number().int().positive(),
66
+ enabledByDefault: z.boolean(),
67
+ title: z.string().min(1),
68
+ description: z.string().min(1),
69
+ icon: z.string().min(1),
70
+ /** True for an action the user wrote in Settings, false for a bundled pack. */
71
+ custom: z.boolean(),
72
+ });
73
+
74
+ export const rejectedPackSchema = z.object({
75
+ source: z.string().min(1),
76
+ reason: z.string().min(1),
77
+ });
78
+
79
+ /**
80
+ * The registry for the caller's custom actions, with no switches applied. Which
81
+ * actions are enabled is a client-side decision; the RPC stays a pure function of
82
+ * the bundled packs plus the `customActions` it is given.
83
+ */
84
+ export const actionsListRpc = defineRpc({
85
+ name: "prompt-kit.actions.list",
86
+ input: z.object({
87
+ customActions: z.array(actionPackSchema),
88
+ }),
89
+ output: z.object({
90
+ actions: z.array(actionSummarySchema),
91
+ rejected: z.array(rejectedPackSchema),
92
+ }),
93
+ });
94
+
95
+ export const thinkingOptionSchema = z.object({
96
+ id: z.string().min(1),
97
+ label: z.string().min(1),
98
+ });
99
+
100
+ export const providerModelSchema = z.object({
101
+ id: z.string().min(1),
102
+ label: z.string().min(1),
103
+ thinkingOptions: z.array(thinkingOptionSchema),
104
+ defaultThinkingOptionId: z.string().min(1).nullable(),
105
+ });
106
+
107
+ export const providerCatalogEntrySchema = z.object({
108
+ provider: z.string().min(1),
109
+ label: z.string().min(1),
110
+ available: z.boolean(),
111
+ models: z.array(providerModelSchema),
112
+ });
113
+
114
+ export const providerCatalogRpc = defineRpc({
115
+ name: "prompt-kit.providers",
116
+ input: z.object({ cwd: z.string().min(1).optional() }),
117
+ output: z.object({
118
+ providers: z.array(providerCatalogEntrySchema),
119
+ }),
120
+ });
121
+
122
+ /**
123
+ * Checks one API endpoint from the settings screen: resolves its key, asks the
124
+ * endpoint which models it offers, and reports the outcome.
125
+ *
126
+ * It exists so a wrong base URL, a missing key or an unreachable host is found on
127
+ * the settings screen rather than on the next rewrite. The answer never carries a
128
+ * key value: a failure names the variable, never the secret.
129
+ */
130
+ export const apiTestRpc = defineRpc({
131
+ name: "prompt-kit.api.test",
132
+ input: z.object({
133
+ endpoint: apiEndpointSchema,
134
+ secretsDir: z.string().min(1).nullable(),
135
+ }),
136
+ output: z.discriminatedUnion("status", [
137
+ z.object({
138
+ status: z.literal("ok"),
139
+ models: z.array(z.string()),
140
+ }),
141
+ z.object({
142
+ status: z.literal("error"),
143
+ error: rewriteErrorSchema,
144
+ }),
145
+ ]),
146
+ });
147
+
148
+ const secretsResultSchema = z.discriminatedUnion("status", [
149
+ z.object({ status: z.literal("ok") }),
150
+ z.object({ status: z.literal("error"), message: z.string() }),
151
+ ]);
152
+
153
+ /**
154
+ * Stores one secrets.json entry on the daemon (`value`), or removes it (`null`).
155
+ * Write-only: no RPC ever returns a key value.
156
+ */
157
+ export const secretsWriteRpc = defineRpc({
158
+ name: "prompt-kit.secrets.write",
159
+ input: z.object({
160
+ secretsDir: z.string().min(1).nullable(),
161
+ name: z.string().min(1).max(120),
162
+ value: z.string().trim().min(1).max(4_096).nullable(),
163
+ }),
164
+ output: secretsResultSchema,
165
+ });
166
+
167
+ /** Whether secrets.json holds a value for `name`; the answer is a boolean, never the value. */
168
+ export const secretsStatusRpc = defineRpc({
169
+ name: "prompt-kit.secrets.status",
170
+ input: z.object({
171
+ secretsDir: z.string().min(1).nullable(),
172
+ name: z.string().min(1).max(120),
173
+ }),
174
+ output: z.discriminatedUnion("status", [
175
+ z.object({ status: z.literal("ok"), stored: z.boolean() }),
176
+ z.object({ status: z.literal("error"), message: z.string() }),
177
+ ]),
178
+ });
179
+
180
+ export type RewriteInput = z.output<typeof rewriteRpc.input>;
181
+ export type RewriteOutput = z.output<typeof rewriteRpc.output>;
182
+ export type RewriteError = z.output<typeof rewriteErrorSchema>;
183
+ export type ActionSummary = z.output<typeof actionSummarySchema>;
184
+ export type ActionsListOutput = z.output<typeof actionsListRpc.output>;
185
+ export type ProviderCatalogOutput = z.output<typeof providerCatalogRpc.output>;
186
+ export type ApiTestInput = z.output<typeof apiTestRpc.input>;
187
+ export type ApiTestOutput = z.output<typeof apiTestRpc.output>;
@@ -0,0 +1,90 @@
1
+ import { defineSettings } from "@getpaseo/plugin";
2
+ import { z } from "zod";
3
+ import { actionPackSchema } from "./action-registry/schema.js";
4
+ import { apiEndpointSchema } from "./api-protocol.js";
5
+ import { CLI_FAMILY_IDS } from "./cli-families.js";
6
+ import { LANGUAGE_ID_PATTERN, SOURCE_LANGUAGE } from "./language-registry/schema.js";
7
+
8
+ /** Which model the CLI transport runs. The API transport ignores it. */
9
+ export const modelModeSchema = z.enum(["current", "dedicated"]);
10
+
11
+ /**
12
+ * How the model is reached. `cli` spawns the provider's CLI and takes its model
13
+ * from `modelMode`; `api` posts to `apiEndpointId` with `apiModel`, or to a
14
+ * provider's mapped endpoint with that agent's own model.
15
+ */
16
+ export const transportSchema = z.enum(["cli", "api"]);
17
+
18
+ /** Rewrite budget bounds. `hostRpcCapMs` is the daemon's own 30 s plugin-RPC cap. */
19
+ export const TIMEOUT_MS = {
20
+ min: 1_000,
21
+ max: 600_000,
22
+ default: 90_000,
23
+ hostRpcCapMs: 30_000,
24
+ } as const;
25
+
26
+ /**
27
+ * Host-scoped PromptKit settings. Every field has a default so `{}` parses and
28
+ * an incomplete dedicated selection can never silently select another model.
29
+ *
30
+ * A settings document travels to the client, so no API key is ever stored here:
31
+ * an endpoint carries the *name* of its key (`apiKeyEnv`) and the server resolves
32
+ * the value. See `README.md`, "API keys".
33
+ */
34
+ export const promptKitSettingsSchema = z.object({
35
+ modelMode: modelModeSchema.default("current"),
36
+ transport: transportSchema.default("cli"),
37
+ dedicatedProvider: z.string().min(1).nullable().default(null),
38
+ dedicatedModel: z.string().min(1).nullable().default(null),
39
+ dedicatedThinkingOptionId: z.string().min(1).nullable().default(null),
40
+ /**
41
+ * Maps a Paseo provider id to the CLI family that runs it. Paseo names a
42
+ * built-in provider after its CLI (`pi`, `codex`) and a custom profile after
43
+ * the role it plays (`pi-peer`, `codex-lead`), so the leading segment resolves
44
+ * most ids without an entry here. An entry is needed only for a profile whose
45
+ * id does not mention its CLI, and an unknown id fails closed either way.
46
+ */
47
+ providerCli: z.record(z.string(), z.enum(CLI_FAMILY_IDS)).default({}),
48
+ /** The API endpoints this host can reach. Key values are never stored here. */
49
+ apiEndpoints: z.array(apiEndpointSchema).default([]),
50
+ /** The endpoint `transport: "api"` uses for an agent whose provider is not mapped. */
51
+ apiEndpointId: z.string().min(1).nullable().default(null),
52
+ /** The model id sent to that endpoint. */
53
+ apiModel: z.string().min(1).nullable().default(null),
54
+ /**
55
+ * Maps a Paseo provider id to an endpoint id, so an agent whose provider is
56
+ * served by a direct API can rewrite over HTTP instead of paying a CLI cold
57
+ * start. The counterpart of `providerCli`: that one says which CLI runs a
58
+ * provider, this one says which endpoint serves it.
59
+ */
60
+ apiEndpointByProvider: z.record(z.string(), z.string().min(1)).default({}),
61
+ /**
62
+ * Directory holding `secrets.json` for every endpoint whose key source is `secrets_file`,
63
+ * or null for `<PASEO_HOME>/plugin-settings/prompt-kit`. Absolute or `~/`-prefixed.
64
+ */
65
+ secretsDir: z.string().min(1).nullable().default(null),
66
+ timeoutMs: z.number().int().min(TIMEOUT_MS.min).max(TIMEOUT_MS.max).default(TIMEOUT_MS.default),
67
+ /**
68
+ * Per-action user toggle, keyed by action id. An id absent here falls back to
69
+ * the pack's `enabledByDefault`, so a newly added pack is usable without a
70
+ * settings migration and a removed pack leaves no stale state behind.
71
+ */
72
+ actionEnabled: z.record(z.string(), z.boolean()).default({}),
73
+ /** Actions the user wrote in Settings; same pack schema and rewrite path as the bundled ones. */
74
+ customActions: z.array(actionPackSchema).default([]),
75
+ /** `SOURCE_LANGUAGE` or a loaded id from `shared/languages/`. */
76
+ outputLanguage: z.string().regex(LANGUAGE_ID_PATTERN).default(SOURCE_LANGUAGE),
77
+ });
78
+
79
+ export type PromptKitSettings = z.output<typeof promptKitSettingsSchema>;
80
+
81
+ export const promptKitSettings = defineSettings({
82
+ id: "prompt-kit",
83
+ scope: "host",
84
+ version: 1,
85
+ schema: promptKitSettingsSchema,
86
+ });
87
+
88
+ export function isDedicatedSelectionComplete(settings: PromptKitSettings): boolean {
89
+ return settings.dedicatedProvider !== null && settings.dedicatedModel !== null;
90
+ }