refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
@@ -10,12 +10,12 @@ function output(over: Partial<HookOutput> = {}): HookOutput {
|
||||
describe('hook/* session events', () => {
|
||||
it('appendHookInvoked records a log-only hook/invoked (with matcher when present)', () => {
|
||||
const session = Session.create(SessionId('s'))
|
||||
appendHookInvoked(session, { turn: 1, point: 'PreToolUse', dialect: 'claude', handlerId: 'h1', matcher: 'Bash' })
|
||||
appendHookInvoked(session, { turn: 1, point: 'PreToolUse', dialect: 'claude-code', handlerId: 'h1', matcher: 'Bash' })
|
||||
|
||||
const ev = [...session.events].find(e => e.type === 'hook/invoked')
|
||||
expect(ev?.type).toBe('hook/invoked')
|
||||
if (ev?.type === 'hook/invoked') {
|
||||
expect(ev.data).toMatchObject({ turn: 1, point: 'PreToolUse', dialect: 'claude', handlerId: 'h1', matcher: 'Bash' })
|
||||
expect(ev.data).toMatchObject({ turn: 1, point: 'PreToolUse', dialect: 'claude-code', handlerId: 'h1', matcher: 'Bash' })
|
||||
}
|
||||
// Log-only: no surfaceOp on the event.
|
||||
expect((ev as unknown as { surfaceOp?: unknown }).surfaceOp).toBeUndefined()
|
||||
@@ -95,7 +95,7 @@ describe('hook/* session events', () => {
|
||||
|
||||
it('an invoked/result pair correlates by handlerId', () => {
|
||||
const session = Session.create(SessionId('s'))
|
||||
appendHookInvoked(session, { turn: 1, point: 'PreToolUse', dialect: 'claude', handlerId: 'pair-1' })
|
||||
appendHookInvoked(session, { turn: 1, point: 'PreToolUse', dialect: 'claude-code', handlerId: 'pair-1' })
|
||||
appendHookResult(session, { turn: 1, point: 'PreToolUse', handlerId: 'pair-1', stderrSummaryMaxChars: 500, durationMs: 5, output: output({ decision: 'allow' }) })
|
||||
|
||||
const invoked = [...session.events].find(e => e.type === 'hook/invoked')
|
||||
|
||||
@@ -2,12 +2,12 @@ import { describe, expect, it } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import SessionStore, { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import * as HookInvariant from '@deepseek-ai/dsh-hook-protocol/invariant'
|
||||
import InvariantService from '@deepseek-ai/dsh-invariants'
|
||||
import InvariantRegistry from '@deepseek-ai/dsh-invariants'
|
||||
|
||||
async function setup(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await ctx.plugin(HookInvariant)
|
||||
return ctx
|
||||
}
|
||||
@@ -15,7 +15,7 @@ async function setup(): Promise<Context> {
|
||||
const invoked = (overrides: Record<string, unknown> = {}) => ({
|
||||
turn: 1,
|
||||
point: 'PreToolUse',
|
||||
dialect: 'claude' as const,
|
||||
dialect: 'claude-code' as const,
|
||||
handlerId: 'hook-1',
|
||||
...overrides,
|
||||
})
|
||||
@@ -51,7 +51,7 @@ describe('hook-protocol invariants', () => {
|
||||
const session = ctx.sessions.create()
|
||||
session.append('turn/start', { turn: 1 })
|
||||
session.append('hook/invoked', invoked())
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await ctx.plugin(HookInvariant)
|
||||
expect(() => session.append('hook/result', result())).not.toThrow()
|
||||
session.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
@@ -89,7 +89,7 @@ describe('hook-protocol invariants', () => {
|
||||
startTurn(session)
|
||||
session.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
session.append('hook/invoked', invoked())
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await expect(ctx.plugin(HookInvariant).then(() => undefined)).rejects.toThrow(/outside any open turn/)
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import { matcherDiagnostic, matchesMatcher } from '@deepseek-ai/dsh-hook-protocol'
|
||||
|
||||
describe('matchesMatcher — match-all sentinels (both dialects)', () => {
|
||||
for (const mode of ['claude', 'codex'] as const) {
|
||||
for (const mode of ['claude-code', 'codex'] as const) {
|
||||
it(`${mode}: absent / empty / '*' match everything`, () => {
|
||||
expect(matchesMatcher(undefined, 'Bash', mode)).toBe(true)
|
||||
expect(matchesMatcher('', 'anything', mode)).toBe(true)
|
||||
@@ -13,24 +13,24 @@ describe('matchesMatcher — match-all sentinels (both dialects)', () => {
|
||||
|
||||
describe('matchesMatcher — claude dialect (literal-or-regex)', () => {
|
||||
it('a pure word-char pattern is a LITERAL exact match (not substring)', () => {
|
||||
expect(matchesMatcher('Bash', 'Bash', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('Bash', 'Bash', 'claude-code')).toBe(true)
|
||||
// literal exact: "Bash" must NOT match "BashOutput" (a regex would, substring)
|
||||
expect(matchesMatcher('Bash', 'BashOutput', 'claude')).toBe(false)
|
||||
expect(matchesMatcher('Bash', 'BashOutput', 'claude-code')).toBe(false)
|
||||
})
|
||||
|
||||
it('a pipe pattern is literal ALTERNATION (exact match any alternative)', () => {
|
||||
expect(matchesMatcher('Edit|Write', 'Edit', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('Edit|Write', 'Write', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('Edit|Write', 'Read', 'claude')).toBe(false)
|
||||
expect(matchesMatcher('Edit|Write', 'Edit', 'claude-code')).toBe(true)
|
||||
expect(matchesMatcher('Edit|Write', 'Write', 'claude-code')).toBe(true)
|
||||
expect(matchesMatcher('Edit|Write', 'Read', 'claude-code')).toBe(false)
|
||||
// still exact per-alternative, not substring
|
||||
expect(matchesMatcher('Edit|Write', 'EditFile', 'claude')).toBe(false)
|
||||
expect(matchesMatcher('Edit|Write', 'EditFile', 'claude-code')).toBe(false)
|
||||
})
|
||||
|
||||
it('a non-word pattern falls through to regex (unanchored)', () => {
|
||||
expect(matchesMatcher('^Bash$', 'Bash', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('Bash.*', 'BashOutput', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('.*\\.ts$', 'foo.ts', 'claude')).toBe(true)
|
||||
expect(matchesMatcher('.*\\.ts$', 'foo.js', 'claude')).toBe(false)
|
||||
expect(matchesMatcher('^Bash$', 'Bash', 'claude-code')).toBe(true)
|
||||
expect(matchesMatcher('Bash.*', 'BashOutput', 'claude-code')).toBe(true)
|
||||
expect(matchesMatcher('.*\\.ts$', 'foo.ts', 'claude-code')).toBe(true)
|
||||
expect(matchesMatcher('.*\\.ts$', 'foo.js', 'claude-code')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -51,24 +51,24 @@ describe('matchesMatcher — codex dialect (always regex)', () => {
|
||||
describe('matchesMatcher — invalid regex is a non-match (never throws)', () => {
|
||||
it('an unbalanced pattern matches nothing rather than throwing', () => {
|
||||
// '(' is not the claude-literal charset, so it goes to the regex path and is invalid.
|
||||
expect(() => matchesMatcher('(', 'x', 'claude')).not.toThrow()
|
||||
expect(matchesMatcher('(', 'x', 'claude')).toBe(false)
|
||||
expect(() => matchesMatcher('(', 'x', 'claude-code')).not.toThrow()
|
||||
expect(matchesMatcher('(', 'x', 'claude-code')).toBe(false)
|
||||
expect(matchesMatcher('[', 'x', 'codex')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('matcherDiagnostic — parse-time diagnostics', () => {
|
||||
it('accepts match-all sentinels, Claude literals, and valid regexes', () => {
|
||||
expect(matcherDiagnostic(undefined, 'claude')).toBeUndefined()
|
||||
expect(matcherDiagnostic(undefined, 'claude-code')).toBeUndefined()
|
||||
expect(matcherDiagnostic('', 'codex')).toBeUndefined()
|
||||
expect(matcherDiagnostic('*', 'codex')).toBeUndefined()
|
||||
expect(matcherDiagnostic('Edit|Write', 'claude')).toBeUndefined()
|
||||
expect(matcherDiagnostic('^Bash$', 'claude')).toBeUndefined()
|
||||
expect(matcherDiagnostic('Edit|Write', 'claude-code')).toBeUndefined()
|
||||
expect(matcherDiagnostic('^Bash$', 'claude-code')).toBeUndefined()
|
||||
expect(matcherDiagnostic('Edit|Write', 'codex')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('returns a stable diagnostic for invalid regexes in either dialect', () => {
|
||||
expect(matcherDiagnostic('(', 'claude')).toBe('invalid claude regex matcher "("')
|
||||
expect(matcherDiagnostic('(', 'claude-code')).toBe('invalid claude-code regex matcher "("')
|
||||
expect(matcherDiagnostic('[', 'codex')).toBe('invalid codex regex matcher "["')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { describe, expect, expectTypeOf, it } from 'vitest'
|
||||
import type { BashExecRequest, BashExecSpec, BashExecutor, BashRunResult } from '@deepseek-ai/dsh-bash'
|
||||
import type { ShellExecRequest, ShellExecSpec, ShellExecutor, ShellRunResult } from '@deepseek-ai/dsh-shell'
|
||||
import { DEFAULT_HOOK_TIMEOUT_MS, runHook } from '@deepseek-ai/dsh-hook-protocol'
|
||||
import type { RunHookOptions } from '@deepseek-ai/dsh-hook-protocol'
|
||||
|
||||
/**
|
||||
* A minimal stand-in for the bits of {@link BashExecutor} that {@link runHook}
|
||||
* A minimal stand-in for the bits of {@link ShellExecutor} that {@link runHook}
|
||||
* actually calls (`resolve` then `run`). `runHook` is pure plumbing over those
|
||||
* two methods, so a duck-typed recorder is the right test hook — the REAL
|
||||
* executor (dsh-bash-local) is exercised end-to-end by the hook-bridge plugins
|
||||
* that consume this library, not here.
|
||||
*/
|
||||
function recordingBash(run: (spec: BashExecSpec) => Promise<BashRunResult>): {
|
||||
bash: BashExecutor
|
||||
specs: BashExecSpec[]
|
||||
function recordingBash(run: (spec: ShellExecSpec) => Promise<ShellRunResult>): {
|
||||
bash: ShellExecutor
|
||||
specs: ShellExecSpec[]
|
||||
} {
|
||||
const specs: BashExecSpec[] = []
|
||||
const specs: ShellExecSpec[] = []
|
||||
const bash = {
|
||||
resolve(request: BashExecRequest): BashExecSpec {
|
||||
resolve(request: ShellExecRequest): ShellExecSpec {
|
||||
// Carry the request through verbatim, defaulting the required spec fields —
|
||||
// exactly what dsh-bash-local's resolve does for the fields runHook sets.
|
||||
return {
|
||||
@@ -30,15 +30,15 @@ function recordingBash(run: (spec: BashExecSpec) => Promise<BashRunResult>): {
|
||||
sandboxPolicy: request.sandboxPolicy,
|
||||
}
|
||||
},
|
||||
async run(spec: BashExecSpec): Promise<BashRunResult> {
|
||||
async run(spec: ShellExecSpec): Promise<ShellRunResult> {
|
||||
specs.push(spec)
|
||||
return run(spec)
|
||||
},
|
||||
} as unknown as BashExecutor
|
||||
} as unknown as ShellExecutor
|
||||
return { bash, specs }
|
||||
}
|
||||
|
||||
function result(over: Partial<BashRunResult> = {}): BashRunResult {
|
||||
function result(over: Partial<ShellRunResult> = {}): ShellRunResult {
|
||||
return {
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
|
||||
Reference in New Issue
Block a user