@dugleelabs/copair 1.6.0 → 1.7.0

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.
package/dist/api.d.ts CHANGED
@@ -216,21 +216,42 @@ declare class ToolRegistry {
216
216
  getAllDefinitions(): ToolDefinition[];
217
217
  }
218
218
 
219
+ /**
220
+ * Path-level permissions — model-agnostic.
221
+ * Applies regardless of which tool the model uses (read, bash cat, grep, etc.).
222
+ * write permission implies read.
223
+ */
224
+ interface PathPermissions {
225
+ read: string[];
226
+ write: string[];
227
+ }
219
228
  interface AllowRules {
220
229
  /** bash entries: exact match, or prefix if the pattern ends with " *" */
221
230
  bash: string[];
222
231
  /**
223
232
  * git entries: matched against the args string.
224
- * Entry is the subcommand (e.g. "diff") — automatically covers all
225
- * flags for that subcommand (e.g. "diff --cached", "diff HEAD~1").
233
+ * Entry is the subcommand (e.g. "diff") — covers all flags for that subcommand.
226
234
  */
227
235
  git: string[];
228
236
  /**
229
- * write / edit entries: glob patterns matched against the file path.
230
- * Supports * (within a segment) and ** (across segments).
237
+ * Tool-specific read/write/edit entries (kept for backward-compat and
238
+ * fine-grained tool control). For multi-model setups, prefer `paths:`.
231
239
  */
240
+ read: string[];
232
241
  write: string[];
233
242
  edit: string[];
243
+ /**
244
+ * Path-level permissions — the preferred way to allow cross-repo access.
245
+ * Works regardless of which tool the model chooses to use for an operation.
246
+ *
247
+ * Example allow.yaml:
248
+ * paths:
249
+ * read:
250
+ * - "../../other-repo/**"
251
+ * write:
252
+ * - "../../shared-output/**"
253
+ */
254
+ paths: PathPermissions;
234
255
  }
235
256
  declare class AllowList {
236
257
  private rules;
@@ -238,11 +259,25 @@ declare class AllowList {
238
259
  /**
239
260
  * Returns true when the operation is explicitly listed and should bypass
240
261
  * the approval prompt. Called by ApprovalGate before prompting.
262
+ *
263
+ * Check order per tool:
264
+ * 1. Tool-specific entries (bash:, git:, read:, write:, edit:) — fine-grained
265
+ * 2. Path-level entries (paths.read / paths.write) — model-agnostic
241
266
  */
242
267
  matches(toolName: string, input: Record<string, unknown>): boolean;
243
268
  private matchBash;
269
+ /**
270
+ * Path-level bash matching: extract path tokens from the command, classify
271
+ * as read or write intent, then check against paths.read / paths.write.
272
+ * All path tokens in the command must be covered for the check to pass.
273
+ */
274
+ private matchBashByPath;
244
275
  private matchGit;
245
276
  private matchPath;
277
+ /**
278
+ * Check filePath against paths.read or paths.write (write implies read).
279
+ */
280
+ private matchPathAgainstPermissions;
246
281
  }
247
282
 
248
283
  interface ToolInfo {
@@ -275,15 +310,27 @@ interface TokenUsage {
275
310
  contextPercent?: number;
276
311
  }
277
312
  type ApprovalAnswer = 'allow' | 'always' | 'deny' | 'all' | 'similar';
313
+ /** Pre-approval diff shown at the approval prompt (before execution). */
314
+ interface ApprovalDiffPreview {
315
+ filePath: string;
316
+ oldContent: string | null;
317
+ newContent: string;
318
+ diffText: string;
319
+ }
278
320
  interface ApprovalRequest {
279
321
  toolName: string;
280
322
  input: Record<string, unknown>;
281
323
  summary: string;
282
324
  index: number;
283
325
  total: number;
284
- diff?: DiffInfo;
326
+ /** Pre-approval diff preview (shown before user approves). */
327
+ diff?: ApprovalDiffPreview | null;
285
328
  /** Present when a bash command references a sensitive system path. */
286
329
  warning?: string;
330
+ /** Present when a bash command references a path outside the project root. */
331
+ crossRepoBashPath?: string;
332
+ /** Present when a read/glob/grep targets a path outside the project root. */
333
+ crossRepoReadPath?: string;
287
334
  }
288
335
  interface AgentBridgeEvents {
289
336
  'stream-text': (text: string) => void;
@@ -297,11 +344,13 @@ interface AgentBridgeEvents {
297
344
  'approval-request': (request: ApprovalRequest, respond: (answer: ApprovalAnswer) => void) => void;
298
345
  'diff': (diff: DiffInfo) => void;
299
346
  'usage': (usage: TokenUsage) => void;
300
- 'thinking-start': () => void;
347
+ 'thinking-start': (label?: string) => void;
301
348
  'thinking-stop': () => void;
302
349
  'turn-complete': () => void;
303
350
  'error': (message: string) => void;
304
351
  'input-request': (respond: (input: string) => void) => void;
352
+ 'context-limit-warning': () => void;
353
+ 'context-limit-action': (respond: (action: 'compact' | 'abort') => void) => void;
305
354
  }
306
355
  type EventName = keyof AgentBridgeEvents;
307
356
  /**
@@ -335,8 +384,8 @@ declare class AgentBridge extends EventEmitter {
335
384
  * input_summary is always redacted and truncated to ≤ 200 chars before
336
385
  * writing so that raw secrets never appear in the audit log.
337
386
  */
338
- type AuditEvent = 'session_start' | 'session_end' | 'tool_call' | 'approval' | 'denial' | 'path_block' | 'schema_rejection' | 'bash_sensitive_path';
339
- type AuditOutcome = 'allowed' | 'denied' | 'error';
387
+ type AuditEvent = 'session_start' | 'session_end' | 'tool_call' | 'approval' | 'denial' | 'path_block' | 'schema_rejection' | 'bash_sensitive_path' | 'bash_cross_repo' | 'cross_repo_read';
388
+ type AuditOutcome = 'allowed' | 'denied' | 'error' | 'flagged';
340
389
  interface AuditEntry {
341
390
  ts: string;
342
391
  event: AuditEvent;
@@ -386,7 +435,7 @@ declare class ApprovalGate {
386
435
  * The agent never calls this. ToolExecutor calls it. The agent only
387
436
  * sees the resulting ExecutionResult.
388
437
  */
389
- allow(toolName: string, input: Record<string, unknown>): Promise<boolean>;
438
+ allow(toolName: string, input: Record<string, unknown>, diffPreview?: ApprovalDiffPreview): Promise<boolean>;
390
439
  /** Bridge-based approval: emit event and await response from ink UI. */
391
440
  private bridgePrompt;
392
441
  /** Legacy approval prompt: reads from /dev/tty directly (not stdin).
@@ -455,7 +504,15 @@ declare class PathGuard {
455
504
  * @param mustExist true for read operations (file must exist); false for
456
505
  * write/edit operations (parent dir must exist).
457
506
  */
458
- check(rawPath: string, mustExist: boolean): PathGuardResult;
507
+ check(rawPath: string, mustExist: boolean, opts?: {
508
+ skipBoundaryCheck?: boolean;
509
+ }): PathGuardResult;
510
+ /**
511
+ * Check whether a raw path resolves to somewhere inside the project root.
512
+ * Used by the tool executor to flag cross-repo references before the gate fires.
513
+ * Returns false on any resolution error — treat as outside.
514
+ */
515
+ isInsideProject(rawPath: string): boolean;
459
516
  private isDenied;
460
517
  private isAllowed;
461
518
  /**
@@ -664,6 +721,8 @@ interface AgentOptions {
664
721
  toolCallFormat?: FormatName;
665
722
  bridge?: AgentBridge;
666
723
  pluginManager?: PluginManager;
724
+ /** Fraction of maxTokens at which to warn about context limit (0–1, default 0.9). */
725
+ contextLimitThresholdPct?: number;
667
726
  }
668
727
  declare class Agent {
669
728
  private provider;
@@ -693,6 +752,14 @@ declare class Agent {
693
752
  /** Input tokens from the last API call — reflects actual context window usage. */
694
753
  lastInputTokens: number;
695
754
  }>;
755
+ /**
756
+ * Detect whether the model likely hit its context limit this turn.
757
+ * Two signals:
758
+ * 1. Token threshold: input tokens ≥ contextLimitThresholdPct of maxTokens
759
+ * 2. Truncation heuristic: text present, no tool calls, and response ends
760
+ * without terminal punctuation (sentence was cut off mid-stream)
761
+ */
762
+ private detectContextLimit;
696
763
  }
697
764
 
698
765
  interface SessionMetadata {