@arnilo/prism-coding-agent 0.0.24 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ import type { AgentIdentity, ExecutionPolicy, OwnershipScope } from "@arnilo/prism";
2
+ /** Duck-typed long-running sandbox handle (mirrors coding-security SandboxProcessHandle). */
3
+ export interface ProcessSandboxHandle {
4
+ write(data: Uint8Array): Promise<void>;
5
+ signal(name: string): Promise<void>;
6
+ kill(): Promise<void>;
7
+ release(): Promise<void>;
8
+ wait(options?: {
9
+ timeoutMs?: number;
10
+ signal?: AbortSignal;
11
+ }): Promise<{
12
+ exitCode: number | null;
13
+ }>;
14
+ }
15
+ export interface ProcessSandboxStartRequest {
16
+ readonly file: string;
17
+ readonly args: readonly string[];
18
+ readonly cwd?: string;
19
+ readonly env?: Readonly<Record<string, string>>;
20
+ readonly onData?: (data: Buffer) => void;
21
+ readonly signal?: AbortSignal;
22
+ readonly timeout?: number;
23
+ }
24
+ /**
25
+ * Optional sandbox backend for ProcessSessions.
26
+ * Presence of `startProcess` = long-running capable; absence fails closed.
27
+ */
28
+ export interface ProcessSandboxBackend {
29
+ startProcess?(request: ProcessSandboxStartRequest): Promise<ProcessSandboxHandle>;
30
+ status?(): Promise<{
31
+ readonly state: string;
32
+ }>;
33
+ }
34
+ export type ProcessSessionState = "starting" | "running" | "exited" | "killed" | "released" | "expired" | "unknown";
35
+ export type ProcessSessionErrorCode = "ERR_PRISM_PROCESS_POLICY" | "ERR_PRISM_PROCESS_OWNERSHIP" | "ERR_PRISM_PROCESS_STATE" | "ERR_PRISM_PROCESS_LIMIT" | "ERR_PRISM_PROCESS_PTY_UNSUPPORTED" | "ERR_PRISM_PROCESS_UNSUPPORTED";
36
+ export declare class ProcessSessionError extends Error {
37
+ readonly code: ProcessSessionErrorCode;
38
+ constructor(code: ProcessSessionErrorCode, message: string);
39
+ }
40
+ export interface ProcessSessionLimits {
41
+ readonly maxSessions?: number;
42
+ readonly maxInputBytes?: number;
43
+ readonly maxLifetimeMs?: number;
44
+ readonly maxOutputChunkBytes?: number;
45
+ readonly maxTotalOutputBytes?: number;
46
+ }
47
+ export interface ResolvedProcessSessionLimits {
48
+ readonly maxSessions: number;
49
+ readonly maxInputBytes: number;
50
+ readonly maxLifetimeMs: number;
51
+ readonly maxOutputChunkBytes: number;
52
+ readonly maxTotalOutputBytes: number;
53
+ }
54
+ export declare function resolveProcessSessionLimits(limits?: ProcessSessionLimits): ResolvedProcessSessionLimits;
55
+ export interface ProcessStartRequest {
56
+ readonly command: string;
57
+ readonly args?: readonly string[];
58
+ readonly cwd?: string;
59
+ readonly env?: Readonly<Record<string, string>>;
60
+ /** Default false. true on unsupported platform → ERR_PRISM_PROCESS_PTY_UNSUPPORTED. */
61
+ readonly pty?: boolean;
62
+ readonly lifetimeMs?: number;
63
+ /** Owner string for this session; defaults to registry ownership key. */
64
+ readonly owner?: string;
65
+ /** When true, run cancel releases instead of killing (default kill). */
66
+ readonly releaseOnCancel?: boolean;
67
+ }
68
+ export interface ProcessOutputChunk {
69
+ readonly data: string;
70
+ /** Next byte cursor for paging. */
71
+ readonly cursor: number;
72
+ readonly eof: boolean;
73
+ }
74
+ export interface ProcessExitResult {
75
+ readonly exitCode: number | null;
76
+ readonly state: ProcessSessionState;
77
+ }
78
+ export interface ProcessSessionMetadata {
79
+ readonly id: string;
80
+ readonly commandFingerprint: string;
81
+ readonly owner: string;
82
+ readonly workspace: string;
83
+ readonly policyDecision: string;
84
+ readonly startedAt: string;
85
+ readonly exitedAt?: string;
86
+ readonly state: ProcessSessionState;
87
+ readonly releaseOnCancel: boolean;
88
+ }
89
+ export interface ProcessSession {
90
+ readonly id: string;
91
+ readonly state: ProcessSessionState;
92
+ readonly owner: string;
93
+ metadata(): ProcessSessionMetadata;
94
+ output(request?: {
95
+ cursor?: number;
96
+ maxBytes?: number;
97
+ }): Promise<ProcessOutputChunk>;
98
+ input(data: string | Uint8Array): Promise<void>;
99
+ wait(options?: {
100
+ timeoutMs?: number;
101
+ signal?: AbortSignal;
102
+ }): Promise<ProcessExitResult>;
103
+ signal(name: "SIGTERM" | "SIGINT" | "SIGHUP"): Promise<void>;
104
+ kill(): Promise<void>;
105
+ release(): Promise<void>;
106
+ }
107
+ export type CodingProcessEvent = {
108
+ readonly type: "process_started" | "process_exited" | "process_killed" | "process_released" | "process_expired" | "process_unknown";
109
+ readonly sessionId: string;
110
+ readonly processId: string;
111
+ readonly owner: string;
112
+ readonly exitCode?: number | null;
113
+ readonly at: string;
114
+ };
115
+ export interface ProcessSessions {
116
+ start(request: ProcessStartRequest): Promise<ProcessSession>;
117
+ get(sessionId: string, owner?: string): ProcessSession;
118
+ /** Kill (default) or release all sessions for `owner`. */
119
+ cancelOwned(owner: string, options?: {
120
+ release?: boolean;
121
+ }): Promise<void>;
122
+ /** Mark a running session unknown (backend loss); never fabricates exitCode. */
123
+ markUnknown(sessionId: string, owner?: string): Promise<void>;
124
+ /**
125
+ * Host resume / sandbox-loss reconciliation: mark every running/starting session unknown.
126
+ * Never fabricates exitCode. O(owned sessions).
127
+ */
128
+ reconcile(): Promise<{
129
+ readonly markedUnknown: number;
130
+ }>;
131
+ dispose(): Promise<void>;
132
+ }
133
+ export interface CreateProcessSessionsOptions {
134
+ readonly cwd: string;
135
+ readonly policy?: ExecutionPolicy;
136
+ readonly limits?: ProcessSessionLimits;
137
+ readonly onEvent?: (event: CodingProcessEvent) => void;
138
+ readonly ownership?: OwnershipScope;
139
+ /** Host-verified identity; projects onto default owner when ownership omitted. */
140
+ readonly identity?: AgentIdentity;
141
+ /**
142
+ * When set: use `startProcess` if present; otherwise start() fails closed
143
+ * (`ERR_PRISM_PROCESS_UNSUPPORTED`). Native spawn only when sandbox omitted.
144
+ */
145
+ readonly sandbox?: ProcessSandboxBackend;
146
+ }
@@ -0,0 +1,19 @@
1
+ import { DEFAULT_MAX_PROCESS_INPUT_BYTES, DEFAULT_MAX_PROCESS_LIFETIME_MS, DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, DEFAULT_MAX_PROCESS_SESSIONS, DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES, validateCodingLimit, } from "../limits.js";
2
+ export class ProcessSessionError extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "ProcessSessionError";
7
+ this.code = code;
8
+ }
9
+ }
10
+ export function resolveProcessSessionLimits(limits) {
11
+ return {
12
+ maxSessions: validateCodingLimit("maxSessions", limits?.maxSessions ?? DEFAULT_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_SESSIONS),
13
+ maxInputBytes: validateCodingLimit("maxInputBytes", limits?.maxInputBytes ?? DEFAULT_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_INPUT_BYTES),
14
+ maxLifetimeMs: validateCodingLimit("maxLifetimeMs", limits?.maxLifetimeMs ?? DEFAULT_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_LIFETIME_MS),
15
+ maxOutputChunkBytes: validateCodingLimit("maxOutputChunkBytes", limits?.maxOutputChunkBytes ?? DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES),
16
+ maxTotalOutputBytes: validateCodingLimit("maxTotalOutputBytes", limits?.maxTotalOutputBytes ?? DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES),
17
+ };
18
+ }
19
+ //# sourceMappingURL=types.js.map
@@ -146,5 +146,25 @@ export declare function compileSearchPattern(query: string, caseSensitive: boole
146
146
  } | null;
147
147
  patternBytes: number;
148
148
  };
149
+ export interface RepositoryWalkLimits {
150
+ maxDepth: number;
151
+ maxEntries: number;
152
+ maxFiles: number;
153
+ exclude: ReadonlySet<string>;
154
+ includeHidden: boolean;
155
+ signal?: AbortSignal;
156
+ deadlineAt?: number;
157
+ }
158
+ export type RepositoryWalkEvent = {
159
+ type: "entry";
160
+ entry: RepoListEntry;
161
+ absolutePath: string;
162
+ depth: number;
163
+ } | {
164
+ type: "limit";
165
+ truncatedBy: "entries" | "files" | "depth";
166
+ };
167
+ /** Injectable enumerator for list/search/glob. Default is the native opendir walker. */
168
+ export type RepositoryWalk = (rootReal: string, startAbsolute: string, limits: RepositoryWalkLimits) => AsyncGenerator<RepositoryWalkEvent>;
149
169
  /** Local filesystem repository operations (default backend). */
150
- export declare function createLocalRepositoryOperations(limits?: RepositoryLimitOptions): RepositoryOperations;
170
+ export declare function createLocalRepositoryOperations(limits?: RepositoryLimitOptions, walk?: RepositoryWalk): RepositoryOperations;
@@ -239,7 +239,7 @@ async function* walkRepository(rootReal, startAbsolute, limits) {
239
239
  }
240
240
  }
241
241
  }
242
- async function listLocal(request, defaults) {
242
+ async function listLocal(request, defaults, walk) {
243
243
  const resolved = await resolveRepoPath(request.root, request.path);
244
244
  const maxResults = validateCodingLimit("maxResults", request.maxResults ?? defaults.maxResults, HARD_MAX_REPO_RESULTS);
245
245
  const offset = validateCodingLimitAllowZero("offset", request.offset ?? 0, HARD_MAX_REPO_ENTRIES);
@@ -286,7 +286,7 @@ async function listLocal(request, defaults) {
286
286
  throw new RepositoryError(`cannot open path: ${message}`);
287
287
  }
288
288
  try {
289
- for await (const event of walkRepository(resolved.rootReal, resolved.absolute, {
289
+ for await (const event of walk(resolved.rootReal, resolved.absolute, {
290
290
  maxDepth,
291
291
  maxEntries: defaults.maxEntries,
292
292
  maxFiles: defaults.maxFiles,
@@ -458,7 +458,7 @@ async function searchFileLines(absolutePath, relativePath, testLine, options) {
458
458
  await handle.close();
459
459
  }
460
460
  }
461
- async function searchLocal(request, defaults) {
461
+ async function searchLocal(request, defaults, walk) {
462
462
  const mode = request.mode ?? "literal";
463
463
  if (mode !== "literal") {
464
464
  throw new RepositoryError(`unsupported search mode: ${String(mode)} (literal only)`);
@@ -519,7 +519,7 @@ async function searchLocal(request, defaults) {
519
519
  await runFile(resolved.absolute, resolved.relative);
520
520
  }
521
521
  else if (startStat.isDirectory()) {
522
- for await (const event of walkRepository(resolved.rootReal, resolved.absolute, {
522
+ for await (const event of walk(resolved.rootReal, resolved.absolute, {
523
523
  maxDepth: defaults.maxDepth,
524
524
  maxEntries: defaults.maxEntries,
525
525
  maxFiles: defaults.maxFiles,
@@ -603,7 +603,7 @@ async function searchLocal(request, defaults) {
603
603
  filesSkippedOversize,
604
604
  };
605
605
  }
606
- async function globLocal(request, defaults) {
606
+ async function globLocal(request, defaults, walk) {
607
607
  try {
608
608
  validateGlobPattern(request.pattern, defaults.maxPatternBytes);
609
609
  }
@@ -669,7 +669,7 @@ async function globLocal(request, defaults) {
669
669
  throw new RepositoryError(`cannot open path: ${message}`);
670
670
  }
671
671
  try {
672
- for await (const event of walkRepository(resolved.rootReal, resolved.absolute, {
672
+ for await (const event of walk(resolved.rootReal, resolved.absolute, {
673
673
  maxDepth,
674
674
  maxEntries: defaults.maxEntries,
675
675
  maxFiles: defaults.maxFiles,
@@ -728,12 +728,12 @@ async function globLocal(request, defaults) {
728
728
  };
729
729
  }
730
730
  /** Local filesystem repository operations (default backend). */
731
- export function createLocalRepositoryOperations(limits) {
731
+ export function createLocalRepositoryOperations(limits, walk = walkRepository) {
732
732
  const resolved = resolveRepositoryLimits(limits);
733
733
  return {
734
- list: (request) => listLocal(request, resolved),
735
- search: (request) => searchLocal(request, resolved),
736
- glob: (request) => globLocal(request, resolved),
734
+ list: (request) => listLocal(request, resolved, walk),
735
+ search: (request) => searchLocal(request, resolved, walk),
736
+ glob: (request) => globLocal(request, resolved, walk),
737
737
  };
738
738
  }
739
739
  //# sourceMappingURL=repository.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism-coding-agent",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "description": "Optional coding-agent tools (shell, read, write, edit, repo_list, repo_search, glob, delete, move, opt-in Git/check/ask-user-decision, and durable plan/checkpoint helpers) package for Prism.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,8 +28,8 @@
28
28
  "diff": "^9.0.0"
29
29
  },
30
30
  "peerDependencies": {
31
- "@arnilo/prism": "0.0.24",
32
- "@arnilo/prism-workflows": "0.0.24"
31
+ "@arnilo/prism": "0.0.26",
32
+ "@arnilo/prism-workflows": "0.0.26"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@arnilo/prism": "file:../..",