Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/app/src/components/prompt-input-v2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,16 @@ export function usePromptInputV2Controller(props: PromptInputV2ControllerProps):
t: (key, params) => language.t(key as Parameters<typeof language.t>[0], params as never),
}),
)
const designPlaceholder = () => promptDesignPlaceholder(mode(), placeholder())
// The design placeholder takes the translate callback: the helper calls it
// in the non-shell branch, so the 2-arg form passes undefined there —
// minified "n is not a function" on every non-shell composer render.
// #929 (59b447e7) fixed this amicode-side; the fork→overlay sync ff7b69c8
// regressed it back to the 2-arg call. Mirrored to the sync source per
// harmoniqs/amicode#964 so the next sync brings the fix, not the regression.
const designPlaceholder = () =>
promptDesignPlaceholder(mode(), placeholder(), (key, params) =>
language.t(key as Parameters<typeof language.t>[0], params as never),
)

const historyComments = () => {
const byID = new Map(comments.all().map((item) => [`${item.file}\n${item.id}`, item] as const))
Expand Down
34 changes: 33 additions & 1 deletion packages/app/src/components/prompt-input/placeholder.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
import { describe, expect, test } from "bun:test"
import { promptPlaceholder } from "./placeholder"
import { promptDesignPlaceholder, promptPlaceholder } from "./placeholder"

// harmoniqs/amicode#964 — the design placeholder takes the translate callback
// (the #929 contract, mirrored to the sync source). A 2-arg call passes
// undefined as the translate callback, which the helper calls in the
// non-shell branch: the "n is not a function" failure Aaron hit live
// post-cutover 2026-09-10.
describe("promptDesignPlaceholder", () => {
const t = (key: string, params?: Record<string, string>) => {
let out = key
for (const [k, v] of Object.entries(params ?? {})) out = out.split(`{{${k}}}`).join(v)
return out
}

test("returns the shell placeholder verbatim in shell mode", () => {
expect(promptDesignPlaceholder("shell", "git status", t)).toBe("git status")
})

test("translates through the callback in normal mode", () => {
expect(promptDesignPlaceholder("normal", "fallback", t)).toBe(
"ui.promptInput.placeholder.normal",
)
})

test("the translate callback is REQUIRED — the regressed 2-arg call throws", () => {
expect(() =>
(promptDesignPlaceholder as unknown as (mode: "normal", placeholder: string) => string)(
"normal",
"fallback",
),
).toThrow(/is not a function/)
})
})

describe("promptPlaceholder", () => {
const t = (key: string, params?: Record<string, string>) => `${key}${params?.example ? `:${params.example}` : ""}`
Expand Down
15 changes: 12 additions & 3 deletions packages/app/src/components/prompt-input/placeholder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@ export function promptPlaceholder(input: PromptPlaceholderInput) {
return input.t("prompt.placeholder.normal", { example: input.example })
}

export function promptDesignPlaceholder(mode: PromptPlaceholderInput["mode"], placeholder: string) {
// Mirrored from amicode's overlay (upstream v1.18.29 contract): the design
// placeholder takes the translate callback and calls it in the non-shell
// branch — a 2-arg call passes undefined there and throws "n is not a
// function" on every non-shell composer render. The amicode hard-coded brand
// line ("Ask Amico anything, ...") is superseded by the translated key the
// ui locales already carry. See harmoniqs/amicode#929/#964.
export function promptDesignPlaceholder(
mode: PromptPlaceholderInput["mode"],
placeholder: string,
t: PromptPlaceholderInput["t"],
) {
if (mode === "shell") return placeholder
// amicode: brand the composer prompt
return "Ask Amico anything, / for commands, @ for context..."
return t("ui.promptInput.placeholder.normal", { slash: "/", at: "@" })
}
Loading