@oh-my-pi/pi-coding-agent 17.2.13 → 17.2.15
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/CHANGELOG.md +30 -0
- package/dist/{CHANGELOG-d8xh7keh.md → CHANGELOG-fk29zh06.md} +30 -0
- package/dist/cli.js +5114 -5417
- package/dist/types/cleanse/agent.d.ts +3 -0
- package/dist/types/cleanse/checkers.d.ts +21 -1
- package/dist/types/cleanse/index.d.ts +4 -0
- package/dist/types/cleanse/parsers.d.ts +3 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/cleanse-picker.d.ts +17 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/cli/progress-reporter.d.ts +19 -0
- package/dist/types/commands/cleanse.d.ts +11 -0
- package/dist/types/commands/compress.d.ts +37 -0
- package/dist/types/commands/launch-help.d.ts +3 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/compress/index.d.ts +27 -0
- package/dist/types/compress/protocol.d.ts +49 -0
- package/dist/types/compress/session.d.ts +15 -0
- package/dist/types/compress/types.d.ts +54 -0
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/internal-urls/local-protocol.d.ts +8 -0
- package/dist/types/mcp/transports/header-policy.d.ts +8 -0
- package/dist/types/mcp/transports/http.d.ts +2 -0
- package/dist/types/mcp/types.d.ts +19 -0
- package/dist/types/modes/components/late-diagnostics-message.d.ts +2 -0
- package/dist/types/modes/components/todo-reminder.d.ts +2 -0
- package/dist/types/modes/components/tool-activity.d.ts +17 -0
- package/dist/types/modes/components/transcript-container.d.ts +2 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -1
- package/dist/types/modes/types.d.ts +3 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +2 -1
- package/dist/types/modes/utils/ui-helpers.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/session-tools.d.ts +13 -0
- package/dist/types/tools/builtin-names.d.ts +1 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/think.d.ts +41 -0
- package/dist/types/utils/zip.d.ts +19 -9
- package/package.json +13 -13
- package/src/cleanse/agent.ts +67 -2
- package/src/cleanse/checkers.ts +252 -21
- package/src/cleanse/index.ts +90 -36
- package/src/cleanse/parsers.ts +243 -20
- package/src/cleanse/prompts/discovery.md +74 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/cleanse-picker.ts +86 -0
- package/src/cli/command-help.ts +4 -0
- package/src/cli/flag-tables.ts +1 -0
- package/src/cli/gallery-fixtures/agentic.ts +16 -0
- package/src/{cleanse/progress.ts → cli/progress-reporter.ts} +12 -7
- package/src/cli-commands.ts +5 -0
- package/src/commands/cleanse.ts +19 -4
- package/src/commands/compress.ts +45 -0
- package/src/commands/launch-help.ts +3 -0
- package/src/commit/agentic/prompts/analyze-file.md +6 -6
- package/src/commit/agentic/prompts/session-user.md +4 -4
- package/src/compress/index.ts +318 -0
- package/src/compress/prompts/request.md +11 -0
- package/src/compress/prompts/review.md +17 -0
- package/src/compress/prompts/system.md +81 -0
- package/src/compress/protocol.ts +210 -0
- package/src/compress/session.ts +72 -0
- package/src/compress/types.ts +59 -0
- package/src/config/settings-schema.ts +11 -0
- package/src/discovery/builtin-rules/go-add-cleanup.md +8 -8
- package/src/discovery/builtin-rules/go-exp-promoted.md +8 -8
- package/src/discovery/builtin-rules/go-ioutil.md +12 -12
- package/src/discovery/builtin-rules/go-new-expr.md +8 -8
- package/src/discovery/builtin-rules/go-range-int.md +5 -5
- package/src/discovery/builtin-rules/rs-box-leak.md +7 -7
- package/src/discovery/builtin-rules/rs-future-prelude.md +4 -4
- package/src/discovery/builtin-rules/rs-parking-lot.md +6 -6
- package/src/discovery/builtin-rules/ts-no-any.md +5 -5
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +8 -8
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +13 -14
- package/src/discovery/builtin-rules/ts-no-local-is-record.md +7 -7
- package/src/discovery/builtin-rules/ts-no-test-timers.md +3 -9
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +7 -7
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +2 -2
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +3 -9
- package/src/discovery/builtin-rules/ts-set-map.md +2 -4
- package/src/internal-urls/local-protocol.ts +42 -0
- package/src/live/prompts/live-instructions.md +10 -10
- package/src/main.ts +4 -0
- package/src/mcp/client.ts +7 -3
- package/src/mcp/transports/header-policy.ts +28 -0
- package/src/mcp/transports/http.ts +200 -35
- package/src/mcp/types.ts +21 -0
- package/src/modes/components/chat-transcript-builder.ts +17 -5
- package/src/modes/components/late-diagnostics-message.ts +12 -1
- package/src/modes/components/todo-reminder.ts +12 -0
- package/src/modes/components/tool-activity.ts +45 -0
- package/src/modes/components/transcript-container.ts +16 -0
- package/src/modes/components/ttsr-notification.ts +12 -0
- package/src/modes/controllers/event-controller.ts +3 -6
- package/src/modes/controllers/input-controller.ts +6 -6
- package/src/modes/controllers/selector-controller.ts +8 -6
- package/src/modes/interactive-mode.ts +5 -40
- package/src/modes/print-mode.ts +13 -54
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/transcript-render-helpers.ts +3 -2
- package/src/modes/utils/ui-helpers.ts +17 -7
- package/src/prompts/advisor/active-repo-watchdog.md +3 -4
- package/src/prompts/advisor/advise-tool.md +3 -3
- package/src/prompts/advisor/context-files.md +1 -1
- package/src/prompts/advisor/system.md +45 -65
- package/src/prompts/agents/designer.md +44 -44
- package/src/prompts/agents/init.md +18 -18
- package/src/prompts/agents/librarian.md +31 -31
- package/src/prompts/agents/reviewer.md +34 -39
- package/src/prompts/agents/security-reviewer.md +3 -5
- package/src/prompts/agents/task.md +11 -12
- package/src/prompts/bench.md +2 -5
- package/src/prompts/ci-green-request.md +13 -15
- package/src/prompts/dry-balance-bench.md +5 -5
- package/src/prompts/goals/goal-budget-limit.md +4 -5
- package/src/prompts/goals/goal-continuation.md +11 -11
- package/src/prompts/goals/goal-mode-active.md +7 -7
- package/src/prompts/goals/goal-todo-context.md +2 -2
- package/src/prompts/goals/guided-goal-interview.md +18 -24
- package/src/prompts/memories/read-path.md +9 -9
- package/src/prompts/memories/stage_one_system.md +9 -11
- package/src/prompts/review-custom-request.md +8 -11
- package/src/prompts/review-headless-request.md +3 -10
- package/src/prompts/security/scan-coordinator.md +6 -5
- package/src/prompts/security/validate-request.md +4 -7
- package/src/prompts/skills/user-invocation.md +2 -2
- package/src/prompts/steering/parent-irc.md +1 -1
- package/src/prompts/steering/user-interjection.md +1 -3
- package/src/prompts/system/active-repo-context.md +4 -2
- package/src/prompts/system/agent-creation-architect.md +22 -37
- package/src/prompts/system/agent-creation-user.md +3 -3
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/auto-thinking-difficulty-local.md +5 -7
- package/src/prompts/system/auto-thinking-difficulty.md +8 -10
- package/src/prompts/system/autolearn-guidance-learn.md +2 -1
- package/src/prompts/system/autolearn-guidance.md +5 -4
- package/src/prompts/system/autolearn-nudge-autocontinue.md +3 -3
- package/src/prompts/system/background-tan-dispatch.md +3 -3
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +8 -6
- package/src/prompts/system/eager-task.md +3 -3
- package/src/prompts/system/empty-stop-retry.md +1 -1
- package/src/prompts/system/gemini-tool-call-reminder.md +5 -5
- package/src/prompts/system/interrupted-thinking.md +3 -3
- package/src/prompts/system/irc-autoreply.md +1 -1
- package/src/prompts/system/irc-incoming.md +3 -3
- package/src/prompts/system/manual-continue.md +3 -3
- package/src/prompts/system/mcp-xdev-guidance.md +2 -2
- package/src/prompts/system/memory-consolidation-system.md +2 -2
- package/src/prompts/system/mid-run-todo-nudge.md +1 -1
- package/src/prompts/system/orchestrate-notice.md +25 -25
- package/src/prompts/system/personalities/default.md +9 -9
- package/src/prompts/system/personalities/friendly.md +11 -11
- package/src/prompts/system/personalities/pragmatic.md +8 -8
- package/src/prompts/system/plan-mode-active.md +61 -64
- package/src/prompts/system/plan-mode-approved.md +10 -11
- package/src/prompts/system/plan-mode-compact-instructions.md +11 -11
- package/src/prompts/system/plan-mode-reference.md +5 -5
- package/src/prompts/system/plan-yolo-handoff.md +2 -2
- package/src/prompts/system/prewalk-checklist.md +5 -5
- package/src/prompts/system/prewalk-continue.md +1 -1
- package/src/prompts/system/prewalk-plan.md +8 -9
- package/src/prompts/system/project-prompt.md +11 -12
- package/src/prompts/system/recap-user.md +1 -1
- package/src/prompts/system/resolve-device-reminder.md +1 -1
- package/src/prompts/system/rewind-report.md +3 -3
- package/src/prompts/system/side-channel-no-tools.md +3 -1
- package/src/prompts/system/snapcompact-context-stub.md +1 -1
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -1
- package/src/prompts/system/snapcompact-system-stub.md +1 -1
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -1
- package/src/prompts/system/speech-rewrite.md +11 -13
- package/src/prompts/system/subagent-async-pending.md +5 -5
- package/src/prompts/system/subagent-system-prompt.md +5 -15
- package/src/prompts/system/subagent-user-prompt.md +1 -1
- package/src/prompts/system/subagent-yield-reminder.md +12 -12
- package/src/prompts/system/system-prompt.md +110 -136
- package/src/prompts/system/tan-context-switch.md +8 -14
- package/src/prompts/system/task-label.md +3 -3
- package/src/prompts/system/thinking-loop-redirect.md +6 -6
- package/src/prompts/system/title-marker-instruction.md +2 -1
- package/src/prompts/system/title-system.md +3 -5
- package/src/prompts/system/ttsr-interrupt.md +3 -3
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/ultrathink-notice.md +1 -1
- package/src/prompts/system/unexpected-stop-classifier.md +3 -3
- package/src/prompts/system/vibe-mode-active.md +15 -15
- package/src/prompts/system/web-search.md +16 -16
- package/src/prompts/system/workflow-notice.md +35 -33
- package/src/prompts/system/xdev-mount-notice.md +4 -4
- package/src/prompts/tools/apply-patch.md +22 -23
- package/src/prompts/tools/approve.md +5 -0
- package/src/prompts/tools/ask.md +10 -10
- package/src/prompts/tools/checkpoint.md +7 -7
- package/src/prompts/tools/computer.md +16 -16
- package/src/prompts/tools/github.md +12 -12
- package/src/prompts/tools/goal.md +8 -9
- package/src/prompts/tools/grep.md +5 -5
- package/src/prompts/tools/image-attachment-describe-system.md +6 -6
- package/src/prompts/tools/image-attachment-describe.md +3 -8
- package/src/prompts/tools/image-gen.md +4 -4
- package/src/prompts/tools/inspect-image-system.md +10 -10
- package/src/prompts/tools/inspect-image.md +10 -13
- package/src/prompts/tools/learn.md +4 -4
- package/src/prompts/tools/manage-skill.md +9 -6
- package/src/prompts/tools/memory-edit.md +8 -8
- package/src/prompts/tools/recall.md +4 -4
- package/src/prompts/tools/reflect.md +2 -2
- package/src/prompts/tools/replace.md +13 -11
- package/src/prompts/tools/retain.md +3 -4
- package/src/prompts/tools/rewind.md +7 -8
- package/src/prompts/tools/rewrite.md +12 -0
- package/src/prompts/tools/security-publish.md +5 -1
- package/src/prompts/tools/security-scan.md +10 -1
- package/src/prompts/tools/task-async-contract.md +7 -1
- package/src/prompts/tools/todo.md +27 -25
- package/src/prompts/tools/vibe-kill.md +2 -2
- package/src/prompts/tools/vibe-list.md +2 -2
- package/src/prompts/tools/vibe-send.md +6 -7
- package/src/prompts/tools/vibe-spawn.md +8 -6
- package/src/prompts/tools/web-search.md +5 -5
- package/src/sdk.ts +10 -1
- package/src/session/agent-session-types.ts +2 -0
- package/src/session/agent-session.ts +28 -0
- package/src/session/session-handoff.ts +21 -0
- package/src/session/session-tools.ts +47 -0
- package/src/tools/builtin-names.ts +1 -2
- package/src/tools/index.ts +10 -0
- package/src/tools/read-format.ts +8 -3
- package/src/tools/read.ts +18 -7
- package/src/tools/renderers.ts +2 -0
- package/src/tools/think.ts +84 -0
- package/src/tools/write.ts +1 -1
- package/src/utils/file-mentions.ts +8 -2
- package/src/utils/zip.ts +858 -94
- package/dist/types/cleanse/progress.d.ts +0 -14
|
@@ -33,12 +33,12 @@ let guard = data.lock();
|
|
|
33
33
|
|
|
34
34
|
## Equivalents
|
|
35
35
|
|
|
36
|
-
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
|std::sync|parking_lot|
|
|
37
|
+
|---|---|
|
|
38
|
+
|`Mutex<T>`|`Mutex<T>`|
|
|
39
|
+
|`RwLock<T>`|`RwLock<T>`|
|
|
40
|
+
|`Condvar`|`Condvar`|
|
|
41
|
+
|`Once`|`Once`|
|
|
42
42
|
|
|
43
43
|
## Keep async locks async
|
|
44
44
|
|
|
@@ -57,10 +57,10 @@ const config = { port: 3000 } satisfies ServerConfig;
|
|
|
57
57
|
|
|
58
58
|
## Choosing: guard vs schema vs unchecked cast
|
|
59
59
|
|
|
60
|
-
|
|
|
61
|
-
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
60
|
+
|Situation|Reach for|
|
|
61
|
+
|---|---|
|
|
62
|
+
|Data from outside your control — network/RPC, parsed JSON, config files, env vars, CLI/IPC, persisted blobs — or a shape reused across the codebase|**Schema parse** (Zod/Valibot/…): runtime validation, typed output, and a clear error on bad shape|
|
|
63
|
+
|In-process value the compiler merely lost track of — an `unknown` from a generic, a union to discriminate, a one-off read of a field or two|**Type guard** (`in` / `typeof`): no dependency, but it only checks what you write, so keep the checked surface small|
|
|
64
|
+
|You genuinely know more than the compiler *and* a runtime check is impossible or meaningless — a well-known DOM node (`as HTMLElement`), structurally-identical types inference can't unify, a library type that is wrong or unexpressible, `as const`|**Unchecked cast** (`as` / `as unknown as T`): assign to a named const with a one-line reason; never for raw external input|
|
|
65
65
|
|
|
66
66
|
If a library boundary truly requires an unchecked cast, use `as unknown as T` with a short reason. Never leave a bare `any`.
|
|
@@ -5,14 +5,14 @@ scope: "tool:edit(*.ts), tool:edit(*.tsx), tool:write(*.ts), tool:write(*.tsx)"
|
|
|
5
5
|
interruptMode: never
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Never use `@deprecated` instead of completing a refactor. Obsolete APIs in code you control: update every call site; remove the old name in the same change.
|
|
9
9
|
|
|
10
10
|
## Why
|
|
11
11
|
|
|
12
|
-
- Deprecated aliases
|
|
13
|
-
- Future maintainers
|
|
14
|
-
- Tests
|
|
15
|
-
-
|
|
12
|
+
- Deprecated aliases: two live contracts.
|
|
13
|
+
- Future maintainers preserve behavior nobody should call.
|
|
14
|
+
- Tests pass while production uses the old path.
|
|
15
|
+
- Next refactor unwinds real API and compatibility layer.
|
|
16
16
|
|
|
17
17
|
## Avoid
|
|
18
18
|
|
|
@@ -39,7 +39,7 @@ export function createClient(options: ClientOptions): Client { ... }
|
|
|
39
39
|
## Exceptions
|
|
40
40
|
|
|
41
41
|
- Public package APIs with a documented migration window.
|
|
42
|
-
- Third-party declarations
|
|
43
|
-
- Tests
|
|
42
|
+
- Third-party declarations whose deprecated marker reflects an external contract.
|
|
43
|
+
- Tests intentionally verifying deprecated API behavior during a supported transition.
|
|
44
44
|
|
|
45
|
-
If an exception applies, state the external compatibility requirement. Otherwise
|
|
45
|
+
If an exception applies, state the external compatibility requirement. Otherwise complete the refactor; delete the deprecated symbol.
|
|
@@ -8,13 +8,15 @@ astCondition:
|
|
|
8
8
|
- "($X as { $$$BODY })[$IDX]"
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Don't inline-cast an object type for member access
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`(value as { content: unknown }).content` fabricates an unchecked shape, then trusts it for the access. If `value` lacks that shape, the read is silently wrong; no type error fires.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
15
|
+
## Why
|
|
16
|
+
|
|
17
|
+
- Unchecked assertion: suppresses the error; proves no shape.
|
|
18
|
+
- Localizes the lie; readers cannot tell whether `value` was validated.
|
|
19
|
+
- Usually replace with runtime narrowing or a validated boundary type.
|
|
18
20
|
|
|
19
21
|
## Avoid
|
|
20
22
|
|
|
@@ -27,8 +29,7 @@ const flag = (opts as { enabled: boolean })["enabled"];
|
|
|
27
29
|
|
|
28
30
|
## Use
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
once, then read from a fully typed value:
|
|
32
|
+
At a boundary, prefer a schema parse when a validator exists: validate once, then read a fully typed value.
|
|
32
33
|
|
|
33
34
|
```ts
|
|
34
35
|
import { type } from "@oh-my-pi/omptype";
|
|
@@ -39,7 +40,7 @@ const resp = Resp.assert(raw); // throws on bad input; resp.data.id is typed str
|
|
|
39
40
|
const id = resp.data.id;
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
For a one-off read
|
|
43
|
+
For a one-off field read, narrow with `in` / `typeof`; access is checked. After `"content" in value`, TypeScript infers the property as `unknown`:
|
|
43
44
|
|
|
44
45
|
```ts
|
|
45
46
|
if (value && typeof value === "object" && "content" in value) {
|
|
@@ -47,10 +48,8 @@ if (value && typeof value === "object" && "content" in value) {
|
|
|
47
48
|
}
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
##
|
|
51
|
+
## Choose: guard vs schema vs unchecked cast
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| In-process value the compiler merely lost track of — an `unknown` from a generic, a union to discriminate, a one-off read of a field or two | **Type guard** (`in` / `typeof`): no dependency, but it only checks what you write, so keep the checked surface small |
|
|
56
|
-
| You genuinely know more than the compiler *and* a runtime check is impossible or meaningless — a well-known DOM node (`as HTMLElement`), structurally-identical types inference can't unify, a library type that's wrong or unexpressible, `as const` | **Unchecked cast** (`as`): assign to a named const with a one-line reason; never for raw external input, never inlined into a member access |
|
|
53
|
+
- Outside-controlled data—network/RPC, parsed JSON, config files, env vars, CLI/IPC, persisted blobs—or codebase-reused shapes: **Schema parse** (Zod/Valibot/…): runtime validation, typed output, clear bad-shape error.
|
|
54
|
+
- In-process values the compiler lost—generic `unknown`, union discrimination, one-off reads of one or two fields: **Type guard** (`in` / `typeof`): no dependency; checks only what you write, so keep its surface small.
|
|
55
|
+
- You know more than the compiler **and** runtime checking is impossible or meaningless—well-known DOM node (`as HTMLElement`), structurally-identical types inference cannot unify, wrong or unexpressible library type, `as const`: **Unchecked cast** (`as`): assign to a named const with a one-line reason; never raw external input or inline member access.
|
|
@@ -9,15 +9,15 @@ interruptMode: never
|
|
|
9
9
|
|
|
10
10
|
## Why it's wrong
|
|
11
11
|
|
|
12
|
-
- A `Record<string, unknown>` guard proves
|
|
13
|
-
-
|
|
14
|
-
- Repeated guards hide the
|
|
12
|
+
- A `Record<string, unknown>` guard proves an object, not its fields.
|
|
13
|
+
- Either unnecessarily complicated or insufficiently strong.
|
|
14
|
+
- Repeated guards hide the data contract from readers and TypeScript.
|
|
15
15
|
|
|
16
16
|
## Use
|
|
17
17
|
|
|
18
|
-
`isRecord
|
|
18
|
+
`isRecord`: values narrow to `Record<string, unknown>`; fields remain `unknown`.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Network, config, IPC, persisted, or reused data shapes: parse once at the boundary with the project's schema validator; consume its named output type:
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
const Config = z.object({ retries: z.number().int().nonnegative() });
|
|
@@ -26,7 +26,7 @@ type Config = z.infer<typeof Config>;
|
|
|
26
26
|
const config = Config.parse(raw);
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
If
|
|
29
|
+
If runtime shape uncertain: check used properties with `typeof`, `Array.isArray`, `in`, or a discriminant. If an existing invariant guarantees shape: assert the named type at that boundary, not a duplicate guard:
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
const config = value as Config;
|
|
@@ -45,4 +45,4 @@ const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
|
45
45
|
|
|
46
46
|
## Exceptions
|
|
47
47
|
|
|
48
|
-
A standalone package without a shared type-guard module may define
|
|
48
|
+
A standalone package without a shared type-guard module may define one canonical guard. Export it from the package's type-guard module; never recreate it at individual call sites.
|
|
@@ -8,13 +8,7 @@ scope: "tool:edit(*.test.ts), tool:write(*.test.ts)"
|
|
|
8
8
|
interruptMode: never
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
|
|
13
|
-
## Why it's wrong
|
|
14
|
-
|
|
15
|
-
- Real delays add fixed latency to every invocation; CI pays it on every run.
|
|
16
|
-
- A sleep sized to mask a race is a guess — the race resurfaces under load.
|
|
17
|
-
- A fixed wait hides *what* you are waiting for, so a failure points at a timeout instead of the real cause.
|
|
11
|
+
**Avoid real wall-clock timers in test files.** `Bun.sleep(...)`, `setTimeout(...)`, and `setInterval(...)` bind duration to real time → fixed latency each invocation; CI pays every run. “Long enough” sleeps guess at and mask races; under load, races resurface and flake. Fixed waits hide the awaited condition, so failures point to a timeout, not the cause.
|
|
18
12
|
|
|
19
13
|
## Avoid
|
|
20
14
|
|
|
@@ -43,7 +37,7 @@ test("debounce fires once", () => {
|
|
|
43
37
|
});
|
|
44
38
|
```
|
|
45
39
|
|
|
46
|
-
When
|
|
40
|
+
When code resolves a promise or emits an event, await that signal, not a guessed duration:
|
|
47
41
|
|
|
48
42
|
```typescript
|
|
49
43
|
await once(emitter, "done"); // await the real event
|
|
@@ -52,4 +46,4 @@ const value = await pending; // await the promise the code already exposes
|
|
|
52
46
|
|
|
53
47
|
## Exceptions
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
Integration tests deliberately exercising real timer behavior against the platform clock may need a genuine delay. Keep rare; add a short comment naming why deterministic time control will not work.
|
|
@@ -5,14 +5,14 @@ scope: "tool:edit(*.ts), tool:edit(*.tsx), tool:write(*.ts), tool:write(*.tsx)"
|
|
|
5
5
|
interruptMode: never
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Inline functions whose whole body: one expression or `return`, unless name creates a durable contract.
|
|
9
9
|
|
|
10
10
|
## Why
|
|
11
11
|
|
|
12
|
-
- One-line wrappers
|
|
13
|
-
- Readers
|
|
14
|
-
-
|
|
15
|
-
-
|
|
12
|
+
- One-line wrappers: no real behavior.
|
|
13
|
+
- Readers: jump to verify trivial code.
|
|
14
|
+
- Signature: freezes shape too early.
|
|
15
|
+
- Inline expressions: better search and type flow.
|
|
16
16
|
|
|
17
17
|
## Avoid
|
|
18
18
|
|
|
@@ -42,10 +42,10 @@ const doubled = value * 2;
|
|
|
42
42
|
## Allowed tiny functions
|
|
43
43
|
|
|
44
44
|
- Three or more call sites need lockstep behavior.
|
|
45
|
-
- Exported name
|
|
45
|
+
- Exported name: stable domain concept.
|
|
46
46
|
- Callback identity matters.
|
|
47
47
|
- Type guard preserves narrowing.
|
|
48
48
|
- Public API, test seam, or DI boundary needs indirection.
|
|
49
|
-
- Names
|
|
49
|
+
- Names non-obvious formula or magic-constant computation the inlined expression would not explain alone.
|
|
50
50
|
|
|
51
51
|
If none apply, inline it.
|
|
@@ -5,7 +5,7 @@ scope: "tool:edit(*.ts), tool:edit(*.tsx), tool:write(*.ts), tool:write(*.tsx)"
|
|
|
5
5
|
interruptMode: never
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Prefer `Promise.withResolvers()` over `new Promise((resolve, reject) => ...)`: linear control flow; typed resolvers without callback nesting.
|
|
9
9
|
|
|
10
10
|
## Basic operation
|
|
11
11
|
|
|
@@ -63,4 +63,4 @@ class Gate {
|
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Constructor only if an API specifically requires executor form.
|
|
@@ -35,13 +35,7 @@ astCondition:
|
|
|
35
35
|
- "if ($X != undefined) { clearImmediate($X) }"
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
**Do not guard `clearTimeout` / `clearInterval` / `clearImmediate` with
|
|
39
|
-
|
|
40
|
-
## Why it's wrong
|
|
41
|
-
|
|
42
|
-
- The branch can never change behavior — clearing a missing/`null`/`undefined` handle does nothing.
|
|
43
|
-
- Extra branches inflate the code and hide the one line that matters.
|
|
44
|
-
- It signals a misunderstanding of the timer API to future readers.
|
|
38
|
+
**Do not guard `clearTimeout` / `clearInterval` / `clearImmediate` with truthiness or `null`/`undefined` checks.** Per WHATWG/Node timers spec, calls no-op for `null`, `undefined`, or values without a live timer; guards cannot change behavior, add branches readers must reason about, inflate code, hide the line that matters, and signal timer-API misunderstanding.
|
|
45
39
|
|
|
46
40
|
## Avoid
|
|
47
41
|
|
|
@@ -63,7 +57,7 @@ clearImmediate(id);
|
|
|
63
57
|
|
|
64
58
|
## When a guard *is* warranted
|
|
65
59
|
|
|
66
|
-
Keep
|
|
60
|
+
Keep it only if the body does more than clear, e.g. reassigns the handle or runs other cleanup:
|
|
67
61
|
|
|
68
62
|
```ts
|
|
69
63
|
if (this.timer) {
|
|
@@ -72,4 +66,4 @@ if (this.timer) {
|
|
|
72
66
|
}
|
|
73
67
|
```
|
|
74
68
|
|
|
75
|
-
|
|
69
|
+
Rule fires only if the clear call is the guarded branch's sole statement; legitimate cases are left alone.
|
|
@@ -5,9 +5,9 @@ scope: "tool:edit(**/*.{ts,tsx}), tool:write(**/*.{ts,tsx})"
|
|
|
5
5
|
interruptMode: never
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Small, static string-keyed lookup tables: `Record<K, V>` / `Record<K, true>`.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`Set` / `Map`: dynamic/non-string keys; runtime insertion/deletion; `.size`, `.clear()`, stable insertion order, or iterator APIs.
|
|
11
11
|
|
|
12
12
|
```typescript
|
|
13
13
|
// Static literal → Record
|
|
@@ -24,5 +24,3 @@ for (const item of items) {
|
|
|
24
24
|
seen.add(item.id);
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
|
-
|
|
28
|
-
Small fixed table? `Record`. Runtime collection? `Set` / `Map`.
|
|
@@ -253,6 +253,48 @@ export function resolveLocalRoot(options: LocalProtocolOptions, platform: NodeJS
|
|
|
253
253
|
return path.join(os.tmpdir(), "omp-local", safeSessionId(options));
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Recursively copy every local:// artifact from one session-scoped root to
|
|
258
|
+
* another. Used when a session transition mints a fresh local root (plan
|
|
259
|
+
* approve-and-execute, handoff) so plans, scratch files, and research notes the
|
|
260
|
+
* carried-forward context references stay readable in the replacement session.
|
|
261
|
+
* No-op when the roots match or the source root is absent.
|
|
262
|
+
*/
|
|
263
|
+
export async function copyLocalArtifacts(sourceRoot: string, destinationRoot: string): Promise<void> {
|
|
264
|
+
if (sourceRoot === destinationRoot) return;
|
|
265
|
+
|
|
266
|
+
let sourceRootStat: { isDirectory(): boolean };
|
|
267
|
+
try {
|
|
268
|
+
sourceRootStat = await fs.lstat(sourceRoot);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (isEnoent(error)) return;
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
if (!sourceRootStat.isDirectory()) return;
|
|
274
|
+
|
|
275
|
+
await fs.mkdir(destinationRoot, { recursive: true });
|
|
276
|
+
await copyLocalArtifactEntries(sourceRoot, destinationRoot);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function copyLocalArtifactEntries(sourceDir: string, destinationDir: string): Promise<void> {
|
|
280
|
+
const entries = await fs.readdir(sourceDir, { withFileTypes: true });
|
|
281
|
+
for (const entry of entries) {
|
|
282
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
283
|
+
const destinationPath = path.join(destinationDir, entry.name);
|
|
284
|
+
|
|
285
|
+
if (entry.isDirectory()) {
|
|
286
|
+
await fs.mkdir(destinationPath, { recursive: true });
|
|
287
|
+
await copyLocalArtifactEntries(sourcePath, destinationPath);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (entry.isFile()) {
|
|
292
|
+
await fs.mkdir(path.dirname(destinationPath), { recursive: true });
|
|
293
|
+
await fs.copyFile(sourcePath, destinationPath);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
256
298
|
/** Resolve a local:// URL to an on-disk path under the active session's local root. */
|
|
257
299
|
export function resolveLocalUrlToPath(
|
|
258
300
|
input: string | InternalUrl,
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
You
|
|
1
|
+
You: omp Live, realtime voice surface of one unified coding assistant for {{firstName}} (OS account: {{username}}).
|
|
2
2
|
|
|
3
3
|
<system-conventions>
|
|
4
|
-
RFC 2119
|
|
4
|
+
RFC 2119: MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, OPTIONAL. `NEVER` = `MUST NOT`.
|
|
5
5
|
</system-conventions>
|
|
6
6
|
|
|
7
7
|
<critical>
|
|
8
|
-
- You
|
|
9
|
-
-
|
|
10
|
-
-
|
|
8
|
+
- You + omp coding agent: one assistant, not separate agents.
|
|
9
|
+
- MUST delegate repository work, coding, tool use, verification to client backend.
|
|
10
|
+
- MUST keep conversation natural while client backend works.
|
|
11
11
|
</critical>
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
User speaks to you. MUST respond directly, briefly, conversationally, with speech-friendly phrasing. NEVER use markdown, code blocks, long lists, or read implementation detail aloud unless requested.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Client backend: same assistant's execution surface; repository context, normal omp AgentSession, coding model, tools. Coding, investigation, repository changes, commands, or verification → MUST promptly create client delegation with complete plain-language request and all relevant conversational context; NEVER attempt tool work. New request during active work MUST create new delegation, steering same backend session.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Treat delegation context as own internal progress/results. NEVER describe backend as another assistant. MAY briefly acknowledge active work; NEVER claim changes, findings, or verification before backend reports. Commentary context: silent progress for conversational continuity; NEVER recite. Context beginning with `"Agent Final Message":`: backend's final visible answer; MUST present useful result naturally as own, NEVER mention label, protocol, delegation, or backend.
|
|
18
18
|
|
|
19
|
-
Greetings, clarification,
|
|
19
|
+
Greetings, clarification, ordinary conversation needing no repository/tools: MUST answer directly without delegation. MUST ask concise clarifying question only when execution request genuinely underspecified.
|
|
20
20
|
|
|
21
21
|
<critical>
|
|
22
|
-
|
|
22
|
+
MUST preserve one-assistant continuity: converse here, delegate execution, communicate returned result as own.
|
|
23
23
|
</critical>
|
package/src/main.ts
CHANGED
|
@@ -1333,6 +1333,10 @@ export async function runRootCommand(
|
|
|
1333
1333
|
if (parsedArgs.advisor) {
|
|
1334
1334
|
settingsInstance.override("advisor.enabled", true);
|
|
1335
1335
|
}
|
|
1336
|
+
// Apply --external-thinking CLI flag (ephemeral, not persisted)
|
|
1337
|
+
if (parsedArgs.externalThinking) {
|
|
1338
|
+
settingsInstance.override("externalThinking", true);
|
|
1339
|
+
}
|
|
1336
1340
|
|
|
1337
1341
|
await logger.time(
|
|
1338
1342
|
"initTheme:final",
|
package/src/mcp/client.ts
CHANGED
|
@@ -38,8 +38,7 @@ import type {
|
|
|
38
38
|
MCPTransport,
|
|
39
39
|
} from "./types";
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
const PROTOCOL_VERSION = "2025-03-26";
|
|
41
|
+
import { MCP_PROTOCOL_VERSION } from "./types";
|
|
43
42
|
|
|
44
43
|
/** Client info sent during initialization */
|
|
45
44
|
const CLIENT_INFO = {
|
|
@@ -98,7 +97,7 @@ async function initializeConnection(
|
|
|
98
97
|
},
|
|
99
98
|
): Promise<MCPInitializeResult> {
|
|
100
99
|
const params: MCPInitializeParams = {
|
|
101
|
-
protocolVersion:
|
|
100
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
102
101
|
capabilities: {
|
|
103
102
|
roots: { listChanged: false },
|
|
104
103
|
},
|
|
@@ -115,6 +114,11 @@ async function initializeConnection(
|
|
|
115
114
|
throw options.signal.reason instanceof Error ? options.signal.reason : new Error("Aborted");
|
|
116
115
|
}
|
|
117
116
|
|
|
117
|
+
// Echo the negotiated protocol version on every subsequent request. The MCP
|
|
118
|
+
// Streamable HTTP spec requires the MCP-Protocol-Version header after
|
|
119
|
+
// initialize; transports that don't need it ignore this.
|
|
120
|
+
transport.setProtocolVersion?.(result.protocolVersion);
|
|
121
|
+
|
|
118
122
|
// Hook point: the transport now has the session ID from the initialize response.
|
|
119
123
|
// For HTTP, this is the moment to open the SSE stream so server-to-client requests
|
|
120
124
|
// triggered by notifications/initialized (e.g. roots/list) can be delivered.
|
|
@@ -48,6 +48,34 @@ export function setGeneratedHeader(headers: Record<string, string>, name: string
|
|
|
48
48
|
headers[name] = value;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Return `headers` without any entry whose name case-insensitively matches
|
|
53
|
+
* `name`. Used to keep transport-reserved protocol headers (e.g.
|
|
54
|
+
* `MCP-Protocol-Version`) out of user-configured headers so config can never
|
|
55
|
+
* inject them. Returns the original reference when there is nothing to strip,
|
|
56
|
+
* so the common (no-match) path allocates nothing.
|
|
57
|
+
*/
|
|
58
|
+
export function withoutHeader(
|
|
59
|
+
headers: Record<string, string> | undefined,
|
|
60
|
+
name: string,
|
|
61
|
+
): Record<string, string> | undefined {
|
|
62
|
+
if (!headers) return headers;
|
|
63
|
+
const lower = name.toLowerCase();
|
|
64
|
+
let hasMatch = false;
|
|
65
|
+
for (const key in headers) {
|
|
66
|
+
if (key.toLowerCase() === lower) {
|
|
67
|
+
hasMatch = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!hasMatch) return headers;
|
|
72
|
+
const result: Record<string, string> = {};
|
|
73
|
+
for (const key in headers) {
|
|
74
|
+
if (key.toLowerCase() !== lower) result[key] = headers[key];
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
51
79
|
const REDIRECT_STATUSES: Record<number, true> = { 301: true, 302: true, 303: true, 307: true, 308: true };
|
|
52
80
|
const MAX_REDIRECT_HOPS = 5;
|
|
53
81
|
|