opencodekit 0.21.3 → 0.21.5

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 (34) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/.template-manifest.json +8 -8
  3. package/dist/template/.opencode/.version +1 -1
  4. package/dist/template/.opencode/AGENTS.md +55 -36
  5. package/dist/template/.opencode/agent/build.md +13 -3
  6. package/dist/template/.opencode/agent/explore.md +14 -0
  7. package/dist/template/.opencode/agent/general.md +13 -2
  8. package/dist/template/.opencode/agent/painter.md +9 -0
  9. package/dist/template/.opencode/agent/plan.md +26 -4
  10. package/dist/template/.opencode/agent/review.md +10 -0
  11. package/dist/template/.opencode/agent/scout.md +16 -1
  12. package/dist/template/.opencode/agent/vision.md +23 -0
  13. package/dist/template/.opencode/command/design.md +27 -8
  14. package/dist/template/.opencode/command/plan.md +22 -0
  15. package/dist/template/.opencode/command/ship.md +31 -5
  16. package/dist/template/.opencode/command/status.md +14 -5
  17. package/dist/template/.opencode/command/ui-review.md +38 -18
  18. package/dist/template/.opencode/command/ui-slop-check.md +30 -7
  19. package/dist/template/.opencode/command/verify.md +3 -0
  20. package/dist/template/.opencode/memory.db +0 -0
  21. package/dist/template/.opencode/memory.db-shm +0 -0
  22. package/dist/template/.opencode/memory.db-wal +0 -0
  23. package/dist/template/.opencode/opencode.json +164 -329
  24. package/dist/template/.opencode/plugin/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +162 -168
  25. package/dist/template/.opencode/plugin/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +16 -16
  26. package/dist/template/.opencode/plugin/sdk/copilot/chat/openai-compatible-chat-language-model.ts +807 -805
  27. package/dist/template/.opencode/plugin/sdk/copilot/chat/openai-compatible-prepare-tools.ts +77 -77
  28. package/dist/template/.opencode/plugin/sdk/copilot/copilot-provider.ts +75 -80
  29. package/dist/template/.opencode/skill/playwright/SKILL.md +51 -2
  30. package/dist/template/.opencode/skill/portless/SKILL.md +109 -0
  31. package/dist/template/.opencode/skill/terse-output-mode/SKILL.md +95 -0
  32. package/dist/template/.opencode/skill/think-in-code/SKILL.md +136 -0
  33. package/dist/template/.opencode/skill/ux-quality-gates/SKILL.md +137 -0
  34. package/package.json +1 -1
@@ -1,178 +1,172 @@
1
1
  import {
2
- type LanguageModelV2Prompt,
3
- type SharedV2ProviderMetadata,
4
- UnsupportedFunctionalityError,
2
+ type LanguageModelV3Prompt,
3
+ type SharedV3ProviderOptions,
4
+ UnsupportedFunctionalityError,
5
5
  } from "@ai-sdk/provider";
6
6
  import { convertToBase64 } from "@ai-sdk/provider-utils";
7
7
  import type { OpenAICompatibleChatPrompt } from "./openai-compatible-api-types.js";
8
8
 
9
- function getOpenAIMetadata(message: {
10
- providerOptions?: SharedV2ProviderMetadata;
11
- }) {
12
- return message?.providerOptions?.copilot ?? {};
9
+ function getOpenAIMetadata(message: { providerOptions?: SharedV3ProviderOptions }) {
10
+ return message?.providerOptions?.copilot ?? {};
13
11
  }
14
12
 
15
13
  export function convertToOpenAICompatibleChatMessages(
16
- prompt: LanguageModelV2Prompt,
14
+ prompt: LanguageModelV3Prompt,
17
15
  ): OpenAICompatibleChatPrompt {
18
- const messages: OpenAICompatibleChatPrompt = [];
19
- for (const { role, content, ...message } of prompt) {
20
- const metadata = getOpenAIMetadata({ ...message });
21
- switch (role) {
22
- case "system": {
23
- // v1.1.49 fix: Copilot API expects system message content as plain string,
24
- // not array format. Array format causes AGENTS.md to be silently ignored.
25
- messages.push({
26
- role: "system",
27
- content: content,
28
- ...metadata,
29
- });
30
- break;
31
- }
32
-
33
- case "user": {
34
- if (content.length === 1 && content[0].type === "text") {
35
- messages.push({
36
- role: "user",
37
- content: content[0].text,
38
- ...getOpenAIMetadata(content[0]),
39
- });
40
- break;
41
- }
42
-
43
- messages.push({
44
- role: "user",
45
- content: content.map((part) => {
46
- const partMetadata = getOpenAIMetadata(part);
47
- switch (part.type) {
48
- case "text": {
49
- return {
50
- type: "text" as const,
51
- text: part.text,
52
- ...partMetadata,
53
- };
54
- }
55
- case "file": {
56
- if (part.mediaType.startsWith("image/")) {
57
- const mediaType =
58
- part.mediaType === "image/*"
59
- ? "image/jpeg"
60
- : part.mediaType;
61
-
62
- return {
63
- type: "image_url" as const,
64
- image_url: {
65
- url:
66
- part.data instanceof URL
67
- ? part.data.toString()
68
- : `data:${mediaType};base64,${convertToBase64(part.data)}`,
69
- },
70
- ...partMetadata,
71
- };
72
- } else {
73
- throw new UnsupportedFunctionalityError({
74
- functionality: `file part media type ${part.mediaType}`,
75
- });
76
- }
77
- }
78
- }
79
- }),
80
- ...metadata,
81
- });
82
-
83
- break;
84
- }
85
-
86
- case "assistant": {
87
- let text = "";
88
- let reasoningText: string | undefined;
89
- let reasoningOpaque: string | undefined;
90
- const toolCalls: Array<{
91
- id: string;
92
- type: "function";
93
- function: { name: string; arguments: string };
94
- }> = [];
95
-
96
- for (const part of content) {
97
- const partMetadata = getOpenAIMetadata(part);
98
- // Check for reasoningOpaque on any part (may be attached to text/tool-call)
99
- const partOpaque = (
100
- part.providerOptions as { copilot?: { reasoningOpaque?: string } }
101
- )?.copilot?.reasoningOpaque;
102
- if (partOpaque && !reasoningOpaque) {
103
- reasoningOpaque = partOpaque;
104
- }
105
-
106
- switch (part.type) {
107
- case "text": {
108
- text += part.text;
109
- break;
110
- }
111
- case "reasoning": {
112
- reasoningText = part.text;
113
- break;
114
- }
115
- case "tool-call": {
116
- toolCalls.push({
117
- id: part.toolCallId,
118
- type: "function",
119
- function: {
120
- name: part.toolName,
121
- arguments: JSON.stringify(part.input),
122
- },
123
- ...partMetadata,
124
- });
125
- break;
126
- }
127
- }
128
- }
129
-
130
- messages.push({
131
- role: "assistant",
132
- content: text || null,
133
- tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
134
- reasoning_text: reasoningText,
135
- reasoning_opaque: reasoningOpaque,
136
- ...metadata,
137
- });
138
-
139
- break;
140
- }
141
-
142
- case "tool": {
143
- for (const toolResponse of content) {
144
- const output = toolResponse.output;
145
-
146
- let contentValue: string;
147
- switch (output.type) {
148
- case "text":
149
- case "error-text":
150
- contentValue = output.value;
151
- break;
152
- case "content":
153
- case "json":
154
- case "error-json":
155
- contentValue = JSON.stringify(output.value);
156
- break;
157
- }
158
-
159
- const toolResponseMetadata = getOpenAIMetadata(toolResponse);
160
- messages.push({
161
- role: "tool",
162
- tool_call_id: toolResponse.toolCallId,
163
- content: contentValue,
164
- ...toolResponseMetadata,
165
- });
166
- }
167
- break;
168
- }
169
-
170
- default: {
171
- const _exhaustiveCheck: never = role;
172
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
173
- }
174
- }
175
- }
176
-
177
- return messages;
16
+ const messages: OpenAICompatibleChatPrompt = [];
17
+ for (const { role, content, ...message } of prompt) {
18
+ const metadata = getOpenAIMetadata({ ...message });
19
+ switch (role) {
20
+ case "system": {
21
+ messages.push({
22
+ role: "system",
23
+ content: content,
24
+ ...metadata,
25
+ });
26
+ break;
27
+ }
28
+
29
+ case "user": {
30
+ if (content.length === 1 && content[0].type === "text") {
31
+ messages.push({
32
+ role: "user",
33
+ content: content[0].text,
34
+ ...getOpenAIMetadata(content[0]),
35
+ });
36
+ break;
37
+ }
38
+
39
+ messages.push({
40
+ role: "user",
41
+ content: content.map((part) => {
42
+ const partMetadata = getOpenAIMetadata(part);
43
+ switch (part.type) {
44
+ case "text": {
45
+ return { type: "text" as const, text: part.text, ...partMetadata };
46
+ }
47
+ case "file": {
48
+ if (part.mediaType.startsWith("image/")) {
49
+ const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType;
50
+
51
+ return {
52
+ type: "image_url" as const,
53
+ image_url: {
54
+ url:
55
+ part.data instanceof URL
56
+ ? part.data.toString()
57
+ : `data:${mediaType};base64,${convertToBase64(part.data)}`,
58
+ },
59
+ ...partMetadata,
60
+ };
61
+ } else {
62
+ throw new UnsupportedFunctionalityError({
63
+ functionality: `file part media type ${part.mediaType}`,
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }),
69
+ ...metadata,
70
+ });
71
+
72
+ break;
73
+ }
74
+
75
+ case "assistant": {
76
+ let text = "";
77
+ let reasoningText: string | undefined;
78
+ let reasoningOpaque: string | undefined;
79
+ const toolCalls: Array<{
80
+ id: string;
81
+ type: "function";
82
+ function: { name: string; arguments: string };
83
+ }> = [];
84
+
85
+ for (const part of content) {
86
+ const partMetadata = getOpenAIMetadata(part);
87
+ // Check for reasoningOpaque on any part (may be attached to text/tool-call)
88
+ const partOpaque = (part.providerOptions as { copilot?: { reasoningOpaque?: string } })
89
+ ?.copilot?.reasoningOpaque;
90
+ if (partOpaque && !reasoningOpaque) {
91
+ reasoningOpaque = partOpaque;
92
+ }
93
+
94
+ switch (part.type) {
95
+ case "text": {
96
+ text += part.text;
97
+ break;
98
+ }
99
+ case "reasoning": {
100
+ if (part.text) reasoningText = part.text;
101
+ break;
102
+ }
103
+ case "tool-call": {
104
+ toolCalls.push({
105
+ id: part.toolCallId,
106
+ type: "function",
107
+ function: {
108
+ name: part.toolName,
109
+ arguments: JSON.stringify(part.input),
110
+ },
111
+ ...partMetadata,
112
+ });
113
+ break;
114
+ }
115
+ }
116
+ }
117
+
118
+ messages.push({
119
+ role: "assistant",
120
+ content: text || null,
121
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
122
+ reasoning_text: reasoningOpaque ? reasoningText : undefined,
123
+ reasoning_opaque: reasoningOpaque,
124
+ ...metadata,
125
+ });
126
+
127
+ break;
128
+ }
129
+
130
+ case "tool": {
131
+ for (const toolResponse of content) {
132
+ if (toolResponse.type === "tool-approval-response") {
133
+ continue;
134
+ }
135
+ const output = toolResponse.output;
136
+
137
+ let contentValue: string;
138
+ switch (output.type) {
139
+ case "text":
140
+ case "error-text":
141
+ contentValue = output.value;
142
+ break;
143
+ case "execution-denied":
144
+ contentValue = output.reason ?? "Tool execution denied.";
145
+ break;
146
+ case "content":
147
+ case "json":
148
+ case "error-json":
149
+ contentValue = JSON.stringify(output.value);
150
+ break;
151
+ }
152
+
153
+ const toolResponseMetadata = getOpenAIMetadata(toolResponse);
154
+ messages.push({
155
+ role: "tool",
156
+ tool_call_id: toolResponse.toolCallId,
157
+ content: contentValue,
158
+ ...toolResponseMetadata,
159
+ });
160
+ }
161
+ break;
162
+ }
163
+
164
+ default: {
165
+ const _exhaustiveCheck: never = role;
166
+ throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
167
+ }
168
+ }
169
+ }
170
+
171
+ return messages;
178
172
  }
@@ -1,19 +1,19 @@
1
- import type { LanguageModelV2FinishReason } from "@ai-sdk/provider";
1
+ import type { LanguageModelV3FinishReason } from "@ai-sdk/provider";
2
2
 
3
3
  export function mapOpenAICompatibleFinishReason(
4
- finishReason: string | null | undefined,
5
- ): LanguageModelV2FinishReason {
6
- switch (finishReason) {
7
- case "stop":
8
- return "stop";
9
- case "length":
10
- return "length";
11
- case "content_filter":
12
- return "content-filter";
13
- case "function_call":
14
- case "tool_calls":
15
- return "tool-calls";
16
- default:
17
- return "unknown";
18
- }
4
+ finishReason: string | null | undefined,
5
+ ): LanguageModelV3FinishReason["unified"] {
6
+ switch (finishReason) {
7
+ case "stop":
8
+ return "stop";
9
+ case "length":
10
+ return "length";
11
+ case "content_filter":
12
+ return "content-filter";
13
+ case "function_call":
14
+ case "tool_calls":
15
+ return "tool-calls";
16
+ default:
17
+ return "other";
18
+ }
19
19
  }