opencodekit 0.21.4 → 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.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +55 -36
- package/dist/template/.opencode/agent/build.md +13 -3
- package/dist/template/.opencode/agent/explore.md +14 -0
- package/dist/template/.opencode/agent/general.md +13 -2
- package/dist/template/.opencode/agent/painter.md +9 -0
- package/dist/template/.opencode/agent/plan.md +26 -4
- package/dist/template/.opencode/agent/review.md +10 -0
- package/dist/template/.opencode/agent/scout.md +16 -1
- package/dist/template/.opencode/agent/vision.md +23 -0
- package/dist/template/.opencode/command/design.md +27 -8
- package/dist/template/.opencode/command/plan.md +22 -0
- package/dist/template/.opencode/command/ship.md +31 -5
- package/dist/template/.opencode/command/status.md +14 -5
- package/dist/template/.opencode/command/ui-review.md +38 -18
- package/dist/template/.opencode/command/ui-slop-check.md +30 -7
- package/dist/template/.opencode/command/verify.md +3 -0
- package/dist/template/.opencode/memory.db +0 -0
- package/dist/template/.opencode/memory.db-shm +0 -0
- package/dist/template/.opencode/memory.db-wal +0 -0
- package/dist/template/.opencode/plugin/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +162 -168
- package/dist/template/.opencode/plugin/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +16 -16
- package/dist/template/.opencode/plugin/sdk/copilot/chat/openai-compatible-chat-language-model.ts +807 -805
- package/dist/template/.opencode/plugin/sdk/copilot/chat/openai-compatible-prepare-tools.ts +77 -77
- package/dist/template/.opencode/plugin/sdk/copilot/copilot-provider.ts +75 -80
- package/dist/template/.opencode/skill/playwright/SKILL.md +51 -2
- package/dist/template/.opencode/skill/portless/SKILL.md +109 -0
- package/dist/template/.opencode/skill/terse-output-mode/SKILL.md +95 -0
- package/dist/template/.opencode/skill/think-in-code/SKILL.md +136 -0
- package/dist/template/.opencode/skill/ux-quality-gates/SKILL.md +137 -0
- package/package.json +1 -1
|
@@ -1,92 +1,92 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
type LanguageModelV3CallOptions,
|
|
3
|
+
type SharedV3Warning,
|
|
4
|
+
UnsupportedFunctionalityError,
|
|
5
5
|
} from "@ai-sdk/provider";
|
|
6
6
|
|
|
7
7
|
export function prepareTools({
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
tools,
|
|
9
|
+
toolChoice,
|
|
10
10
|
}: {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
tools: LanguageModelV3CallOptions["tools"];
|
|
12
|
+
toolChoice?: LanguageModelV3CallOptions["toolChoice"];
|
|
13
13
|
}): {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
tools:
|
|
15
|
+
| undefined
|
|
16
|
+
| Array<{
|
|
17
|
+
type: "function";
|
|
18
|
+
function: {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string | undefined;
|
|
21
|
+
parameters: unknown;
|
|
22
|
+
};
|
|
23
|
+
}>;
|
|
24
|
+
toolChoice:
|
|
25
|
+
| { type: "function"; function: { name: string } }
|
|
26
|
+
| "auto"
|
|
27
|
+
| "none"
|
|
28
|
+
| "required"
|
|
29
|
+
| undefined;
|
|
30
|
+
toolWarnings: SharedV3Warning[];
|
|
31
31
|
} {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// when the tools array is empty, change it to undefined to prevent errors:
|
|
33
|
+
tools = tools?.length ? tools : undefined;
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const toolWarnings: SharedV3Warning[] = [];
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (tools == null) {
|
|
38
|
+
return { tools: undefined, toolChoice: undefined, toolWarnings };
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
const openaiCompatTools: Array<{
|
|
42
|
+
type: "function";
|
|
43
|
+
function: {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string | undefined;
|
|
46
|
+
parameters: unknown;
|
|
47
|
+
};
|
|
48
|
+
}> = [];
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
for (const tool of tools) {
|
|
51
|
+
if (tool.type === "provider") {
|
|
52
|
+
toolWarnings.push({ type: "unsupported", feature: `tool type: ${tool.type}` });
|
|
53
|
+
} else {
|
|
54
|
+
openaiCompatTools.push({
|
|
55
|
+
type: "function",
|
|
56
|
+
function: {
|
|
57
|
+
name: tool.name,
|
|
58
|
+
description: tool.description,
|
|
59
|
+
parameters: tool.inputSchema,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if (toolChoice == null) {
|
|
66
|
+
return { tools: openaiCompatTools, toolChoice: undefined, toolWarnings };
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
const type = toolChoice.type;
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
switch (type) {
|
|
72
|
+
case "auto":
|
|
73
|
+
case "none":
|
|
74
|
+
case "required":
|
|
75
|
+
return { tools: openaiCompatTools, toolChoice: type, toolWarnings };
|
|
76
|
+
case "tool":
|
|
77
|
+
return {
|
|
78
|
+
tools: openaiCompatTools,
|
|
79
|
+
toolChoice: {
|
|
80
|
+
type: "function",
|
|
81
|
+
function: { name: toolChoice.toolName },
|
|
82
|
+
},
|
|
83
|
+
toolWarnings,
|
|
84
|
+
};
|
|
85
|
+
default: {
|
|
86
|
+
const _exhaustiveCheck: never = type;
|
|
87
|
+
throw new UnsupportedFunctionalityError({
|
|
88
|
+
functionality: `tool choice type: ${_exhaustiveCheck}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
92
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LanguageModelV3 } from "@ai-sdk/provider";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
type FetchFunction,
|
|
4
|
+
withoutTrailingSlash,
|
|
5
|
+
withUserAgentSuffix,
|
|
6
6
|
} from "@ai-sdk/provider-utils";
|
|
7
7
|
import { OpenAICompatibleChatLanguageModel } from "./chat/openai-compatible-chat-language-model.js";
|
|
8
8
|
import { OpenAIResponsesLanguageModel } from "./responses/openai-responses-language-model.js";
|
|
@@ -13,37 +13,37 @@ const VERSION = "0.1.0";
|
|
|
13
13
|
export type OpenaiCompatibleModelId = string;
|
|
14
14
|
|
|
15
15
|
export interface OpenaiCompatibleProviderSettings {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
/**
|
|
17
|
+
* API key for authenticating requests.
|
|
18
|
+
*/
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Base URL for the OpenAI Compatible API calls.
|
|
23
|
+
*/
|
|
24
|
+
baseURL?: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Name of the provider.
|
|
28
|
+
*/
|
|
29
|
+
name?: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Custom headers to include in the requests.
|
|
33
|
+
*/
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Custom fetch implementation.
|
|
38
|
+
*/
|
|
39
|
+
fetch?: FetchFunction;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export interface OpenaiCompatibleProvider {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
(modelId: OpenaiCompatibleModelId): LanguageModelV3;
|
|
44
|
+
chat(modelId: OpenaiCompatibleModelId): LanguageModelV3;
|
|
45
|
+
responses(modelId: OpenaiCompatibleModelId): LanguageModelV3;
|
|
46
|
+
languageModel(modelId: OpenaiCompatibleModelId): LanguageModelV3;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -51,55 +51,50 @@ export interface OpenaiCompatibleProvider {
|
|
|
51
51
|
* This custom provider handles Claude reasoning tokens (thinking_budget).
|
|
52
52
|
*/
|
|
53
53
|
export function createOpenaiCompatible(
|
|
54
|
-
|
|
54
|
+
options: OpenaiCompatibleProviderSettings = {},
|
|
55
55
|
): OpenaiCompatibleProvider {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
provider.languageModel = createLanguageModel;
|
|
99
|
-
provider.chat = createChatModel;
|
|
100
|
-
provider.responses = createResponsesModel;
|
|
101
|
-
|
|
102
|
-
return provider as OpenaiCompatibleProvider;
|
|
56
|
+
const baseURL = withoutTrailingSlash(options.baseURL ?? "https://api.openai.com/v1");
|
|
57
|
+
|
|
58
|
+
if (!baseURL) {
|
|
59
|
+
throw new Error("baseURL is required");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Merge headers: defaults first, then user overrides
|
|
63
|
+
const headers = {
|
|
64
|
+
// Default OpenAI Compatible headers (can be overridden by user)
|
|
65
|
+
...(options.apiKey && { Authorization: `Bearer ${options.apiKey}` }),
|
|
66
|
+
...options.headers,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const getHeaders = () => withUserAgentSuffix(headers, `ai-sdk/openai-compatible/${VERSION}`);
|
|
70
|
+
|
|
71
|
+
const createChatModel = (modelId: OpenaiCompatibleModelId) => {
|
|
72
|
+
return new OpenAICompatibleChatLanguageModel(modelId, {
|
|
73
|
+
provider: `${options.name ?? "openai-compatible"}.chat`,
|
|
74
|
+
headers: getHeaders,
|
|
75
|
+
url: ({ path }) => `${baseURL}${path}`,
|
|
76
|
+
fetch: options.fetch,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const createResponsesModel = (modelId: OpenaiCompatibleModelId) => {
|
|
81
|
+
return new OpenAIResponsesLanguageModel(modelId, {
|
|
82
|
+
provider: `${options.name ?? "openai-compatible"}.responses`,
|
|
83
|
+
headers: getHeaders,
|
|
84
|
+
url: ({ path, modelId: _modelId }) => `${baseURL}${path}`,
|
|
85
|
+
fetch: options.fetch,
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const createLanguageModel = (modelId: OpenaiCompatibleModelId) => createChatModel(modelId);
|
|
90
|
+
|
|
91
|
+
const provider = (modelId: OpenaiCompatibleModelId) => createChatModel(modelId);
|
|
92
|
+
|
|
93
|
+
provider.languageModel = createLanguageModel;
|
|
94
|
+
provider.chat = createChatModel;
|
|
95
|
+
provider.responses = createResponsesModel;
|
|
96
|
+
|
|
97
|
+
return provider as OpenaiCompatibleProvider;
|
|
103
98
|
}
|
|
104
99
|
|
|
105
100
|
// Default OpenAI Compatible provider instance
|
|
@@ -306,14 +306,63 @@ skill_mcp(
|
|
|
306
306
|
|
|
307
307
|
---
|
|
308
308
|
|
|
309
|
+
## Token Discipline (Snapshots / Console / Network)
|
|
310
|
+
|
|
311
|
+
Browser introspection tools return huge payloads. A single `browser_snapshot` of a real app is routinely **50K–150K tokens**. A single full `browser_console_messages` or `browser_network_requests` can be similar. Pulling that raw into context wrecks the session.
|
|
312
|
+
|
|
313
|
+
**Rule**: when an MCP browser tool supports a `filename` parameter, **always save to a file first, then read selectively**. Reserve direct (no-`filename`) calls for tiny pages or when you genuinely need the whole tree in context.
|
|
314
|
+
|
|
315
|
+
### Tools that MUST use `filename` for non-trivial pages
|
|
316
|
+
|
|
317
|
+
| Tool | When to use `filename` |
|
|
318
|
+
| -------------------------- | --------------------------------------------------------- |
|
|
319
|
+
| `browser_snapshot` | Always on real apps — accessibility trees explode in size |
|
|
320
|
+
| `browser_take_screenshot` | Always — never inline binary data |
|
|
321
|
+
| `browser_console_messages` | When you expect >20 lines or you don't know the volume |
|
|
322
|
+
| `browser_network_requests` | When you expect >20 requests or full bodies |
|
|
323
|
+
| `browser_pdf_save` | Always |
|
|
324
|
+
|
|
325
|
+
### Pattern
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// 1. Save the heavy artifact to a file
|
|
329
|
+
skill_mcp(
|
|
330
|
+
(skill_name = "playwright"),
|
|
331
|
+
(tool_name = "browser_snapshot"),
|
|
332
|
+
(arguments = '{"filename": "/tmp/snapshot.yaml"}'),
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
// 2. Search the file for what you actually need
|
|
336
|
+
bash({ command: "grep -n -E 'role=button|role=textbox' /tmp/snapshot.yaml | head -40" });
|
|
337
|
+
|
|
338
|
+
// 3. Read just the relevant slice
|
|
339
|
+
read({ filePath: "/tmp/snapshot.yaml", offset: 120, limit: 40 });
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
CLI mode has the same discipline — `playwright-cli snapshot > /tmp/snap.yaml` then `grep`/`head`, never paste the whole snapshot into the conversation.
|
|
343
|
+
|
|
344
|
+
### Anti-Patterns
|
|
345
|
+
|
|
346
|
+
| Anti-Pattern | Cost | Fix |
|
|
347
|
+
| ------------------------------------------------------------- | ----------------------------- | --------------------------------------------------- |
|
|
348
|
+
| `browser_snapshot` with no `filename` on a real app | 50K–150K tokens in one shot | Add `filename`, then `grep` / `read` slice |
|
|
349
|
+
| `browser_console_messages` with no `filename` on a noisy page | Floods context with logs | Add `filename`, `grep ERROR` after |
|
|
350
|
+
| `browser_network_requests` with no `filename` | Hundreds of requests + bodies | Add `filename`, then filter by URL/status |
|
|
351
|
+
| Pasting full snapshot YAML into a follow-up prompt | Re-bills the same tokens | Reference the file path; re-read only what's needed |
|
|
352
|
+
|
|
353
|
+
Adapted from the **context saving** discipline in [context-mode](https://github.com/mksglu/context-mode); their measurements show ~99% reduction (135K → ~250 bytes per snapshot) when using `filename` + selective reads.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
309
357
|
## Best Practices
|
|
310
358
|
|
|
311
359
|
1. **Default to CLI** for token efficiency
|
|
312
360
|
2. **Snapshot before interact** - always get element refs first
|
|
313
361
|
3. **Use named sessions** (`-s=`) for isolated browser contexts
|
|
314
362
|
4. **Save outputs to /tmp** for easy access and cleanup
|
|
315
|
-
5. **
|
|
316
|
-
6. **
|
|
363
|
+
5. **Use `filename` on heavy MCP tools** — see Token Discipline above
|
|
364
|
+
6. **Check console/network** for debugging: `playwright-cli console error`
|
|
365
|
+
7. **Use eval for custom checks** when built-in commands aren't enough
|
|
317
366
|
|
|
318
367
|
## Troubleshooting
|
|
319
368
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: portless
|
|
3
|
+
description: Use when local web app, browser, OAuth callback, webhook, or multi-service verification would benefit from stable named localhost URLs via Portless. Keeps Portless optional and safety-gated because it can alter local networking, trust stores, and hosts files.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [workflow, integration, testing]
|
|
6
|
+
dependencies: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Portless Local URL Workflow
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Portless replaces ad-hoc port numbers with stable, named local URLs such as `https://myapp.localhost`. In OpenCodeKit, treat it as an **optional verification aid** for local web workflows, not as a project dependency or default dev-server wrapper.
|
|
14
|
+
|
|
15
|
+
Core rule: **read-only checks are allowed; installation, proxy startup, CA trust, hosts changes, cleanup, and LAN exposure require explicit user approval.**
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- A PRD or task requires browser verification, OAuth callbacks, webhooks, cookies, cross-origin flows, or multiple local services.
|
|
20
|
+
- Port numbers are brittle across git worktrees, parallel dev servers, or subagent/browser automation.
|
|
21
|
+
- A user asks for stable local URLs, Portless setup, Portless troubleshooting, or named `.localhost` routes.
|
|
22
|
+
- You need to record a human-verifiable local URL in `/ship`, `/verify`, or PR testing notes.
|
|
23
|
+
|
|
24
|
+
## When NOT to Use
|
|
25
|
+
|
|
26
|
+
- Pure CLI, library, docs, config, or unit-test-only work.
|
|
27
|
+
- CI verification or non-interactive environments where privileged proxy setup could hang or fail.
|
|
28
|
+
- The user has not approved installing Portless or making local machine changes.
|
|
29
|
+
- The only goal is to run a single test or inspect code; use normal project commands instead.
|
|
30
|
+
|
|
31
|
+
## Safety Model
|
|
32
|
+
|
|
33
|
+
Portless can touch machine-level state. Classify commands before running them:
|
|
34
|
+
|
|
35
|
+
| Class | Examples | Policy |
|
|
36
|
+
| ---------------- | --------------------------------------------------------------------- | -------------------------------------------------- |
|
|
37
|
+
| Read-only | `portless --version`, `portless list`, `portless get <service>` | OK if binary exists |
|
|
38
|
+
| Process-local | `portless run npm run dev` | Ask first; starts a long-running server/proxy path |
|
|
39
|
+
| Machine-mutating | install, CA trust, hosts sync, proxy start/stop, aliases, prune/clean | Ask first; explain impact |
|
|
40
|
+
| Network-exposing | LAN mode, `.local` sharing | Ask first; mention local network exposure |
|
|
41
|
+
|
|
42
|
+
Never run `sudo`, trust a CA, edit `/etc/hosts`, start/stop global proxies, prune/clean state, or expose LAN services without explicit approval in the current conversation.
|
|
43
|
+
|
|
44
|
+
## Detection Checklist
|
|
45
|
+
|
|
46
|
+
Before suggesting Portless:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
command -v portless >/dev/null 2>&1 && portless --version
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If installed, read current state without mutating it:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
portless list
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If a service is already known, resolve its URL:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
portless get <service>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If Portless is not installed, do **not** install automatically. Ask whether the user wants global/user-local Portless setup and state that it may configure local proxy, HTTPS trust, and hosts entries depending on the chosen setup path.
|
|
65
|
+
|
|
66
|
+
## Verification Workflow
|
|
67
|
+
|
|
68
|
+
When approved and useful for a local web task:
|
|
69
|
+
|
|
70
|
+
1. Prefer the project's existing dev command from `package.json`, `Makefile`, or docs.
|
|
71
|
+
2. Ask before wrapping it with Portless.
|
|
72
|
+
3. Start the dev server with Portless in a visible terminal/process:
|
|
73
|
+
```bash
|
|
74
|
+
portless run npm run dev
|
|
75
|
+
```
|
|
76
|
+
4. Resolve the stable URL:
|
|
77
|
+
```bash
|
|
78
|
+
portless get <service>
|
|
79
|
+
```
|
|
80
|
+
5. Use the stable URL for browser automation, OAuth/webhook callback notes, manual checkpoints, or PR testing instructions.
|
|
81
|
+
6. Keep normal verification gates (`typecheck`, `lint`, `test`, `build`) separate; a reachable Portless URL does not prove code correctness.
|
|
82
|
+
|
|
83
|
+
## Command Integration Rules
|
|
84
|
+
|
|
85
|
+
- `/create` and `/plan`: mention Portless only when success criteria involve browser/manual local-web verification or callback URLs.
|
|
86
|
+
- `/ship`: use Portless during Phase 4 only if approved and relevant; never auto-install or auto-start it.
|
|
87
|
+
- `/verify`: may use read-only `portless list` / `portless get` evidence and approved stable URLs for manual or browser checks.
|
|
88
|
+
- `/status`: may include `portless list` if installed; no Portless mutations from status.
|
|
89
|
+
- `/lfg`: inherits Portless behavior through `/plan`, `/ship`, and `/verify`; do not add a separate Portless branch.
|
|
90
|
+
|
|
91
|
+
## Reporting
|
|
92
|
+
|
|
93
|
+
When Portless is used, report:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
Portless: [not installed | installed | approved active]
|
|
97
|
+
Service: <name>
|
|
98
|
+
URL: https://<name>.localhost
|
|
99
|
+
Evidence: <command used to resolve or verify>
|
|
100
|
+
Limitations: normal gates still required
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If setup was skipped because approval was missing, say exactly what was skipped and continue with normal localhost/port verification.
|
|
104
|
+
|
|
105
|
+
## Gotchas
|
|
106
|
+
|
|
107
|
+
- **Privileged local networking is not a harmless helper** — Portless may bind 80/443, invoke sudo, add a local CA, or mutate hosts/proxy state. Always separate read-only discovery from machine-mutating setup.
|
|
108
|
+
- **Pre-1.0 tool behavior can churn** — Verify current CLI behavior with `portless --version` and read-only commands before relying on exact subcommand output.
|
|
109
|
+
- **Stable URL reachability is not correctness** — A named URL only proves routing. Still run project gates and feature-specific tests before claiming completion.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: terse-output-mode
|
|
3
|
+
description: Use when the user asks for terse, brief, less-wordy, token-efficient, or caveman-style responses. Applies concise output style while preserving technical precision, verification evidence, safety warnings, and exact code/command/error text.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [workflow]
|
|
6
|
+
dependencies: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Terse Output Mode
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Terse output mode reduces assistant prose, not tool output or reasoning quality. Use it to answer with fewer words while preserving exact technical substance, safety constraints, and verification evidence.
|
|
14
|
+
|
|
15
|
+
Default style is professional terse. Use meme-like caveman phrasing only when the user explicitly asks for `caveman mode`.
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- User says: "be brief", "less words", "terse", "concise", "token-efficient", "caveman mode", or similar.
|
|
20
|
+
- User wants short implementation progress updates.
|
|
21
|
+
- User asks for compact status, diff summaries, review findings, or next actions.
|
|
22
|
+
- Context pressure is high and user-facing prose can be shortened without losing fidelity.
|
|
23
|
+
|
|
24
|
+
## When NOT to Use
|
|
25
|
+
|
|
26
|
+
- Security warnings, secrets handling, destructive actions, or irreversible confirmations.
|
|
27
|
+
- PRDs, implementation plans, ADRs, migrations, release notes, or docs where clarity beats brevity.
|
|
28
|
+
- Debugging explanations where missing nuance could cause a wrong fix.
|
|
29
|
+
- User appears confused, asks for clarification, or repeats a question.
|
|
30
|
+
- Verification evidence would be hidden by compression.
|
|
31
|
+
|
|
32
|
+
## Core Rules
|
|
33
|
+
|
|
34
|
+
1. **Preserve exact technical content** — never rewrite code, commands, file paths, error strings, versions, numbers, API names, or config keys.
|
|
35
|
+
2. **Cut filler first** — remove pleasantries, hedging, throat-clearing, repeated context, and generic reassurance.
|
|
36
|
+
3. **Keep evidence** — completion claims still need command output, counts, exit status, or file references.
|
|
37
|
+
4. **Prefer fragments when safe** — short noun-verb sentences are fine for status updates.
|
|
38
|
+
5. **Cite precisely** — keep `file:line` references when making code claims.
|
|
39
|
+
6. **Do not hide uncertainty** — if uncertain, say what is missing in fewer words.
|
|
40
|
+
7. **Normal code artifacts** — commits, PR descriptions, docs, specs, and user-facing copy keep normal professional language unless requested otherwise.
|
|
41
|
+
|
|
42
|
+
## Auto-Clarity Escape Hatch
|
|
43
|
+
|
|
44
|
+
Temporarily leave terse mode when brevity would create risk:
|
|
45
|
+
|
|
46
|
+
| Situation | Action |
|
|
47
|
+
| ----------------------------- | ---------------------------------------- |
|
|
48
|
+
| Security or data-loss warning | Use normal explicit wording |
|
|
49
|
+
| Destructive confirmation | State full impact and options |
|
|
50
|
+
| Multi-step manual instruction | Use numbered complete steps |
|
|
51
|
+
| Ambiguous user intent | Ask one clear question |
|
|
52
|
+
| User confusion | Explain normally, then resume terse mode |
|
|
53
|
+
|
|
54
|
+
After the risky section, return to terse output automatically.
|
|
55
|
+
|
|
56
|
+
## Output Patterns
|
|
57
|
+
|
|
58
|
+
### Status Update
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
Changed `src/auth.ts:42` guard. Typecheck running.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Findings
|
|
65
|
+
|
|
66
|
+
```markdown
|
|
67
|
+
Critical: `src/form.tsx:88` error text is not associated with input. Screen readers miss failure.
|
|
68
|
+
Fix: add `aria-describedby`, `aria-invalid`, and `role="alert"`.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Final Report
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
Added optional terse output mode and intent mapping.
|
|
75
|
+
`npm run lint` passes: 0 warnings, 0 errors. Typecheck passes.
|
|
76
|
+
No commit made.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Boundaries
|
|
80
|
+
|
|
81
|
+
- This skill is output style only.
|
|
82
|
+
- It does not replace `rtk-command-compression`; RTK handles shell/tool output compression.
|
|
83
|
+
- It does not replace DCP/context compression; DCP handles conversation compression.
|
|
84
|
+
- It does not install hooks, plugins, binaries, or dependencies.
|
|
85
|
+
- It does not rewrite memory files or project documentation unless explicitly asked.
|
|
86
|
+
|
|
87
|
+
## Common Mistakes
|
|
88
|
+
|
|
89
|
+
| Mistake | Fix |
|
|
90
|
+
| ----------------------------------- | -------------------------------------------------------------- |
|
|
91
|
+
| Making terse mode always-on | Activate only on user request or clear token-efficiency intent |
|
|
92
|
+
| Dropping verification evidence | Keep fresh command evidence for any completion claim |
|
|
93
|
+
| Rewriting exact errors or commands | Preserve exact text in code spans |
|
|
94
|
+
| Using caveman meme voice by default | Default to professional terse |
|
|
95
|
+
| Compressing plans/specs too hard | Use normal detail for durable artifacts |
|