diff --git a/config/oxlint-anti-slop.json b/config/oxlint-anti-slop.json
index 3a115684ba9..bba8588d949 100644
--- a/config/oxlint-anti-slop.json
+++ b/config/oxlint-anti-slop.json
@@ -35,7 +35,7 @@
"anti-slop/no-reflect-apply": "error",
"anti-slop/no-reflect-get": "error",
"anti-slop/no-runtime-typeof": "off",
- "anti-slop/no-shape-in-symbol-names": "off",
+ "anti-slop/no-shape-in-symbol-names": "error",
"anti-slop/no-unknown-parameters": "off",
"anti-slop/no-unknown-returns": "off",
"anti-slop/no-unknown-type-aliases": "error",
@@ -55,6 +55,56 @@
"rules": {
"anti-slop/no-module-mocking": "off"
}
+ },
+ // The exemptions below are file-scoped rather than inline `oxlint-disable` comments
+ // because the root lint scan does not load this plugin, so an inline directive naming
+ // an anti-slop rule always reads back as an unused directive there.
+ //
+ // In the screenshot annotator a "shape" is the drawn geometry -- pen, arrow, rect,
+ // ellipse, highlight. A domain noun, and it pervades every symbol in the module.
+ // mobile/src/test-support/rpc-recording is the golden recorder engine. recorder-digest.ts
+ // hashes these files' RAW BYTES into every golden's `recorderSha256` header, so any edit
+ // here -- a rename or even an added comment -- invalidates all 208 recordings. The exemption
+ // is config-scoped for that reason: an inline directive would change the bytes it protects.
+ {
+ "files": ["**/test-support/rpc-recording/**"],
+ "rules": {
+ "anti-slop/no-shape-in-symbol-names": "off"
+ }
+ },
+ {
+ "files": ["**/browser-pane/annotate/**"],
+ "rules": {
+ "anti-slop/no-shape-in-symbol-names": "off"
+ }
+ },
+ // lucide exports the icon component as `Shapes`, and the matching REPO_LUCIDE_ICONS key
+ // is the persisted icon name shared by the desktop picker and mobile.
+ {
+ "files": [
+ "**/components/repo/repo-icon.tsx",
+ "**/worktree-list/rows/repo-header-project-actions.tsx",
+ "**/components/MobileRepoIcon.tsx"
+ ],
+ "rules": {
+ "anti-slop/no-shape-in-symbol-names": "off"
+ }
+ },
+ // `shapedSidebar` is a persisted onboarding-checklist field and a telemetry enum member;
+ // renaming it would orphan saved state.
+ {
+ "files": ["**/src/shared/constants.ts", "**/src/shared/onboarding-state-types.ts"],
+ "rules": {
+ "anti-slop/no-shape-in-symbol-names": "off"
+ }
+ },
+ // Matching zod's own literal `shape` property is what selects the ZodObject branch of
+ // RpcSendInput's conditional type.
+ {
+ "files": ["**/rpc-contract/rpc-send-params.ts"],
+ "rules": {
+ "anti-slop/no-shape-in-symbol-names": "off"
+ }
}
]
}
diff --git a/config/scripts/agent-lineage-cycle-cleanup-benchmark.mjs b/config/scripts/agent-lineage-cycle-cleanup-benchmark.mjs
index 47407764e0f..59f4e387beb 100644
--- a/config/scripts/agent-lineage-cycle-cleanup-benchmark.mjs
+++ b/config/scripts/agent-lineage-cycle-cleanup-benchmark.mjs
@@ -50,7 +50,7 @@ for (let sample = 0; sample < 500; sample++) {
}
const results = []
-for (const [shape, count] of [
+for (const [topology, count] of [
['flat', 1000],
['all-cycles', 1000],
['mixed-cycles', 100],
@@ -58,9 +58,9 @@ for (const [shape, count] of [
['mixed-cycles', 1000]
]) {
const rows = Array.from({ length: count }, (_, index) =>
- row(index, shape === 'flat' ? undefined : index ^ 1)
+ row(index, topology === 'flat' ? undefined : index ^ 1)
)
- if (shape === 'mixed-cycles') {
+ if (topology === 'mixed-cycles') {
rows.unshift(row('root', undefined))
}
assert.deepEqual(after(rows), before(rows))
@@ -83,7 +83,7 @@ for (const [shape, count] of [
samples[arm].push({ wallMs, cpuMs: (used.user + used.system) / 30_000 })
}
}
- results.push({ shape, count, samples })
+ results.push({ topology, count, samples })
}
console.log(
JSON.stringify({ baseline, node: process.version, parityGraphs: 500, results }, null, 2)
diff --git a/config/scripts/agent-lineage-reachability-benchmark.mjs b/config/scripts/agent-lineage-reachability-benchmark.mjs
index 4122ac18dab..6d542367c18 100644
--- a/config/scripts/agent-lineage-reachability-benchmark.mjs
+++ b/config/scripts/agent-lineage-reachability-benchmark.mjs
@@ -58,15 +58,19 @@ for (let trial = 0; trial < 5000; trial += 1) {
const results = []
for (const count of [8, 32, 128, 512, 1024]) {
- for (const shape of ['flat', 'fanout', 'balanced', 'chain']) {
+ for (const topology of ['flat', 'fanout', 'balanced', 'chain']) {
const rows = Array.from({ length: count }, (_, index) => {
const parent =
- shape === 'fanout' ? 0 : shape === 'balanced' ? Math.floor((index - 1) / 4) : index - 1
+ topology === 'fanout'
+ ? 0
+ : topology === 'balanced'
+ ? Math.floor((index - 1) / 4)
+ : index - 1
return {
paneKey: `pane-${index}`,
entry: {
orchestration:
- index > 0 && shape !== 'flat' ? { parentPaneKey: `pane-${parent}` } : undefined
+ index > 0 && topology !== 'flat' ? { parentPaneKey: `pane-${parent}` } : undefined
}
}
})
@@ -92,7 +96,7 @@ for (const count of [8, 32, 128, 512, 1024]) {
}
results.push({
count,
- shape,
+ topology,
iterations,
meanMicrosecondsPerTree: Object.fromEntries(
Object.entries(samples).map(([arm, values]) => [
diff --git a/config/scripts/mobile-markdown-placeholder-benchmark.mjs b/config/scripts/mobile-markdown-placeholder-benchmark.mjs
index 20280e5a8d2..dd5cf22d9dc 100644
--- a/config/scripts/mobile-markdown-placeholder-benchmark.mjs
+++ b/config/scripts/mobile-markdown-placeholder-benchmark.mjs
@@ -40,7 +40,7 @@ function measure(fn, input, repeats) {
return samples.sort((a, b) => a - b)[Math.floor(samples.length / 2)]
}
const results = []
-for (const [shape, input] of [
+for (const [inputCase, input] of [
['ordinary Markdown', '# Hello\n\n
Use `Array` and bold.
'],
...[2048, 8192, 16384].map((length) => [
`${length} underscore collision`,
@@ -49,7 +49,7 @@ for (const [shape, input] of [
]) {
assert.equal(after(input), before(input))
results.push({
- shape,
+ inputCase,
bytes: Buffer.byteLength(input),
beforeMs: measure(before, input, 5),
afterMs: measure(after, input, 15)
diff --git a/config/scripts/redactor-environment-lines-benchmark.mjs b/config/scripts/redactor-environment-lines-benchmark.mjs
index 71aebf9fe88..b30e56fee05 100644
--- a/config/scripts/redactor-environment-lines-benchmark.mjs
+++ b/config/scripts/redactor-environment-lines-benchmark.mjs
@@ -25,7 +25,7 @@ function median(fn, input, repeats) {
return samples.sort((a, b) => a - b)[Math.floor(samples.length / 2)]
}
const rows = []
-for (const [shape, input] of [
+for (const [label, input] of [
['8KiB blank lines', '\n'.repeat(8192)],
['16KiB blank lines', '\n'.repeat(16384)],
['32KiB blank lines', '\n'.repeat(32768)],
@@ -37,7 +37,7 @@ for (const [shape, input] of [
const beforeMs = median(before, input, 3)
const afterMs = median(redactString, input, 15)
rows.push({
- shape,
+ label,
bytes: Buffer.byteLength(input),
beforeMs,
afterMs,
diff --git a/config/scripts/repo-icon-source-href-benchmark.mjs b/config/scripts/repo-icon-source-href-benchmark.mjs
index 76c42d261b4..da560724a23 100644
--- a/config/scripts/repo-icon-source-href-benchmark.mjs
+++ b/config/scripts/repo-icon-source-href-benchmark.mjs
@@ -36,15 +36,15 @@ function measurePair(source) {
const results = []
for (const size of [8192, 16384, 32768]) {
- for (const shape of ['no icon', 'rel without href', 'unterminated link starts']) {
+ for (const variant of ['no icon', 'rel without href', 'unterminated link starts']) {
const source =
- shape === 'unterminated link starts'
+ variant === 'unterminated link starts'
? ' interactive login shell -> git',
fast: 'env -> git'
},
diff --git a/mobile/src/components/MobileRepoIcon.tsx b/mobile/src/components/MobileRepoIcon.tsx
index e4f7f9664cf..2ea1f8d573b 100644
--- a/mobile/src/components/MobileRepoIcon.tsx
+++ b/mobile/src/components/MobileRepoIcon.tsx
@@ -16,6 +16,7 @@ import {
Palette,
Rocket,
Server,
+ // `Shapes` is lucide's own export name; exempted in config/oxlint-anti-slop.json.
Shapes,
Sparkles,
SquareTerminal,
diff --git a/mobile/src/tasks/use-mobile-tasks-provider-view-projection.test.tsx b/mobile/src/tasks/use-mobile-tasks-provider-view-projection.test.tsx
index 0eb8d3d32f7..3ab8ae149d4 100644
--- a/mobile/src/tasks/use-mobile-tasks-provider-view-projection.test.tsx
+++ b/mobile/src/tasks/use-mobile-tasks-provider-view-projection.test.tsx
@@ -243,7 +243,7 @@ function countLinearWork(run: () => void): WorkCounts {
}
}
-function shape(sections: LinearIssueSection[]) {
+function summarizeSections(sections: LinearIssueSection[]) {
return sections.map((section) => ({
key: section.key,
label: section.label,
@@ -268,8 +268,8 @@ describe('useMobileTasksProviderViewProjection linear sections', () => {
(linearGroupBy) => {
const projection = mount({ linearGroupBy })
expect(projection.linearBoardSections).toBe(projection.linearIssueSections)
- expect(shape(projection.linearBoardSections)).toEqual(
- shape(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy }).boardSections)
+ expect(summarizeSections(projection.linearBoardSections)).toEqual(
+ summarizeSections(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy }).boardSections)
)
}
)
@@ -278,8 +278,12 @@ describe('useMobileTasksProviderViewProjection linear sections', () => {
const projection = mount({ linearGroupBy: 'none' })
const legacy = legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'none' })
expect(projection.linearBoardSections).not.toBe(projection.linearIssueSections)
- expect(shape(projection.linearIssueSections)).toEqual(shape(legacy.listSections))
- expect(shape(projection.linearBoardSections)).toEqual(shape(legacy.boardSections))
+ expect(summarizeSections(projection.linearIssueSections)).toEqual(
+ summarizeSections(legacy.listSections)
+ )
+ expect(summarizeSections(projection.linearBoardSections)).toEqual(
+ summarizeSections(legacy.boardSections)
+ )
expect(projection.linearIssueSections.map((section) => section.key)).toEqual(['all'])
expect(projection.linearBoardSections.length).toBeGreaterThan(1)
expect(projection.linearListEntries.every((entry) => entry.type === 'issue')).toBe(true)
@@ -293,8 +297,12 @@ describe('useMobileTasksProviderViewProjection linear sections', () => {
linearGroupBy,
linearOrderBy: order
})
- expect(shape(projection.linearIssueSections)).toEqual(shape(legacy.listSections))
- expect(shape(projection.linearBoardSections)).toEqual(shape(legacy.boardSections))
+ expect(summarizeSections(projection.linearIssueSections)).toEqual(
+ summarizeSections(legacy.listSections)
+ )
+ expect(summarizeSections(projection.linearBoardSections)).toEqual(
+ summarizeSections(legacy.boardSections)
+ )
expect(projection.linearIssuesForView.map((issue) => issue.id)).toEqual(
legacy.issuesForView.map((issue) => issue.id)
)
@@ -310,20 +318,24 @@ describe('useMobileTasksProviderViewProjection transitions', () => {
const grouped = rerender({ linearGroupBy: 'status' })
expect(grouped.linearBoardSections).toBe(grouped.linearIssueSections)
- expect(shape(grouped.linearBoardSections)).toEqual(
- shape(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'status' }).boardSections)
+ expect(summarizeSections(grouped.linearBoardSections)).toEqual(
+ summarizeSections(
+ legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'status' }).boardSections
+ )
)
const assignee = rerender({ linearGroupBy: 'assignee' })
expect(assignee.linearBoardSections).toBe(assignee.linearIssueSections)
- expect(shape(assignee.linearBoardSections)).toEqual(
- shape(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'assignee' }).boardSections)
+ expect(summarizeSections(assignee.linearBoardSections)).toEqual(
+ summarizeSections(
+ legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'assignee' }).boardSections
+ )
)
const none = rerender({ linearGroupBy: 'none' })
expect(none.linearBoardSections).not.toBe(none.linearIssueSections)
- expect(shape(none.linearBoardSections)).toEqual(
- shape(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'none' }).boardSections)
+ expect(summarizeSections(none.linearBoardSections)).toEqual(
+ summarizeSections(legacyProjection({ ...DEFAULT_INPUT, linearGroupBy: 'none' }).boardSections)
)
})
@@ -333,8 +345,8 @@ describe('useMobileTasksProviderViewProjection transitions', () => {
const next = rerender({ linearGroupBy: 'priority', linearOrderBy: 'identifier' })
expect(next.linearBoardSections).not.toBe(firstSections)
expect(next.linearBoardSections).toBe(next.linearIssueSections)
- expect(shape(next.linearBoardSections)).toEqual(
- shape(
+ expect(summarizeSections(next.linearBoardSections)).toEqual(
+ summarizeSections(
legacyProjection({
...DEFAULT_INPUT,
linearGroupBy: 'priority',
@@ -369,17 +381,17 @@ describe('useMobileTasksProviderViewProjection transitions', () => {
const refreshed = rerender({ linearGroupBy: 'status', items: makeItems(50) })
expect(refreshed.linearBoardSections).not.toBe(sections)
expect(refreshed.linearBoardSections).toBe(refreshed.linearIssueSections)
- expect(shape(refreshed.linearBoardSections)).toEqual(shape(sections))
+ expect(summarizeSections(refreshed.linearBoardSections)).toEqual(summarizeSections(sections))
})
it('does not mutate the shared sections when the list entries are built', () => {
const projection = mount({ linearGroupBy: 'status' })
- const before = shape(projection.linearIssueSections)
+ const before = summarizeSections(projection.linearIssueSections)
const entryIssueIds = projection.linearListEntries
.filter((entry) => entry.type === 'issue')
.map((entry) => (entry.type === 'issue' ? entry.issue.id : ''))
expect(entryIssueIds).toHaveLength(50)
- expect(shape(projection.linearBoardSections)).toEqual(before)
+ expect(summarizeSections(projection.linearBoardSections)).toEqual(before)
})
})
diff --git a/src/cli/handlers/skills.ts b/src/cli/handlers/skills.ts
index 1b068fc80b0..325262a42f5 100644
--- a/src/cli/handlers/skills.ts
+++ b/src/cli/handlers/skills.ts
@@ -17,7 +17,7 @@ import {
UnsafeWindowsBatchArgumentsError,
WINDOWS_BATCH_UNSAFE_CHARACTERS_LABEL
} from '../../shared/windows-batch-spawn'
-import { isSkillsCliAgentKeyShaped, toSkillsCliAgentKeys } from '../../shared/skills-cli-agent-keys'
+import { isUsableSkillsCliAgentKey, toSkillsCliAgentKeys } from '../../shared/skills-cli-agent-keys'
import {
buildAgentFeatureSkillInstallArgs,
buildAgentFeatureSkillUpdateArgs
@@ -150,7 +150,7 @@ function resolveInstallAgentKeys(flags: Map): string[]
if (keys.length === 0) {
throw new RuntimeClientError('invalid_argument', 'Missing required --agent')
}
- const unusable = keys.find((key) => !isSkillsCliAgentKeyShaped(key))
+ const unusable = keys.find((key) => !isUsableSkillsCliAgentKey(key))
if (unusable !== undefined) {
// Why: the skills CLI drops a value starting with `-`, which leaves it with
// no target and installs into every agent it knows.
diff --git a/src/main/ai-vault-search/session-search-lifecycle-matrix.test.ts b/src/main/ai-vault-search/session-search-lifecycle-matrix.test.ts
index 79cbe70eb7f..220e7d8390d 100644
--- a/src/main/ai-vault-search/session-search-lifecycle-matrix.test.ts
+++ b/src/main/ai-vault-search/session-search-lifecycle-matrix.test.ts
@@ -47,7 +47,7 @@ const CAN_DENY_READ = process.platform !== 'win32' && process.getuid?.() !== 0
const INTERVAL_MS = 20_000
const SESSIONS = ['aaaaaaaa', 'bbbbbbbb', 'cccccccc']
-type RootShape = {
+type RootLayout = {
name: string
/** Where the unreachable root's transcripts live, and where its files go. */
detachedRoot: (harness: SessionSearchIndexerHarness) => string
@@ -59,7 +59,7 @@ type RootShape = {
const OPENCLAW_SESSION_DIR = join('agents', 'main', 'sessions')
-const ROOT_SHAPES: RootShape[] = [
+const ROOT_LAYOUTS: RootLayout[] = [
{
name: 'roots discovery reports one per directory',
detachedRoot: (harness) => harness.roots.claudeProjectsDir ?? '',
@@ -81,7 +81,7 @@ const ROOT_SHAPES: RootShape[] = [
}
]
-type UnreachableShape = {
+type UnreachableMode = {
name: string
needsDeniedRead: boolean
/**
@@ -97,7 +97,7 @@ type UnreachableShape = {
attach: (root: string, transcriptDir: string, parked: string) => Promise
}
-const UNREACHABLE_SHAPES: UnreachableShape[] = [
+const UNREACHABLE_MODES: UnreachableMode[] = [
{
name: 'the root itself is not there',
needsDeniedRead: false,
@@ -276,8 +276,8 @@ function indexedSessions(): string[] {
.sort()
}
-for (const roots of ROOT_SHAPES) {
- for (const unreachable of UNREACHABLE_SHAPES) {
+for (const roots of ROOT_LAYOUTS) {
+ for (const unreachable of UNREACHABLE_MODES) {
describe.skipIf(unreachable.needsDeniedRead && !CAN_DENY_READ)(
`${roots.name}, ${unreachable.name}`,
() => {
@@ -298,7 +298,7 @@ for (const roots of ROOT_SHAPES) {
// pass, so the setup drives passes until the index has caught up.
await driveUntilIndexed(SESSIONS.length * 2)
const detachedIds = detachedPaths.map((_path, index) =>
- roots === ROOT_SHAPES[0]
+ roots === ROOT_LAYOUTS[0]
? fullSessionId(SESSIONS[index] ?? '')
: (SESSIONS[index] ?? '')
)
diff --git a/src/main/ai-vault-search/session-search-query-planner.ts b/src/main/ai-vault-search/session-search-query-planner.ts
index 6c2c2f3b91c..91e8711fbe3 100644
--- a/src/main/ai-vault-search/session-search-query-planner.ts
+++ b/src/main/ai-vault-search/session-search-query-planner.ts
@@ -17,7 +17,7 @@ const MAX_TERMS = 64
// A query that quotes something from a transcript: camelCase, SCREAMING_SNAKE,
// a dotted or snake_case name, a path, a filename, a PR number, a ticket, code
// punctuation, or an error word.
-const LITERAL_SHAPE =
+const LITERAL_PATTERN =
/[A-Za-z0-9_]*[a-z][A-Z][A-Za-z0-9_]*|\b[A-Z][A-Z0-9]{2,}(_[A-Z0-9]+)+\b|\b\w{2,}[._]\w{2,}\b|\b[\w.-]+\/[\w/.-]+\b|\b\w+\.(ts|tsx|js|jsx|py|rs|go|json|md|sh|yml|yaml|toml|c|cc|h|java|sql)\b|#\d{3,}|\b[A-Z]{2,6}-\d{2,}\b|[(){};=]|::|->|--\w|\b(Error|Exception|Traceback|error:|warning:)\b/
const QUOTED = /"[^"]{3,}"|'[^']{3,}'/
@@ -36,7 +36,7 @@ export type SessionSearchQueryPlan = {
}
export function isLiteralQuery(query: string): boolean {
- return QUOTED.test(query) || LITERAL_SHAPE.test(query)
+ return QUOTED.test(query) || LITERAL_PATTERN.test(query)
}
/**
diff --git a/src/main/ai-vault/session-delete-target.ts b/src/main/ai-vault/session-delete-target.ts
index 13320ce39e9..a893e639fad 100644
--- a/src/main/ai-vault/session-delete-target.ts
+++ b/src/main/ai-vault/session-delete-target.ts
@@ -21,7 +21,7 @@ import type { AiVaultScanOptions } from './session-scanner-types'
// Agents whose session IS the directory holding the scanned file: everything
// beside it belongs to the same session (rovo's session_context.json, grok's
// chat_history.jsonl), so the directory is the only complete delete unit.
-const AI_VAULT_DIRECTORY_SHAPED_DELETE_AGENTS = new Set([
+const AI_VAULT_WHOLE_DIRECTORY_DELETE_AGENTS = new Set([
'rovo',
'grok',
'cline'
@@ -109,7 +109,7 @@ function sessionDeleteRemovals(args: {
}): readonly AiVaultSessionDeleteRemoval[] | null {
const { agent, resolvedPath, matchedRoot, roots } = args
- if (AI_VAULT_DIRECTORY_SHAPED_DELETE_AGENTS.has(agent)) {
+ if (AI_VAULT_WHOLE_DIRECTORY_DELETE_AGENTS.has(agent)) {
const sessionDir = dirname(resolvedPath)
if (sessionDir === matchedRoot || !isPathInsideOrEqual(matchedRoot, sessionDir)) {
return null
diff --git a/src/main/browser/browser-cookie-samesite.electron.test.ts b/src/main/browser/browser-cookie-samesite.electron.test.ts
index 4f04f93c72e..561bff2a407 100644
--- a/src/main/browser/browser-cookie-samesite.electron.test.ts
+++ b/src/main/browser/browser-cookie-samesite.electron.test.ts
@@ -33,7 +33,7 @@ type FixtureResult = {
afterCookies: JarCookie[]
}
-type SourceShape = {
+type SourceCookieRow = {
name: string
samesite: number | null
is_secure: number
@@ -147,18 +147,26 @@ run().catch((error) => {
`
}
-function readSourceShape(sourceDbPath: string): SourceShape[] {
+function readSourceCookieRows(sourceDbPath: string): SourceCookieRow[] {
const db = new DatabaseSync(sourceDbPath, { readOnly: true })
try {
return db
.prepare('SELECT name, samesite, is_secure FROM cookies ORDER BY rowid')
- .all() as SourceShape[]
+ .all()
+ .map((row) => ({
+ name: String(row.name),
+ samesite: row.samesite === null ? null : Number(row.samesite),
+ is_secure: Number(row.is_secure)
+ }))
} finally {
db.close()
}
}
-async function runFixture(): Promise<{ fixture: FixtureResult; sourceShape: SourceShape[] }> {
+async function runFixture(): Promise<{
+ fixture: FixtureResult
+ sourceCookieRows: SourceCookieRow[]
+}> {
const root = mkdtempSync(join(tmpdir(), 'orca-samesite-enum-'))
fixtureRoots.push(root)
const bundlePath = join(root, 'cookie-import-samesite.cjs')
@@ -176,7 +184,7 @@ async function runFixture(): Promise<{ fixture: FixtureResult; sourceShape: Sour
})
)
createChromiumCookieTestDatabase(sourceDbPath, rows).close()
- const sourceShape = readSourceShape(sourceDbPath)
+ const sourceCookieRows = readSourceCookieRows(sourceDbPath)
writeFileSync(
bundleEntryPath,
`export { importCookiesFromBrowser } from ${JSON.stringify(join(process.cwd(), 'src/main/browser/browser-cookie-import.ts'))}`
@@ -212,22 +220,23 @@ async function runFixture(): Promise<{ fixture: FixtureResult; sourceShape: Sour
const fixtureResult = existsSync(resultPath) ? readFileSync(resultPath, 'utf8') : 'no result'
expect(run.error).toBeUndefined()
expect(run.status, `${fixtureResult}\n${run.stdout}\n${run.stderr}`).toBe(0)
- return { fixture: JSON.parse(fixtureResult) as FixtureResult, sourceShape }
+ const fixture: FixtureResult = JSON.parse(fixtureResult)
+ return { fixture, sourceCookieRows }
}
describe('Chromium SameSite storage enum import', () => {
let fixture: FixtureResult
- let sourceShape: SourceShape[]
+ let sourceCookieRows: SourceCookieRow[]
beforeAll(async () => {
- ;({ fixture, sourceShape } = await runFixture())
+ ;({ fixture, sourceCookieRows } = await runFixture())
}, 120_000)
it('runs the real Chromium import against the complete synthetic matrix', () => {
expect(fixture.step).toBe('import finished')
expect(fixture.beforeCookieCount).toBe(0)
expect(fixture.importResult.ok).toBe(true)
- expect(sourceShape).toEqual(
+ expect(sourceCookieRows).toEqual(
[REJECTION_CONTROL, ...VALID_COMBINATIONS, NULL_CASE].map(
({ name, rawSameSite, secure }) => ({
name,
diff --git a/src/main/claude-accounts/runtime-auth-service-readback-identity.test.ts b/src/main/claude-accounts/runtime-auth-service-readback-identity.test.ts
index 1cd86014c29..2806d44e82a 100644
--- a/src/main/claude-accounts/runtime-auth-service-readback-identity.test.ts
+++ b/src/main/claude-accounts/runtime-auth-service-readback-identity.test.ts
@@ -70,7 +70,7 @@ describe('ClaudeRuntimeAuthService', () => {
it('rejects wrong-shaped refreshed credentials during read-back', async () => {
const runtimeCredentialsPath = join(testState.fakeHomeDir, '.claude', '.credentials.json')
const originalCredentials = createClaudeCredentialsJson('user@example.com', 'original')
- const wrongShapedRefresh = `${JSON.stringify({
+ const malformedRefresh = `${JSON.stringify({
claudeAiOauth: {
email: 'user@example.com',
expiresAt: Date.now() + 120_000
@@ -91,7 +91,7 @@ describe('ClaudeRuntimeAuthService', () => {
settings.activeClaudeManagedAccountId = 'account-1'
await service.syncForCurrentSelection()
- writeFileSync(runtimeCredentialsPath, wrongShapedRefresh, 'utf-8')
+ writeFileSync(runtimeCredentialsPath, malformedRefresh, 'utf-8')
await service.syncForCurrentSelection()
expect(readManagedCredentialsForTest('account-1', managedAuthPath)).toBe(originalCredentials)
diff --git a/src/main/codex/codex-structured-item-translation.test.ts b/src/main/codex/codex-structured-item-translation.test.ts
index 53cf94e265c..ad63d624f58 100644
--- a/src/main/codex/codex-structured-item-translation.test.ts
+++ b/src/main/codex/codex-structured-item-translation.test.ts
@@ -806,7 +806,7 @@ describe('codex item bodies', () => {
// Both the row label and the run header read top-level input keys only, so a
// shape whose detail sits inside `action` renders as the input's raw JSON.
const url = 'https://example.com/docs/page'
- const shapes: [string, unknown, string, string][] = [
+ const cases: [string, unknown, string, string][] = [
['started', null, '', ''],
[
'search',
@@ -823,7 +823,7 @@ describe('codex item bodies', () => {
],
['other', { type: 'other' }, 'other', '']
]
- for (const [name, action, label, brief] of shapes) {
+ for (const [name, action, label, brief] of cases) {
// Codex leaves the item's own `query` empty on most completed searches.
const query = name === 'search' || name === 'findInPage' ? 'a sample query' : ''
const input = toolCallInput({ type: 'webSearch', id: 'w', query, action })
diff --git a/src/main/cursor/hook-service.ts b/src/main/cursor/hook-service.ts
index b07639f108a..ed431509346 100644
--- a/src/main/cursor/hook-service.ts
+++ b/src/main/cursor/hook-service.ts
@@ -168,13 +168,13 @@ export class CursorHookService {
}
const cleaned = removeManagedCommands(definitions, isManagedCommand)
// Also strip entries with the command at the top level (Cursor schema).
- const strippedCursorShape = cleaned.filter(
+ const strippedTopLevelCommands = cleaned.filter(
(definition) => !isManagedCommand(definition.command)
)
- if (strippedCursorShape.length === 0) {
+ if (strippedTopLevelCommands.length === 0) {
delete nextHooks[eventName]
} else {
- nextHooks[eventName] = strippedCursorShape
+ nextHooks[eventName] = strippedTopLevelCommands
}
}
diff --git a/src/main/git/push-target-validation.ts b/src/main/git/push-target-validation.ts
index 055eab8537c..133b1ee8b2b 100644
--- a/src/main/git/push-target-validation.ts
+++ b/src/main/git/push-target-validation.ts
@@ -1,5 +1,5 @@
import type { GitPushTarget } from '../../shared/worktree/types'
-import { assertGitPushTargetShape } from '../../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../../shared/git-push-target-validation'
import { gitExecFileAsync } from './runner'
import type { GitExecOptions as GitCommandExecOptions } from './command-runner/git-exec-options'
@@ -10,7 +10,7 @@ export async function validateGitPushTarget(
target: unknown,
options: GitExecOptions = {}
): Promise {
- assertGitPushTargetShape(target)
+ assertValidGitPushTarget(target)
await gitExecFileAsync(['check-ref-format', '--branch', target.branchName], {
cwd: repoPath,
...options
diff --git a/src/main/github/client-stack-merge-guard.test.ts b/src/main/github/client-stack-merge-guard.test.ts
index 57cd5df8bfd..c47f786d2ed 100644
--- a/src/main/github/client-stack-merge-guard.test.ts
+++ b/src/main/github/client-stack-merge-guard.test.ts
@@ -592,9 +592,9 @@ describe('GitHub GraphQL rate-limit guard', () => {
})
it.each([
- { stackShape: 'omits stack', stackField: {} },
- { stackShape: 'sets stack to null', stackField: { stack: null } }
- ])('keeps legacy merge when an ordinary GitHub response $stackShape', async (scenario) => {
+ { stackVariant: 'omits stack', stackField: {} },
+ { stackVariant: 'sets stack to null', stackField: { stack: null } }
+ ])('keeps legacy merge when an ordinary GitHub response $stackVariant', async (scenario) => {
ghExecFileAsyncMock
.mockResolvedValueOnce({
stdout: JSON.stringify({
diff --git a/src/main/github/default-branch-stale-pr.test.ts b/src/main/github/default-branch-stale-pr.test.ts
index 4361c9759e7..276d63e38ac 100644
--- a/src/main/github/default-branch-stale-pr.test.ts
+++ b/src/main/github/default-branch-stale-pr.test.ts
@@ -164,7 +164,7 @@ function primeGitExecForDefaultBranch({
})
}
-type RestPRShape = {
+type RestPROverrides = {
number?: number
state?: string
merged_at?: string | null
@@ -178,7 +178,7 @@ function restPR({
merged_at = null,
head_ref = 'master',
head_sha = 'stale-master-oid'
-}: RestPRShape = {}): Record {
+}: RestPROverrides = {}): Record {
return {
number,
title: 'Historical PR',
diff --git a/src/main/github/project-view/internals.ts b/src/main/github/project-view/internals.ts
index 1c828909669..3bea5b5584d 100644
--- a/src/main/github/project-view/internals.ts
+++ b/src/main/github/project-view/internals.ts
@@ -17,7 +17,7 @@ import {
classifyProjectError,
driftError,
rateLimitedError,
- type GhGraphqlErrorShape
+ type GhGraphqlError
} from './project-error-classification'
export {
@@ -172,7 +172,7 @@ export async function runGraphql(
...(exec?.host ? { host: exec.host } : {})
})
try {
- const parsed = JSON.parse(stdout) as { data?: T; errors?: GhGraphqlErrorShape[] }
+ const parsed: { data?: T; errors?: GhGraphqlError[] } = JSON.parse(stdout)
if (parsed.errors && parsed.errors.length > 0) {
return {
ok: false,
diff --git a/src/main/github/project-view/project-error-classification.ts b/src/main/github/project-view/project-error-classification.ts
index 6b3d9a3fe09..a9d12fa44f1 100644
--- a/src/main/github/project-view/project-error-classification.ts
+++ b/src/main/github/project-view/project-error-classification.ts
@@ -4,14 +4,14 @@
import type { GitHubProjectViewError } from '../../../shared/github/project-result-types'
import { githubProjectHost } from '../../../shared/github/project-identity'
-export type GhGraphqlErrorShape = {
+export type GhGraphqlError = {
type?: string
message?: string
path?: (string | number)[]
extensions?: { code?: string }
}
-export function extractGraphqlErrors(stderr: string, stdout: string): GhGraphqlErrorShape[] {
+export function extractGraphqlErrors(stderr: string, stdout: string): GhGraphqlError[] {
// `gh api graphql` prints the response JSON to stdout even on GraphQL
// errors, and the stderr carries a summary. Try stdout first; if parsing
// fails, fall back to stderr.
@@ -21,7 +21,7 @@ export function extractGraphqlErrors(stderr: string, stdout: string): GhGraphqlE
continue
}
try {
- const parsed = JSON.parse(src) as { errors?: GhGraphqlErrorShape[] }
+ const parsed: { errors?: GhGraphqlError[] } = JSON.parse(src)
if (parsed.errors && parsed.errors.length > 0) {
return parsed.errors
}
@@ -32,7 +32,7 @@ export function extractGraphqlErrors(stderr: string, stdout: string): GhGraphqlE
return []
}
-export function errorsIndicateParentField(errors: GhGraphqlErrorShape[], stderr: string): boolean {
+export function errorsIndicateParentField(errors: GhGraphqlError[], stderr: string): boolean {
const lower = stderr.toLowerCase()
// Preview-header shape: gh returns a 4xx with "preview" in the message.
if (lower.includes('preview') && lower.includes('parent')) {
diff --git a/src/main/github/project-view/project-view-item-page.ts b/src/main/github/project-view/project-view-item-page.ts
index ca135fded51..e0ea53d059b 100644
--- a/src/main/github/project-view/project-view-item-page.ts
+++ b/src/main/github/project-view/project-view-item-page.ts
@@ -14,7 +14,7 @@ import {
classifyProjectError,
driftError,
rateLimitedError,
- type GhGraphqlErrorShape
+ type GhGraphqlError
} from './project-error-classification'
import { ownerQueryRoot } from './project-view-config'
import type { RawItem } from './project-view-item-normalization'
@@ -47,7 +47,7 @@ export async function fetchItemsPageWithRaw(args: {
| {
ok: false
error: GitHubProjectViewError
- rawErrors: GhGraphqlErrorShape[]
+ rawErrors: GhGraphqlError[]
stderr: string
}
> {
@@ -117,7 +117,7 @@ export async function fetchItemsPageWithRaw(args: {
stdout = extracted.stdout
execFailed = true
}
- let parsed: { data?: Record; errors?: GhGraphqlErrorShape[] } = {}
+ let parsed: { data?: Record; errors?: GhGraphqlError[] } = {}
try {
parsed = JSON.parse(stdout)
} catch {
diff --git a/src/main/ipc/filesystem/git-remote/branch-mutation-handlers.ts b/src/main/ipc/filesystem/git-remote/branch-mutation-handlers.ts
index 2c3273b8c00..1ad9b926e21 100644
--- a/src/main/ipc/filesystem/git-remote/branch-mutation-handlers.ts
+++ b/src/main/ipc/filesystem/git-remote/branch-mutation-handlers.ts
@@ -8,7 +8,7 @@ import {
} from '../../../providers/ssh-git-dispatch'
import { resolveRegisteredWorktreePath } from '../../registered-worktree-roots-cache'
import { getLocalGitOptionsForRegisteredWorktree } from '../../local-worktree-runtime-options'
-import { assertGitPushTargetShape } from '../../../../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../../../../shared/git-push-target-validation'
import {
materializeWorktreePushTargetRemote,
materializeWorktreePushTargetRemoteSsh
@@ -35,7 +35,7 @@ export function registerGitRemoteBranchMutationHandlers(context: FilesystemHandl
const publish = args.publish === true
if (args.connectionId) {
if (args.pushTarget) {
- assertGitPushTargetShape(args.pushTarget)
+ assertValidGitPushTarget(args.pushTarget)
}
const provider = getSshGitProvider(args.connectionId)
if (!provider) {
@@ -99,7 +99,7 @@ export function registerGitRemoteBranchMutationHandlers(context: FilesystemHandl
): Promise => {
if (args.connectionId) {
if (args.pushTarget) {
- assertGitPushTargetShape(args.pushTarget)
+ assertValidGitPushTarget(args.pushTarget)
}
const provider = getSshGitProvider(args.connectionId)
if (!provider) {
@@ -159,7 +159,7 @@ export function registerGitRemoteBranchMutationHandlers(context: FilesystemHandl
): Promise => {
if (args.connectionId) {
if (args.pushTarget) {
- assertGitPushTargetShape(args.pushTarget)
+ assertValidGitPushTarget(args.pushTarget)
}
const provider = getSshGitProvider(args.connectionId)
if (!provider) {
diff --git a/src/main/ipc/filesystem/git-remote/sync-handlers.ts b/src/main/ipc/filesystem/git-remote/sync-handlers.ts
index a924c393a04..b487d54f39e 100644
--- a/src/main/ipc/filesystem/git-remote/sync-handlers.ts
+++ b/src/main/ipc/filesystem/git-remote/sync-handlers.ts
@@ -15,7 +15,7 @@ import {
} from '../../../providers/ssh-git-dispatch'
import { resolveRegisteredWorktreePath } from '../../registered-worktree-roots-cache'
import { getLocalGitOptionsForRegisteredWorktree } from '../../local-worktree-runtime-options'
-import { assertGitPushTargetShape } from '../../../../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../../../../shared/git-push-target-validation'
import { validateGitForkSyncExpectedUpstream } from '../../../../shared/git-fork-sync'
import {
materializeWorktreePushTargetRemote,
@@ -34,7 +34,7 @@ export function registerGitRemoteSyncHandlers(context: FilesystemHandlerContext)
): Promise => {
if (args.connectionId) {
if (args.pushTarget) {
- assertGitPushTargetShape(args.pushTarget)
+ assertValidGitPushTarget(args.pushTarget)
}
const provider = getSshGitProvider(args.connectionId)
if (!provider) {
@@ -65,7 +65,7 @@ export function registerGitRemoteSyncHandlers(context: FilesystemHandlerContext)
): Promise => {
if (args.connectionId) {
if (args.pushTarget) {
- assertGitPushTargetShape(args.pushTarget)
+ assertValidGitPushTarget(args.pushTarget)
}
const provider = getSshGitProvider(args.connectionId)
if (!provider) {
diff --git a/src/main/ipc/readdir-error-diagnostics.test.ts b/src/main/ipc/readdir-error-diagnostics.test.ts
index cf599afbdf1..c1c7041a662 100644
--- a/src/main/ipc/readdir-error-diagnostics.test.ts
+++ b/src/main/ipc/readdir-error-diagnostics.test.ts
@@ -1,24 +1,27 @@
import { describe, expect, it } from 'vitest'
-import { buildReadDirErrorBreadcrumb, describeReadDirPathShape } from './readdir-error-diagnostics'
+import { buildReadDirErrorBreadcrumb, classifyReadDirPath } from './readdir-error-diagnostics'
-describe('describeReadDirPathShape', () => {
+describe('classifyReadDirPath', () => {
it('classifies a WSL UNC path without leaking it', () => {
- const shape = describeReadDirPathShape('\\\\wsl.localhost\\Ubuntu\\home\\u\\repo', undefined)
- expect(shape).toEqual({ hasConnectionId: false, isUNC: true, isWsl: true })
+ const classification = classifyReadDirPath(
+ '\\\\wsl.localhost\\Ubuntu\\home\\u\\repo',
+ undefined
+ )
+ expect(classification).toEqual({ hasConnectionId: false, isUNC: true, isWsl: true })
})
it('classifies the legacy \\\\wsl$ root as WSL', () => {
- expect(describeReadDirPathShape('\\\\wsl$\\Ubuntu\\home', undefined).isWsl).toBe(true)
+ expect(classifyReadDirPath('\\\\wsl$\\Ubuntu\\home', undefined).isWsl).toBe(true)
})
it('classifies a plain network UNC share as UNC but not WSL', () => {
- const shape = describeReadDirPathShape('\\\\fileserver\\share\\dir', undefined)
- expect(shape).toMatchObject({ isUNC: true, isWsl: false })
- expect(shape.driveLetter).toBeUndefined()
+ const classification = classifyReadDirPath('\\\\fileserver\\share\\dir', undefined)
+ expect(classification).toMatchObject({ isUNC: true, isWsl: false })
+ expect(classification.driveLetter).toBeUndefined()
})
it('extracts an uppercased drive letter for mapped drives', () => {
- expect(describeReadDirPathShape('z:\\projects\\repo', undefined)).toEqual({
+ expect(classifyReadDirPath('z:\\projects\\repo', undefined)).toEqual({
hasConnectionId: false,
isUNC: false,
isWsl: false,
@@ -27,18 +30,18 @@ describe('describeReadDirPathShape', () => {
})
it('flags the SSH connection without recording it', () => {
- const shape = describeReadDirPathShape('/remote/repo', 'ssh-1')
- expect(shape).toEqual({ hasConnectionId: true, isUNC: false, isWsl: false })
+ const classification = classifyReadDirPath('/remote/repo', 'ssh-1')
+ expect(classification).toEqual({ hasConnectionId: true, isUNC: false, isWsl: false })
})
- it('never includes the raw path in the shape', () => {
- const shape = describeReadDirPathShape('\\\\wsl.localhost\\Ubuntu\\secret\\path', 'ssh-9')
- expect(JSON.stringify(shape)).not.toContain('secret')
+ it('never includes the raw path in the classification', () => {
+ const classification = classifyReadDirPath('\\\\wsl.localhost\\Ubuntu\\secret\\path', 'ssh-9')
+ expect(JSON.stringify(classification)).not.toContain('secret')
})
})
describe('buildReadDirErrorBreadcrumb', () => {
- it('captures throw site, error code/name, and path shape', () => {
+ it('captures throw site, error code/name, and path classification', () => {
const breadcrumb = buildReadDirErrorBreadcrumb({
dirPath: '\\\\wsl.localhost\\Ubuntu\\home\\u\\repo',
connectionId: undefined,
diff --git a/src/main/ipc/readdir-error-diagnostics.ts b/src/main/ipc/readdir-error-diagnostics.ts
index dd77dda8837..fc7c54c433f 100644
--- a/src/main/ipc/readdir-error-diagnostics.ts
+++ b/src/main/ipc/readdir-error-diagnostics.ts
@@ -11,7 +11,7 @@ export type ReadDirThrowSite = 'ssh-provider' | 'authorize' | 'readdir'
* even though breadcrumbs are path-redacted downstream, never collecting the
* raw path is the safer default.
*/
-export function describeReadDirPathShape(
+export function classifyReadDirPath(
dirPath: string,
connectionId: string | undefined
): CrashReportBreadcrumbData {
@@ -52,6 +52,6 @@ export function buildReadDirErrorBreadcrumb(args: {
throwSite: args.throwSite,
errorName: args.error instanceof Error ? args.error.name : typeof args.error,
...(errorCode(args.error) ? { errorCode: errorCode(args.error)! } : {}),
- ...describeReadDirPathShape(args.dirPath, args.connectionId)
+ ...classifyReadDirPath(args.dirPath, args.connectionId)
}
}
diff --git a/src/main/ipc/worktree-remote.ts b/src/main/ipc/worktree-remote.ts
index ef65f2fcb53..c64710b804c 100644
--- a/src/main/ipc/worktree-remote.ts
+++ b/src/main/ipc/worktree-remote.ts
@@ -48,7 +48,7 @@ import { resolveWorktreeAddBaseRef } from '../../shared/worktree/base-ref'
import { getHostedReviewForBranch } from '../source-control/hosted-review'
import type { ForgeProviderId } from '../source-control/forge-provider'
import { validateGitPushTarget } from '../git/push-target-validation'
-import { assertGitPushTargetShape } from '../../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../../shared/git-push-target-validation'
import { gitExecFileAsync } from '../git/runner'
import type {
OrcaRuntimeService,
@@ -1277,7 +1277,7 @@ export async function prepareWorktreePushTargetSsh(
store?: WorktreePushTargetStore,
repoId?: string
): Promise {
- assertGitPushTargetShape(target)
+ assertValidGitPushTarget(target)
const execGit: GitRemoteExec = (args, cwd) => provider.exec(args, cwd)
const { remoteCreated: _ignoredRemoteCreated, ...sanitizedTarget } = target
await provider.exec(['check-ref-format', '--branch', target.branchName], repoPath)
diff --git a/src/main/native-chat/agent-session-journal/journal-lifecycle-batch-partition.ts b/src/main/native-chat/agent-session-journal/journal-lifecycle-batch-partition.ts
index 305fa462f60..f109451edb9 100644
--- a/src/main/native-chat/agent-session-journal/journal-lifecycle-batch-partition.ts
+++ b/src/main/native-chat/agent-session-journal/journal-lifecycle-batch-partition.ts
@@ -63,14 +63,12 @@ function serializedLifecycleBatchFits(
fence: Number.MAX_SAFE_INTEGER,
ts: Number.MAX_SAFE_INTEGER,
settlementId,
- mutations: mutations.map(lifecycleMutationRowShape)
+ mutations: mutations.map(toLifecycleMutationRow)
}
return Buffer.byteLength(JSON.stringify(row), 'utf8') + 1 <= MAX_JOURNAL_LIFECYCLE_BATCH_BYTES
}
-function lifecycleMutationRowShape(
- mutation: JournalLifecycleMutationInput
-): JournalLifecycleMutation {
+function toLifecycleMutationRow(mutation: JournalLifecycleMutationInput): JournalLifecycleMutation {
const itemId = agentJournalItemKey(mutation.identity)
return mutation.kind === 'item'
? {
diff --git a/src/main/native-chat/agent-session-wire/agent-session-history-page-grouping-parity.test.ts b/src/main/native-chat/agent-session-wire/agent-session-history-page-grouping-parity.test.ts
index e1e8f68f7bd..677e75edc7d 100644
--- a/src/main/native-chat/agent-session-wire/agent-session-history-page-grouping-parity.test.ts
+++ b/src/main/native-chat/agent-session-wire/agent-session-history-page-grouping-parity.test.ts
@@ -75,14 +75,14 @@ function item(index: number, sequence: number): AgentJournalRenderItem {
}
}
-/** Every sequence-run shape of `length` items, as run-length compositions. */
-function* runShapes(length: number): Generator {
+/** Every run-length composition of `length` items. */
+function* runLengthCompositions(length: number): Generator {
if (length === 0) {
yield []
return
}
for (let first = 1; first <= length; first += 1) {
- for (const rest of runShapes(length - first)) {
+ for (const rest of runLengthCompositions(length - first)) {
yield [first, ...rest]
}
}
@@ -105,7 +105,7 @@ function buildItems(runs: number[], repeatSequence: boolean): AgentJournalRender
it('matches eager grouping at every newest-window limit for every run shape', () => {
let cases = 0
for (let length = 0; length <= 7; length += 1) {
- for (const runs of runShapes(length)) {
+ for (const runs of runLengthCompositions(length)) {
for (const repeatSequence of [false, true]) {
const items = buildItems(runs, repeatSequence)
// Every boundary, including 0, each exact group edge, and past the end.
@@ -127,7 +127,7 @@ it('matches eager byte bounding at every budget boundary in both directions', ()
let truncatedCases = 0
let partialCases = 0
for (let length = 1; length <= 6; length += 1) {
- for (const runs of runShapes(length)) {
+ for (const runs of runLengthCompositions(length)) {
for (const repeatSequence of [false, true]) {
const items = buildItems(runs, repeatSequence)
const perItem = historyEntryBytes(items[0]!, submissionBytes)
diff --git a/src/main/native-chat/agent-session-wire/provider-frame-disposition.test.ts b/src/main/native-chat/agent-session-wire/provider-frame-disposition.test.ts
index a57aa5d9ed1..b1acb14eee3 100644
--- a/src/main/native-chat/agent-session-wire/provider-frame-disposition.test.ts
+++ b/src/main/native-chat/agent-session-wire/provider-frame-disposition.test.ts
@@ -3,7 +3,7 @@ import { CODEX_APP_SERVER_NOTIFICATION_METHODS } from '../../codex/codex-app-ser
import { CLAUDE_STREAM_JSON_FRAME_KINDS } from './claude-stream-json-frame-schema'
import {
classifyProviderFrame,
- isDeltaShapedProviderFrameKind,
+ isDeltaProviderFrameKind,
PROVIDER_FRAME_CLASSIFICATIONS
} from './provider-frame-disposition'
import { unhandledProviderFrameJournalItem } from './unhandled-provider-frame'
@@ -25,7 +25,7 @@ describe('provider frame classification catalog', () => {
const deltaKinds = [
...Object.keys(PROVIDER_FRAME_CLASSIFICATIONS.codex),
...Object.keys(PROVIDER_FRAME_CLASSIFICATIONS.claude)
- ].filter(isDeltaShapedProviderFrameKind)
+ ].filter(isDeltaProviderFrameKind)
expect(deltaKinds.length).toBeGreaterThan(0)
for (const kind of deltaKinds) {
diff --git a/src/main/native-chat/agent-session-wire/provider-frame-disposition.ts b/src/main/native-chat/agent-session-wire/provider-frame-disposition.ts
index 548a719ceb1..dea830b1315 100644
--- a/src/main/native-chat/agent-session-wire/provider-frame-disposition.ts
+++ b/src/main/native-chat/agent-session-wire/provider-frame-disposition.ts
@@ -226,7 +226,7 @@ function itemKind(kind: string): string | null {
return kind.startsWith('item:') ? kind.slice('item:'.length) : null
}
-export function isDeltaShapedProviderFrameKind(kind: string): boolean {
+export function isDeltaProviderFrameKind(kind: string): boolean {
return notificationKind(kind).toLowerCase().endsWith('delta')
}
@@ -260,7 +260,7 @@ export function classifyProviderFrame(
if (hasProviderError(payload)) {
return 'error-surface'
}
- if (isDeltaShapedProviderFrameKind(kind)) {
+ if (isDeltaProviderFrameKind(kind)) {
return 'stream-into-item'
}
if (provider === 'claude' && kind === 'message:result') {
diff --git a/src/main/observability/redactor.test.ts b/src/main/observability/redactor.test.ts
index 0b8ee0f9e61..19324cc08b2 100644
--- a/src/main/observability/redactor.test.ts
+++ b/src/main/observability/redactor.test.ts
@@ -25,7 +25,7 @@ const SECRETS = {
pem: '-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQ\n-----END PRIVATE KEY-----'
}
-const SHAPES: { label: string; raw: string; tag: string }[] = [
+const PROVIDER_KEY_CASES: { label: string; raw: string; tag: string }[] = [
{ label: 'anthropic', raw: SECRETS.anthropic, tag: 'anthropic-key' },
{ label: 'openai', raw: SECRETS.openai, tag: 'openai-key' },
{ label: 'github', raw: SECRETS.github, tag: 'github-token' },
@@ -37,7 +37,7 @@ const SHAPES: { label: string; raw: string; tag: string }[] = [
]
describe('redactor — provider-key fingerprints', () => {
- for (const { label, raw, tag } of SHAPES) {
+ for (const { label, raw, tag } of PROVIDER_KEY_CASES) {
describe(`${label}`, () => {
it('redacts when the secret appears as an attribute value', () => {
// Bare "" without a labeled-kv keyword nearby — exercises the
diff --git a/src/main/persistence/loading-store/persisted-state-redundancy.test.ts b/src/main/persistence/loading-store/persisted-state-redundancy.test.ts
index bccef63b39c..9a30b26da38 100644
--- a/src/main/persistence/loading-store/persisted-state-redundancy.test.ts
+++ b/src/main/persistence/loading-store/persisted-state-redundancy.test.ts
@@ -138,7 +138,7 @@ function writeLegacyFile(dataFile: string): void {
/** Inverse of everything this change does, applied to a compact file: what the old serializer
* would have written for the same state. */
-function reexpandToLegacyShape(state: PersistedState): PersistedState {
+function reexpandToLegacySerialization(state: PersistedState): PersistedState {
const expanded = structuredClone(state)
for (const map of [expanded.worktreeMeta, expanded.worktreeMetaByIdentity]) {
for (const [key, meta] of Object.entries(map ?? {})) {
@@ -207,7 +207,7 @@ describe('persisted-state redundancy', () => {
// Apples to apples: re-expand the file we just wrote back into the old shape and compare, so
// the number is the redundancy alone and not the settings defaults a synthetic fixture lacks.
expect(Buffer.byteLength(rewritten)).toBeLessThan(
- Buffer.byteLength(JSON.stringify(reexpandToLegacyShape(onDisk))) * 0.6
+ Buffer.byteLength(JSON.stringify(reexpandToLegacySerialization(onDisk))) * 0.6
)
// load(save(state)) deep-equals the pre-save state for every field touched.
diff --git a/src/main/pi/titlebar-extension-overlay-path.test.ts b/src/main/pi/titlebar-extension-overlay-path.test.ts
index db5bfeedbd9..1a4ace7d352 100644
--- a/src/main/pi/titlebar-extension-overlay-path.test.ts
+++ b/src/main/pi/titlebar-extension-overlay-path.test.ts
@@ -8,7 +8,7 @@ const userDataDir = mkdtempSync(join(tmpdir(), 'orca-pi-overlay-path-userdata-')
import { PiTitlebarExtensionService } from './titlebar-extension-service'
-const PATH_SHAPED_PTY_ID = [
+const PATH_LIKE_PTY_ID = [
'50c010a2-bc8e-4eb1-8847-5812133ad6df',
'Users',
'dev',
@@ -45,7 +45,7 @@ describe('PiTitlebarExtensionService legacy overlay paths', () => {
const svc = new PiTitlebarExtensionService()
try {
- const env = svc.buildPtyEnv(PATH_SHAPED_PTY_ID, piHome, 'pi')
+ const env = svc.buildPtyEnv(PATH_LIKE_PTY_ID, piHome, 'pi')
expect(env.PI_CODING_AGENT_DIR).toBeUndefined()
expect(env.ORCA_PI_SOURCE_AGENT_DIR).toBe(piHome)
@@ -61,12 +61,12 @@ describe('PiTitlebarExtensionService legacy overlay paths', () => {
})
it('clears legacy raw path-shaped daemon overlays during teardown', () => {
- const legacyOverlayDir = legacyOverlayPath('pi', PATH_SHAPED_PTY_ID)
+ const legacyOverlayDir = legacyOverlayPath('pi', PATH_LIKE_PTY_ID)
mkdirSync(legacyOverlayDir, { recursive: true })
writeFileSync(join(legacyOverlayDir, 'stale.txt'), 'stale overlay')
const svc = new PiTitlebarExtensionService()
- svc.clearPty(PATH_SHAPED_PTY_ID)
+ svc.clearPty(PATH_LIKE_PTY_ID)
expect(existsSync(legacyOverlayDir)).toBe(false)
})
diff --git a/src/main/runtime/rpc/terminal-output-frame-chunks-equivalence.test.ts b/src/main/runtime/rpc/terminal-output-frame-chunks-equivalence.test.ts
index 233aa3e4bc2..85e01116c3c 100644
--- a/src/main/runtime/rpc/terminal-output-frame-chunks-equivalence.test.ts
+++ b/src/main/runtime/rpc/terminal-output-frame-chunks-equivalence.test.ts
@@ -132,10 +132,10 @@ function* legacyIterateTerminalOutputFrameChunks(
}
}
-type FrameShape = { base64: string; seq: number | 'undefined'; opcode: number | 'undefined' }
+type FrameSummary = { base64: string; seq: number | 'undefined'; opcode: number | 'undefined' }
-function describeFrames(frames: Iterable): FrameShape[] {
- const out: FrameShape[] = []
+function describeFrames(frames: Iterable): FrameSummary[] {
+ const out: FrameSummary[] = []
for (const frame of frames) {
out.push({
base64: Buffer.from(frame.bytes).toString('base64'),
@@ -170,10 +170,10 @@ const SURROGATE_EDGES = [
'\udfff\udc00'
]
-// Meta shapes exercised against every fixture: no meta, seq-preserved (rawLength ===
+// Meta variants exercised against every fixture: no meta, seq-preserved (rawLength ===
// data.length), the delayed-final-seq path (rawLength !== data.length -> OutputSpan),
// transformed, and cwd-only.
-function metaShapesFor(data: string): { label: string; meta: TerminalOutputMeta | undefined }[] {
+function metaVariantsFor(data: string): { label: string; meta: TerminalOutputMeta | undefined }[] {
return [
{ label: 'no-meta', meta: undefined },
{ label: 'seq-only', meta: { seq: 5_000_000 } },
@@ -187,8 +187,8 @@ function metaShapesFor(data: string): { label: string; meta: TerminalOutputMeta
}
function sweepAll(data: string, label: string): void {
- for (const shape of metaShapesFor(data)) {
- expectEquivalent(data, shape.meta, `${label} [${shape.label}]`)
+ for (const variant of metaVariantsFor(data)) {
+ expectEquivalent(data, variant.meta, `${label} [${variant.label}]`)
}
}
diff --git a/src/main/runtime/terminal-wait-tail-state.ts b/src/main/runtime/terminal-wait-tail-state.ts
index 712b301a961..8d0ce1f2e88 100644
--- a/src/main/runtime/terminal-wait-tail-state.ts
+++ b/src/main/runtime/terminal-wait-tail-state.ts
@@ -32,15 +32,15 @@ export function computeTerminalTailWaitState(
partialLine: string,
preview: string
): TerminalTailWaitState {
- const tailShape = inspectTerminalWaitTail(lines, partialLine)
- if (!tailShape.fromTail) {
+ const tailInspection = inspectTerminalWaitTail(lines, partialLine)
+ if (!tailInspection.fromTail) {
return {
waitText: preview,
signal: findActionableTerminalWaitBlockedSignal(preview.toLowerCase()),
fromTail: false
}
}
- if (!tailShape.mayContainBlockedSignal) {
+ if (!tailInspection.mayContainBlockedSignal) {
// Why: reads waitText only when a signal exists; avoid retaining a rebuilt 256 KiB string in the common case.
return { waitText: '', signal: null, fromTail: true }
}
diff --git a/src/main/skills/skill-bundle-artifacts.ts b/src/main/skills/skill-bundle-artifacts.ts
index 08e33a0eeba..f8c19b58185 100644
--- a/src/main/skills/skill-bundle-artifacts.ts
+++ b/src/main/skills/skill-bundle-artifacts.ts
@@ -18,7 +18,7 @@ export type SkillBundleArtifacts = {
}
const sha256Schema = z.string().regex(/^[a-f0-9]{64}$/)
-const snapshotShape = {
+const snapshotFields = {
releaseRevision: z.number().int().positive(),
packageDigest: sha256Schema,
gitTreeSha: z.string().regex(/^[a-f0-9]{40}$/),
@@ -38,7 +38,7 @@ const snapshotShape = {
)
.min(1)
}
-const knownSnapshotSchema = z.object(snapshotShape).strict()
+const knownSnapshotSchema = z.object(snapshotFields).strict()
const manifestSchema = z
.object({
schemaVersion: z.literal(2),
@@ -47,7 +47,7 @@ const manifestSchema = z
.object({
name: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
sourcePath: z.string().min(1),
- ...snapshotShape
+ ...snapshotFields
})
.strict()
)
diff --git a/src/main/ssh/ssh-host-key-store.test.ts b/src/main/ssh/ssh-host-key-store.test.ts
index 4e18df099e4..835601aeac2 100644
--- a/src/main/ssh/ssh-host-key-store.test.ts
+++ b/src/main/ssh/ssh-host-key-store.test.ts
@@ -303,7 +303,7 @@ describe('a host key store written by a newer version', () => {
const storeFile = join(dir, 'ssh-host-keys.json')
const future = JSON.stringify({
version: 99,
- hostKeys: [{ shape: 'we do not understand' }]
+ hostKeys: [{ unrecognized: 'we do not understand' }]
})
await writeFile(storeFile, future, 'utf-8')
diff --git a/src/main/ssh/ssh-orphan-sweep-pane-state-verdicts.test.ts b/src/main/ssh/ssh-orphan-sweep-pane-state-verdicts.test.ts
index 560d18b8b62..9bb42a2cb27 100644
--- a/src/main/ssh/ssh-orphan-sweep-pane-state-verdicts.test.ts
+++ b/src/main/ssh/ssh-orphan-sweep-pane-state-verdicts.test.ts
@@ -167,9 +167,9 @@ describe('what the host publishes about a pane, read by the sweep', () => {
it('records that a backgrounded and a suspended shell are indistinguishable at tpgid/pgid', () => {
// The premise of the whole file. If this ever fails, the fixtures drifted and every verdict
// below is testing something other than the defect. Pids differ between captures, so the
- // comparison is of the shell row's shape: who its parent is, whether it leads its own process
- // group, whether that group owns the terminal, and its state flags.
- const shellShape = (capture: { rootPid: number; table: readonly string[] }): string => {
+ // comparison is of the shell row's signature: who its parent is, whether it leads its own
+ // process group, whether that group owns the terminal, and its state flags.
+ const shellRowSignature = (capture: { rootPid: number; table: readonly string[] }): string => {
const row = parseStrictProcessTableRows(capture.table.join('\n')).find(
(candidate) => candidate.pid === capture.rootPid
)!
@@ -181,19 +181,21 @@ describe('what the host publishes about a pane, read by the sweep', () => {
].join(' ')
}
- expect(shellShape(CAPTURES.idle)).toBe('ppid=1 leadsOwnGroup=true ownsTerminal=true stat=Ss+')
- expect(shellShape(CAPTURES.background)).toBe(shellShape(CAPTURES.idle))
- expect(shellShape(CAPTURES.ctrlz)).toBe(shellShape(CAPTURES.idle))
- expect(shellShape(CAPTURES.foreground)).not.toBe(shellShape(CAPTURES.idle))
+ expect(shellRowSignature(CAPTURES.idle)).toBe(
+ 'ppid=1 leadsOwnGroup=true ownsTerminal=true stat=Ss+'
+ )
+ expect(shellRowSignature(CAPTURES.background)).toBe(shellRowSignature(CAPTURES.idle))
+ expect(shellRowSignature(CAPTURES.ctrlz)).toBe(shellRowSignature(CAPTURES.idle))
+ expect(shellRowSignature(CAPTURES.foreground)).not.toBe(shellRowSignature(CAPTURES.idle))
// Same premise for the `set +m` captures, minus `ppid`: their harness keeps its parent alive
- // rather than reparenting the shell to init, and the ppid is the one field of the shape the
- // predicate never reads.
- const paneShape = (capture: { rootPid: number; table: readonly string[] }): string =>
- shellShape(capture).split(' ').slice(1).join(' ')
- expect(paneShape(CAPTURES.setMinusMBackground)).toBe(paneShape(CAPTURES.idle))
- expect(paneShape(CAPTURES.nottyGroupMember)).toBe(paneShape(CAPTURES.idle))
- expect(paneShape(CAPTURES.doubleForkedGroupMember)).toBe(paneShape(CAPTURES.idle))
+ // rather than reparenting the shell to init, and the ppid is the one field of the signature
+ // the predicate never reads.
+ const paneRowSignature = (capture: { rootPid: number; table: readonly string[] }): string =>
+ shellRowSignature(capture).split(' ').slice(1).join(' ')
+ expect(paneRowSignature(CAPTURES.setMinusMBackground)).toBe(paneRowSignature(CAPTURES.idle))
+ expect(paneRowSignature(CAPTURES.nottyGroupMember)).toBe(paneRowSignature(CAPTURES.idle))
+ expect(paneRowSignature(CAPTURES.doubleForkedGroupMember)).toBe(paneRowSignature(CAPTURES.idle))
})
it('sweeps an idle shell', async () => {
diff --git a/src/main/ssh/ssh-relay-deploy-helpers.test.ts b/src/main/ssh/ssh-relay-deploy-helpers.test.ts
index 1d73e188d19..adb14925636 100644
--- a/src/main/ssh/ssh-relay-deploy-helpers.test.ts
+++ b/src/main/ssh/ssh-relay-deploy-helpers.test.ts
@@ -232,9 +232,9 @@ describe('waitForSentinel', () => {
it.each(['ssh2 channel', 'system-SSH child stdio'])(
'forwards write(false), callback settlement, and drain for a %s',
- async (shape) => {
+ async (channelKind) => {
const channel = createMockChannel()
- if (shape.startsWith('system')) {
+ if (channelKind.startsWith('system')) {
Object.assign(channel, { _process: new EventEmitter() })
}
const callback = vi.fn()
diff --git a/src/main/ssh/ssh-remote-platform-detection.ts b/src/main/ssh/ssh-remote-platform-detection.ts
index 6fd0f87c767..499e088e49c 100644
--- a/src/main/ssh/ssh-remote-platform-detection.ts
+++ b/src/main/ssh/ssh-remote-platform-detection.ts
@@ -38,7 +38,7 @@ export async function detectRemoteHostPlatform(
}
// Why: only the PowerShell probe can settle a uname the parser cannot map
// (Cygwin, say), so a refused or timed-out channel leaves it unsettled.
- const windowsProbeNeverRan = windows.kind === 'failed' && isTransportShapedError(windows.error)
+ const windowsProbeNeverRan = windows.kind === 'failed' && isTransportFailure(windows.error)
if ((uname.kind === 'unsupported' && !windowsProbeNeverRan) || windows.kind === 'unsupported') {
const reported = uname.kind === 'unsupported' ? uname.uname : probeUname(windows)
console.warn(`[ssh-relay] Remote reported an unsupported platform: ${reported}`)
@@ -66,7 +66,7 @@ function undetectedPlatformError(
windows: PlatformProbeOutcome
): Error {
for (const outcome of [uname, windows]) {
- if (outcome.kind === 'failed' && isTransportShapedError(outcome.error)) {
+ if (outcome.kind === 'failed' && isTransportFailure(outcome.error)) {
return wrapProbeError(outcome.error)
}
}
@@ -84,7 +84,7 @@ function undetectedPlatformError(
// Why: a refused or timed-out channel explains the failure better than the
// other probe's mundane non-zero exit (e.g. "sh: not found" on Windows).
-function isTransportShapedError(error: unknown): boolean {
+function isTransportFailure(error: unknown): boolean {
return (
isSshSessionLimitError(error) ||
isUnconfirmedSshCommandTermination(error) ||
diff --git a/src/main/text-generation/commit-message-text-generation-failure-sanitization.test.ts b/src/main/text-generation/commit-message-text-generation-failure-sanitization.test.ts
index 6d20998b625..ac6577b2d96 100644
--- a/src/main/text-generation/commit-message-text-generation-failure-sanitization.test.ts
+++ b/src/main/text-generation/commit-message-text-generation-failure-sanitization.test.ts
@@ -327,7 +327,7 @@ describe('generateCommitMessageFromContext', () => {
'401: {"message":"slot 1:/Users/name/alt failed"}',
'Pi CLI command failed with code 1: 401: {"message":"slot 1:[path] failed"}'
]
- ])('redacts a %s in provider bodies', async (_shape, stderr, expected) => {
+ ])('redacts a %s in provider bodies', async (_variant, stderr, expected) => {
const result = await generateCommitMessageFromContext(
{
branch: 'main',
diff --git a/src/main/wsl-unc-delete-symlink-repro.test.ts b/src/main/wsl-unc-delete-symlink-repro.test.ts
index ace95afe933..a594b444e75 100644
--- a/src/main/wsl-unc-delete-symlink-repro.test.ts
+++ b/src/main/wsl-unc-delete-symlink-repro.test.ts
@@ -55,7 +55,7 @@ describe('WSL vault intermediate-symlink reproduction', () => {
it.each([
['file-shaped', `${FIXTURE_ROOT}/linked-project/session.json`, false],
['directory-shaped', `${FIXTURE_ROOT}/linked-project/session`, true]
- ])('rejects a %s target before removal', async (_shape, target, recursive) => {
+ ])('rejects a %s target before removal', async (_targetKind, target, recursive) => {
const options = { recursive, approvedRoots: [unc(FIXTURE_ROOT)] }
let rejection: unknown
diff --git a/src/main/wsl-unc-delete.wsl.test.ts b/src/main/wsl-unc-delete.wsl.test.ts
index 36175b62626..25036380b00 100644
--- a/src/main/wsl-unc-delete.wsl.test.ts
+++ b/src/main/wsl-unc-delete.wsl.test.ts
@@ -46,7 +46,7 @@ describe.skipIf(!runRealWsl)('WSL contained delete integration', () => {
it.each([
['file-shaped', 'file-link/session.json', false],
['directory-shaped', 'dir-link/session', true]
- ])('rejects a %s escape and preserves all outside entries', async (_shape, path, recursive) => {
+ ])('rejects a %s escape and preserves all outside entries', async (_label, path, recursive) => {
const vaultRoot = `${fixtureRoot}/vault`
await expect(
diff --git a/src/main/wsl.test.ts b/src/main/wsl.test.ts
index 6ef8adbbb61..55327c465e5 100644
--- a/src/main/wsl.test.ts
+++ b/src/main/wsl.test.ts
@@ -547,10 +547,10 @@ describe('WSL availability cache', () => {
it.each([
['wsl.exe reports WSL unusable', { status: 1 }],
['wsl.exe is not installed', { code: 'ENOENT' }]
- ])('holds a definitive failure far longer than a timeout when %s', (_label, errorShape) => {
+ ])('holds a definitive failure far longer than a timeout when %s', (_label, errorFields) => {
vi.useFakeTimers()
execFileSyncMock.mockImplementationOnce(() => {
- throw Object.assign(new Error('definitive failure'), errorShape)
+ throw Object.assign(new Error('definitive failure'), errorFields)
})
execFileSyncMock.mockReturnValueOnce('')
@@ -621,10 +621,10 @@ describe('WSL availability cache', () => {
it.each([
['a definitive failure', { status: 1 }],
['a timeout', { code: 'ETIMEDOUT', status: null, signal: 'SIGTERM' }]
- ])('re-probes availability once a distro list succeeds after %s', (_label, errorShape) => {
+ ])('re-probes availability once a distro list succeeds after %s', (_label, errorFields) => {
vi.useFakeTimers()
execFileSyncMock.mockImplementationOnce(() => {
- throw Object.assign(new Error('probe failed'), errorShape)
+ throw Object.assign(new Error('probe failed'), errorFields)
})
try {
diff --git a/src/relay/git-exec-validator.ts b/src/relay/git-exec-validator.ts
index 82cc72d1d2e..9f9b5866ebc 100644
--- a/src/relay/git-exec-validator.ts
+++ b/src/relay/git-exec-validator.ts
@@ -96,7 +96,7 @@ const DIFF_ALLOWED_FLAGS = new Set([
// only those two exact shapes, held to the same remote-name and URL rules the
// relay already enforces on every pushTarget-carrying RPC. Everything else --
// set-url, rename, prune, flags before the action -- stays blocked.
-function isAllowedRemoteWriteShape(args: string[]): boolean {
+function isAllowedRemoteWriteInvocation(args: string[]): boolean {
if (args[1] === 'add') {
return args.length === 4 && isSafeGitRemoteName(args[2]) && isSafePushTargetRemoteUrl(args[3])
}
@@ -197,7 +197,7 @@ export function validateGitExecArgs(args: string[]): void {
if (
remoteSubcmd &&
REMOTE_WRITE_SUBCOMMANDS.has(remoteSubcmd) &&
- !isAllowedRemoteWriteShape(args)
+ !isAllowedRemoteWriteInvocation(args)
) {
throw new Error('Destructive git remote operations are not allowed via exec')
}
diff --git a/src/relay/git-handler-branch-diff-equivalence.test.ts b/src/relay/git-handler-branch-diff-equivalence.test.ts
index d33886b4f5a..ff399d92a7c 100644
--- a/src/relay/git-handler-branch-diff-equivalence.test.ts
+++ b/src/relay/git-handler-branch-diff-equivalence.test.ts
@@ -128,10 +128,10 @@ describe('pinned and legacy branch diff equivalence against real Git', () => {
for (const entry of compare.entries) {
// Exactly what the renderer sends: paths from the compare entry list,
// OIDs from the compare summary that produced that same list.
- const callerShape = { filePath: entry.path, oldPath: entry.oldPath }
- const legacy = await branchDiff(callerShape)
+ const callerParams = { filePath: entry.path, oldPath: entry.oldPath }
+ const legacy = await branchDiff(callerParams)
const pinned = await branchDiff({
- ...callerShape,
+ ...callerParams,
baseRef: compare.summary.mergeBase,
headOid: compare.summary.headOid
})
diff --git a/src/relay/git-handler-comparison-operations.ts b/src/relay/git-handler-comparison-operations.ts
index e5ebe65365b..f4c1e55fa5e 100644
--- a/src/relay/git-handler-comparison-operations.ts
+++ b/src/relay/git-handler-comparison-operations.ts
@@ -5,7 +5,7 @@ import { parseBranchDiff } from './git-handler-utils'
import { parseNumstat } from '../shared/git-uncommitted-line-stats'
import { isNoUpstreamError, normalizeGitErrorMessage } from '../shared/git-remote-error'
import { upstreamOnlyCommitsArePatchEquivalent } from '../shared/git-upstream-status'
-import { assertGitPushTargetShape } from '../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../shared/git-push-target-validation'
import { getPublishTargetStatus, type GitCommandRunner } from '../shared/git-publish-target-status'
import type { GitPushTarget } from '../shared/worktree/types'
import { getEffectiveGitUpstreamStatus } from '../shared/git-effective-upstream'
@@ -46,7 +46,7 @@ export class GitHandlerComparisonOperations extends GitHandlerOperationContext {
try {
if (params.pushTarget !== undefined) {
- assertGitPushTargetShape(params.pushTarget)
+ assertValidGitPushTarget(params.pushTarget)
const pushTarget = params.pushTarget as GitPushTarget
await this.git(['check-ref-format', '--branch', pushTarget.branchName], worktreePath)
return await getPublishTargetStatus(
diff --git a/src/relay/git-handler-fetch-operations.ts b/src/relay/git-handler-fetch-operations.ts
index cd3a86fcb63..fd13cdc07c2 100644
--- a/src/relay/git-handler-fetch-operations.ts
+++ b/src/relay/git-handler-fetch-operations.ts
@@ -1,6 +1,6 @@
import type { RequestContext } from './dispatcher'
import { GitHandlerOperationContext } from './git-handler-operation-context'
-import { assertGitPushTargetShape } from '../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../shared/git-push-target-validation'
import type { GitPushTarget } from '../shared/worktree/types'
import { normalizeGitErrorMessage, isExecKilledError } from '../shared/git-remote-error'
import { syncForkDefaultBranch, validateGitForkSyncExpectedUpstream } from '../shared/git-fork-sync'
@@ -21,7 +21,7 @@ export class GitHandlerFetchOperations extends GitHandlerOperationContext {
try {
try {
if (params.pushTarget !== undefined) {
- assertGitPushTargetShape(params.pushTarget)
+ assertValidGitPushTarget(params.pushTarget)
const pushTarget = params.pushTarget as GitPushTarget
await this.git(['check-ref-format', '--branch', pushTarget.branchName], worktreePath)
await this.git(['fetch', '--prune', pushTarget.remoteName], worktreePath)
diff --git a/src/relay/git-handler-push-target.ts b/src/relay/git-handler-push-target.ts
index 6663b5b3ad3..57a39e632d3 100644
--- a/src/relay/git-handler-push-target.ts
+++ b/src/relay/git-handler-push-target.ts
@@ -1,4 +1,4 @@
-import { assertGitPushTargetShape } from '../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../shared/git-push-target-validation'
import {
resolveConfiguredGitPushTarget,
type ResolvedGitPushTarget
@@ -15,7 +15,7 @@ export async function resolveRelayPushTarget(
if (pushTarget === undefined) {
return resolveConfiguredGitPushTarget((args) => git(args, worktreePath))
}
- assertGitPushTargetShape(pushTarget)
+ assertValidGitPushTarget(pushTarget)
const explicitTarget: GitPushTarget = pushTarget
// Why here and not in the shared resolver: an explicit target arrives over the wire,
// so the host re-validates its shape and asks Git to vet the branch name itself.
diff --git a/src/relay/git-handler-sync-operations.ts b/src/relay/git-handler-sync-operations.ts
index 262517b33cc..9c0922c34df 100644
--- a/src/relay/git-handler-sync-operations.ts
+++ b/src/relay/git-handler-sync-operations.ts
@@ -3,7 +3,7 @@ import type { RequestContext } from './dispatcher'
import { GitHandlerOperationContext } from './git-handler-operation-context'
import { resolveRelayPushTarget } from './git-handler-push-target'
import { normalizeGitErrorMessage, runPullWithDivergenceFallback } from '../shared/git-remote-error'
-import { assertGitPushTargetShape } from '../shared/git-push-target-validation'
+import { assertValidGitPushTarget } from '../shared/git-push-target-validation'
import type { GitCommandRunner } from '../shared/git-publish-target-status'
import type { GitPushTarget } from '../shared/worktree/types'
import { resolveEffectiveGitUpstream } from '../shared/git-effective-upstream'
@@ -63,7 +63,7 @@ export class GitHandlerSyncOperations extends GitHandlerOperationContext {
const worktreePath = params.worktreePath as string
const runPull = async (effectiveArgs: string[]): Promise => {
if (params.pushTarget !== undefined) {
- assertGitPushTargetShape(params.pushTarget)
+ assertValidGitPushTarget(params.pushTarget)
const pushTarget = params.pushTarget as GitPushTarget
await this.git(['check-ref-format', '--branch', pushTarget.branchName], worktreePath)
await this.git(
diff --git a/src/renderer/src/components/editor/rich-markdown-html-superscript-link.ts b/src/renderer/src/components/editor/rich-markdown-html-superscript-link.ts
index a60a6e9c777..6d8c2b44f15 100644
--- a/src/renderer/src/components/editor/rich-markdown-html-superscript-link.ts
+++ b/src/renderer/src/components/editor/rich-markdown-html-superscript-link.ts
@@ -149,7 +149,7 @@ function parseStructuredPayload(value: string): HtmlSuperscriptLinkSource | null
} catch {
return null
}
- if (!isCitationShape(candidate)) {
+ if (!isCitationSource(candidate)) {
return null
}
const parsed = parseHtmlSuperscriptLinkSource(candidate.source)
@@ -197,7 +197,7 @@ function hasOnlyAttributes(element: Element, allowed: string[]): boolean {
return Array.from(element.attributes).every((attribute) => allowedSet.has(attribute.name))
}
-function isCitationShape(value: unknown): value is HtmlSuperscriptLinkSource {
+function isCitationSource(value: unknown): value is HtmlSuperscriptLinkSource {
if (!value || typeof value !== 'object') {
return false
}
diff --git a/src/renderer/src/components/repo/repo-icon.tsx b/src/renderer/src/components/repo/repo-icon.tsx
index 9e9ad0c24ac..b778ead4426 100644
--- a/src/renderer/src/components/repo/repo-icon.tsx
+++ b/src/renderer/src/components/repo/repo-icon.tsx
@@ -16,6 +16,7 @@ import {
Palette,
Rocket,
Server,
+ // `Shapes` is lucide-react's own export name; exempted in config/oxlint-anti-slop.json.
Shapes,
Sparkles,
SquareTerminal,
diff --git a/src/renderer/src/components/right-sidebar/source-control/commit/discard-confirmation.ts b/src/renderer/src/components/right-sidebar/source-control/commit/discard-confirmation.ts
index e9f5a65788e..1a6121b535b 100644
--- a/src/renderer/src/components/right-sidebar/source-control/commit/discard-confirmation.ts
+++ b/src/renderer/src/components/right-sidebar/source-control/commit/discard-confirmation.ts
@@ -13,9 +13,7 @@ export type DiscardConfirmationCopy = {
* Untracked and newly-added paths have no HEAD version to restore, so Orca's discard removes the
* working-tree file. Every surface that names the operation must say "delete" for these.
*/
-export function isDeleteShapedDiscardEntry(
- entry: Pick
-): boolean {
+export function discardDeletesEntryFile(entry: Pick): boolean {
return entry.area === 'untracked' || entry.status === 'untracked' || entry.status === 'added'
}
@@ -24,7 +22,7 @@ export function getDiscardEntryConfirmationCopy(
): DiscardConfirmationCopy {
const name = basename(entry.path)
- if (isDeleteShapedDiscardEntry(entry)) {
+ if (discardDeletesEntryFile(entry)) {
return {
title: translate(
'auto.components.right.sidebar.source.control.discard.confirmation.96c772bee9',
diff --git a/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.test.ts b/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.test.ts
index 92f69010c9f..340b6e3a7e5 100644
--- a/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.test.ts
+++ b/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.test.ts
@@ -61,7 +61,7 @@ describe('showSourceControlEntryFailureToast', () => {
it('says "delete" for an entry whose discard removes the file rather than restoring it', () => {
// Why: untracked and added paths have no HEAD version, so the row button and the confirmation
// dialog both say "delete" — the failure must not contradict the verb the user pressed.
- show({ operation: 'discard', deleteShaped: true })
+ show({ operation: 'discard', deletesFile: true })
expect(lastToast().title).toBe('Failed to delete “src/app.ts”')
})
diff --git a/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.ts b/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.ts
index 13ab65c6fb8..9668ee1e16a 100644
--- a/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.ts
+++ b/src/renderer/src/components/right-sidebar/source-control/commit/source-control-entry-failure-toast.ts
@@ -26,7 +26,7 @@ export function dismissSourceControlEntryFailureToast(worktreeId: string | null)
function entryFailureTitle(
operation: SourceControlEntryOperation,
filePath: string,
- deleteShaped: boolean
+ deletesFile: boolean
): string {
switch (operation) {
case 'stage':
@@ -42,7 +42,7 @@ function entryFailureTitle(
{ value0: filePath }
)
case 'discard':
- return deleteShaped
+ return deletesFile
? translate(
'auto.components.right.sidebar.SourceControl.entryDeleteFailed',
'Failed to delete “{{value0}}”',
@@ -67,7 +67,7 @@ function entryFailureTitle(
export function showSourceControlEntryFailureToast({
operation,
filePath,
- deleteShaped = false,
+ deletesFile = false,
error,
worktreeId,
worktreeName,
@@ -76,7 +76,7 @@ export function showSourceControlEntryFailureToast({
operation: SourceControlEntryOperation
filePath: string
/** True when this discard deletes the file rather than restoring it — see `discard-confirmation`. */
- deleteShaped?: boolean
+ deletesFile?: boolean
error: unknown
/** The worktree the failed attempt ran against. */
worktreeId: string | null
@@ -85,7 +85,7 @@ export function showSourceControlEntryFailureToast({
onRetry?: () => void
}): void {
const isActiveWorktree = useAppStore.getState().activeWorktreeId === worktreeId
- const title = entryFailureTitle(operation, filePath, deleteShaped)
+ const title = entryFailureTitle(operation, filePath, deletesFile)
const offerRetry = Boolean(onRetry) && isActiveWorktree
entryFailureSlotOwner = { worktreeId }
toast.error(
diff --git a/src/renderer/src/components/right-sidebar/source-control/commit/use-discard-confirmation.ts b/src/renderer/src/components/right-sidebar/source-control/commit/use-discard-confirmation.ts
index f158c971a23..ae1c47398c5 100644
--- a/src/renderer/src/components/right-sidebar/source-control/commit/use-discard-confirmation.ts
+++ b/src/renderer/src/components/right-sidebar/source-control/commit/use-discard-confirmation.ts
@@ -10,7 +10,7 @@ import {
runDiscardAllForArea,
type DiscardAllArea
} from './discard-all-sequence'
-import { isDeleteShapedDiscardEntry } from './discard-confirmation'
+import { discardDeletesEntryFile } from './discard-confirmation'
import { readIpcErrorMessage } from '@/lib/ipc-error'
import {
dismissSourceControlEntryFailureToast,
@@ -62,7 +62,7 @@ export function useSourceControlDiscardConfirmation({
showSourceControlEntryFailureToast({
operation: 'discard',
filePath: entry.path,
- deleteShaped: isDeleteShapedDiscardEntry(entry),
+ deletesFile: discardDeletesEntryFile(entry),
error,
worktreeId: activeWorktreeId,
worktreeName: worktreePath ? basename(worktreePath) : null
diff --git a/src/renderer/src/components/shared/useDaemonActions.tsx b/src/renderer/src/components/shared/useDaemonActions.tsx
index 8c386b5ef13..93c4477cf66 100644
--- a/src/renderer/src/components/shared/useDaemonActions.tsx
+++ b/src/renderer/src/components/shared/useDaemonActions.tsx
@@ -223,14 +223,14 @@ export function useDaemonActions(callbacks?: DaemonActionCallbacks): DaemonActio
}
}
-type CopyShape = {
+type DaemonActionCopy = {
title: string
description: React.ReactNode
confirmLabel: string
busyLabel: string
}
-function getCopy(kind: DaemonActionKind): CopyShape {
+function getCopy(kind: DaemonActionKind): DaemonActionCopy {
if (kind === 'restart') {
return {
title: translate(
diff --git a/src/renderer/src/components/sidebar/comment-markdown-native-chat-file-links.ts b/src/renderer/src/components/sidebar/comment-markdown-native-chat-file-links.ts
index ee81b859dcc..47ee65b2a72 100644
--- a/src/renderer/src/components/sidebar/comment-markdown-native-chat-file-links.ts
+++ b/src/renderer/src/components/sidebar/comment-markdown-native-chat-file-links.ts
@@ -164,11 +164,11 @@ function exactFileLink(value: string, allowSpacedRelative: boolean): ParsedTermi
if (!parsed) {
return null
}
- const hasPathShape =
+ const looksLikePath =
ROOTED_PATH_PREFIX_PATTERN.test(parsed.pathText) ||
/[\\/]/.test(parsed.pathText) ||
/\.[\p{L}][\p{L}\p{N}\p{M}_+-]*$/u.test(parsed.pathText)
- if (!hasPathShape) {
+ if (!looksLikePath) {
return null
}
const explicitLink = {
diff --git a/src/renderer/src/components/sidebar/worktree-list/rows/repo-header-project-actions.tsx b/src/renderer/src/components/sidebar/worktree-list/rows/repo-header-project-actions.tsx
index ba4751b597c..cfa97732a53 100644
--- a/src/renderer/src/components/sidebar/worktree-list/rows/repo-header-project-actions.tsx
+++ b/src/renderer/src/components/sidebar/worktree-list/rows/repo-header-project-actions.tsx
@@ -6,6 +6,7 @@ import {
FolderInput,
FolderTree,
Plus,
+ // `Shapes` is lucide-react's own export name; exempted in config/oxlint-anti-slop.json.
Shapes,
SlidersHorizontal,
Trash2
diff --git a/src/renderer/src/components/terminal-pane/remote-runtime-outage-toast-flood-and-stuck-reconnect.test.ts b/src/renderer/src/components/terminal-pane/remote-runtime-outage-toast-flood-and-stuck-reconnect.test.ts
index 9ac752b2b31..65c7a90e72f 100644
--- a/src/renderer/src/components/terminal-pane/remote-runtime-outage-toast-flood-and-stuck-reconnect.test.ts
+++ b/src/renderer/src/components/terminal-pane/remote-runtime-outage-toast-flood-and-stuck-reconnect.test.ts
@@ -31,7 +31,7 @@ import { REMOTE_RUNTIME_AUTO_RECOVERY_TIMEOUT_MS } from './remote-runtime-pty-re
const ELECTRON_IPC_PREFIX = "Error invoking remote method 'runtimeEnvironments:call': "
/** A rejection exactly as the renderer sees it after Electron IPC strips custom props. */
-function electronIpcShapedRejection(errorName: string, message: string): Error {
+function electronIpcRejection(errorName: string, message: string): Error {
return new Error(`${ELECTRON_IPC_PREFIX}${errorName}: ${message}`)
}
@@ -192,7 +192,7 @@ describe('remote runtime outage: toast flood and stuck reconnect (issue3)', () =
const { isRecoverableRemoteRuntimeConnectionError, toRemoteRuntimeClientErrorLike } =
await import('../../../../shared/remote-runtime-client-error-classification')
const rendererSide = toRemoteRuntimeClientErrorLike(
- electronIpcShapedRejection('RemoteRuntimeClientError', TIMEOUT_WITH_TAILSCALE_HINT)
+ electronIpcRejection('RemoteRuntimeClientError', TIMEOUT_WITH_TAILSCALE_HINT)
)
// Electron IPC stripped the code; the fragment list still catches this one.
expect(rendererSide.code).toBeUndefined()
@@ -201,7 +201,7 @@ describe('remote runtime outage: toast flood and stuck reconnect (issue3)', () =
// per-selector RPC queue saturated by 15s-timeout calls) is classified
// fatal even though its own code says "retry later".
const overload = toRemoteRuntimeClientErrorLike(
- electronIpcShapedRejection('RuntimeRpcCallQueueOverloadError', QUEUE_OVERLOAD_RAW)
+ electronIpcRejection('RuntimeRpcCallQueueOverloadError', QUEUE_OVERLOAD_RAW)
)
expect(overload.code).toBeUndefined()
// DESIRED: transient capacity pressure during an outage is recoverable,
@@ -220,7 +220,7 @@ describe('remote runtime outage: toast flood and stuck reconnect (issue3)', () =
runtimeCall.mockImplementation(async (request: { method: string; params?: unknown }) => {
if (request.method === 'terminal.send') {
sendRejections += 1
- throw electronIpcShapedRejection('RuntimeRpcCallQueueOverloadError', QUEUE_OVERLOAD_RAW)
+ throw electronIpcRejection('RuntimeRpcCallQueueOverloadError', QUEUE_OVERLOAD_RAW)
}
return healthyImpl(request)
})
@@ -294,7 +294,7 @@ describe('remote runtime outage: toast flood and stuck reconnect (issue3)', () =
if (request.method === 'terminal.resolvePane') {
throw Object.assign(new Error(fatalMessage), { code: 'unauthorized' })
}
- throw electronIpcShapedRejection('RemoteRuntimeClientError', TIMEOUT_WITH_TAILSCALE_HINT)
+ throw electronIpcRejection('RemoteRuntimeClientError', TIMEOUT_WITH_TAILSCALE_HINT)
})
subscriptionCallbacks?.onClose?.()
await vi.waitFor(() => expect(onError).toHaveBeenCalled())
diff --git a/src/renderer/src/components/terminal-search-decoration-leak.test.ts b/src/renderer/src/components/terminal-search-decoration-leak.test.ts
index 07c4ba998e5..b508d6d6c00 100644
--- a/src/renderer/src/components/terminal-search-decoration-leak.test.ts
+++ b/src/renderer/src/components/terminal-search-decoration-leak.test.ts
@@ -107,7 +107,7 @@ function openTerminalWithSearch(): SearchHarness {
* showed up for some of them, so the regression has to sweep rather than pin
* one lucky case.
*/
-const CONTENT_SHAPES: readonly (readonly [string, string])[] = [
+const CONTENT_LAYOUTS: readonly (readonly [string, string])[] = [
['matches on two lines', 'needle one\r\nneedle two\r\n'],
['matches on three lines', 'needle one\r\nneedle two\r\nneedle three\r\n'],
['matches on four lines', 'needle a\r\nneedle b\r\nneedle c\r\nneedle d\r\n'],
@@ -128,7 +128,7 @@ describe('terminal search decoration cleanup (STA-2707)', () => {
document.body.replaceChildren()
})
- it.each(CONTENT_SHAPES)(
+ it.each(CONTENT_LAYOUTS)(
'leaves no highlighted cells after closing search (%s)',
async (_name, content) => {
// Sweeping the match-navigation count matters: which decoration is the
diff --git a/src/renderer/src/hooks/useEditorExternalWatch.ts b/src/renderer/src/hooks/useEditorExternalWatch.ts
index 20f02e719d5..c9b7db652f8 100644
--- a/src/renderer/src/hooks/useEditorExternalWatch.ts
+++ b/src/renderer/src/hooks/useEditorExternalWatch.ts
@@ -7,7 +7,7 @@ import {
getEditorExternalWatchTargetKey,
selectEditorExternalWatchTargets,
type EditorExternalWatchTarget,
- type EditorExternalWatchTargetState as EditorExternalWatchTargetStateShape
+ type EditorExternalWatchTargetState
} from './editor-external-watch-targets'
import {
buildEditorExternalWatchEventHandler,
@@ -15,7 +15,7 @@ import {
} from './editor-external-watch-event-reconciliation'
import { verifyLatchedEditorMoveDestinations } from './editor-external-watch-disk-verification'
-export type EditorExternalWatchTargetState = EditorExternalWatchTargetStateShape
+export type { EditorExternalWatchTargetState }
function warnExternalWatchFailure(target: EditorExternalWatchTarget, err: unknown): void {
console.warn('[filesystem-watch] failed to watch worktree', {
diff --git a/src/renderer/src/lib/tab-agent-identity-decision-table.test.ts b/src/renderer/src/lib/tab-agent-identity-decision-table.test.ts
index 6c543db3594..dc4fa218fa9 100644
--- a/src/renderer/src/lib/tab-agent-identity-decision-table.test.ts
+++ b/src/renderer/src/lib/tab-agent-identity-decision-table.test.ts
@@ -11,7 +11,7 @@ import type { TuiAgent } from '../../../shared/tui-agent'
const AGENTS: readonly TuiAgent[] = ['claude', 'codex']
const SLOT_COUNT = 7
-const SHAPE_COUNT = 3 ** SLOT_COUNT * 4 * 2
+const COMBINATION_COUNT = 3 ** SLOT_COUNT * 4 * 2
const TITLES: readonly string[] = ['', 'zsh', 'Task - claude', 'Task - codex']
type Breakdown = Record<
@@ -124,7 +124,7 @@ describe('renderer ladder decision table', () => {
const proofFree = runDecisionTable(false)
const freshProof = runDecisionTable(true)
const result = {
- shapes: SHAPE_COUNT,
+ combinations: COMBINATION_COUNT,
proofOmitted: proofFree,
freshProof,
flippedByAddingProof: proofFree.flipped
diff --git a/src/renderer/src/lib/typing-latency/diagnostic-summary.ts b/src/renderer/src/lib/typing-latency/diagnostic-summary.ts
index 5cb96d684d9..a5a21fcef46 100644
--- a/src/renderer/src/lib/typing-latency/diagnostic-summary.ts
+++ b/src/renderer/src/lib/typing-latency/diagnostic-summary.ts
@@ -131,7 +131,7 @@ export type FocusedPaneCensus = {
type CountableRecord = Record | null | undefined
-export type TypingCensusStoreShape = {
+export type TypingCensusStoreView = {
worktreesByRepo?: Record | null
tabsByWorktree?: Record | null
unifiedTabsByWorktree?: Record | null
@@ -231,7 +231,7 @@ function collectWorktrees(
}
export function summarizeTypingScaleCensus(input: {
- state: TypingCensusStoreShape | null
+ state: TypingCensusStoreView | null
appVersion: string | null
livePaneCount: number | null
instrumentedPaneCount: number
diff --git a/src/renderer/src/lib/worktree-runtime-owner-index.detected.test.ts b/src/renderer/src/lib/worktree-runtime-owner-index.detected.test.ts
index 2191a083e2a..eb868674b64 100644
--- a/src/renderer/src/lib/worktree-runtime-owner-index.detected.test.ts
+++ b/src/renderer/src/lib/worktree-runtime-owner-index.detected.test.ts
@@ -67,11 +67,11 @@ function buildCase(random: () => number): {
worktreesByRepo: Record
probeIds: string[]
} {
- const shape = random()
- if (shape < 0.05) {
+ const roll = random()
+ if (roll < 0.05) {
return { detectedWorktreesByRepo: undefined, worktreesByRepo: {}, probeIds: ['repo-0::absent'] }
}
- if (shape < 0.1) {
+ if (roll < 0.1) {
return { detectedWorktreesByRepo: {}, worktreesByRepo: {}, probeIds: ['repo-0::absent'] }
}
const repoCount = 1 + Math.floor(random() * 6)
diff --git a/src/renderer/src/runtime/sync-runtime-graph-agent-status-projection.test.ts b/src/renderer/src/runtime/sync-runtime-graph-agent-status-projection.test.ts
index 3ae6769bb15..2ac4a8bbfd7 100644
--- a/src/renderer/src/runtime/sync-runtime-graph-agent-status-projection.test.ts
+++ b/src/renderer/src/runtime/sync-runtime-graph-agent-status-projection.test.ts
@@ -65,19 +65,19 @@ function makeEntry(index: number, overrides: Record = {}): neve
}
describe('mobile agent-status projection equivalence', () => {
- it('matches the whole-array serialization across shapes and cache reuse', () => {
+ it('matches the whole-array serialization across status maps and cache reuse', () => {
resetRuntimeMobileAgentStatusProjectionCacheForTests()
- const shapes: AppState['agentStatusByPaneKey'][] = []
- shapes.push({})
- shapes.push({ 'tab-0:leaf-0': makeEntry(0) })
- shapes.push({ 'tab-0:leaf-0': makeEntry(0, { workingMode: 'monitoring' }) })
+ const statusMaps: AppState['agentStatusByPaneKey'][] = []
+ statusMaps.push({})
+ statusMaps.push({ 'tab-0:leaf-0': makeEntry(0) })
+ statusMaps.push({ 'tab-0:leaf-0': makeEntry(0, { workingMode: 'monitoring' }) })
const many: AppState['agentStatusByPaneKey'] = {}
for (let index = 0; index < 12; index += 1) {
many[`tab-${index}:leaf-0`] = makeEntry(index)
}
- shapes.push(many)
+ statusMaps.push(many)
// Optional fields absent entirely, which the ?? null fallbacks must cover.
- shapes.push({
+ statusMaps.push({
'tab-9:leaf-1': makeEntry(9, {
agentType: undefined,
terminalTitle: undefined,
@@ -89,17 +89,17 @@ describe('mobile agent-status projection equivalence', () => {
})
})
// Keys deliberately out of insertion order to pin the sort.
- shapes.push({
+ statusMaps.push({
'tab-z:leaf-0': makeEntry(2),
'tab-a:leaf-0': makeEntry(1),
'tab-m:leaf-0': makeEntry(3)
})
- for (const [index, shape] of shapes.entries()) {
+ for (const [index, statusMap] of statusMaps.entries()) {
expect({
index,
- projection: buildRuntimeMobileAgentStatusProjectionForTests(shape)
- }).toEqual({ index, projection: referenceProjection(shape) })
+ projection: buildRuntimeMobileAgentStatusProjectionForTests(statusMap)
+ }).toEqual({ index, projection: referenceProjection(statusMap) })
}
// Now exercise the cache: replace one entry the way setAgentStatus does and
diff --git a/src/renderer/src/runtime/sync-runtime-graph-projection-hot-path.test.ts b/src/renderer/src/runtime/sync-runtime-graph-projection-hot-path.test.ts
index ed1991e60d2..1a163ada0a8 100644
--- a/src/renderer/src/runtime/sync-runtime-graph-projection-hot-path.test.ts
+++ b/src/renderer/src/runtime/sync-runtime-graph-projection-hot-path.test.ts
@@ -256,7 +256,7 @@ describe('editor draft projection on the typing path', () => {
})
it('matches the uncached projection byte for byte across draft shapes', () => {
- const shapes: Record[] = [
+ const draftCases: Record[] = [
{},
{ 'file-a': '' },
{ 'file-a': 'hello' },
@@ -267,10 +267,10 @@ describe('editor draft projection on the typing path', () => {
{ 'file-a': 'hello', 'file-b': 'world', 'file-c': 'third' },
{ 'file-a': 'HELLO', 'file-c': 'third' }
]
- for (const [index, shape] of shapes.entries()) {
- expect({ index, projection: buildRuntimeMobileEditorDraftsProjection(shape) }).toEqual({
+ for (const [index, draft] of draftCases.entries()) {
+ expect({ index, projection: buildRuntimeMobileEditorDraftsProjection(draft) }).toEqual({
index,
- projection: referenceEditorDraftsProjection(shape)
+ projection: referenceEditorDraftsProjection(draft)
})
}
})
@@ -402,7 +402,7 @@ describe('open-files and browser projections', () => {
})
it('matches the uncached projections byte for byte across shapes', () => {
- const openFileShapes: AppState['openFiles'][] = [
+ const openFileCases: AppState['openFiles'][] = [
[] as unknown as AppState['openFiles'],
[makeOpenFile(0)] as unknown as AppState['openFiles'],
[makeOpenFile(0, { isDirty: true })] as unknown as AppState['openFiles'],
@@ -412,14 +412,14 @@ describe('open-files and browser projections', () => {
makeOpenFile(2, { isUntitled: true, deleteUntouchedOnClose: true, language: undefined })
] as unknown as AppState['openFiles']
]
- for (const [index, shape] of openFileShapes.entries()) {
- expect({ index, projection: buildRuntimeMobileOpenFilesProjection(shape) }).toEqual({
+ for (const [index, openFiles] of openFileCases.entries()) {
+ expect({ index, projection: buildRuntimeMobileOpenFilesProjection(openFiles) }).toEqual({
index,
- projection: referenceOpenFilesProjection(shape)
+ projection: referenceOpenFilesProjection(openFiles)
})
}
- const browserShapes: AppState[] = [
+ const browserCases: AppState[] = [
makeState({}),
makeState({ browserTabsByWorktree: { 'wt-1': [makeBrowserWorkspace(0)] } as never }),
makeState({
@@ -437,10 +437,10 @@ describe('open-files and browser projections', () => {
browserPagesByWorkspace: { 'ws-9': [makeBrowserPage(9, { url: 'a"b\\c' })] } as never
})
]
- for (const [index, shape] of browserShapes.entries()) {
- expect({ index, projection: buildRuntimeMobileBrowserProjection(shape) }).toEqual({
+ for (const [index, state] of browserCases.entries()) {
+ expect({ index, projection: buildRuntimeMobileBrowserProjection(state) }).toEqual({
index,
- projection: referenceBrowserProjection(shape)
+ projection: referenceBrowserProjection(state)
})
}
})
diff --git a/src/renderer/src/store/slices/usage-provider-slices.ts b/src/renderer/src/store/slices/usage-provider-slices.ts
index 16855b08a48..5c275ef7e86 100644
--- a/src/renderer/src/store/slices/usage-provider-slices.ts
+++ b/src/renderer/src/store/slices/usage-provider-slices.ts
@@ -30,13 +30,17 @@ type UsageSnapshot = {
recentSessions: object[]
}
-type UsageShape = {
+type UsageProviderTypes<
+ Scope extends string,
+ Range extends string,
+ Snapshot extends UsageSnapshot
+> = {
scope: Scope
range: Range
snapshot: Snapshot
}
-type UsageData> = {
+type UsageData> = {
scope: T['scope']
range: T['range']
scanState: T['snapshot']['scanState'] | null
@@ -47,7 +51,7 @@ type UsageData> = {
recentSessions: T['snapshot']['recentSessions']
}
-type UsageApi> = {
+type UsageApi> = {
getScanState: () => Promise
setEnabled: (args: { enabled: boolean }) => Promise
refresh: (args?: { force?: boolean }) => Promise
@@ -61,7 +65,7 @@ type UsageApi> = {
type ProviderUsageSlice<
Prefix extends string,
Name extends string,
- T extends UsageShape
+ T extends UsageProviderTypes
> = {
[K in keyof UsageData as `${Prefix}Usage${Capitalize}`]: UsageData[K]
} & Record<`set${Name}UsageEnabled`, (enabled: boolean) => Promise> &
@@ -74,7 +78,7 @@ type ProviderUsageSlice<
type UsageProviderConfig<
Prefix extends string,
Name extends string,
- T extends UsageShape
+ T extends UsageProviderTypes
> = {
prefix: Prefix
name: Name
@@ -93,13 +97,13 @@ const usageDataFields = [
'modelBreakdown',
'projectBreakdown',
'recentSessions'
-] as const satisfies readonly (keyof UsageData>)[]
+] as const satisfies readonly (keyof UsageData>)[]
function usageDataKey(prefix: string, field: string): string {
return `${prefix}Usage${field[0].toUpperCase()}${field.slice(1)}`
}
-function readUsageData>(
+function readUsageData>(
state: AppState,
prefix: string
): UsageData {
@@ -109,7 +113,7 @@ function readUsageData>(
) as UsageData
}
-function createUsagePatch>(
+function createUsagePatch>(
prefix: string,
patch: Partial>
): Partial {
@@ -123,7 +127,7 @@ function createUsagePatch>(
function createUsageProviderSlice<
Prefix extends string,
Name extends string,
- T extends UsageShape
+ T extends UsageProviderTypes
>(
config: UsageProviderConfig
): StateCreator> {
@@ -255,18 +259,22 @@ function createUsageProviderSlice<
}
}
-type ClaudeUsageShape = UsageShape
-type CodexUsageShape = UsageShape
-type OpenCodeUsageShape = UsageShape
+type ClaudeUsageTypes = UsageProviderTypes
+type CodexUsageTypes = UsageProviderTypes
+type OpenCodeUsageTypes = UsageProviderTypes<
+ OpenCodeUsageScope,
+ OpenCodeUsageRange,
+ OpenCodeUsageSnapshot
+>
-export type ClaudeUsageSlice = ProviderUsageSlice<'claude', 'Claude', ClaudeUsageShape>
-export type CodexUsageSlice = ProviderUsageSlice<'codex', 'Codex', CodexUsageShape>
-export type OpenCodeUsageSlice = ProviderUsageSlice<'openCode', 'OpenCode', OpenCodeUsageShape>
+export type ClaudeUsageSlice = ProviderUsageSlice<'claude', 'Claude', ClaudeUsageTypes>
+export type CodexUsageSlice = ProviderUsageSlice<'codex', 'Codex', CodexUsageTypes>
+export type OpenCodeUsageSlice = ProviderUsageSlice<'openCode', 'OpenCode', OpenCodeUsageTypes>
export const createClaudeUsageSlice = createUsageProviderSlice<
'claude',
'Claude',
- ClaudeUsageShape
+ ClaudeUsageTypes
>({
prefix: 'claude',
name: 'Claude',
@@ -276,7 +284,7 @@ export const createClaudeUsageSlice = createUsageProviderSlice<
hasCachedData: (state) => state.hasAnyClaudeData
})
-export const createCodexUsageSlice = createUsageProviderSlice<'codex', 'Codex', CodexUsageShape>({
+export const createCodexUsageSlice = createUsageProviderSlice<'codex', 'Codex', CodexUsageTypes>({
prefix: 'codex',
name: 'Codex',
initialScope: 'orca',
@@ -288,7 +296,7 @@ export const createCodexUsageSlice = createUsageProviderSlice<'codex', 'Codex',
export const createOpenCodeUsageSlice = createUsageProviderSlice<
'openCode',
'OpenCode',
- OpenCodeUsageShape
+ OpenCodeUsageTypes
>({
prefix: 'openCode',
name: 'OpenCode',
diff --git a/src/shared/agent-feature-install-commands.ts b/src/shared/agent-feature-install-commands.ts
index 29d1f60b349..4813c17f807 100644
--- a/src/shared/agent-feature-install-commands.ts
+++ b/src/shared/agent-feature-install-commands.ts
@@ -1,4 +1,4 @@
-import { isSkillsCliAgentKeyShaped } from './skills-cli-agent-keys'
+import { isUsableSkillsCliAgentKey } from './skills-cli-agent-keys'
export const ORCA_SKILLS_REPOSITORY_URL = 'https://github.com/stablyai/orca'
@@ -35,7 +35,7 @@ export function buildAgentFeatureSkillInstallArgs(
}
// Why: a value the skills CLI would drop leaves it with no target at all, which
// is the same all-agents install as passing no --agent.
- const unusable = agents.find((agent) => !isSkillsCliAgentKeyShaped(agent))
+ const unusable = agents.find((agent) => !isUsableSkillsCliAgentKey(agent))
if (unusable !== undefined) {
throw new Error(`"${unusable}" is not a usable install target.`)
}
diff --git a/src/shared/agent-resume-launch-command.test.ts b/src/shared/agent-resume-launch-command.test.ts
index 5bf4797472b..544cd92cd20 100644
--- a/src/shared/agent-resume-launch-command.test.ts
+++ b/src/shared/agent-resume-launch-command.test.ts
@@ -17,7 +17,7 @@ const SHELLS: { platform: NodeJS.Platform; shell: AgentStartupShell }[] = [
/** Independent selector oracle — deliberately NOT the implementation's own
* predicate, so a regression that shrinks the stripped set cannot also blind
* this assertion. */
-function isSelectorShapedToken(token: string): boolean {
+function isResumeSelectorToken(token: string): boolean {
return (
['--resume', '--continue', '-r', '-c'].includes(token) ||
['--resume=', '--continue=', '-r=', '-c='].some((prefix) => token.startsWith(prefix))
@@ -31,7 +31,7 @@ function expectSingleAuthoritativeResume(command: string, shell: AgentStartupShe
if (!tokenized.ok) {
return
}
- const selectors = tokenized.tokens.filter(isSelectorShapedToken)
+ const selectors = tokenized.tokens.filter(isResumeSelectorToken)
expect(selectors).toEqual(['--resume'])
const index = tokenized.tokens.indexOf('--resume')
expect(tokenized.tokens[index + 1]).toBe(SESSION_ID)
diff --git a/src/shared/agent-session-journal-schemas.ts b/src/shared/agent-session-journal-schemas.ts
index eaee6bb9a63..1c3ad47d3c6 100644
--- a/src/shared/agent-session-journal-schemas.ts
+++ b/src/shared/agent-session-journal-schemas.ts
@@ -242,7 +242,7 @@ export function isAdmissibleAgentJournalSubmission(
* never reject a row a writer in this build produced. The schemas are
* deliberately wider on open string fields, so only this direction holds. */
type Admits = T
-export type CanonicalJournalShapesAreAdmissible = [
+export type CanonicalJournalTypesAreAdmissible = [
Admits ? true : false>,
Admits ? true : false>,
Admits<
diff --git a/src/shared/agent-session-record.ts b/src/shared/agent-session-record.ts
index a8add5c1128..2248647c3c2 100644
--- a/src/shared/agent-session-record.ts
+++ b/src/shared/agent-session-record.ts
@@ -337,7 +337,7 @@ export function isAgentSessionRecord(value: unknown): value is AgentSessionRecor
return false
}
const record = value as Partial
- const shapeValid =
+ const fieldsValid =
record.schemaVersion === AGENT_SESSION_RECORD_SCHEMA_VERSION &&
isAgentSessionId(record.sessionId) &&
isAgentSessionExecutionLocation(record.location) &&
@@ -356,7 +356,7 @@ export function isAgentSessionRecord(value: unknown): value is AgentSessionRecor
record.lease.sessionId === record.sessionId &&
Number.isSafeInteger(record.createdAt) &&
Number.isSafeInteger(record.updatedAt)
- if (!shapeValid) {
+ if (!fieldsValid) {
return false
}
const validated = record as AgentSessionRecord
diff --git a/src/shared/git-push-target-validation.test.ts b/src/shared/git-push-target-validation.test.ts
index 7b5dd096eb8..0215611ce52 100644
--- a/src/shared/git-push-target-validation.test.ts
+++ b/src/shared/git-push-target-validation.test.ts
@@ -1,19 +1,19 @@
import { describe, expect, it } from 'vitest'
-import { assertGitPushTargetShape } from './git-push-target-validation'
+import { assertValidGitPushTarget } from './git-push-target-validation'
-describe('assertGitPushTargetShape', () => {
+describe('assertValidGitPushTarget', () => {
it('accepts slash-separated git remote names', () => {
expect(() =>
- assertGitPushTargetShape({ remoteName: 'foo/bar', branchName: 'feature/fix' })
+ assertValidGitPushTarget({ remoteName: 'foo/bar', branchName: 'feature/fix' })
).not.toThrow()
})
it('rejects remote names with empty or parent segments', () => {
expect(() =>
- assertGitPushTargetShape({ remoteName: 'foo//bar', branchName: 'feature/fix' })
+ assertValidGitPushTarget({ remoteName: 'foo//bar', branchName: 'feature/fix' })
).toThrow('Invalid git remote name')
expect(() =>
- assertGitPushTargetShape({ remoteName: 'foo/../bar', branchName: 'feature/fix' })
+ assertValidGitPushTarget({ remoteName: 'foo/../bar', branchName: 'feature/fix' })
).toThrow('Invalid git remote name')
})
})
diff --git a/src/shared/git-push-target-validation.ts b/src/shared/git-push-target-validation.ts
index 4f907d568e7..7fa666136c1 100644
--- a/src/shared/git-push-target-validation.ts
+++ b/src/shared/git-push-target-validation.ts
@@ -32,7 +32,7 @@ export function isSafePushTargetRemoteUrl(remoteUrl: string): boolean {
return GITHUB_CLONE_URL.test(remoteUrl) || GITHUB_SSH_URL.test(remoteUrl)
}
-export function assertGitPushTargetShape(target: unknown): asserts target is GitPushTarget {
+export function assertValidGitPushTarget(target: unknown): asserts target is GitPushTarget {
if (typeof target !== 'object' || target === null) {
throw new Error('Invalid PR push target.')
}
diff --git a/src/shared/native-chat-ask.ts b/src/shared/native-chat-ask.ts
index 7096db88353..f8655a11d2f 100644
--- a/src/shared/native-chat-ask.ts
+++ b/src/shared/native-chat-ask.ts
@@ -19,7 +19,7 @@ export function registerQuestionTool(toolName: string, parser: InteractiveQuesti
QUESTION_TOOL_PARSERS.set(toolName, parser)
}
-function parseQuestionsShape(input: unknown): AskPrompt | null {
+function parseCanonicalQuestionsInput(input: unknown): AskPrompt | null {
if (!input || typeof input !== 'object') {
return null
}
@@ -73,12 +73,12 @@ function parseOptions(raw: unknown): AskOption[] {
}
for (const name of ['AskUserQuestion', 'ask_user_question', 'askUserQuestion']) {
- QUESTION_TOOL_PARSERS.set(name, parseQuestionsShape)
+ QUESTION_TOOL_PARSERS.set(name, parseCanonicalQuestionsInput)
}
function parseToolInput(toolName: string | undefined, input: unknown): AskPrompt | null {
const parser = toolName ? QUESTION_TOOL_PARSERS.get(toolName) : undefined
- return (parser ? parser(input) : null) ?? parseQuestionsShape(input)
+ return (parser ? parser(input) : null) ?? parseCanonicalQuestionsInput(input)
}
export function parseAskFromStatus(
diff --git a/src/shared/onboarding-state-types.ts b/src/shared/onboarding-state-types.ts
index 669c70b94f3..20aefb45e26 100644
--- a/src/shared/onboarding-state-types.ts
+++ b/src/shared/onboarding-state-types.ts
@@ -9,6 +9,8 @@ export type OnboardingChecklistState = {
ranFirstAgent: boolean
ranSecondAgentOnSameTask: boolean
triedCmdJ: boolean
+ // Persisted field, also a telemetry enum member in ./telemetry-onboarding-foundation-schemas;
+ // renaming it would orphan saved state. Rule exemption: config/oxlint-anti-slop.json.
shapedSidebar: boolean
reviewedDiff: boolean
openedPr: boolean
diff --git a/src/shared/pane-agent-identity-resolver.test.ts b/src/shared/pane-agent-identity-resolver.test.ts
index 2f14a54976a..d11416a1d8f 100644
--- a/src/shared/pane-agent-identity-resolver.test.ts
+++ b/src/shared/pane-agent-identity-resolver.test.ts
@@ -52,8 +52,8 @@ describe('resolvePaneAgentIdentity', () => {
})
describe('run generation separates the bug from the legitimate reclaim', () => {
- // Both shapes are `completed hook = A, title = B`. Ordering alone cannot tell them apart.
- const shape = (hookRun: number, titleRun: number): PaneAgentEvidence[] => [
+ // Both cases are `completed hook = A, title = B`. Ordering alone cannot tell them apart.
+ const evidenceFor = (hookRun: number, titleRun: number): PaneAgentEvidence[] => [
{ source: 'completed-hook', agent: 'claude', run: { authorityId: H, incarnation: hookRun } },
{ source: 'title', agent: 'codex', run: { authorityId: H, incarnation: titleRun } }
]
@@ -61,7 +61,7 @@ describe('resolvePaneAgentIdentity', () => {
it('keeps the completed hook when both belong to the current run', () => {
// The reported bug: nothing new started, so the hook is still the truth.
const result = resolvePaneAgentIdentity({
- evidence: shape(7, 7),
+ evidence: evidenceFor(7, 7),
currentRun: { authorityId: H, incarnation: 7 }
})
expect(result).toMatchObject({ agent: 'claude', source: 'completed-hook' })
@@ -72,7 +72,7 @@ describe('resolvePaneAgentIdentity', () => {
// The legitimate reclaim: the pane was reused, so run 7's hook describes an agent that is
// no longer there. It is ineligible, not merely outranked.
const result = resolvePaneAgentIdentity({
- evidence: shape(7, 8),
+ evidence: evidenceFor(7, 8),
currentRun: { authorityId: H, incarnation: 8 }
})
expect(result).toMatchObject({ agent: 'codex', source: 'title' })
@@ -82,11 +82,11 @@ describe('resolvePaneAgentIdentity', () => {
it('produces opposite answers from identical evidence, given only the run ids', () => {
// The whole point, stated as one assertion.
const bug = resolvePaneAgentIdentity({
- evidence: shape(7, 7),
+ evidence: evidenceFor(7, 7),
currentRun: { authorityId: H, incarnation: 7 }
})
const reclaim = resolvePaneAgentIdentity({
- evidence: shape(7, 8),
+ evidence: evidenceFor(7, 8),
currentRun: { authorityId: H, incarnation: 8 }
})
expect(bug.agent).not.toBe(reclaim.agent)
diff --git a/src/shared/plugins/plugin-language-pack-artifact.test.ts b/src/shared/plugins/plugin-language-pack-artifact.test.ts
index a313cc33839..1c58189845c 100644
--- a/src/shared/plugins/plugin-language-pack-artifact.test.ts
+++ b/src/shared/plugins/plugin-language-pack-artifact.test.ts
@@ -5,7 +5,7 @@ import {
PLUGIN_LANGUAGE_CATALOG_MAX_DEPTH,
PLUGIN_LANGUAGE_CATALOG_MAX_ENTRIES,
validatePluginLanguagePackCatalog,
- validatePluginLanguagePackCatalogShape,
+ checkPluginLanguagePackCatalog,
pluginLanguageResourceId
} from './plugin-language-pack-artifact'
@@ -205,7 +205,7 @@ describe('plugin language-pack artifacts', () => {
}
})
- expect(validatePluginLanguagePackCatalogShape(catalog)).toEqual({
+ expect(checkPluginLanguagePackCatalog(catalog)).toEqual({
ok: true,
entries: PLUGIN_LANGUAGE_CATALOG_MAX_ENTRIES
})
diff --git a/src/shared/plugins/plugin-language-pack-artifact.ts b/src/shared/plugins/plugin-language-pack-artifact.ts
index 7bcfacf47d4..b2daf8bc1c7 100644
--- a/src/shared/plugins/plugin-language-pack-artifact.ts
+++ b/src/shared/plugins/plugin-language-pack-artifact.ts
@@ -37,7 +37,7 @@ export function isPluginLanguagePackRegistration(
pack.resourceLanguage === pluginLanguageResourceId(pack.id as `plugin:${string}`) &&
typeof pack.pluginKey === 'string' &&
typeof pack.locale === 'string' &&
- validatePluginLanguagePackCatalogShape(pack.catalog).ok
+ checkPluginLanguagePackCatalog(pack.catalog).ok
)
}
@@ -119,7 +119,7 @@ export function validatePluginLanguagePackCatalog(source: unknown): PluginLangua
return { ok: true, catalog: result.catalog!, entries: result.entries }
}
-export function validatePluginLanguagePackCatalogShape(
+export function checkPluginLanguagePackCatalog(
source: unknown
): PluginLanguagePackValidationResult {
const result = walkPluginLanguagePackCatalog(source, false)
diff --git a/src/shared/remote-pairing-verification.ts b/src/shared/remote-pairing-verification.ts
index 02d58b97bed..47475144b0a 100644
--- a/src/shared/remote-pairing-verification.ts
+++ b/src/shared/remote-pairing-verification.ts
@@ -31,7 +31,7 @@ function isNonNegativeSafeInteger(value: unknown): value is number {
return Number.isSafeInteger(value) && Number(value) >= 0
}
-function hasValidRuntimeStatusShape(status: Record): boolean {
+function hasValidRuntimeStatus(status: Record): boolean {
return (
typeof status.runtimeId === 'string' &&
status.runtimeId.length > 0 &&
@@ -103,7 +103,7 @@ export function verifyRemotePairingRuntimeStatus(
: 'Update Orca on the remote host before adding it.'
}
}
- if (!hasValidRuntimeStatusShape(status)) {
+ if (!hasValidRuntimeStatus(status)) {
return {
ok: false,
kind: 'connection-interrupted',
diff --git a/src/shared/rpc-contract/repo-update-params.ts b/src/shared/rpc-contract/repo-update-params.ts
index 179bb1994dc..3eb1477adb2 100644
--- a/src/shared/rpc-contract/repo-update-params.ts
+++ b/src/shared/rpc-contract/repo-update-params.ts
@@ -34,12 +34,14 @@ export const RepoUpstream = z
.nullable()
.optional()
-// The return type is inferred on purpose: an explicit z.ZodObject<...z.ZodRawShape>
-// annotation widened `updates` to an open record, which erased all 24 named fields
-// from RpcParams<'repo.update'> for every typed caller.
-export function createRepoUpdateSchema(selectorShape: T) {
+// The return type is inferred on purpose: an explicit z.ZodObject<...> annotation
+// widened `updates` to an open record, which erased all 24 named fields from
+// RpcParams<'repo.update'> for every typed caller.
+export function createRepoUpdateSchema>>(
+ selectorFields: T
+) {
return z.object({
- ...selectorShape,
+ ...selectorFields,
updates: z.object({
displayName: OptionalString,
badgeColor: RepoBadgeColor,
diff --git a/src/shared/rpc-contract/rpc-send-params.ts b/src/shared/rpc-contract/rpc-send-params.ts
index fcb6d66a359..148f5aa6d6c 100644
--- a/src/shared/rpc-contract/rpc-send-params.ts
+++ b/src/shared/rpc-contract/rpc-send-params.ts
@@ -21,15 +21,15 @@ type Prettify = { [K in keyof T]: T[K] } & {}
/** zod's own input-side key-optionality rule, copied from $InferObjectInput. */
type SendOptionalSchema = { _zod: { optin: 'optional' | 'defaulted' } }
-type SendShape = Prettify<
+type SendFields = Prettify<
{
- -readonly [K in keyof Shape as Shape[K] extends SendOptionalSchema ? never : K]: RpcSendInput<
- Shape[K]
+ -readonly [K in keyof Fields as Fields[K] extends SendOptionalSchema ? never : K]: RpcSendInput<
+ Fields[K]
>
} & {
- -readonly [K in keyof Shape as Shape[K] extends SendOptionalSchema ? K : never]?: RpcSendInput<
- Shape[K]
- >
+ -readonly [
+ K in keyof Fields as Fields[K] extends SendOptionalSchema ? K : never
+ ]?: RpcSendInput
}
>
@@ -50,11 +50,11 @@ export type RpcSendInput =
? RpcSendInput[]
: // ZodObject is the only schema carrying a `shape`, and matching on it keeps
// .strict()/.extend()/.superRefine() results in this branch.
- Schema extends { shape: infer Shape }
- ? keyof Shape extends never
+ Schema extends { shape: infer Fields }
+ ? keyof Fields extends never
? // Mirrors $InferObjectOutput: a no-field object admits no properties.
Record
- : SendShape
+ : SendFields
: // ZodDiscriminatedUnion extends ZodUnion, so both land here.
Schema extends z.ZodUnion
? RpcSendInput
diff --git a/src/shared/rpc-contract/ui-update-value-tolerance-params.ts b/src/shared/rpc-contract/ui-update-value-tolerance-params.ts
index 1b8ca0c2cd4..308c1183d02 100644
--- a/src/shared/rpc-contract/ui-update-value-tolerance-params.ts
+++ b/src/shared/rpc-contract/ui-update-value-tolerance-params.ts
@@ -7,13 +7,15 @@ import type { z } from 'zod'
* dropped from the payload and the rest of the batch still lands. Unknown KEYS
* stay a hard rejection — the parity assertions exist to catch those.
*/
-export function tolerateUnknownValues(shape: TShape): TShape {
- return Object.fromEntries(
- Object.entries(shape).map(([key, schema]) => [
- key,
- (schema as z.ZodType).catch(() => undefined)
- ])
- ) as unknown as TShape
+export function tolerateUnknownValues>>(
+ fields: TFields
+): TFields {
+ const tolerant: Record = {}
+ for (const [key, schema] of Object.entries(fields)) {
+ tolerant[key] = schema.catch(() => undefined)
+ }
+ // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the loop copies every key of `fields` and only wraps its schema in `.catch()`, so the result carries exactly `TFields`' keys; Object.entries erases that key identity.
+ return tolerant as TFields
}
/** Drops the `undefined` entries `tolerateUnknownValues` leaves behind, so a
diff --git a/src/shared/skills-cli-agent-keys.test.ts b/src/shared/skills-cli-agent-keys.test.ts
index 4359d879c48..02bdd8b52df 100644
--- a/src/shared/skills-cli-agent-keys.test.ts
+++ b/src/shared/skills-cli-agent-keys.test.ts
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
import { TUI_AGENT_CONFIG } from './tui-agent-config'
import {
SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT,
- isSkillsCliAgentKeyShaped,
+ isUsableSkillsCliAgentKey,
SKILLS_CLI_UNIVERSAL_AGENT_KEY,
toSkillsCliAgentKeys
} from './skills-cli-agent-keys'
@@ -117,10 +117,10 @@ describe('skills CLI agent keys', () => {
it('rejects values the skills CLI would drop, and allows the explicit wildcard', () => {
for (const bad of ['-y', '--copy', '', ' ', 'a b', 'a,b']) {
- expect(isSkillsCliAgentKeyShaped(bad), bad).toBe(false)
+ expect(isUsableSkillsCliAgentKey(bad), bad).toBe(false)
}
for (const good of ['claude-code', 'universal', 'trae-cn', 'inference-sh', '*']) {
- expect(isSkillsCliAgentKeyShaped(good), good).toBe(true)
+ expect(isUsableSkillsCliAgentKey(good), good).toBe(true)
}
})
diff --git a/src/shared/skills-cli-agent-keys.ts b/src/shared/skills-cli-agent-keys.ts
index 3126c0a81e5..8f77675e8c0 100644
--- a/src/shared/skills-cli-agent-keys.ts
+++ b/src/shared/skills-cli-agent-keys.ts
@@ -68,7 +68,7 @@ export const SKILLS_CLI_UNIVERSAL_AGENT_KEY = 'universal'
* emptiness. An unknown-but-plausible key is left to the CLI, which rejects it
* loudly with its own valid list before writing anything.
*/
-export function isSkillsCliAgentKeyShaped(value: string): boolean {
+export function isUsableSkillsCliAgentKey(value: string): boolean {
return /^(?:\*|[a-z0-9][a-z0-9.-]*)$/i.test(value)
}
diff --git a/src/shared/telemetry-event-classification.ts b/src/shared/telemetry-event-classification.ts
index 23b471fd4f5..cc932fe9411 100644
--- a/src/shared/telemetry-event-classification.ts
+++ b/src/shared/telemetry-event-classification.ts
@@ -8,32 +8,32 @@ export type EventName = keyof EventMap
export type EventProps = EventMap[N]
// Why: non-`ZodObject` schemas have no `.shape`; return null so `key in undefined` can't throw at module load.
-function eventSchemaShape(schema: z.ZodTypeAny): z.ZodRawShape | null {
+// Why `object` and not zod's own field-record type: callers only ask `key in fields`.
+function eventSchemaFields(schema: z.ZodTypeAny): object | null {
if (schema instanceof z.ZodObject) {
return schema.shape
}
- const shapeBearingSchema = schema as { shape?: unknown }
// Why: refined object schemas may expose `.shape` even when refinement breaks `instanceof ZodObject`.
- if (shapeBearingSchema.shape && typeof shapeBearingSchema.shape === 'object') {
- return shapeBearingSchema.shape as z.ZodRawShape
+ if ('shape' in schema && typeof schema.shape === 'object' && schema.shape !== null) {
+ return schema.shape
}
return null
}
-function eventsWithShapeKey(key: string): ReadonlySet {
+function eventsDeclaringKey(key: string): ReadonlySet {
return new Set(
(Object.entries(eventSchemas) as [EventName, z.ZodTypeAny][])
.filter(([, schema]) => {
- const shape = eventSchemaShape(schema)
- return shape !== null && key in shape
+ const fields = eventSchemaFields(schema)
+ return fields !== null && key in fields
})
.map(([name]) => name)
)
}
// Cohort injection is gated on this derived set because `.strict()` schemas drop events that don't declare `nth_repo_added`.
-const COHORT_EXTENDED_SET = eventsWithShapeKey('nth_repo_added')
+const COHORT_EXTENDED_SET = eventsDeclaringKey('nth_repo_added')
// Compile-time roster guarding the runtime injection set against silent schema drift.
type _CohortExtendedRoster =
@@ -78,7 +78,7 @@ export function isCohortExtendedEvent(name: EventName): boolean {
}
// Events whose schema declares `cohort`: the IPC handler injects cohort only for these — a `.strict()` schema without it would reject the event.
-const ONBOARDING_COHORT_SET = eventsWithShapeKey('cohort')
+const ONBOARDING_COHORT_SET = eventsDeclaringKey('cohort')
// `NonNullable` strips `undefined` introduced by `cohortSchema`'s `.optional()`.
export type OnboardingCohort = NonNullable>
diff --git a/src/shared/zod-salvage-absence.test.ts b/src/shared/zod-salvage-absence.test.ts
index 065c6118ec1..5b6ca28f94f 100644
--- a/src/shared/zod-salvage-absence.test.ts
+++ b/src/shared/zod-salvage-absence.test.ts
@@ -20,7 +20,7 @@ const CONTAINERS: [string, () => z.ZodType, unknown][] = [
['salvagingArray', () => salvagingArray(z.string()), ['v']]
]
-describe('salvaging containers used bare in an object shape', () => {
+describe('salvaging containers used bare in an object schema', () => {
it.each(CONTAINERS)('%s is neither optional-in nor optional-out', (_name, build) => {
const { optin, optout } = optionalityOf(build())
expect(optin).toBeUndefined()
@@ -28,12 +28,12 @@ describe('salvaging containers used bare in an object shape', () => {
})
it.each(CONTAINERS)('%s rejects an absent key and an explicit undefined', (_name, build, ok) => {
- const shape = z.object({ a: build() })
+ const schema = z.object({ a: build() })
- expect(shape.safeParse({}).success).toBe(false)
- expect(shape.safeParse({ a: undefined }).success).toBe(false)
+ expect(schema.safeParse({}).success).toBe(false)
+ expect(schema.safeParse({ a: undefined }).success).toBe(false)
// Why: a positive control, so the two rejections above cannot pass by rejecting everything.
- expect(shape.safeParse({ a: ok })).toMatchObject({ success: true })
+ expect(schema.safeParse({ a: ok })).toMatchObject({ success: true })
})
it.each(CONTAINERS)(
diff --git a/tests/e2e/helpers/host-created-terminal-retention-oracle.ts b/tests/e2e/helpers/host-created-terminal-retention-oracle.ts
index b3c4d8c2d21..9a1af6a957b 100644
--- a/tests/e2e/helpers/host-created-terminal-retention-oracle.ts
+++ b/tests/e2e/helpers/host-created-terminal-retention-oracle.ts
@@ -48,7 +48,7 @@ const HOST_TERMINAL_SURFACE_SEPARATOR = '::'
/** Daemon session id form. Deliberately excluded from id-shape classification,
* which is why a host-created tab needs its own binding to be preserved —
* a `serve-`/`ssh-` shaped id would take an already-correct path instead. */
-function isDaemonShapedPtyId(ptyId: string, worktreeId: string): boolean {
+function isDaemonPtyIdForm(ptyId: string, worktreeId: string): boolean {
return (
ptyId.startsWith(`${worktreeId}@@`) &&
!ptyId.startsWith('serve-') &&
@@ -156,7 +156,7 @@ export async function createHostCliTerminal(
throw new Error('Host did not report a leaf id for the CLI-created terminal')
}
expect(
- isDaemonShapedPtyId(ptyId, worktreeId),
+ isDaemonPtyIdForm(ptyId, worktreeId),
`CLI terminal ${ptyId} must carry the daemon id shape this seam excludes from classification`
).toBe(true)
await expect
diff --git a/tests/e2e/terminal-cjk-ime-committed-text.spec.ts b/tests/e2e/terminal-cjk-ime-committed-text.spec.ts
index fb98b2d1975..056929de8bb 100644
--- a/tests/e2e/terminal-cjk-ime-committed-text.spec.ts
+++ b/tests/e2e/terminal-cjk-ime-committed-text.spec.ts
@@ -73,7 +73,7 @@ const SUBSTITUTION_GROUPS = [
* The two ways a substituted keystroke can reach the renderer. Both are real; only the second one
* regressed, and only the second one can regress, which is why running both is the point.
*/
-const SUBSTITUTION_SHAPES: readonly {
+const SUBSTITUTION_ROUTES: readonly {
name: string
slug: string
dispatch: (session: CDPSession, keystroke: SubstitutedKeystroke) => Promise
@@ -165,9 +165,9 @@ test.describe('Terminal CJK IME committed text', () => {
}
})
- for (const shape of SUBSTITUTION_SHAPES) {
+ for (const route of SUBSTITUTION_ROUTES) {
for (const group of SUBSTITUTION_GROUPS) {
- test(`sends full-width ${group.label} and never their ASCII form when ${shape.name}`, async ({
+ test(`sends full-width ${group.label} and never their ASCII form when ${route.name}`, async ({
orcaPage,
testRepoPath
}, testInfo) => {
@@ -179,7 +179,7 @@ test.describe('Terminal CJK IME committed text', () => {
try {
await startTerminalImeByteReader(orcaPage, arena.ptyId, reader)
for (const keystroke of group.keystrokes) {
- await shape.dispatch(arena.session, keystroke)
+ await route.dispatch(arena.session, keystroke)
await orcaPage.waitForTimeout(60)
}
await dispatchPlainEnter(arena.session)
@@ -200,7 +200,7 @@ test.describe('Terminal CJK IME committed text', () => {
await closeTerminalImePaneArena(
arena,
testInfo,
- `full-width-${group.label}-${shape.slug}`,
+ `full-width-${group.label}-${route.slug}`,
!completed
)
removeTerminalImeByteReader(reader)
diff --git a/tests/tools/win-crash-survival-e2e/cli-args.mjs b/tests/tools/win-crash-survival-e2e/cli-args.mjs
index e3533342e4d..1276d5e2eb4 100644
--- a/tests/tools/win-crash-survival-e2e/cli-args.mjs
+++ b/tests/tools/win-crash-survival-e2e/cli-args.mjs
@@ -69,7 +69,7 @@ export function parseArgs(argv) {
function validate(opts, exePathFlagPresent, argv) {
const errors = []
- errors.push(...validateArgShape(argv))
+ errors.push(...validateArgSyntax(argv))
if (!opts.expect) {
errors.push('Missing --expect ')
} else if (!VALID_PROFILES.has(opts.expect)) {
@@ -94,7 +94,7 @@ function validate(opts, exePathFlagPresent, argv) {
return errors
}
-function validateArgShape(argv) {
+function validateArgSyntax(argv) {
const errors = []
const seen = new Set()
for (let index = 0; index < argv.length; index++) {