@gajae-code/coding-agent 0.11.5 → 0.11.7

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/commands/daemon.d.ts +2 -2
  5. package/dist/types/commands/sdk.d.ts +20 -2
  6. package/dist/types/config/keybindings.d.ts +1 -1
  7. package/dist/types/config/settings-schema.d.ts +67 -7
  8. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  9. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +5 -5
  10. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +20 -0
  11. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +19 -5
  12. package/dist/types/main.d.ts +24 -1
  13. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  14. package/dist/types/modes/components/model-selector.d.ts +2 -0
  15. package/dist/types/modes/components/tool-status-header.d.ts +1 -0
  16. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  17. package/dist/types/modes/interactive-mode.d.ts +2 -0
  18. package/dist/types/modes/types.d.ts +1 -0
  19. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  20. package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -0
  21. package/dist/types/sdk/bus/index.d.ts +1 -1
  22. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  23. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  24. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +13 -3
  25. package/dist/types/sdk/bus/telegram-daemon.d.ts +61 -3
  26. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  27. package/dist/types/sdk/client/discovery.d.ts +2 -0
  28. package/dist/types/sdk/client/liveness.d.ts +7 -0
  29. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  30. package/dist/types/sdk/transport/index.d.ts +12 -0
  31. package/dist/types/sdk/transport/relay.d.ts +43 -0
  32. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  33. package/dist/types/sdk/transport/socket.d.ts +7 -0
  34. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  35. package/dist/types/session/agent-session.d.ts +28 -5
  36. package/dist/types/session/btw-contract.d.ts +16 -0
  37. package/dist/types/session/internal/managed-session-scope.d.ts +21 -7
  38. package/dist/types/session/internal/managed-session-storage.d.ts +10 -8
  39. package/dist/types/session/session-manager.d.ts +35 -4
  40. package/dist/types/session/yield-queue.d.ts +8 -0
  41. package/dist/types/setup/credential-import.d.ts +5 -1
  42. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  43. package/dist/types/ssh/utils.d.ts +1 -0
  44. package/dist/types/task/discovery.d.ts +3 -1
  45. package/dist/types/tools/fetch.d.ts +5 -8
  46. package/dist/types/tools/image-gen.d.ts +16 -0
  47. package/dist/types/tools/skill-discovery.d.ts +7 -0
  48. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  49. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  50. package/dist/types/web/insane/bridge.d.ts +1 -0
  51. package/dist/types/web/insane/url-guard.d.ts +17 -0
  52. package/package.json +8 -8
  53. package/scripts/generate-sdk-operation-inventory.ts +3 -0
  54. package/src/capability/index.ts +50 -42
  55. package/src/capability/types.ts +3 -0
  56. package/src/cli/setup-cli.ts +10 -4
  57. package/src/cli.ts +34 -9
  58. package/src/commands/daemon.ts +22 -5
  59. package/src/commands/sdk.ts +42 -9
  60. package/src/config/keybindings.ts +1 -1
  61. package/src/config/model-profiles.ts +18 -0
  62. package/src/config/settings-schema.ts +71 -7
  63. package/src/defaults/gjc/skills/ultragoal/SKILL.md +42 -1
  64. package/src/discovery/ssh.ts +12 -1
  65. package/src/eval/py/kernel.ts +1 -21
  66. package/src/eval/py/runner-artifact.ts +84 -0
  67. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  68. package/src/gjc-runtime/ultragoal-guard.ts +88 -10
  69. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +103 -0
  70. package/src/gjc-runtime/ultragoal-runtime.ts +275 -12
  71. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  72. package/src/gjc-runtime/workflow-manifest.ts +23 -0
  73. package/src/internal-urls/docs-index.generated.ts +9 -8
  74. package/src/internal-urls/local-protocol.ts +32 -6
  75. package/src/main.ts +87 -28
  76. package/src/modes/action-registry.ts +1 -1
  77. package/src/modes/components/btw-panel.ts +82 -16
  78. package/src/modes/components/model-selector.ts +31 -3
  79. package/src/modes/components/tool-status-header.ts +6 -1
  80. package/src/modes/controllers/btw-controller.ts +119 -36
  81. package/src/modes/controllers/command-controller.ts +15 -0
  82. package/src/modes/controllers/extension-ui-controller.ts +14 -2
  83. package/src/modes/controllers/input-controller.ts +31 -0
  84. package/src/modes/controllers/selector-controller.ts +106 -12
  85. package/src/modes/interactive-mode.ts +16 -7
  86. package/src/modes/runtime-init.ts +16 -2
  87. package/src/modes/types.ts +1 -0
  88. package/src/prompts/system/btw-user.md +3 -8
  89. package/src/prompts/tools/skill-discovery.md +1 -0
  90. package/src/runtime-mcp/client.ts +41 -55
  91. package/src/runtime-mcp/content-limits.ts +71 -0
  92. package/src/runtime-mcp/json-rpc.ts +23 -9
  93. package/src/runtime-mcp/transports/http.ts +50 -16
  94. package/src/sdk/bus/chat-daemon-control.ts +20 -7
  95. package/src/sdk/bus/index.ts +8 -7
  96. package/src/sdk/bus/lifecycle-commands.ts +16 -7
  97. package/src/sdk/bus/notification-service.ts +41 -18
  98. package/src/sdk/bus/telegram-daemon-contract.ts +13 -3
  99. package/src/sdk/bus/telegram-daemon-control.ts +26 -8
  100. package/src/sdk/bus/telegram-daemon.ts +1736 -338
  101. package/src/sdk/bus/topic-registry.ts +451 -12
  102. package/src/sdk/client/discovery.ts +19 -3
  103. package/src/sdk/client/liveness.ts +49 -0
  104. package/src/sdk/host/control/dispatch.ts +14 -5
  105. package/src/sdk/protocol/operation-inventory.generated.json +29 -0
  106. package/src/sdk/session.ts +29 -5
  107. package/src/sdk/transport/auth-preface.ts +82 -0
  108. package/src/sdk/transport/index.ts +18 -0
  109. package/src/sdk/transport/relay.ts +252 -0
  110. package/src/sdk/transport/serve-cli.ts +105 -0
  111. package/src/sdk/transport/socket.ts +197 -0
  112. package/src/sdk/transport/stdio.ts +17 -0
  113. package/src/session/agent-session.ts +1212 -768
  114. package/src/session/blob-store.ts +19 -6
  115. package/src/session/btw-contract.ts +59 -0
  116. package/src/session/internal/managed-session-scope.ts +313 -57
  117. package/src/session/internal/managed-session-storage.ts +146 -35
  118. package/src/session/session-manager.ts +385 -85
  119. package/src/session/yield-queue.ts +20 -0
  120. package/src/setup/credential-import.ts +28 -3
  121. package/src/setup/provider-onboarding.ts +30 -1
  122. package/src/setup/provider-presets.json +2 -1
  123. package/src/slash-commands/builtin-registry.ts +37 -1
  124. package/src/ssh/utils.ts +14 -0
  125. package/src/task/discovery.ts +8 -2
  126. package/src/tools/ask-answer-registry.ts +15 -1
  127. package/src/tools/ask.ts +1 -1
  128. package/src/tools/fetch.ts +13 -131
  129. package/src/tools/image-gen.ts +301 -20
  130. package/src/tools/read.ts +2 -0
  131. package/src/tools/skill-discovery.ts +39 -3
  132. package/src/tools/sqlite-reader.ts +63 -5
  133. package/src/utils/pasted-image-path.ts +15 -6
  134. package/src/utils/shell-snapshot.ts +173 -63
  135. package/src/web/insane/bridge.ts +5 -1
  136. package/src/web/insane/url-guard.ts +138 -27
  137. package/src/web/scrapers/types.ts +19 -49
  138. package/src/web/scrapers/utils.ts +12 -26
@@ -3,6 +3,7 @@ export declare const MANAGED_ARTIFACT_MAX_DEPTH = 32;
3
3
  export declare const MANAGED_ARTIFACT_MAX_FILES = 10000;
4
4
  export declare const MANAGED_ARTIFACT_MAX_FILE_BYTES: number;
5
5
  export declare const MANAGED_ARTIFACT_MAX_TOTAL_BYTES: number;
6
+ export type ManagedSessionSecurityPolicy = "default" | "windows-existing-verify-first";
6
7
  export type ManagedStorageFailure = "migration_busy" | "binding_conflict" | "binding_invalid" | "destination_conflict" | "source_changed" | "unsafe_artifacts" | "durability_failed" | "migration_retired" | "managed_storage_unsupported";
7
8
  export interface ManagedStorageLock {
8
9
  path: string;
@@ -40,10 +41,11 @@ export declare class ManagedSessionDescendantStore {
40
41
  constructor(root: ManagedDirectoryRoot, baseDir: string, retained?: {
41
42
  authority: RecoveryFsRoot;
42
43
  authorityBaseDir: string;
43
- });
44
+ }, policy?: ManagedSessionSecurityPolicy);
44
45
  get dir(): string;
45
46
  get rootAuthority(): ManagedDirectoryRoot;
46
47
  get subtreeRootAuthority(): ManagedDirectoryRoot;
48
+ get securityPolicy(): ManagedSessionSecurityPolicy;
47
49
  deriveSubtree(relativePath: string): ManagedSessionDescendantStore;
48
50
  retainAuthority(): RecoveryFsRoot | undefined;
49
51
  assertBound(): void;
@@ -72,21 +74,21 @@ export declare class ManagedSessionDescendantStore {
72
74
  }
73
75
  export declare function shouldFsyncManagedDirectory(platform?: NodeJS.Platform): boolean;
74
76
  /** Create a managed directory and fail closed unless its owner-only mode/ACL verifies. */
75
- export declare function ensureManagedDirectory(pathname: string, root?: ManagedDirectoryRoot): void;
77
+ export declare function ensureManagedDirectory(pathname: string, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
76
78
  /** Captures a bounded prefix from one no-follow descriptor and rechecks the pathname before use. */
77
79
  export declare function captureManagedFilePrefixNoFollow(pathname: string, maxBytes: number): ManagedFileSnapshot;
78
80
  /** Captures header/hash/copy input from one no-follow descriptor and rechecks the pathname before use. */
79
81
  export declare function captureManagedFileNoFollow(pathname: string): ManagedFileSnapshot;
80
82
  /** Atomically publishes bytes without replacing an existing destination. */
81
- export declare function publishManagedFileNoReplace(destination: string, bytes: Uint8Array, assertOwned?: () => void, root?: ManagedDirectoryRoot): Promise<void>;
82
- export declare function publishManagedFileNoReplaceSync(destination: string, bytes: Uint8Array, root?: ManagedDirectoryRoot): void;
83
+ export declare function publishManagedFileNoReplace(destination: string, bytes: Uint8Array, assertOwned?: () => void, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
84
+ export declare function publishManagedFileNoReplaceSync(destination: string, bytes: Uint8Array, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
83
85
  /** Replace one managed regular file while retaining the secured staging fd through publication. */
84
- export declare function replaceManagedFileSync(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot): void;
85
- export declare function replaceManagedFile(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot): Promise<void>;
86
+ export declare function replaceManagedFileSync(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
87
+ export declare function replaceManagedFile(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
86
88
  /** Copy the exact bytes captured from one no-follow source descriptor. */
87
- export declare function copyManagedFileNoReplace(source: string, destination: string, snapshot?: ManagedFileSnapshot, root?: ManagedDirectoryRoot): Promise<void>;
89
+ export declare function copyManagedFileNoReplace(source: string, destination: string, snapshot?: ManagedFileSnapshot, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
88
90
  /** Acquire a lease lock with bounded wait, heartbeats, conservative stale reclaim, and fencing. */
89
- export declare function acquireManagedLock(locksDirectory: string, name: string, root?: ManagedDirectoryRoot): Promise<ManagedStorageLock>;
91
+ export declare function acquireManagedLock(locksDirectory: string, name: string, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<ManagedStorageLock>;
90
92
  /** Bounds a no-follow artifact tree before it can be copied or deleted. */
91
93
  export declare function validateManagedArtifactTree(root: string): void;
92
94
  /** Flush a copied managed artifact tree, including empty directories, before publishing its receipt. */
@@ -553,7 +553,7 @@ export interface ResolvedSessionMatch {
553
553
  session: SessionInfo;
554
554
  scope: "local" | "global";
555
555
  }
556
- export declare function resolveResumableSession(sessionArg: string, cwd: string, sessionDir?: string, storage?: SessionStorage): Promise<ResolvedSessionMatch | undefined>;
556
+ export declare function resolveResumableSession(sessionArg: string, cwd: string, sessionDir?: string, storage?: SessionStorage, managedAgentDir?: string): Promise<ResolvedSessionMatch | undefined>;
557
557
  interface SessionManagerStateSnapshot {
558
558
  sessionId: string;
559
559
  sessionName: string | undefined;
@@ -595,6 +595,16 @@ export declare class SessionManager {
595
595
  newSession(options?: NewSessionOptions): Promise<string | undefined>;
596
596
  /** Tombstone and exact-delete managed transcripts, detaching the active transcript first. */
597
597
  dropSession(sessionPath: string): Promise<void>;
598
+ /**
599
+ * Exact-delete a session transcript and its artifacts by path WITHOUT requiring
600
+ * managed logical authorization. This is only for discarding an UNCOMMITTED
601
+ * successor that a transaction (e.g. handoff) created via `newSession()` but
602
+ * never durably authorized — such a session has no managed candidate listing
603
+ * yet, so `dropSession` would refuse it and leak its resident-cache/artifact
604
+ * root. Bounded to this manager's configured session root and refuses to touch
605
+ * the active session; tolerates missing files.
606
+ */
607
+ discardUncommittedSession(sessionPath: string): Promise<void>;
598
608
  /**
599
609
  * Fork the current session, creating a new session file with the same entries.
600
610
  * Returns both the old and new session file paths for artifact copying.
@@ -639,6 +649,8 @@ export declare class SessionManager {
639
649
  /** Get usage statistics across all assistant messages in the session. */
640
650
  getUsageStatistics(): UsageStatistics;
641
651
  getSessionDir(): string;
652
+ /** Lists picker candidates within this manager's captured destination authority. */
653
+ listForResumePickerReadOnly(): Promise<SessionInfo[]>;
642
654
  getSessionId(): string;
643
655
  getSessionFile(): string | undefined;
644
656
  /**
@@ -891,8 +903,12 @@ export declare class SessionManager {
891
903
  static managedDestination(cwd: string, agentDir?: string, storage?: SessionStorage): SessionDestination;
892
904
  static explicitDestination(directory: string): SessionDestination;
893
905
  static create(cwd: string, destinationInput?: SessionDestinationInput, storage?: SessionStorage): SessionManager;
906
+ /** Prepare a selected candidate using this manager's captured managed destination authority. */
907
+ prepareManagedCandidateForWrite(filePath: string, migrationPolicy: SessionDirectoryMigrationPolicy, expectedIdentity?: ResumeSessionIdentity): Promise<string>;
908
+ /** Prepare a managed candidate and retain its exact post-preparation identity for the next adoption. */
909
+ prepareManagedCandidateForStrictAdoption(filePath: string, migrationPolicy: SessionDirectoryMigrationPolicy, expectedIdentity: ResumeSessionIdentity): Promise<string>;
894
910
  /** Resolve a default-managed candidate through binding validation and copy-retain migration before mutation. */
895
- static prepareManagedCandidateForWrite(filePath: string, migrationPolicy: SessionDirectoryMigrationPolicy): Promise<string>;
911
+ static prepareManagedCandidateForWrite(filePath: string, migrationPolicy: SessionDirectoryMigrationPolicy, destination: SessionDestination, expectedIdentity?: ResumeSessionIdentity): Promise<string>;
896
912
  /**
897
913
  * Fork a session into the current project directory.
898
914
  * Copies history from another session file while creating a new session file in the current sessionDir.
@@ -906,7 +922,15 @@ export declare class SessionManager {
906
922
  static open(filePath: string, destinationInput?: SessionDestinationInput, storage?: SessionStorage, migrationPolicy?: SessionDirectoryMigrationPolicy): Promise<SessionManager>;
907
923
  static openNestedManaged(filePath: string, destination: SessionDestination, store: ManagedSessionDescendantStore, storage?: SessionStorage): Promise<SessionManager>;
908
924
  /**
909
- * List sessions for the resume picker without recovery or other maintenance writes.
925
+ * List default-managed sessions for the resume picker without recovery or other
926
+ * maintenance writes. This is the only picker inventory that includes legacy
927
+ * sibling directories.
928
+ */
929
+ static listManagedForResumePickerReadOnly(cwd: string, managedAgentDir?: string, storage?: SessionStorage): Promise<SessionInfo[]>;
930
+ /**
931
+ * List sessions from an explicitly supplied picker directory without recovery
932
+ * or other maintenance writes. Unlike managed inventory, this never scans
933
+ * legacy sibling directories.
910
934
  */
911
935
  static listForResumePickerReadOnly(cwd: string, sessionDir?: string, storage?: SessionStorage): Promise<SessionInfo[]>;
912
936
  /** Tombstone and exact-delete a default-managed candidate. */
@@ -956,7 +980,13 @@ export declare class SessionManager {
956
980
  /**
957
981
  * List all sessions across all project directories.
958
982
  */
959
- static listAll(storage?: SessionStorage): Promise<SessionInfo[]>;
983
+ static listAll(storage?: SessionStorage, managedAgentDir?: string): Promise<SessionInfo[]>;
984
+ /**
985
+ * Strict inventory bound to this manager's captured session authority. Managed
986
+ * managers include authorized legacy and current candidates; explicit managers
987
+ * authorize only their exact directory.
988
+ */
989
+ inventorySessionsStrict(): StrictInventoryResult;
960
990
  /**
961
991
  * Strict raw scoped inventory for ACP authorization. Enumerates the scoped
962
992
  * session directory without suppressing any root/scan/lstat/read/parse/stat/
@@ -967,6 +997,7 @@ export declare class SessionManager {
967
997
  static inventorySessionsStrict(cwd: string, options?: {
968
998
  sessionDir?: string;
969
999
  storage?: SessionStorage;
1000
+ destination?: SessionDestination;
970
1001
  }): StrictInventoryResult;
971
1002
  /**
972
1003
  * Propagate the storage-layer verified hard delete bound to exact identity evidence.
@@ -20,5 +20,13 @@ export declare class YieldQueue {
20
20
  has(kind?: string): boolean;
21
21
  flush(mode: YieldFlushMode): Promise<void>;
22
22
  clear(): void;
23
+ /** Drop only the queued entries of a single kind, leaving other kinds intact. */
24
+ clearKind(kind: string): void;
25
+ /**
26
+ * Re-schedule an idle flush if work remains and the session is idle. Used after
27
+ * a transition (e.g. handoff) releases a delivery fence so entries queued while
28
+ * fenced are not stranded until an unrelated enqueue or agent yield.
29
+ */
30
+ rearmIdle(): void;
23
31
  }
24
32
  export {};
@@ -73,7 +73,11 @@ export declare function discoverExternalCredentials(options?: DiscoveryOptions):
73
73
  export declare function formatCredentialSummary(credential: ImportableCredential): string;
74
74
  /** Redacted summary lines for an entire discovery result. Never includes secrets. */
75
75
  export declare function formatDiscoverySummary(result: CredentialDiscoveryResult): string[];
76
- export declare function isAutoImportOAuthCredential(credential: ImportableCredential): boolean;
76
+ /** Reason shown when automatic OAuth import rejects an unusable discovery record. */
77
+ export declare const INVALID_AUTO_IMPORT_OAUTH_EXPIRY_REASON = "OAuth credential has no valid future expiry";
78
+ export declare function isAutoImportOAuthCredential(credential: ImportableCredential, now?: number): boolean;
79
+ /** Keep rejected OAuth discoveries visible to operators without offering them for automatic import. */
80
+ export declare function getAutoImportOAuthCredentialSkips(credentials: readonly ImportableCredential[], now?: number): SkippedCredential[];
77
81
  export declare function filterAutoImportOAuthCredentials(credentials: readonly ImportableCredential[]): ImportableCredential[];
78
82
  /**
79
83
  * Persist discovered credentials via `upsert`. Each credential is imported
@@ -37,6 +37,7 @@ interface ProviderPreset {
37
37
  baseUrl: string;
38
38
  apiKeyEnv: string;
39
39
  models: readonly string[];
40
+ modelApi?: Readonly<Record<string, ProviderSetupApi>>;
40
41
  compat?: ProviderCompatConfig;
41
42
  }
42
43
  export declare const PROVIDER_PRESETS: readonly ProviderPreset[];
@@ -47,6 +48,7 @@ export declare function findProviderPreset(value: string | undefined): ProviderP
47
48
  export declare function formatProviderPresetList(): string;
48
49
  export declare function parseModelList(values: readonly string[]): string[];
49
50
  export declare function redactSecret(secret: string): string;
51
+ export declare function validateModelApi(modelApi: Readonly<Record<string, string>> | undefined, models: readonly string[], presetId: string): void;
50
52
  export declare function addApiCompatibleProvider(input: ProviderSetupInput): Promise<ProviderSetupResult>;
51
53
  export declare function formatProviderSetupResult(result: ProviderSetupResult): string;
52
54
  export {};
@@ -1,2 +1,3 @@
1
1
  export declare function sanitizeHostName(name: string): string;
2
+ export declare function validateSshDestination(username: string | undefined, host: string): string | undefined;
2
3
  export declare function buildSshTarget(username: string | undefined, host: string): string;
@@ -1,3 +1,4 @@
1
+ import type { Settings } from "../config/settings";
1
2
  import type { AgentDefinition } from "./types";
2
3
  /** Result of agent discovery */
3
4
  export interface DiscoveryResult {
@@ -11,8 +12,9 @@ export declare function filterVisibleAgents(agents: readonly AgentDefinition[]):
11
12
  * Precedence (highest wins): .gjc project, .gjc user, GJC plugins, then bundled
12
13
  *
13
14
  * @param cwd - Current working directory for project agent discovery
15
+ * @param activeSettings - Settings used to resolve enabled providers.
14
16
  */
15
- export declare function discoverAgents(cwd: string, home?: string): Promise<DiscoveryResult>;
17
+ export declare function discoverAgents(cwd: string, home?: string, activeSettings?: Settings): Promise<DiscoveryResult>;
16
18
  /**
17
19
  * Get an agent by name from discovered agents.
18
20
  */
@@ -14,6 +14,11 @@ export interface ParsedReadUrlTarget {
14
14
  limit?: number;
15
15
  }
16
16
  export declare function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null;
17
+ export declare function renderHtmlToText(html: string, signal?: AbortSignal): Promise<{
18
+ content: string;
19
+ ok: boolean;
20
+ method: string;
21
+ }>;
17
22
  interface FetchImagePayload {
18
23
  data: string;
19
24
  mimeType: string;
@@ -21,14 +26,6 @@ interface FetchImagePayload {
21
26
  type FetchRenderResult = RenderResult & {
22
27
  image?: FetchImagePayload;
23
28
  };
24
- /**
25
- * Opt-in insane-search fallback for blocked / degraded public URL reads.
26
- *
27
- * Returns a finalized `method: "insane"` result on success, or null (so the
28
- * caller continues with its normal degraded behavior). Fail-closed: no note,
29
- * guard DNS, dependency probe, or subprocess when raw mode or the opt-in
30
- * setting is off. The public-URL guard runs BEFORE any probe/spawn.
31
- */
32
29
  export declare function tryInsaneFallback(args: {
33
30
  url: string;
34
31
  finalUrl: string;
@@ -72,6 +72,22 @@ interface InlineImageData {
72
72
  }
73
73
  /** Set the preferred image provider from settings */
74
74
  export declare function setPreferredImageProvider(provider: ImageProvider | "auto"): void;
75
+ /** Provider → default image model mapping for auto-binding */
76
+ export declare const IMAGE_PROVIDER_DEFAULTS: Record<string, string>;
77
+ /** Resolved image generation configuration from settings */
78
+ export interface ImageProviderConfig {
79
+ provider: ImageProvider | "auto" | "custom";
80
+ model: string | null;
81
+ customUrl?: string;
82
+ customKey?: string;
83
+ customKeyEnv?: string;
84
+ }
85
+ /** Set the configured image provider + model from settings */
86
+ export declare function setConfiguredImageModel(config: ImageProviderConfig | null): void;
87
+ /** Get the current configured image model (for UI display) */
88
+ export declare function getConfiguredImageModel(): ImageProviderConfig | null;
89
+ /** Resolve the effective image model for a configured provider */
90
+ export declare function resolveImageModel(provider: string, modelOverride: string | null): string;
75
91
  export declare function isOpenAIHostedImageModel(model: Model | undefined): model is Model;
76
92
  export declare const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails>;
77
93
  export declare function getImageGenTools(modelRegistry?: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
@@ -15,6 +15,13 @@ export type SkillDiscoveryToolInput = z.infer<typeof skillDiscoverySchema>;
15
15
  export interface SkillDiscoveryToolDetails {
16
16
  candidates: RuntimeSkillDiscoveryCandidate[];
17
17
  count: number;
18
+ /**
19
+ * Present only when zero candidates were returned AND discovery config gates
20
+ * (`skills.enabled` / `skills.enablePiProject` / `skills.enablePiUser`)
21
+ * prevented some or all of the requested scope from being searched. Without
22
+ * this, a disabled config is indistinguishable from "no skills exist".
23
+ */
24
+ notice?: string;
18
25
  }
19
26
  export declare class SkillDiscoveryTool implements AgentTool<typeof skillDiscoverySchema, SkillDiscoveryToolDetails> {
20
27
  #private;
@@ -32,6 +32,13 @@ export type SqliteRowLookup = {
32
32
  } | {
33
33
  kind: "rowid";
34
34
  };
35
+ /**
36
+ * Keep raw reads deliberately narrower than SQLite's full grammar. Comments are
37
+ * rejected, and a statement terminator is accepted only as the final
38
+ * non-whitespace character. Quoted semicolons remain ordinary query data.
39
+ */
40
+ export declare function validateSqliteReadQuery(sql: string): string;
41
+ export declare function enforceSqliteQueryOnly(db: Database): void;
35
42
  export declare function parseSqlitePathCandidates(filePath: string): SqlitePathCandidate[];
36
43
  export declare function isSqliteFile(absolutePath: string): Promise<boolean>;
37
44
  export declare function parseSqliteSelector(subPath: string, queryString: string): SqliteSelector;
@@ -1,5 +1,17 @@
1
+ interface ShellSnapshotCacheOptions {
2
+ tempRoot: string;
3
+ home: string | (() => string);
4
+ platform: NodeJS.Platform;
5
+ }
6
+ declare function createShellSnapshotCache(options: ShellSnapshotCacheOptions): {
7
+ getOrCreateSnapshot(shell: string, env: Record<string, string | undefined>): Promise<string | null>;
8
+ cleanup(): Promise<void>;
9
+ };
10
+ /** @internal Test-only factory for isolated filesystem and platform assertions. */
11
+ export declare const createShellSnapshotCacheForTesting: typeof createShellSnapshotCache;
1
12
  /**
2
13
  * Create a shell snapshot, caching the result.
3
14
  * Returns the path to the snapshot file, or null if creation failed.
4
15
  */
5
16
  export declare function getOrCreateSnapshot(shell: string, env: Record<string, string | undefined>): Promise<string | null>;
17
+ export {};
@@ -16,6 +16,7 @@ import { spawn as nodeSpawn } from "node:child_process";
16
16
  export declare const INSANE_VENDOR_DIR: string;
17
17
  /** Stable note prefixes — tests assert on these without depending on full stderr. */
18
18
  export declare const INSANE_NOTES: {
19
+ readonly securityDisabled: `insane fallback disabled: remote renderer cannot preserve validated network routing`;
19
20
  readonly guardBlocked: (reason: string) => string;
20
21
  readonly vendorMissing: `insane fallback unavailable: vendor engine missing at packages/coding-agent/vendor/insane-search`;
21
22
  readonly noPython: `insane fallback unavailable: python3 not found; install python3 and curl_cffi, then retry with web.insaneFallback=true`;
@@ -10,6 +10,18 @@ export interface PublicUrlRejected {
10
10
  export type PublicUrlResult = PublicUrlAccepted | PublicUrlRejected;
11
11
  /** Resolver seam so tests can inject DNS results without real lookups. */
12
12
  export type AddressResolver = (hostname: string) => Promise<string[]>;
13
+ type ProxyEnvironment = Record<string, string | undefined>;
14
+ export type GuardedPublicFetchResult = {
15
+ ok: true;
16
+ response: Response;
17
+ logicalUrl: URL;
18
+ wireUrl: URL;
19
+ } | {
20
+ ok: false;
21
+ reason: string;
22
+ logicalUrl: string;
23
+ };
24
+ export declare function hasConfiguredProxy(env: ProxyEnvironment): boolean;
13
25
  /** True for any address that is not a routable public unicast address. */
14
26
  export declare function isPrivateOrSpecialAddress(address: string): boolean;
15
27
  /**
@@ -19,7 +31,12 @@ export declare function isPrivateOrSpecialAddress(address: string): boolean;
19
31
  */
20
32
  export declare function validatePublicHttpUrl(rawUrl: string, options?: {
21
33
  resolver?: AddressResolver;
34
+ signal?: AbortSignal;
22
35
  }): Promise<PublicUrlResult>;
36
+ export declare function guardedPublicFetch(rawUrl: string, init?: BunFetchRequestInit, options?: {
37
+ resolver?: AddressResolver;
38
+ }): Promise<GuardedPublicFetchResult>;
23
39
  export declare function validatePublicHttpUrlForInsane(rawUrl: string, options?: {
24
40
  resolver?: AddressResolver;
25
41
  }): Promise<PublicUrlResult>;
42
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.11.5",
4
+ "version": "0.11.7",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -53,13 +53,13 @@
53
53
  "@agentclientprotocol/sdk": "1.2.1",
54
54
  "@babel/parser": "^7.29.3",
55
55
  "@mozilla/readability": "^0.6.0",
56
- "@gajae-code/stats": "0.11.5",
57
- "@gajae-code/agent-core": "0.11.5",
58
- "@gajae-code/ai": "0.11.5",
59
- "@gajae-code/bridge-client": "0.11.5",
60
- "@gajae-code/natives": "0.11.5",
61
- "@gajae-code/tui": "0.11.5",
62
- "@gajae-code/utils": "0.11.5",
56
+ "@gajae-code/stats": "0.11.7",
57
+ "@gajae-code/agent-core": "0.11.7",
58
+ "@gajae-code/ai": "0.11.7",
59
+ "@gajae-code/bridge-client": "0.11.7",
60
+ "@gajae-code/natives": "0.11.7",
61
+ "@gajae-code/tui": "0.11.7",
62
+ "@gajae-code/utils": "0.11.7",
63
63
  "@puppeteer/browsers": "^2.13.0",
64
64
  "@types/turndown": "5.0.6",
65
65
  "@xterm/headless": "^6.0.0",
@@ -147,6 +147,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
147
147
  "agent_session:prepareContributionPrep": "internal accessor/plumbing, not a user-facing control seam",
148
148
  "agent_session:setResourceSampler": "internal accessor/plumbing, not a user-facing control seam",
149
149
  "agent_session:setRetainedMemorySampler": "internal accessor/plumbing, not a user-facing control seam",
150
+ "agent_session:createBtwConversationScope":
151
+ "internal privacy-scoped side-chat snapshot factory, not a user-facing SDK control seam",
150
152
  "agent_session:recordBashResult": "internal accessor/plumbing, not a user-facing control seam",
151
153
  "agent_session:executePython": "internal accessor/plumbing, not a user-facing control seam",
152
154
  "agent_session:assertEvalExecutionAllowed": "internal accessor/plumbing, not a user-facing control seam",
@@ -258,6 +260,7 @@ const SEAM_TO_SDK: Readonly<Record<string, string>> = {
258
260
  "slash_command:clear": "context.clear",
259
261
  "slash_command:new": "session.new",
260
262
  "slash_command:compact": "compaction.run",
263
+ "slash_command:handoff": "session.handoff",
261
264
  "slash_command:resume": "session.resume",
262
265
  "slash_command:retry": "retry.last",
263
266
  "slash_command:background": "bash.background",
@@ -41,6 +41,8 @@ const disabledProviders = new Set<string>();
41
41
 
42
42
  /** Settings manager for persistence (if set) */
43
43
  let settings: Settings | null = null;
44
+ /** Session-local settings keyed by normalized working directory. */
45
+ const settingsByCwd = new Map<string, Settings>();
44
46
 
45
47
  // =============================================================================
46
48
  // Registration API
@@ -208,8 +210,9 @@ async function loadImpl<T>(
208
210
  * Filter providers based on options and disabled state.
209
211
  */
210
212
  function filterProviders<T>(capability: Capability<T>, options: LoadOptions): Provider<T>[] {
211
- let providers = (capability.providers as Provider<T>[]).filter(p => !disabledProviders.has(p.id));
212
-
213
+ const activeSettings = options.settings ?? settingsByCwd.get(path.normalize(options.cwd ?? getProjectDir()));
214
+ const activeDisabledProviders = new Set(activeSettings?.get("disabledProviders") ?? disabledProviders);
215
+ let providers = (capability.providers as Provider<T>[]).filter(p => !activeDisabledProviders.has(p.id));
213
216
  if (options.providers) {
214
217
  const allowed = new Set(options.providers);
215
218
  providers = providers.filter(p => allowed.has(p.id));
@@ -249,63 +252,68 @@ export async function loadCapability<T>(capabilityId: string, options: LoadOptio
249
252
  * Call this once on startup to enable persistent provider state.
250
253
  */
251
254
  export function initializeWithSettings(activeSettings: Settings): void {
255
+ settingsByCwd.set(path.normalize(activeSettings.getCwd()), activeSettings);
252
256
  settings = activeSettings;
253
- // Load disabled providers from settings
254
- const disabled = settings.get("disabledProviders");
257
+ const disabled = activeSettings.get("disabledProviders");
255
258
  disabledProviders.clear();
256
- for (const id of disabled) {
257
- disabledProviders.add(id);
258
- }
259
+ for (const id of disabled) disabledProviders.add(id);
259
260
  }
260
261
 
261
262
  /**
262
263
  * Persist current disabled providers to settings.
263
264
  */
264
- function persistDisabledProviders(): void {
265
- if (settings) {
266
- settings.set("disabledProviders", Array.from(disabledProviders));
267
- }
265
+ function persistDisabledProviders(activeSettings: Settings, providers: ReadonlySet<string>): void {
266
+ activeSettings.set("disabledProviders", Array.from(providers));
268
267
  }
269
268
 
270
- /**
271
- * Disable a provider globally (across all capabilities).
272
- */
273
- export function disableProvider(providerId: string): void {
274
- disabledProviders.add(providerId);
275
- persistDisabledProviders();
269
+ /** Disable a provider for the supplied session settings. */
270
+ export function disableProvider(
271
+ providerId: string,
272
+ activeSettings: Settings = settings ??
273
+ (() => {
274
+ throw new Error("Capability settings unavailable");
275
+ })(),
276
+ ): void {
277
+ const providers = new Set(activeSettings.get("disabledProviders"));
278
+ providers.add(providerId);
279
+ persistDisabledProviders(activeSettings, providers);
276
280
  }
277
281
 
278
- /**
279
- * Enable a previously disabled provider.
280
- */
281
- export function enableProvider(providerId: string): void {
282
- disabledProviders.delete(providerId);
283
- persistDisabledProviders();
282
+ /** Enable a provider for the supplied session settings. */
283
+ export function enableProvider(
284
+ providerId: string,
285
+ activeSettings: Settings = settings ??
286
+ (() => {
287
+ throw new Error("Capability settings unavailable");
288
+ })(),
289
+ ): void {
290
+ const providers = new Set(activeSettings.get("disabledProviders"));
291
+ providers.delete(providerId);
292
+ persistDisabledProviders(activeSettings, providers);
284
293
  }
285
294
 
286
- /**
287
- * Check if a provider is enabled.
288
- */
289
- export function isProviderEnabled(providerId: string): boolean {
290
- return !disabledProviders.has(providerId);
295
+ /** Check whether a provider is enabled by the supplied session settings. */
296
+ export function isProviderEnabled(
297
+ providerId: string,
298
+ activeSettings: Settings | undefined = settings ?? undefined,
299
+ ): boolean {
300
+ return !new Set(activeSettings?.get("disabledProviders") ?? disabledProviders).has(providerId);
291
301
  }
292
302
 
293
- /**
294
- * Get list of all disabled provider IDs.
295
- */
296
- export function getDisabledProviders(): string[] {
297
- return Array.from(disabledProviders);
303
+ /** Get disabled providers from the supplied session settings. */
304
+ export function getDisabledProviders(activeSettings: Settings | undefined = settings ?? undefined): string[] {
305
+ return [...(activeSettings?.get("disabledProviders") ?? disabledProviders)];
298
306
  }
299
307
 
300
- /**
301
- * Set disabled providers from a list (replaces current set).
302
- */
303
- export function setDisabledProviders(providerIds: string[]): void {
304
- disabledProviders.clear();
305
- for (const id of providerIds) {
306
- disabledProviders.add(id);
307
- }
308
- persistDisabledProviders();
308
+ /** Replace disabled providers for the supplied session settings. */
309
+ export function setDisabledProviders(
310
+ providerIds: string[],
311
+ activeSettings: Settings = settings ??
312
+ (() => {
313
+ throw new Error("Capability settings unavailable");
314
+ })(),
315
+ ): void {
316
+ persistDisabledProviders(activeSettings, new Set(providerIds));
309
317
  }
310
318
 
311
319
  // =============================================================================
@@ -6,6 +6,7 @@
6
6
  * and get back a unified array of MCP servers.
7
7
  */
8
8
 
9
+ import type { Settings } from "../config/settings";
9
10
  /**
10
11
  * Context passed to every provider loader.
11
12
  */
@@ -72,6 +73,8 @@ export interface LoadOptions {
72
73
  includeDisabled?: boolean;
73
74
  /** Explicit disabled extension IDs to apply instead of settings. */
74
75
  disabledExtensions?: string[];
76
+ /** Session settings whose provider policy applies to this load. */
77
+ settings?: Settings;
75
78
  }
76
79
 
77
80
  /**
@@ -18,7 +18,11 @@ import {
18
18
  } from "../hooks/codex-native-hooks-config";
19
19
  import { theme } from "../modes/theme/theme";
20
20
  import { formatCredentialAutoImportResult, runExternalCredentialAutoImport } from "../setup/credential-auto-import";
21
- import { filterAutoImportOAuthCredentials, formatDiscoverySummary } from "../setup/credential-import";
21
+ import {
22
+ formatDiscoverySummary,
23
+ getAutoImportOAuthCredentialSkips,
24
+ isAutoImportOAuthCredential,
25
+ } from "../setup/credential-import";
22
26
  import {
23
27
  formatHermesSetupResult,
24
28
  type HermesSetupFlags,
@@ -596,8 +600,10 @@ export async function handleCredentialsSetup(
596
600
  trigger: "setup-cli",
597
601
  });
598
602
  const result = preview.discovery ?? { importable: [], skipped: [], environment: [] };
599
- const candidates = filterAutoImportOAuthCredentials(result.importable);
600
- const filteredResult = { ...result, importable: candidates };
603
+ const now = Date.now();
604
+ const candidates = result.importable.filter(credential => isAutoImportOAuthCredential(credential, now));
605
+ const autoImportSkips = getAutoImportOAuthCredentialSkips(result.importable, now);
606
+ const filteredResult = { ...result, importable: candidates, skipped: [...result.skipped, ...autoImportSkips] };
601
607
  const redactedPlan = {
602
608
  importable: candidates.map(c => ({
603
609
  provider: c.provider,
@@ -607,7 +613,7 @@ export async function handleCredentialsSetup(
607
613
  expiresAt: c.expiresAt,
608
614
  redactedToken: c.redactedToken,
609
615
  })),
610
- skipped: result.skipped,
616
+ skipped: filteredResult.skipped,
611
617
  environment: result.environment,
612
618
  keychainChecked: flags.keychain === true,
613
619
  };