Merge commit 'refs/codex/unblock/master-current' into HEAD
# Conflicts: # docs/event-producer-consumer.md # examples/acp-agent/tests/snapshots/bash-spill/session.jsonl # examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl # examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl # examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl # packages/context/workspace-context/tests/workspace-context.spec.ts # packages/core/agent/src/index.ts # packages/support/invariants/tests/invariants.spec.ts # packages/ui/acp/src/index.ts # packages/ui/tui/tests/harness.ts # packages/ui/tui/tests/tui.spec.ts
This commit is contained in:
631 files changed
+21514
-3341
No files matched your search
@@ -11,11 +11,16 @@
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"lib/types/**/*.d.ts.map",
|
||||
"src"
|
||||
@@ -24,6 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-agent": "^0.0.1",
|
||||
"@deepseek-ai/dsh-fs": "^0.0.1",
|
||||
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.0.1",
|
||||
"@deepseek-ai/dsh-paths": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session": "^0.0.1",
|
||||
@@ -39,6 +45,7 @@
|
||||
"@deepseek-ai/dsh-agent-loop": "workspace:^",
|
||||
"@deepseek-ai/dsh-fs": "workspace:^",
|
||||
"@deepseek-ai/dsh-fs-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm-deepseek": "workspace:^",
|
||||
"@deepseek-ai/dsh-paths": "workspace:^",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Package-owned invariant companion for `@deepseek-ai/dsh-workspace-context`.
|
||||
* @module @deepseek-ai/dsh-workspace-context/invariant
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
import type { Context } from 'cordis'
|
||||
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||
|
||||
const PACKAGE_NAME = '@deepseek-ai/dsh-workspace-context'
|
||||
|
||||
/** Cordis companion plugin name. */
|
||||
export const name = 'workspace-context-invariant'
|
||||
/** Service required before the companion can reserve package ownership. */
|
||||
export const inject = ['invariants']
|
||||
|
||||
/**
|
||||
* No runtime invariant: replay intentionally tolerates unknown or malformed workspace metadata,
|
||||
* while focused pipeline tests own its private pending/cache state transitions.
|
||||
*/
|
||||
const install: InvariantInstaller = () => {}
|
||||
|
||||
/**
|
||||
* Register this package's invariant companion.
|
||||
* @param ctx - Cordis context carrying the invariant service.
|
||||
* @returns the installed registration's disposer after setup succeeds.
|
||||
*/
|
||||
export const apply = (ctx: Context): Promise<() => void> =>
|
||||
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|
||||
/* jscpd:ignore-end */
|
||||
@@ -7,8 +7,9 @@ import Loader from '@cordisjs/plugin-loader'
|
||||
import * as workspaceContext from '@deepseek-ai/dsh-workspace-context'
|
||||
import LlmService, { CallId, type Message, type StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, { Session, SessionId, SESSION_FORMAT_VERSION, type SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
import AgentRegistry, { type Agent, type HookContext } from '@deepseek-ai/dsh-agent'
|
||||
import AgentRegistry, { agentEvents, type Agent, type HookContext } from '@deepseek-ai/dsh-agent'
|
||||
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
||||
import { scopeTarget } from '@deepseek-ai/dsh-scope'
|
||||
import { FileSystem, FsTargetKey, FsVersion } from '@deepseek-ai/dsh-fs'
|
||||
import type {
|
||||
FsDirEntry,
|
||||
@@ -23,7 +24,12 @@ import type {
|
||||
import LocalFileSystem from '@deepseek-ai/dsh-fs-local'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools'
|
||||
import type { ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools'
|
||||
import type {
|
||||
PostToolDecision,
|
||||
ToolExecution,
|
||||
ToolExecutionResult,
|
||||
ToolExecutionToken,
|
||||
} from '@deepseek-ai/dsh-tools'
|
||||
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
|
||||
import {
|
||||
discoverBaselineInstructionFiles,
|
||||
@@ -227,14 +233,31 @@ const composedPrefixes = new WeakMap<object, Message[]>()
|
||||
|
||||
async function composeBaselinePrefix(ctx: Context, agent: Agent): Promise<Message[]> {
|
||||
const empty: Message[] = []
|
||||
const prefix = await ctx.waterfall(
|
||||
'agent/session-prefix', agent, empty, AbortSignal.timeout(1000),
|
||||
const prefix = await agentEvents(ctx, agent).waterfall(
|
||||
'agent/session-prefix', empty, AbortSignal.timeout(1000),
|
||||
() => Promise.resolve(empty),
|
||||
)
|
||||
composedPrefixes.set(agent, prefix)
|
||||
return prefix
|
||||
}
|
||||
|
||||
function toolEventCarrier(ctx: Context, exec: ToolExecution) {
|
||||
return scopeTarget(ctx.get('tools') ?? ctx as unknown as ToolRegistry, exec.agent)
|
||||
}
|
||||
|
||||
function postExecute(
|
||||
ctx: Context,
|
||||
exec: ToolExecution,
|
||||
result: Readonly<ToolExecutionResult>,
|
||||
next: () => Promise<PostToolDecision>,
|
||||
): Promise<PostToolDecision> {
|
||||
return ctx.waterfall(toolEventCarrier(ctx, exec), 'tools/post-execute', exec, result, next)
|
||||
}
|
||||
|
||||
function emitToolResult(ctx: Context, exec: ToolExecution, result: Readonly<ToolExecutionResult>): void {
|
||||
ctx.emit(toolEventCarrier(ctx, exec), 'tools/result', exec, result)
|
||||
}
|
||||
|
||||
function derivedText(agent: Agent): string {
|
||||
return blocksText(composedPrefixes.get(agent)?.[0]?.content)
|
||||
}
|
||||
@@ -522,6 +545,7 @@ describe('workspace context instruction discovery', () => {
|
||||
|
||||
vi.resetModules()
|
||||
vi.doMock('node:os', () => ({ homedir: () => home }))
|
||||
vi.stubEnv('DSH_HOME', undefined)
|
||||
const isolated = await import('@deepseek-ai/dsh-workspace-context')
|
||||
const files = await isolated.discoverBaselineInstructionFiles({ cwd: root })
|
||||
|
||||
@@ -529,6 +553,7 @@ describe('workspace context instruction discovery', () => {
|
||||
} finally {
|
||||
vi.doUnmock('node:os')
|
||||
vi.resetModules()
|
||||
vi.unstubAllEnvs()
|
||||
await rm(root, { recursive: true, force: true })
|
||||
await rm(home, { recursive: true, force: true })
|
||||
}
|
||||
@@ -795,7 +820,7 @@ describe('workspace context request injection', () => {
|
||||
try {
|
||||
await ctx.plugin(workspaceContext, { maxBytes: 65536 })
|
||||
|
||||
const decision = await ctx.waterfall('tools/post-execute', stubToolExecution({
|
||||
const decision = await postExecute(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('no-fs-post-execute'),
|
||||
name: 'read',
|
||||
@@ -844,7 +869,7 @@ describe('workspace context request injection', () => {
|
||||
}
|
||||
|
||||
// A later PostToolUse-style policy blocks this otherwise-successful read.
|
||||
const blocked = await ctx.waterfall('tools/post-execute', exec, result, async () => ({
|
||||
const blocked = await postExecute(ctx, exec, result, async () => ({
|
||||
kind: 'block' as const,
|
||||
feedback: [{ type: 'text' as const, text: 'blocked by policy' }],
|
||||
}))
|
||||
@@ -858,7 +883,7 @@ describe('workspace context request injection', () => {
|
||||
// The same read, when the downstream accepts, DOES surface the nested
|
||||
// instructions — proving the block branch above is what suppressed them,
|
||||
// and that the block did not consume the pending nested change.
|
||||
const accepted = await ctx.waterfall('tools/post-execute', exec, result, async () => ({
|
||||
const accepted = await postExecute(ctx, exec, result, async () => ({
|
||||
kind: 'accept' as const,
|
||||
}))
|
||||
expect(accepted.kind).toBe('accept')
|
||||
@@ -1192,8 +1217,9 @@ describe('workspace context request injection', () => {
|
||||
const controller = new AbortController()
|
||||
const reason = new Error('cancel prefix')
|
||||
const empty: Message[] = []
|
||||
const pending = ctx.waterfall(
|
||||
'agent/session-prefix', stubAgent(root), empty, controller.signal,
|
||||
const agent = stubAgent(root)
|
||||
const pending = agentEvents(ctx, agent).waterfall(
|
||||
'agent/session-prefix', empty, controller.signal,
|
||||
() => Promise.resolve(empty),
|
||||
)
|
||||
|
||||
@@ -1683,7 +1709,7 @@ describe('dynamic nested workspace context injection', () => {
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
const pending = ctx.waterfall('tools/post-execute', exec, {
|
||||
const pending = postExecute(ctx, exec, {
|
||||
content: [{ type: 'text', text: 'ok' }],
|
||||
isError: false,
|
||||
}, () => Promise.resolve({ kind: 'accept' as const }))
|
||||
@@ -2445,13 +2471,13 @@ describe('dynamic nested workspace context injection', () => {
|
||||
isError: false,
|
||||
}
|
||||
|
||||
const failedStat = await ctx.waterfall('tools/post-execute', stubToolExecution({
|
||||
const failedStat = await postExecute(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('provider-stat-failure'), name: 'read', arguments: { file_path: 'pkg/file.txt' }, agent,
|
||||
}), result, async () => ({ kind: 'accept' as const }))
|
||||
fs.throwOnStat.clear()
|
||||
fs.entries.set(join(root, 'pkg/AGENTS.md'), { type: 'directory' })
|
||||
const mismatchedStat = await ctx.waterfall('tools/post-execute', stubToolExecution({
|
||||
const mismatchedStat = await postExecute(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('provider-stat-mismatch'), name: 'read', arguments: { file_path: 'pkg/file.txt' }, agent,
|
||||
}), result, async () => ({ kind: 'accept' as const }))
|
||||
@@ -2693,23 +2719,23 @@ describe('dynamic nested workspace context injection', () => {
|
||||
const parent = Symbol('parent') as ToolExecutionToken
|
||||
const plainResult = { callId: CallId('plain'), content: [], isError: false }
|
||||
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
emitToolResult(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('agentless-child'), name: 'read', arguments: {}, parent,
|
||||
}), plainResult)
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
emitToolResult(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('contextless-child'), name: 'read', arguments: {}, agent, parent,
|
||||
}), { ...plainResult, additionalContexts: [{ content: [], source: { kind: 'plugin', plugin: 'workspace-context' } }] })
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
emitToolResult(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('first-child'), name: 'read', arguments: {}, agent, parent,
|
||||
}), { ...plainResult, additionalContexts: [workspaceChangeContext('first', 'one')] })
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
emitToolResult(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('second-child'), name: 'read', arguments: {}, agent, parent,
|
||||
}), { ...plainResult, additionalContexts: [workspaceChangeContext('second', 'two')] })
|
||||
ctx.emit('tools/result', {
|
||||
emitToolResult(ctx, {
|
||||
...stubToolExecution({ signal: testToolSignal, callId: CallId('agentless-parent'), name: 'composite', arguments: {} }),
|
||||
token: parent,
|
||||
}, plainResult)
|
||||
@@ -2745,7 +2771,7 @@ describe('dynamic nested workspace context injection', () => {
|
||||
]
|
||||
|
||||
for (const item of cases) {
|
||||
const decision = await ctx.waterfall('tools/post-execute', stubToolExecution({
|
||||
const decision = await postExecute(ctx, stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId(`manual-${item.name}-${cases.indexOf(item)}`),
|
||||
name: item.name,
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../util/paths"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user