@gajae-code/coding-agent 0.12.10 → 0.12.12
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/CHANGELOG.md +47 -2
- package/dist/types/cli/notify-cli.d.ts +42 -1
- package/dist/types/cli/update-cli.d.ts +9 -3
- package/dist/types/commands/notify.d.ts +6 -0
- package/dist/types/config/file-lock.d.ts +3 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
- package/dist/types/extensibility/extensions/types.d.ts +2 -0
- package/dist/types/main.d.ts +6 -2
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +23 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
- package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +13 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
- package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
- package/dist/types/sdk/bus/notification-service.d.ts +10 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +25 -7
- package/dist/types/sdk/bus/telegram-daemon.d.ts +104 -16
- package/dist/types/sdk/bus/telegram-reference.d.ts +10 -1
- package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
- package/dist/types/sdk/host/host.d.ts +52 -0
- package/dist/types/sdk/lifecycle-session.d.ts +6 -0
- package/dist/types/sdk/session-activation.d.ts +41 -0
- package/dist/types/sdk/session.d.ts +18 -0
- package/dist/types/sdk/startup-capability.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +7 -0
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +12 -2
- package/dist/types/session/session-manager.d.ts +40 -5
- package/dist/types/session/session-storage.d.ts +1 -0
- package/dist/types/tools/computer.d.ts +35 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/todo-write.d.ts +2 -0
- package/dist/types/utils/npm-registry.d.ts +71 -0
- package/examples/extensions/README.md +38 -4
- package/examples/extensions/ooo-bridge.ts +15 -0
- package/package.json +8 -8
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/src/async/job-manager.ts +9 -2
- package/src/cli/notify-cli.ts +226 -2
- package/src/cli/update-cli.ts +90 -23
- package/src/commands/notify.ts +27 -3
- package/src/commands/sdk.ts +1 -0
- package/src/config/file-lock-gc.ts +18 -0
- package/src/config/file-lock.ts +61 -16
- package/src/config/model-profiles.ts +31 -15
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/question-state.ts +2 -0
- package/src/coordinator-mcp/server.ts +358 -7
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
- package/src/extensibility/extensions/runner.ts +15 -2
- package/src/extensibility/extensions/types.ts +2 -0
- package/src/gjc-runtime/launch-tmux.ts +53 -1
- package/src/internal-urls/docs-index.generated.ts +13 -12
- package/src/main.ts +203 -67
- package/src/modes/DESIGN.md +8 -5
- package/src/modes/components/footer.ts +10 -18
- package/src/modes/components/session-selector.ts +26 -3
- package/src/modes/components/status-line/gh.ts +23 -2
- package/src/modes/controllers/event-controller.ts +3 -0
- package/src/modes/controllers/extension-ui-controller.ts +2 -0
- package/src/modes/controllers/input-controller.ts +11 -0
- package/src/modes/controllers/selector-controller.ts +8 -2
- package/src/modes/interactive-mode.ts +7 -1
- package/src/modes/utils/host-status.ts +38 -0
- package/src/prompts/tools/computer.md +6 -1
- package/src/runtime-mcp/types.ts +2 -0
- package/src/sdk/broker/lifecycle.ts +60 -3
- package/src/sdk/bus/chat-daemon-cli.ts +42 -0
- package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
- package/src/sdk/bus/chat-daemon-control.ts +18 -3
- package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
- package/src/sdk/bus/control-plane-frames.ts +51 -0
- package/src/sdk/bus/conversation-store.ts +29 -1
- package/src/sdk/bus/existing-thread-readiness.ts +155 -0
- package/src/sdk/bus/index.ts +70 -0
- package/src/sdk/bus/notification-service.ts +28 -1
- package/src/sdk/bus/rich-render.ts +3 -2
- package/src/sdk/bus/slack-daemon.ts +99 -4
- package/src/sdk/bus/slack-live-provider.ts +32 -2
- package/src/sdk/bus/slack-provider.ts +11 -0
- package/src/sdk/bus/slack-thread-binding.ts +641 -0
- package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +25 -7
- package/src/sdk/bus/telegram-daemon.ts +1961 -497
- package/src/sdk/bus/telegram-reference.ts +42 -6
- package/src/sdk/bus/topic-registry.ts +674 -181
- package/src/sdk/host/host.ts +180 -1
- package/src/sdk/lifecycle-session.ts +8 -2
- package/src/sdk/protocol/operation-inventory.generated.json +22 -0
- package/src/sdk/session-activation.ts +127 -0
- package/src/sdk/session.ts +139 -28
- package/src/sdk/startup-capability.ts +10 -1
- package/src/session/agent-session.ts +331 -30
- package/src/session/artifacts.ts +56 -13
- package/src/session/internal/managed-session-storage.ts +440 -243
- package/src/session/session-manager.ts +288 -44
- package/src/session/session-storage.ts +3 -0
- package/src/setup/provider-presets.json +1 -1
- package/src/task/index.ts +92 -44
- package/src/tools/computer.ts +322 -45
- package/src/tools/index.ts +8 -0
- package/src/tools/todo-write.ts +29 -11
- package/src/utils/npm-registry.ts +660 -0
|
@@ -333,6 +333,7 @@ export interface ResumeSessionIdentity {
|
|
|
333
333
|
size: number;
|
|
334
334
|
mtimeMs: number;
|
|
335
335
|
mtimeNs: bigint;
|
|
336
|
+
ctimeNs?: bigint;
|
|
336
337
|
sha256: string;
|
|
337
338
|
}
|
|
338
339
|
export interface ResumeTailResumable {
|
|
@@ -348,6 +349,13 @@ export interface ResumeTailError {
|
|
|
348
349
|
reason: "missing" | "malformed" | "unstable" | "read-failed" | "legacy_migration_disabled";
|
|
349
350
|
}
|
|
350
351
|
export type SessionDirectoryMigrationPolicy = ManagedMigrationPolicy;
|
|
352
|
+
export type SessionAppendPersistenceFailurePhase = "current_append" | "prior_failure";
|
|
353
|
+
export declare class SessionAppendPersistenceError extends Error {
|
|
354
|
+
readonly phase: SessionAppendPersistenceFailurePhase;
|
|
355
|
+
readonly entryId: string;
|
|
356
|
+
readonly persistenceError: Error;
|
|
357
|
+
constructor(phase: SessionAppendPersistenceFailurePhase, entryId: string, persistenceError: Error);
|
|
358
|
+
}
|
|
351
359
|
export declare class SessionManagedStorageError extends Error {
|
|
352
360
|
readonly code = "managed_storage_unsupported";
|
|
353
361
|
constructor();
|
|
@@ -607,6 +615,7 @@ interface SessionManagerStateSnapshot {
|
|
|
607
615
|
needsFullRewriteOnNextPersist: boolean;
|
|
608
616
|
fileEntries: FileEntry[];
|
|
609
617
|
materializedFileEntries: FileEntry[];
|
|
618
|
+
adoptedArtifactManager: ArtifactManager | null;
|
|
610
619
|
}
|
|
611
620
|
/** Benchmark-derived cap for strong materialized session snapshots. */
|
|
612
621
|
export declare const MATERIALIZED_CACHE_MAX_BYTES: number;
|
|
@@ -615,6 +624,7 @@ export declare const SessionManagerTestHooks: {
|
|
|
615
624
|
materializedCacheMaxBytesOverride?: number;
|
|
616
625
|
beforeResidentTransitionIndexBuild?: () => void;
|
|
617
626
|
afterForkSnapshot?: () => void | Promise<void>;
|
|
627
|
+
beforeEphemeralArtifactManagerInstall?: (dir: string) => void | Promise<void>;
|
|
618
628
|
};
|
|
619
629
|
export declare class SessionManager {
|
|
620
630
|
#private;
|
|
@@ -635,7 +645,9 @@ export declare class SessionManager {
|
|
|
635
645
|
captureState(): SessionManagerStateSnapshot;
|
|
636
646
|
restoreState(snapshot: SessionManagerStateSnapshot): void;
|
|
637
647
|
/** Switch to a different session file (used for resume and branching). */
|
|
638
|
-
setSessionFile(sessionFile: string
|
|
648
|
+
setSessionFile(sessionFile: string, options?: {
|
|
649
|
+
deferEphemeralArtifactRetirement?: boolean;
|
|
650
|
+
}): Promise<void>;
|
|
639
651
|
/** Start a new session. Closes any existing writer first. */
|
|
640
652
|
newSession(options?: NewSessionOptions): Promise<string | undefined>;
|
|
641
653
|
/**
|
|
@@ -743,13 +755,23 @@ export declare class SessionManager {
|
|
|
743
755
|
* the parent session's artifact directory and ID counter.
|
|
744
756
|
*/
|
|
745
757
|
adoptArtifactManager(manager: ArtifactManager): void;
|
|
758
|
+
/** Release only the matching externally adopted manager. */
|
|
759
|
+
releaseArtifactManager(manager: ArtifactManager): void;
|
|
760
|
+
/** Temporarily release adopted authority while an outer transition validates its successor. */
|
|
761
|
+
stageAdoptedArtifactManagerForTransition(): void;
|
|
762
|
+
/** Prove manager authority by exact object identity, never by pathname shape. */
|
|
763
|
+
isArtifactManagerAuthorized(manager: ArtifactManager): boolean;
|
|
746
764
|
/**
|
|
747
765
|
* Returns the ArtifactManager this session writes through. Lazily creates
|
|
748
766
|
* one bound to the current session file unless an external manager was
|
|
749
|
-
* adopted via `adoptArtifactManager`.
|
|
750
|
-
*
|
|
767
|
+
* adopted via `adoptArtifactManager`. Falls back to the lazily created
|
|
768
|
+
* ephemeral filesystem store once a non-persistent session has saved an
|
|
769
|
+
* artifact, so `artifact://` stays resolvable. Returns null only when no
|
|
770
|
+
* store has been established yet.
|
|
751
771
|
*/
|
|
752
772
|
getArtifactManager(): ArtifactManager | null;
|
|
773
|
+
/** Linearizably establish this session's persistent or ephemeral artifact manager. */
|
|
774
|
+
ensureArtifactManager(): Promise<ArtifactManager | null>;
|
|
753
775
|
/**
|
|
754
776
|
* Allocate a new artifact path and ID for the current session.
|
|
755
777
|
* Returns an empty object when the session is not persisted.
|
|
@@ -760,14 +782,18 @@ export declare class SessionManager {
|
|
|
760
782
|
}>;
|
|
761
783
|
/**
|
|
762
784
|
* Save artifact content under the current session and return artifact ID.
|
|
763
|
-
*
|
|
785
|
+
* Persistent sessions write into the session artifact directory; non-persistent
|
|
786
|
+
* sessions write into a lazily created temporary directory so the content is
|
|
787
|
+
* read back from the filesystem instead of being retained in memory.
|
|
764
788
|
*/
|
|
765
789
|
saveArtifact(content: string, toolType: string): Promise<string | undefined>;
|
|
766
790
|
/**
|
|
767
791
|
* Resolve an artifact ID to an on-disk path for the current session.
|
|
768
|
-
* Returns null when
|
|
792
|
+
* Returns null when the artifact is missing.
|
|
769
793
|
*/
|
|
770
794
|
getArtifactPath(id: string): Promise<string | null>;
|
|
795
|
+
/** Retire predecessor ephemeral artifacts after an outer logical transition commits. */
|
|
796
|
+
retireEphemeralArtifactsAfterTransition(): void;
|
|
771
797
|
/**
|
|
772
798
|
* Persist (or clear) the current editor draft so the next resume of this
|
|
773
799
|
* session can restore it. Empty text deletes any stale draft. No-op when the
|
|
@@ -838,6 +864,15 @@ export declare class SessionManager {
|
|
|
838
864
|
applyEntryMessageUpdates(entries: readonly SessionMessageEntry[]): void;
|
|
839
865
|
/** Write mutated custom-message entries back into the canonical entry store by id. */
|
|
840
866
|
applyCustomMessageEntryUpdates(entries: readonly CustomMessageEntry[]): void;
|
|
867
|
+
/**
|
|
868
|
+
* Rehydrate the canonical transcript after a synchronous persistence failure.
|
|
869
|
+
*
|
|
870
|
+
* The failed append may have committed before reporting an uncertain outcome,
|
|
871
|
+
* so callers must not clear the sticky error or retry against the resident
|
|
872
|
+
* branch. Reloading the exact session file is the only supported recovery
|
|
873
|
+
* boundary for both managed and explicit persistent destinations.
|
|
874
|
+
*/
|
|
875
|
+
recoverPersistenceFailure(): Promise<void>;
|
|
841
876
|
/**
|
|
842
877
|
* Rewrite the session file after in-place entry updates.
|
|
843
878
|
* Use sparingly (e.g., pruning old tool outputs).
|
|
@@ -239,7 +239,7 @@ export interface ComputerScreenshotDetails {
|
|
|
239
239
|
originX?: number;
|
|
240
240
|
originY?: number;
|
|
241
241
|
displayEpoch?: number;
|
|
242
|
-
captureId?:
|
|
242
|
+
captureId?: number;
|
|
243
243
|
pngBytes?: number;
|
|
244
244
|
path?: string;
|
|
245
245
|
}
|
|
@@ -258,11 +258,44 @@ export interface ComputerToolDetails {
|
|
|
258
258
|
keys?: string[];
|
|
259
259
|
ms?: number;
|
|
260
260
|
screenshot?: ComputerScreenshotDetails;
|
|
261
|
+
primaryError?: {
|
|
262
|
+
code: string;
|
|
263
|
+
message: string;
|
|
264
|
+
};
|
|
261
265
|
supervisor?: string;
|
|
262
266
|
steps?: ComputerToolDetails[];
|
|
263
267
|
meta?: OutputMeta;
|
|
264
268
|
}
|
|
269
|
+
type NativeBatchAction = {
|
|
270
|
+
action: "screenshot" | "click" | "double_click" | "move" | "drag" | "scroll" | "type" | "keypress" | "wait";
|
|
271
|
+
x?: number;
|
|
272
|
+
y?: number;
|
|
273
|
+
toX?: number;
|
|
274
|
+
toY?: number;
|
|
275
|
+
scrollX?: number;
|
|
276
|
+
scrollY?: number;
|
|
277
|
+
button?: string;
|
|
278
|
+
text?: string;
|
|
279
|
+
keys?: string[];
|
|
280
|
+
ms?: number;
|
|
281
|
+
timeoutMs?: number;
|
|
282
|
+
timeoutGroup?: number;
|
|
283
|
+
};
|
|
284
|
+
type NativeBatchStepResult = {
|
|
285
|
+
index: number;
|
|
286
|
+
action: string;
|
|
287
|
+
screenshot?: NativeScreenshot;
|
|
288
|
+
};
|
|
289
|
+
type NativeBatchResult = {
|
|
290
|
+
results: NativeBatchStepResult[];
|
|
291
|
+
failureCode?: string;
|
|
292
|
+
failureIndex?: number;
|
|
293
|
+
failureMessage?: string;
|
|
294
|
+
primaryFailureCode?: string;
|
|
295
|
+
primaryFailureMessage?: string;
|
|
296
|
+
};
|
|
265
297
|
type NativeController = {
|
|
298
|
+
executeBatch?: (expectedEpoch: number | undefined, actions: NativeBatchAction[], timeoutMs?: number, signal?: AbortSignal) => Promise<NativeBatchResult> | NativeBatchResult;
|
|
266
299
|
screenshot?: () => Promise<NativeScreenshot> | NativeScreenshot;
|
|
267
300
|
click?: (expectedEpoch: number | undefined, x: number, y: number, button?: string) => void;
|
|
268
301
|
doubleClick?: (expectedEpoch: number | undefined, x: number, y: number, button?: string) => void;
|
|
@@ -282,7 +315,7 @@ type NativeScreenshot = {
|
|
|
282
315
|
originX?: number;
|
|
283
316
|
originY?: number;
|
|
284
317
|
displayEpoch?: number;
|
|
285
|
-
captureId?:
|
|
318
|
+
captureId?: number;
|
|
286
319
|
};
|
|
287
320
|
export type ComputerControllerFactory = () => NativeController;
|
|
288
321
|
export declare const COMPUTER_DISABLED_CODE = "COMPUTER_DISABLED";
|
|
@@ -219,6 +219,14 @@ export interface ToolSession {
|
|
|
219
219
|
getAuthorizedArtifactsDirs?: () => readonly string[];
|
|
220
220
|
/** Get the ArtifactManager backing this session (shared across parent + subagents). */
|
|
221
221
|
getArtifactManager?: () => ArtifactManager | null;
|
|
222
|
+
/** Prove that an ArtifactManager belongs to this concrete session or its explicitly adopted parent tree. */
|
|
223
|
+
isArtifactManagerAuthorized?: (manager: ArtifactManager) => boolean;
|
|
224
|
+
/** Adopt a task-created fallback manager into the concrete session owner. */
|
|
225
|
+
adoptArtifactManager?: (manager: ArtifactManager) => void;
|
|
226
|
+
/** Linearizably establish the concrete session owner's canonical artifact manager. */
|
|
227
|
+
ensureArtifactManager?: () => Promise<ArtifactManager | null>;
|
|
228
|
+
/** Release a task-created fallback manager when its logical session ends. */
|
|
229
|
+
releaseArtifactManager?: (manager: ArtifactManager) => void;
|
|
222
230
|
/** Register teardown work owned by the current logical session. */
|
|
223
231
|
registerSessionCleanup?: (cleanup: () => Promise<void> | void) => () => void;
|
|
224
232
|
/** Allocate a new artifact path and ID for session-scoped truncated output. */
|
|
@@ -25,6 +25,7 @@ export interface TodoPhase {
|
|
|
25
25
|
export interface TodoWriteToolDetails {
|
|
26
26
|
phases: TodoPhase[];
|
|
27
27
|
storage: "session" | "memory";
|
|
28
|
+
failureKind?: "payload_rejected" | "persistence";
|
|
28
29
|
}
|
|
29
30
|
declare function validateRawTodoArguments(arguments_: Record<string, unknown>): RawArgumentValidationResult;
|
|
30
31
|
declare const todoWriteSchema: z.ZodObject<{
|
|
@@ -117,6 +118,7 @@ export declare const todoWriteToolRenderer: {
|
|
|
117
118
|
text?: string;
|
|
118
119
|
}>;
|
|
119
120
|
details?: TodoWriteToolDetails;
|
|
121
|
+
isError?: boolean;
|
|
120
122
|
}, options: RenderResultOptions, uiTheme: Theme, _args?: TodoWriteRenderArgs): Component;
|
|
121
123
|
mergeCallAndResult: boolean;
|
|
122
124
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export declare const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
2
|
+
export type NpmConfigOrigin = "env" | "user" | "global";
|
|
3
|
+
/** Which package manager will run the install this check is gating. */
|
|
4
|
+
export type Installer = "bun" | "npm";
|
|
5
|
+
/** Injection points so tests never read the real environment. */
|
|
6
|
+
export interface NpmRegistryEnvironment {
|
|
7
|
+
/** Manager that will perform the install; decides Bun-vs-npm config priority. */
|
|
8
|
+
installer?: Installer;
|
|
9
|
+
/** Resolves an executable on PATH; used to locate npm's effective prefix. */
|
|
10
|
+
whichExecutable?: (name: string) => string | undefined;
|
|
11
|
+
/** Defaults to `$credentialEnv`, which excludes the caller's `cwd/.env`. */
|
|
12
|
+
lookupEnv?: (name: string) => string | undefined;
|
|
13
|
+
homeDir?: string;
|
|
14
|
+
platform?: NodeJS.Platform;
|
|
15
|
+
readFile?: (filePath: string) => Promise<string | undefined>;
|
|
16
|
+
}
|
|
17
|
+
export interface ResolvedNpmRegistry {
|
|
18
|
+
registry: string;
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
origin: NpmConfigOrigin | "default";
|
|
21
|
+
/** Where the value came from, e.g. `$npm_config_registry` or `~/.npmrc`. */
|
|
22
|
+
source: string;
|
|
23
|
+
/** Config files that exist but could not be read. */
|
|
24
|
+
warnings: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface LatestPackageVersion {
|
|
27
|
+
version: string;
|
|
28
|
+
registry: string;
|
|
29
|
+
/** Config problems that did not stop the lookup but changed its outcome. */
|
|
30
|
+
warnings: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface FetchResponseLike {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
status: number;
|
|
35
|
+
statusText: string;
|
|
36
|
+
json: () => Promise<unknown>;
|
|
37
|
+
}
|
|
38
|
+
export type FetchLike = (input: string, init?: {
|
|
39
|
+
headers?: Record<string, string>;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}) => Promise<FetchResponseLike>;
|
|
42
|
+
export interface NpmRegistryLookupOptions extends NpmRegistryEnvironment {
|
|
43
|
+
fetchImpl?: FetchLike;
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
}
|
|
46
|
+
/** Thrown when a registry is configured but unusable, so it is never silently ignored. */
|
|
47
|
+
export declare class NpmRegistryConfigError extends Error {
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse an `.npmrc` into raw key/value pairs. Later duplicates win, as in npm.
|
|
51
|
+
*
|
|
52
|
+
* @internal Exported for tests; production code goes through `resolveNpmRegistry`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseNpmrc(contents: string, lookupEnv?: (name: string) => string | undefined): Map<string, string>;
|
|
55
|
+
/**
|
|
56
|
+
* Build the credential lookup keys npm calls "nerf darts": `//host/path/`,
|
|
57
|
+
* walking up one path segment at a time until the bare host.
|
|
58
|
+
*
|
|
59
|
+
* @internal Exported for tests; production code goes through `resolveNpmRegistry`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function credentialPrefixes(registry: string): string[];
|
|
62
|
+
/** Resolve the registry npm/bun would use for `packageName`, with credentials attached. */
|
|
63
|
+
export declare function resolveNpmRegistry(packageName: string, environment?: NpmRegistryEnvironment): Promise<ResolvedNpmRegistry>;
|
|
64
|
+
/**
|
|
65
|
+
* Registries can live under a path prefix, so join by string rather than `new URL`.
|
|
66
|
+
*
|
|
67
|
+
* @internal Exported for tests; production code goes through `fetchLatestPackageVersion`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildRegistryPackageUrl(registry: string, packageName: string, spec?: string): string;
|
|
70
|
+
/** Fetch the latest published version of `packageName` from the configured registry. */
|
|
71
|
+
export declare function fetchLatestPackageVersion(packageName: string, options?: NpmRegistryLookupOptions): Promise<LatestPackageVersion>;
|
|
@@ -14,6 +14,39 @@ mkdir -p .gjc/extensions
|
|
|
14
14
|
cp packages/coding-agent/examples/extensions/pirate.ts .gjc/extensions/
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
### Enable the Ouroboros `ooo` bridge
|
|
18
|
+
|
|
19
|
+
Install the version-pinned Ouroboros `v0.50.7` MCP profile, then configure its GJC runtime:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv tool install 'ouroboros-ai[mcp]==0.50.7'
|
|
23
|
+
ouroboros setup --runtime gjc
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`pipx install 'ouroboros-ai[mcp]==0.50.7'` is the equivalent pipx installation. Do not pipe a mutable branch installer into a shell. Pin source audits to commit `cb658aa819bfabafecbbe91bc36327f10691171b`. The [v0.50.7 release](https://github.com/Q00/ouroboros/releases/tag/v0.50.7) publishes `ouroboros_ai-0.50.7-py3-none-any.whl` with SHA-256 `df42f4ef10e032f2edc3249534bf91e8612dee789dfc3517895a9eb2df7f82c4`; verify downloaded release assets before installing them.
|
|
27
|
+
|
|
28
|
+
Ouroboros setup installs its own managed bridge. Replace that file with this standalone GJC bridge, which preserves the interview session across serialized follow-up answers, disposes it on GJC session switches, and drops queued predecessor-session starts. Download the example from immutable GJC commit `4311fefd49e9c6781c4d1111b8dd3f758e7d8974` and verify it before installation:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
curl -fL https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/4311fefd49e9c6781c4d1111b8dd3f758e7d8974/packages/coding-agent/examples/extensions/ooo-bridge.ts -o /tmp/gjc-ooo-bridge.ts
|
|
32
|
+
shasum -a 256 /tmp/gjc-ooo-bridge.ts
|
|
33
|
+
mkdir -p "${HOME}/${GJC_CONFIG_DIR:-.gjc}/agent/extensions/ouroboros-ooo-bridge" && cp /tmp/gjc-ooo-bridge.ts "${HOME}/${GJC_CONFIG_DIR:-.gjc}/agent/extensions/ouroboros-ooo-bridge/index.ts"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The `shasum` output must match `2b0e1e25ac145331f112da629076875542db6f6e63c3c17adcd6770a4dcaf7bd` before the copy. The file has no runtime package imports and uses the host API injected by GJC, so compiled binaries do not require a peer `node_modules` directory beside the installation.
|
|
37
|
+
|
|
38
|
+
For a project-only installation, copy the same verified file to `.gjc/extensions/ouroboros-ooo-bridge/index.ts`. Start a new GJC session after installation, then enter:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
ooo interview "I want to build a task management CLI"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The first question is rendered in GJC. While that interview remains active, ordinary interactive input is sent as the answer with the same Ouroboros session ID; completion clears the correlation and returns subsequent ordinary prompts to GJC. Other `ooo ...` commands continue through `ouroboros dispatch --runtime gjc`, including exit-code `78` pass-through.
|
|
45
|
+
|
|
46
|
+
Set `OUROBOROS_CLI=/absolute/path/to/ouroboros` when the executable is outside `PATH`. Missing executable, MCP startup, and dispatch failures produce an error notification for the claimed input without preventing GJC startup or ordinary prompts.
|
|
47
|
+
|
|
48
|
+
This external path is separate from GJC's native `/skill:deep-interview`: the native skill runs GJC's bundled interview workflow, while `ooo interview` delegates to the installed Ouroboros MCP interview tool.
|
|
49
|
+
|
|
17
50
|
## Examples
|
|
18
51
|
|
|
19
52
|
### Custom Tools & API
|
|
@@ -39,10 +72,11 @@ cp packages/coding-agent/examples/extensions/pirate.ts .gjc/extensions/
|
|
|
39
72
|
|
|
40
73
|
### External Dependencies
|
|
41
74
|
|
|
42
|
-
| Extension | Description
|
|
43
|
-
| ----------------- |
|
|
44
|
-
| `chalk-logger.ts` | Uses chalk from parent node_modules (demonstrates jiti module resolution)
|
|
45
|
-
| `
|
|
75
|
+
| Extension | Description |
|
|
76
|
+
| ----------------- | ---------------------------------------------------------------------------- |
|
|
77
|
+
| `chalk-logger.ts` | Uses chalk from parent node_modules (demonstrates jiti module resolution) |
|
|
78
|
+
| `ooo-bridge.ts` | Opt-in `ooo ...` input bridge to the installed Ouroboros CLI and MCP runtime |
|
|
79
|
+
| `with-deps/` | Extension with its own package.json and dependencies |
|
|
46
80
|
|
|
47
81
|
## Writing Extensions
|
|
48
82
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface OooBridgeExtensionAPI {
|
|
2
|
+
pi: unknown;
|
|
3
|
+
on(event: "input" | "session_switch", handler: (event: unknown, context: unknown) => unknown): void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface OooBridgeHost {
|
|
7
|
+
createOuroborosOooBridge(): ((event: unknown, context: unknown) => unknown) & { reset(): Promise<void> };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function (pi: OooBridgeExtensionAPI) {
|
|
11
|
+
const host = pi.pi as OooBridgeHost;
|
|
12
|
+
const bridge = host.createOuroborosOooBridge();
|
|
13
|
+
pi.on("input", bridge);
|
|
14
|
+
pi.on("session_switch", () => bridge.reset());
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.12",
|
|
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.3.0",
|
|
54
54
|
"@babel/parser": "^7.29.3",
|
|
55
55
|
"@mozilla/readability": "^0.6.0",
|
|
56
|
-
"@gajae-code/stats": "0.12.
|
|
57
|
-
"@gajae-code/agent-core": "0.12.
|
|
58
|
-
"@gajae-code/ai": "0.12.
|
|
59
|
-
"@gajae-code/bridge-client": "0.12.
|
|
60
|
-
"@gajae-code/natives": "0.12.
|
|
61
|
-
"@gajae-code/tui": "0.12.
|
|
62
|
-
"@gajae-code/utils": "0.12.
|
|
56
|
+
"@gajae-code/stats": "0.12.12",
|
|
57
|
+
"@gajae-code/agent-core": "0.12.12",
|
|
58
|
+
"@gajae-code/ai": "0.12.12",
|
|
59
|
+
"@gajae-code/bridge-client": "0.12.12",
|
|
60
|
+
"@gajae-code/natives": "0.12.12",
|
|
61
|
+
"@gajae-code/tui": "0.12.12",
|
|
62
|
+
"@gajae-code/utils": "0.12.12",
|
|
63
63
|
"@puppeteer/browsers": "^2.13.0",
|
|
64
64
|
"@types/turndown": "5.0.6",
|
|
65
65
|
"@xterm/headless": "^6.0.0",
|
|
@@ -37,6 +37,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
37
37
|
"agent_session:constructor": "internal accessor/plumbing, not a user-facing control seam",
|
|
38
38
|
"agent_session:registerToolSessionCleanup":
|
|
39
39
|
"internal tool lifecycle cleanup registration, not a user-facing SDK control seam",
|
|
40
|
+
"agent_session:registerToolSessionTransitionCleanup":
|
|
41
|
+
"internal tool transition cleanup registration for shared artifact-manager ownership, not a user-facing SDK control seam",
|
|
40
42
|
"agent_session:nextToolChoice": "internal accessor/plumbing, not a user-facing control seam",
|
|
41
43
|
"agent_session:setForcedToolChoice": "internal accessor/plumbing, not a user-facing control seam",
|
|
42
44
|
"agent_session:getActiveSkillState": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -66,6 +68,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
66
68
|
"agent_session:closeWriterStrict": "internal ACP lifecycle teardown plumbing, not a user-facing control seam",
|
|
67
69
|
"agent_session:disposeChildSubprocesses": "internal accessor/plumbing, not a user-facing control seam",
|
|
68
70
|
"agent_session:waitForIdle": "internal accessor/plumbing, not a user-facing control seam",
|
|
71
|
+
"agent_session:extendStartupTurnBarrier":
|
|
72
|
+
"internal CLI startup-readiness fence composition, not a user-facing SDK control seam",
|
|
69
73
|
"agent_session:awaitPendingContextTransformations":
|
|
70
74
|
"internal context-transformation lifecycle barrier, not a user-facing SDK control seam",
|
|
71
75
|
"agent_session:drainAsyncJobDeliveriesForAcp": "internal accessor/plumbing, not a user-facing control seam",
|
package/src/async/job-manager.ts
CHANGED
|
@@ -463,6 +463,7 @@ export class AsyncJobManager {
|
|
|
463
463
|
readonly #terminalWaits = new Map<string, TerminalWaitState>();
|
|
464
464
|
#waitSeq = 0;
|
|
465
465
|
readonly #publishedTerminalGenerations = new Set<string>();
|
|
466
|
+
readonly #settledJobIds = new Set<string>();
|
|
466
467
|
#jobGenerationSeq = 0;
|
|
467
468
|
readonly #liveHandles = new Map<string, SubagentLiveHandle>();
|
|
468
469
|
readonly #subagentProgress = new Map<string, AgentProgress>();
|
|
@@ -820,6 +821,7 @@ export class AsyncJobManager {
|
|
|
820
821
|
|
|
821
822
|
this.#expireMonitorTombstones();
|
|
822
823
|
const id = this.#resolveJobId(options?.id);
|
|
824
|
+
this.#settledJobIds.delete(id);
|
|
823
825
|
const abortController = new AbortController();
|
|
824
826
|
const startTime = Date.now();
|
|
825
827
|
|
|
@@ -919,7 +921,9 @@ export class AsyncJobManager {
|
|
|
919
921
|
this.#scheduleEviction(id);
|
|
920
922
|
this.#drainResumeQueue();
|
|
921
923
|
}
|
|
922
|
-
})()
|
|
924
|
+
})().finally(() => {
|
|
925
|
+
this.#settledJobIds.add(id);
|
|
926
|
+
});
|
|
923
927
|
|
|
924
928
|
this.#jobs.set(id, job);
|
|
925
929
|
this.#notifyChange();
|
|
@@ -1218,6 +1222,8 @@ export class AsyncJobManager {
|
|
|
1218
1222
|
) {
|
|
1219
1223
|
continue;
|
|
1220
1224
|
}
|
|
1225
|
+
if (job.status === "cancelled" && this.#settledJobIds.has(job.id) && !this.#subagentRecords.has(subagentId))
|
|
1226
|
+
continue;
|
|
1221
1227
|
if (!targets.has(subagentId)) {
|
|
1222
1228
|
targets.set(subagentId, { subagentId, jobId: job.id, source: "metadata_job" });
|
|
1223
1229
|
}
|
|
@@ -1298,7 +1304,7 @@ export class AsyncJobManager {
|
|
|
1298
1304
|
lease.targets.map(target => target.subagentId),
|
|
1299
1305
|
);
|
|
1300
1306
|
}
|
|
1301
|
-
if (state.phase === "proved" && state.proof) return state.proof;
|
|
1307
|
+
if (state.phase === "proved" && state.proof?.confirmed) return state.proof;
|
|
1302
1308
|
state.phase = "proving";
|
|
1303
1309
|
const settled = new Set<string>();
|
|
1304
1310
|
const promises: Promise<void>[] = [];
|
|
@@ -2064,6 +2070,7 @@ export class AsyncJobManager {
|
|
|
2064
2070
|
this.#purgeTerminalSubagentStateForJob(jobId);
|
|
2065
2071
|
const job = this.#jobs.get(jobId);
|
|
2066
2072
|
this.#jobs.delete(jobId);
|
|
2073
|
+
this.#settledJobIds.delete(jobId);
|
|
2067
2074
|
this.#lifecycles.delete(jobId);
|
|
2068
2075
|
this.#lifecyclePhases.delete(jobId);
|
|
2069
2076
|
this.#deadLetteredDeliveries.delete(jobId);
|