@gajae-code/coding-agent 0.4.1 → 0.4.3

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 (94) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/types/async/job-manager.d.ts +25 -0
  3. package/dist/types/commands/ultragoal.d.ts +1 -0
  4. package/dist/types/commit/model-selection.d.ts +1 -1
  5. package/dist/types/config/model-registry.d.ts +3 -1
  6. package/dist/types/config/model-resolver.d.ts +1 -19
  7. package/dist/types/config/models-config-schema.d.ts +12 -0
  8. package/dist/types/config/settings-schema.d.ts +26 -4
  9. package/dist/types/gjc-runtime/goal-mode-request.d.ts +8 -1
  10. package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
  11. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
  12. package/dist/types/harness-control-plane/finalize.d.ts +8 -0
  13. package/dist/types/harness-control-plane/receipts.d.ts +16 -1
  14. package/dist/types/harness-control-plane/types.d.ts +16 -3
  15. package/dist/types/modes/acp/acp-event-mapper.d.ts +2 -0
  16. package/dist/types/modes/components/custom-editor.d.ts +7 -0
  17. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +18 -0
  18. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +84 -0
  19. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +14 -7
  20. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +37 -0
  21. package/dist/types/modes/shared/agent-wire/protocol.d.ts +13 -34
  22. package/dist/types/reminders/star-reminder.d.ts +115 -0
  23. package/dist/types/session/agent-session.d.ts +30 -1
  24. package/dist/types/session/session-manager.d.ts +1 -1
  25. package/dist/types/tools/bash.d.ts +2 -0
  26. package/dist/types/tools/browser/actions.d.ts +54 -0
  27. package/dist/types/tools/browser.d.ts +80 -0
  28. package/dist/types/tools/image-gen.d.ts +1 -0
  29. package/dist/types/tools/index.d.ts +3 -1
  30. package/dist/types/tools/job.d.ts +1 -1
  31. package/examples/extensions/README.md +20 -41
  32. package/package.json +7 -7
  33. package/src/async/job-manager.ts +120 -1
  34. package/src/cli/grep-cli.ts +1 -1
  35. package/src/commands/harness.ts +42 -3
  36. package/src/commands/ultragoal.ts +8 -1
  37. package/src/commit/agentic/index.ts +2 -2
  38. package/src/commit/model-selection.ts +7 -22
  39. package/src/commit/pipeline.ts +2 -2
  40. package/src/config/model-registry.ts +17 -9
  41. package/src/config/model-resolver.ts +14 -84
  42. package/src/config/models-config-schema.ts +2 -0
  43. package/src/config/settings-schema.ts +27 -4
  44. package/src/defaults/gjc/skills/team/SKILL.md +10 -1
  45. package/src/defaults/gjc/skills/ultragoal/SKILL.md +3 -2
  46. package/src/gjc-runtime/goal-mode-request.ts +21 -1
  47. package/src/gjc-runtime/launch-tmux.ts +25 -2
  48. package/src/gjc-runtime/team-runtime.ts +78 -3
  49. package/src/gjc-runtime/ultragoal-guard.ts +18 -2
  50. package/src/gjc-runtime/ultragoal-runtime.ts +240 -30
  51. package/src/harness-control-plane/finalize.ts +84 -0
  52. package/src/harness-control-plane/owner.ts +16 -3
  53. package/src/harness-control-plane/receipts.ts +39 -1
  54. package/src/harness-control-plane/rpc-adapter.ts +7 -1
  55. package/src/harness-control-plane/types.ts +33 -12
  56. package/src/internal-urls/docs-index.generated.ts +3 -3
  57. package/src/memories/index.ts +1 -1
  58. package/src/modes/acp/acp-agent.ts +17 -9
  59. package/src/modes/acp/acp-event-mapper.ts +33 -1
  60. package/src/modes/components/custom-editor.ts +19 -3
  61. package/src/modes/controllers/input-controller.ts +27 -7
  62. package/src/modes/controllers/selector-controller.ts +7 -1
  63. package/src/modes/interactive-mode.ts +29 -1
  64. package/src/modes/rpc/rpc-client.ts +16 -3
  65. package/src/modes/rpc/rpc-mode.ts +5 -2
  66. package/src/modes/shared/agent-wire/command-contract.ts +18 -0
  67. package/src/modes/shared/agent-wire/event-contract.ts +147 -0
  68. package/src/modes/shared/agent-wire/event-envelope.ts +35 -16
  69. package/src/modes/shared/agent-wire/event-observation.ts +397 -0
  70. package/src/modes/shared/agent-wire/protocol.ts +24 -81
  71. package/src/modes/utils/context-usage.ts +2 -2
  72. package/src/prompts/agents/explore.md +1 -1
  73. package/src/prompts/agents/plan.md +1 -1
  74. package/src/prompts/agents/reviewer.md +1 -1
  75. package/src/prompts/tools/browser.md +3 -2
  76. package/src/reminders/star-reminder.ts +422 -0
  77. package/src/runtime-mcp/manager.ts +15 -2
  78. package/src/sdk.ts +3 -1
  79. package/src/session/agent-session.ts +139 -17
  80. package/src/session/session-manager.ts +1 -1
  81. package/src/task/agents.ts +1 -1
  82. package/src/tools/bash.ts +6 -1
  83. package/src/tools/browser/actions.ts +189 -0
  84. package/src/tools/browser.ts +91 -1
  85. package/src/tools/image-gen.ts +42 -15
  86. package/src/tools/index.ts +7 -1
  87. package/src/tools/inspect-image.ts +10 -8
  88. package/src/tools/job.ts +12 -2
  89. package/src/tools/monitor.ts +98 -17
  90. package/src/utils/commit-message-generator.ts +6 -13
  91. package/src/utils/title-generator.ts +1 -1
  92. package/dist/types/harness-control-plane/frame-mapper.d.ts +0 -29
  93. package/src/harness-control-plane/frame-mapper.ts +0 -286
  94. package/src/priority.json +0 -37
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Canonical AgentSession event observation: the single semantic mapping from
3
+ * `AgentSessionEvent` (and non-event wire frames) to bounded owner observations.
4
+ *
5
+ * This is the one place that derives `AgentWireOwnerObservation`s. Harness (and
6
+ * any other owner control plane) consumes these instead of re-parsing the wire
7
+ * protocol with private knowledge.
8
+ *
9
+ * Hard rule: evidence is BOUNDED — only ids, names, categories, statuses,
10
+ * cursors, timestamps, and short codes/messages. Never assistant text, message
11
+ * deltas, command output, raw args, or raw tool results.
12
+ */
13
+ import type { AgentSessionEvent } from "../../../session/agent-session";
14
+ import type { AgentWireEventPayload, AgentWireOwnerObservation } from "./event-contract";
15
+ import { toAgentWireEventPayload } from "./event-envelope";
16
+ /** True when a tool name or command indicates a test-runner invocation. */
17
+ export declare function isTestRunnerTool(toolName?: unknown, command?: unknown): boolean;
18
+ /** Only accept a known closed-vocabulary tool status; reject arbitrary strings. */
19
+ export declare function boundedStatus(v: unknown): string | undefined;
20
+ /** Accept only identifier-shaped tokens (e.g. RPC command names); reject free text. */
21
+ export declare function boundedToken(v: unknown): string | undefined;
22
+ /**
23
+ * Map a single `AgentSessionEvent` to its bounded owner observation, or null
24
+ * when the event carries no owner-facing signal.
25
+ */
26
+ export declare function observeAgentSessionEvent(event: AgentSessionEvent): AgentWireOwnerObservation | null;
27
+ /** Build the rich event payload (renderer-facing) for an `AgentSessionEvent`. */
28
+ export { toAgentWireEventPayload };
29
+ /** Observe the bounded owner signal carried by a rich event payload. */
30
+ export declare function observeAgentWireEventPayload(payload: AgentWireEventPayload): AgentWireOwnerObservation | null;
31
+ /**
32
+ * Map a single outbound RPC wire frame (docs/rpc.md) to a bounded owner
33
+ * observation, or null when the frame carries no owner-facing signal. Event
34
+ * frames delegate to {@link observeAgentWireEventPayload}; non-event frames are
35
+ * mapped here so owners never re-parse protocol semantics privately.
36
+ */
37
+ export declare function observeRpcOutboundFrame(frame: Record<string, unknown>): AgentWireOwnerObservation | null;
@@ -1,46 +1,25 @@
1
1
  /**
2
2
  * Shared agent-wire protocol primitives for GJC bridge surfaces.
3
3
  *
4
- * This module is the transport-agnostic, versioned frame contract that the
5
- * RPC mode and the (in-progress) `--mode bridge` wiring site both build on.
6
- * It carries the SEMANTIC agent surface events, responses, and UI/permission
7
- * requests — never pixels. See `.gjc/specs/deep-interview-gjc-backend-bridge.md`
8
- * and `.gjc/plans/ralplan/gjc-backend-bridge/pending-approval.md`.
4
+ * The canonical event/frame contract now lives in `event-contract.ts`. This
5
+ * module re-exports it under the historical `Bridge*` names so existing RPC and
6
+ * Bridge code keeps compiling while the adapters migrate to the canonical
7
+ * `AgentWire*` names. See `.gjc/specs/deep-interview-reconcile-rpc-adapters.md`.
9
8
  */
10
- import type { AgentSessionEvent } from "../../../session/agent-session";
9
+ import type { AgentWireEventFrame, AgentWireEventPayload, AgentWireEventType, AgentWireFrameEnvelope, AgentWireFrameType } from "./event-contract";
11
10
  /** Wire protocol version. Bump on breaking envelope/semantic changes. */
12
- export declare const BRIDGE_PROTOCOL_VERSION: 1;
11
+ export declare const BRIDGE_PROTOCOL_VERSION: 2;
13
12
  /** The discriminant of every `AgentSessionEvent` the agent can emit. */
14
- export type AgentSessionEventType = AgentSessionEvent["type"];
13
+ export type AgentSessionEventType = AgentWireEventType;
15
14
  /** Every agent-session event type, derived from the exhaustive registry. */
16
15
  export declare const AGENT_SESSION_EVENT_TYPES: readonly AgentSessionEventType[];
17
16
  /** Top-level frame categories carried over any bridge transport. */
18
- export type BridgeFrameType = "ready" | "event" | "response" | "ui_request" | "permission_request" | "host_tool_call" | "host_uri_request" | "reset" | "workflow_gate" | "error";
19
- /**
20
- * Universal frame envelope. Every frame on every transport carries these
21
- * fields so clients can order (`seq`), resume (`seq` cursor), and correlate
22
- * request/response pairs (`correlation_id`). `session_id` is present from v1
23
- * even though v1 runs one session per process, so in-process multiplexing is
24
- * an additive, non-breaking change later.
25
- */
26
- export interface BridgeFrameEnvelope<TType extends BridgeFrameType = BridgeFrameType, TPayload = unknown> {
27
- protocol_version: typeof BRIDGE_PROTOCOL_VERSION;
28
- session_id: string;
29
- /** Monotonic per-session sequence number, starting at 1. */
30
- seq: number;
31
- /** Unique id for this frame. */
32
- frame_id: string;
33
- /** Ties a request frame to its response frame, when applicable. */
34
- correlation_id?: string;
35
- type: TType;
36
- payload: TPayload;
37
- }
38
- /** Payload carried by an `event` frame. */
39
- export interface BridgeEventPayload {
40
- event_type: AgentSessionEventType;
41
- event: AgentSessionEvent;
42
- }
17
+ export type BridgeFrameType = AgentWireFrameType;
18
+ /** Universal frame envelope. See {@link AgentWireFrameEnvelope}. */
19
+ export type BridgeFrameEnvelope<TType extends BridgeFrameType = BridgeFrameType, TPayload = unknown> = AgentWireFrameEnvelope<TType, TPayload>;
20
+ /** Payload carried by an `event` frame. See {@link AgentWireEventPayload}. */
21
+ export type BridgeEventPayload = AgentWireEventPayload;
43
22
  /** An `AgentSessionEvent` serialized into a versioned wire frame. */
44
- export type BridgeEventFrame = BridgeFrameEnvelope<"event", BridgeEventPayload>;
23
+ export type BridgeEventFrame = AgentWireEventFrame;
45
24
  /** A `workflow_gate` event serialized into a versioned wire frame (#321). */
46
25
  export type BridgeWorkflowGateFrame = BridgeFrameEnvelope<"workflow_gate", import("../../rpc/rpc-types").RpcWorkflowGate>;
@@ -0,0 +1,115 @@
1
+ import type { ImageContent } from "@gajae-code/ai";
2
+ import type { CustomMessage } from "../session/messages";
3
+ export declare const STAR_REMINDER_REPO = "Yeachan-Heo/gajae-code";
4
+ export declare const STAR_REMINDER_CUSTOM_TYPE = "star-reminder";
5
+ export declare const STARRED_CACHE_TTL_MS: number;
6
+ export interface StarReminderState {
7
+ declined: boolean;
8
+ starred: boolean;
9
+ /** ISO-8601 timestamp of the last authoritative star check, or "" if never. */
10
+ starredCheckedAt: string;
11
+ }
12
+ export type StarCheckStatus = "starred" | "unstarred" | "unavailable";
13
+ export interface GhResult {
14
+ exitCode: number;
15
+ stdout: string;
16
+ stderr: string;
17
+ timedOut?: boolean;
18
+ }
19
+ export type RunGh = (args: string[], options?: {
20
+ timeoutMs?: number;
21
+ }) => Promise<GhResult>;
22
+ export interface StarReminderDeps {
23
+ statePath?: string;
24
+ now?: () => Date;
25
+ runGh?: RunGh;
26
+ sleep?: (ms: number) => Promise<void>;
27
+ }
28
+ export declare function getStarReminderStatePath(): string;
29
+ export declare function defaultStarReminderState(): StarReminderState;
30
+ /** Read state without locking. Missing or malformed files return the default. */
31
+ export declare function readStarReminderStateUnlocked(statePath?: string): Promise<StarReminderState>;
32
+ /** Whether a stored `starred:true` is still within the 24h cache window. */
33
+ export declare function isStarredCacheFresh(state: StarReminderState, now?: Date): boolean;
34
+ /**
35
+ * Lock-protected read-modify-write. The mutator receives the freshly re-read
36
+ * state under the lock; callers MUST base monotonic decisions on that value,
37
+ * not on any snapshot captured before the lock was held.
38
+ */
39
+ export declare function updateStarReminderStateLocked(mutator: (current: StarReminderState) => StarReminderState | Promise<StarReminderState>, deps?: StarReminderDeps): Promise<StarReminderState>;
40
+ /** A successful PUT is authoritative: always record starred and clear declined. */
41
+ export declare function recordStarredFromPut(deps?: StarReminderDeps): Promise<StarReminderState>;
42
+ /**
43
+ * Record the result of a fresh `gh` star check performed by this operation.
44
+ * - "starred": authoritative, clears declined so all reminders stop.
45
+ * - "unstarred": may downgrade, but only when the current state is not a
46
+ * still-fresh confirmed star (which a concurrent process may have just
47
+ * written); in that case the fresher confirmation wins.
48
+ */
49
+ export declare function recordFreshStarCheck(status: "starred" | "unstarred", deps?: StarReminderDeps): Promise<StarReminderState>;
50
+ /** Record a launch-nudge decline. Never downgrades a confirmed star. */
51
+ export declare function recordDeclinedAfterNo(deps?: StarReminderDeps): Promise<StarReminderState>;
52
+ /** Default `gh` runner. Returns an unavailable-style result instead of throwing. */
53
+ export declare function runGhDefault(args: string[], options?: {
54
+ timeoutMs?: number;
55
+ }): Promise<GhResult>;
56
+ /** Classify the star state of the repo via `gh api`. */
57
+ export declare function checkGhStarred(deps?: StarReminderDeps): Promise<StarCheckStatus>;
58
+ /** Star the repo via `gh api -X PUT`. Returns whether the PUT succeeded. */
59
+ export declare function autoStarRepo(deps?: StarReminderDeps): Promise<boolean>;
60
+ /**
61
+ * Determine the star state for this session, hitting `gh` only when needed.
62
+ * A fresh cached star skips `gh`; unstarred and declined states are rechecked.
63
+ * Authoritative results are persisted via the monotonic helpers.
64
+ */
65
+ export declare function refreshStarStateForSession(deps?: StarReminderDeps): Promise<StarCheckStatus>;
66
+ export interface StarReminderPromptUI {
67
+ /** Show a yes/no confirmation. Resolves true when the user accepts. */
68
+ confirm(title: string, message: string): Promise<boolean>;
69
+ /** Optional guard; when it returns false the nudge is skipped silently. */
70
+ isIdle?: () => boolean;
71
+ }
72
+ /**
73
+ * Run the launch nudge once. Caller is responsible for the `startup.quiet`,
74
+ * `starReminder.enabled`, and true-interactive gates. All errors are swallowed
75
+ * so the launch path can never be broken by the reminder.
76
+ */
77
+ export declare function maybeShowLaunchStarReminder(ui: StarReminderPromptUI, deps?: StarReminderDeps): Promise<void>;
78
+ /**
79
+ * Schedule the launch nudge to run after the first render so the networked
80
+ * `gh` check never blocks startup. Returns immediately.
81
+ */
82
+ export declare function scheduleLaunchStarReminderAfterFirstRender(ui: StarReminderPromptUI, deps?: StarReminderDeps): void;
83
+ export interface StarReminderLaunchGateInput {
84
+ /** The `starReminder.enabled` setting. */
85
+ enabled: boolean;
86
+ /** The `startup.quiet` setting. */
87
+ quiet: boolean;
88
+ }
89
+ export interface StarReminderLaunchGate {
90
+ /** Whether to register the decline-driven injection contributor. */
91
+ register: boolean;
92
+ /** Whether to schedule the launch nudge after first render. */
93
+ schedule: boolean;
94
+ }
95
+ /**
96
+ * Pure decision for interactive wiring. The injection contributor is registered
97
+ * whenever the feature is enabled; the launch nudge is additionally suppressed
98
+ * by quiet startup. Centralizing this keeps the interactive gate testable.
99
+ */
100
+ export declare function starReminderLaunchGate(input: StarReminderLaunchGateInput): StarReminderLaunchGate;
101
+ export interface StarReminderSessionRef {
102
+ getSessionId(): string | undefined;
103
+ }
104
+ export type StarReminderCustomMessage = Pick<CustomMessage, "customType" | "content" | "display" | "details" | "attribution">;
105
+ export type InternalBeforeAgentStartContributor = (event: {
106
+ prompt: string;
107
+ images?: ImageContent[];
108
+ sessionId: string | undefined;
109
+ }) => Promise<StarReminderCustomMessage | undefined>;
110
+ export declare function createStarReminderMessage(): StarReminderCustomMessage;
111
+ /**
112
+ * Build a before-agent-start contributor that injects the persuasion message
113
+ * once per logical session id, for declined-and-still-unstarred users only.
114
+ */
115
+ export declare function createStarReminderBeforeAgentStartContributor(session: StarReminderSessionRef, deps?: StarReminderDeps): InternalBeforeAgentStartContributor;
@@ -25,6 +25,14 @@ export interface ForkContextSeedMetadata {
25
25
  maxTokens: number;
26
26
  skippedReasons: Record<string, number>;
27
27
  }
28
+ export interface PurgeQueuedCustomMessagesResult {
29
+ agentSteering: number;
30
+ agentFollowUp: number;
31
+ pendingNextTurn: number;
32
+ displaySteering: number;
33
+ displayFollowUp: number;
34
+ totalExecutable: number;
35
+ }
28
36
  export interface ForkContextSeed {
29
37
  messages: Message[];
30
38
  agentMessages: AgentMessage[];
@@ -294,6 +302,18 @@ export interface SessionStats {
294
302
  premiumRequests: number;
295
303
  cost: number;
296
304
  }
305
+ /** A custom message contributed at the before-agent-start point. */
306
+ export type BeforeAgentStartInternalMessage = Pick<CustomMessage, "customType" | "content" | "display" | "details" | "attribution">;
307
+ /**
308
+ * Internal (first-party, non-user-hook) contributor invoked at the active
309
+ * before-agent-start point alongside the extension runner. Returns an optional
310
+ * custom message to append to the prompt context. Errors are nonfatal.
311
+ */
312
+ export type BeforeAgentStartContributor = (event: {
313
+ prompt: string;
314
+ images?: ImageContent[];
315
+ sessionId: string | undefined;
316
+ }) => Promise<BeforeAgentStartInternalMessage | undefined>;
297
317
  export declare class AgentSession {
298
318
  #private;
299
319
  readonly agent: Agent;
@@ -556,6 +576,7 @@ export declare class AgentSession {
556
576
  */
557
577
  followUp(text: string, images?: ImageContent[]): Promise<void>;
558
578
  queueDeferredMessage(message: CustomMessage): void;
579
+ queueDeferredMessageForTests(message: CustomMessage, triggerTurn?: boolean): void;
559
580
  /**
560
581
  * Send a custom message to the session. Creates a CustomMessageEntry.
561
582
  *
@@ -568,6 +589,8 @@ export declare class AgentSession {
568
589
  triggerTurn?: boolean;
569
590
  deliverAs?: "steer" | "followUp" | "nextTurn";
570
591
  }): Promise<void>;
592
+ /** Remove undelivered queued custom messages matching `predicate` from executable queues and tagged display mirrors. */
593
+ purgeQueuedCustomMessages(predicate: (message: CustomMessage) => boolean): PurgeQueuedCustomMessagesResult;
571
594
  /**
572
595
  * Send a user message to the agent.
573
596
  * When deliverAs is set, queue the message instead of starting a new turn.
@@ -671,7 +694,7 @@ export declare class AgentSession {
671
694
  /**
672
695
  * Cycle through configured role models in a fixed order.
673
696
  * Skips missing roles.
674
- * @param roleOrder - Order of roles to cycle through (e.g., ["slow", "default", "smol"])
697
+ * @param roleOrder - Order of roles to cycle through (e.g., ["default"])
675
698
  * @param options - Optional settings: `temporary` to not persist to settings
676
699
  */
677
700
  cycleRoleModels(roleOrder: readonly string[], options?: {
@@ -991,6 +1014,12 @@ export declare class AgentSession {
991
1014
  * Check if extensions have handlers for a specific event type.
992
1015
  */
993
1016
  hasExtensionHandlers(eventType: string): boolean;
1017
+ /**
1018
+ * Register a first-party internal before-agent-start contributor. Returns an
1019
+ * unregister function. This is NOT user-facing hook discovery; it is an
1020
+ * in-core seam invoked alongside the extension runner.
1021
+ */
1022
+ registerBeforeAgentStartContributor(contributor: BeforeAgentStartContributor): () => void;
994
1023
  /**
995
1024
  * Get the extension runner (for setting UI context and error handlers).
996
1025
  */
@@ -38,7 +38,7 @@ export interface ModelChangeEntry extends SessionEntryBase {
38
38
  type: "model_change";
39
39
  /** Model in "provider/modelId" format */
40
40
  model: string;
41
- /** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
41
+ /** Role: "default" or an agent role. Undefined treated as "default" */
42
42
  role?: string;
43
43
  }
44
44
  export interface ServiceTierChangeEntry extends SessionEntryBase {
@@ -78,6 +78,8 @@ export declare class BashTool implements AgentTool<BashToolSchema, BashToolDetai
78
78
  label?: string;
79
79
  ctx?: AgentToolContext;
80
80
  onRawLine?: (line: string, jobId: string) => void;
81
+ shouldAcceptRawLine?: (jobId: string) => boolean;
82
+ lifecycle?: import("../async").AsyncJobLifecycleCleanup;
81
83
  }): Promise<{
82
84
  jobId: string;
83
85
  label: string;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Structured browser action space.
3
+ *
4
+ * Adapts the SOTA computer-use / browser-use pattern: instead of authoring raw
5
+ * JavaScript for every interaction, the model emits a list of structured verbs
6
+ * (navigate / click / type / …) that reference elements by the numeric `id`
7
+ * returned from {@link Observation}. Each verb is compiled onto the existing
8
+ * in-tab `tab.*` helpers and executed through the same worker `run` path, so the
9
+ * worker protocol is unchanged and the raw-JS `run` escape hatch still works.
10
+ */
11
+ export type BrowserActionVerb = "navigate" | "click" | "type" | "fill" | "select" | "press" | "scroll" | "back" | "wait" | "observe" | "extract" | "screenshot";
12
+ export interface BrowserActionStep {
13
+ verb: BrowserActionVerb;
14
+ /** Element id from a prior `observe` (preferred for click/type). */
15
+ id?: number;
16
+ /** CSS / puppeteer selector when not addressing by `id`. */
17
+ selector?: string;
18
+ /** Text to type. */
19
+ text?: string;
20
+ /** Value for `fill`. */
21
+ value?: string;
22
+ /** Option value(s) for `select`. */
23
+ values?: string[];
24
+ /** URL for `navigate`. */
25
+ url?: string;
26
+ /** Key for `press` (e.g. "Enter"). */
27
+ key?: string;
28
+ /** Horizontal scroll delta. */
29
+ dx?: number;
30
+ /** Vertical scroll delta. */
31
+ dy?: number;
32
+ /** Sleep duration for `wait` when no selector is given. */
33
+ ms?: number;
34
+ /** Extract format. */
35
+ format?: "markdown" | "text" | "html";
36
+ /** Navigation wait condition for `navigate`. */
37
+ wait_until?: "load" | "domcontentloaded" | "networkidle0" | "networkidle2";
38
+ /** Only return interactive/viewport elements for `observe`. */
39
+ viewport_only?: boolean;
40
+ include_all?: boolean;
41
+ }
42
+ /**
43
+ * Validate a single step's required fields. Returns an error string, or
44
+ * `undefined` when the step is well-formed.
45
+ */
46
+ export declare function validateActionStep(step: BrowserActionStep, index: number): string | undefined;
47
+ /** Validate the full step list. Throws on the first invalid step. */
48
+ export declare function validateActionSteps(steps: readonly BrowserActionStep[]): void;
49
+ /**
50
+ * Compile structured steps into a JS program for the in-tab `run` worker. Steps
51
+ * are embedded as parsed JSON (no string interpolation, so values cannot inject
52
+ * code) and dispatched by a fixed interpreter against the `tab` / `page` helpers.
53
+ */
54
+ export declare function compileActionSteps(steps: readonly BrowserActionStep[]): string;
@@ -8,6 +8,7 @@ export { extractReadableFromHtml, type ReadableFormat, type ReadableResult } fro
8
8
  export type { Observation, ObservationEntry } from "./browser/tab-protocol";
9
9
  declare const browserSchema: z.ZodObject<{
10
10
  action: z.ZodEnum<{
11
+ act: "act";
11
12
  close: "close";
12
13
  open: "open";
13
14
  run: "run";
@@ -36,6 +37,45 @@ declare const browserSchema: z.ZodObject<{
36
37
  dismiss: "dismiss";
37
38
  }>>;
38
39
  code: z.ZodOptional<z.ZodString>;
40
+ actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
41
+ verb: z.ZodEnum<{
42
+ back: "back";
43
+ click: "click";
44
+ extract: "extract";
45
+ fill: "fill";
46
+ navigate: "navigate";
47
+ observe: "observe";
48
+ press: "press";
49
+ screenshot: "screenshot";
50
+ scroll: "scroll";
51
+ select: "select";
52
+ type: "type";
53
+ wait: "wait";
54
+ }>;
55
+ id: z.ZodOptional<z.ZodNumber>;
56
+ selector: z.ZodOptional<z.ZodString>;
57
+ text: z.ZodOptional<z.ZodString>;
58
+ value: z.ZodOptional<z.ZodString>;
59
+ values: z.ZodOptional<z.ZodArray<z.ZodString>>;
60
+ url: z.ZodOptional<z.ZodString>;
61
+ key: z.ZodOptional<z.ZodString>;
62
+ dx: z.ZodOptional<z.ZodNumber>;
63
+ dy: z.ZodOptional<z.ZodNumber>;
64
+ ms: z.ZodOptional<z.ZodNumber>;
65
+ format: z.ZodOptional<z.ZodEnum<{
66
+ html: "html";
67
+ markdown: "markdown";
68
+ text: "text";
69
+ }>>;
70
+ wait_until: z.ZodOptional<z.ZodEnum<{
71
+ domcontentloaded: "domcontentloaded";
72
+ load: "load";
73
+ networkidle0: "networkidle0";
74
+ networkidle2: "networkidle2";
75
+ }>>;
76
+ viewport_only: z.ZodOptional<z.ZodBoolean>;
77
+ include_all: z.ZodOptional<z.ZodBoolean>;
78
+ }, z.core.$strip>>>;
39
79
  timeout: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
40
80
  all: z.ZodOptional<z.ZodBoolean>;
41
81
  kill: z.ZodOptional<z.ZodBoolean>;
@@ -73,6 +113,7 @@ export declare class BrowserTool implements AgentTool<typeof browserSchema, Brow
73
113
  readonly summary = "Control a headless browser to navigate and interact with web pages";
74
114
  readonly parameters: z.ZodObject<{
75
115
  action: z.ZodEnum<{
116
+ act: "act";
76
117
  close: "close";
77
118
  open: "open";
78
119
  run: "run";
@@ -101,6 +142,45 @@ export declare class BrowserTool implements AgentTool<typeof browserSchema, Brow
101
142
  dismiss: "dismiss";
102
143
  }>>;
103
144
  code: z.ZodOptional<z.ZodString>;
145
+ actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
146
+ verb: z.ZodEnum<{
147
+ back: "back";
148
+ click: "click";
149
+ extract: "extract";
150
+ fill: "fill";
151
+ navigate: "navigate";
152
+ observe: "observe";
153
+ press: "press";
154
+ screenshot: "screenshot";
155
+ scroll: "scroll";
156
+ select: "select";
157
+ type: "type";
158
+ wait: "wait";
159
+ }>;
160
+ id: z.ZodOptional<z.ZodNumber>;
161
+ selector: z.ZodOptional<z.ZodString>;
162
+ text: z.ZodOptional<z.ZodString>;
163
+ value: z.ZodOptional<z.ZodString>;
164
+ values: z.ZodOptional<z.ZodArray<z.ZodString>>;
165
+ url: z.ZodOptional<z.ZodString>;
166
+ key: z.ZodOptional<z.ZodString>;
167
+ dx: z.ZodOptional<z.ZodNumber>;
168
+ dy: z.ZodOptional<z.ZodNumber>;
169
+ ms: z.ZodOptional<z.ZodNumber>;
170
+ format: z.ZodOptional<z.ZodEnum<{
171
+ html: "html";
172
+ markdown: "markdown";
173
+ text: "text";
174
+ }>>;
175
+ wait_until: z.ZodOptional<z.ZodEnum<{
176
+ domcontentloaded: "domcontentloaded";
177
+ load: "load";
178
+ networkidle0: "networkidle0";
179
+ networkidle2: "networkidle2";
180
+ }>>;
181
+ viewport_only: z.ZodOptional<z.ZodBoolean>;
182
+ include_all: z.ZodOptional<z.ZodBoolean>;
183
+ }, z.core.$strip>>>;
104
184
  timeout: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
105
185
  all: z.ZodOptional<z.ZodBoolean>;
106
186
  kill: z.ZodOptional<z.ZodBoolean>;
@@ -72,6 +72,7 @@ interface InlineImageData {
72
72
  }
73
73
  /** Set the preferred image provider from settings */
74
74
  export declare function setPreferredImageProvider(provider: ImageProvider | "auto"): void;
75
+ export declare function isOpenAIHostedImageModel(model: Model | undefined): model is Model;
75
76
  export declare const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails>;
76
77
  export declare function getImageGenTools(modelRegistry?: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
77
78
  export declare function getImageGenToolsWithRegistry(modelRegistry: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
@@ -8,7 +8,7 @@ import type { HindsightSessionState } from "../hindsight/state";
8
8
  import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/unattended-session";
9
9
  import type { PlanModeState } from "../plan-mode/state";
10
10
  import type { AgentRegistry } from "../registry/agent-registry";
11
- import type { ForkContextSeed, ForkContextSeedOptions } from "../session/agent-session";
11
+ import type { ForkContextSeed, ForkContextSeedOptions, PurgeQueuedCustomMessagesResult } from "../session/agent-session";
12
12
  import type { ArtifactManager } from "../session/artifacts";
13
13
  import type { ClientBridge } from "../session/client-bridge";
14
14
  import type { CustomMessage } from "../session/messages";
@@ -117,6 +117,8 @@ export interface ToolSession {
117
117
  /** Agent identity used for IRC routing. Returns the registry id (e.g. "0-Main", "0-AuthLoader"). */
118
118
  getAgentId?: () => string | null;
119
119
  /** Look up a registered tool by name (used by the eval js backend's tool bridge). */
120
+ /** Purge undelivered queued custom messages matching the predicate. Returns counts. */
121
+ purgeQueuedCustomMessages?: (predicate: (message: CustomMessage) => boolean) => PurgeQueuedCustomMessagesResult;
120
122
  getToolByName?: (name: string) => AgentTool | undefined;
121
123
  /** Agent registry for IRC routing across live sessions. */
122
124
  agentRegistry?: AgentRegistry;
@@ -19,7 +19,7 @@ interface JobSnapshot {
19
19
  resultText?: string;
20
20
  errorText?: string;
21
21
  }
22
- type CancelStatus = "cancelled" | "not_found" | "already_completed";
22
+ type CancelStatus = "cancelled" | "not_found" | "already_completed" | "already_cancelled";
23
23
  export interface JobToolDetails {
24
24
  jobs: JobSnapshot[];
25
25
  cancelled?: {
@@ -5,57 +5,37 @@ Example extensions for gajae-code.
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
- # Load an extension with --extension flag
9
- pi --extension examples/extensions/permission-gate.ts
8
+ # Copy an existing extension into the user extension directory for auto-discovery
9
+ mkdir -p ~/.gjc/agent/extensions
10
+ cp packages/coding-agent/examples/extensions/hello.ts ~/.gjc/agent/extensions/
10
11
 
11
- # Or copy to extensions directory for auto-discovery
12
- cp permission-gate.ts ~/.gjc/agent/extensions/
12
+ # Project-local extensions can live in .gjc/extensions/
13
+ mkdir -p .gjc/extensions
14
+ cp packages/coding-agent/examples/extensions/pirate.ts .gjc/extensions/
13
15
  ```
14
16
 
15
17
  ## Examples
16
18
 
17
- ### Lifecycle & Safety
19
+ ### Custom Tools & API
18
20
 
19
- | Extension | Description |
20
- | ------------------------ | ---------------------------------------------------------------------------- |
21
- | `permission-gate.ts` | Prompts for confirmation before dangerous bash commands (rm -rf, sudo, etc.) |
22
- | `protected-paths.ts` | Blocks writes to protected paths (.env, .git/, node_modules/) |
23
- | `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, branch) |
24
- | `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
25
-
26
- ### Custom Tools
27
-
28
- | Extension | Description |
29
- | ------------- | ----------------------------------------------------------------------------- |
30
- | `todo.ts` | Todo list tool + `/todos` command with custom rendering and state persistence |
31
- | `hello.ts` | Minimal custom tool example |
32
- | `question.ts` | Demonstrates `ctx.ui.select()` for asking the user questions |
33
- | `subagent/` | Delegate tasks to specialized subagents with isolated context windows |
21
+ | Extension | Description |
22
+ | ------------- | ---------------------------------------------------------- |
23
+ | `hello.ts` | Minimal custom tool example |
24
+ | `api-demo.ts` | Demonstrates logger access, injected `pi.zod`, and modules |
34
25
 
35
26
  ### Commands & UI
36
27
 
37
- | Extension | Description |
38
- | ---------------- | ------------------------------------------------------------------------------ |
39
- | `plan-mode.ts` | Anthropic Code-style plan mode for read-only exploration with `/plan` command |
40
- | `tools.ts` | Interactive `/tools` command to enable/disable tools with session persistence |
41
- | `handoff.ts` | Transfer context to a new focused session via `/handoff <goal>` |
42
- | `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
43
- | `status-line.ts` | Shows turn progress in footer via `ctx.ui.setStatus()` with themed colors |
44
- | `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
45
-
46
- ### Git Integration
47
-
48
- | Extension | Description |
49
- | ------------------------ | ------------------------------------------------------------------------- |
50
- | `git-checkpoint.ts` | Creates git stash checkpoints at each turn for code restoration on branch |
51
- | `auto-commit-on-exit.ts` | Auto-commits on exit using last assistant message for commit message |
28
+ | Extension | Description |
29
+ | ------------------- | ----------------------------------------------------------------------------- |
30
+ | `plan-mode.ts` | Anthropic Code-style plan mode for read-only exploration with `/plan` command |
31
+ | `tools.ts` | Interactive `/tools` command to enable/disable tools with session persistence |
32
+ | `reload-runtime.ts` | Adds a command and tool for reloading extensions, skills, prompts, and themes |
52
33
 
53
34
  ### System Prompt & Compaction
54
35
 
55
- | Extension | Description |
56
- | ---------------------- | --------------------------------------------------------------------- |
57
- | `pirate.ts` | Demonstrates `systemPromptAppend` to dynamically modify system prompt |
58
- | `custom-compaction.ts` | Custom compaction that summarizes entire conversation |
36
+ | Extension | Description |
37
+ | ----------- | -------------------------------------------------------------------- |
38
+ | `pirate.ts` | Demonstrates `systemPromptAppend` to dynamically modify system prompt |
59
39
 
60
40
  ### External Dependencies
61
41
 
@@ -63,11 +43,10 @@ cp permission-gate.ts ~/.gjc/agent/extensions/
63
43
  | ----------------- | ------------------------------------------------------------------------- |
64
44
  | `chalk-logger.ts` | Uses chalk from parent node_modules (demonstrates jiti module resolution) |
65
45
  | `with-deps/` | Extension with its own package.json and dependencies |
66
- | `file-trigger.ts` | Watches a trigger file and injects contents into conversation |
67
46
 
68
47
  ## Writing Extensions
69
48
 
70
- See [docs/extensions.md](../../docs/extensions.md) for full documentation.
49
+ The examples below show the core extension patterns used by this directory.
71
50
 
72
51
  ```typescript
73
52
  import type { ExtensionAPI } from "@gajae-code/coding-agent";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.4.1",
4
+ "version": "0.4.3",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -50,12 +50,12 @@
50
50
  "@agentclientprotocol/sdk": "0.21.0",
51
51
  "@babel/parser": "^7.29.3",
52
52
  "@mozilla/readability": "^0.6.0",
53
- "@gajae-code/stats": "0.4.1",
54
- "@gajae-code/agent-core": "0.4.1",
55
- "@gajae-code/ai": "0.4.1",
56
- "@gajae-code/natives": "0.4.1",
57
- "@gajae-code/tui": "0.4.1",
58
- "@gajae-code/utils": "0.4.1",
53
+ "@gajae-code/stats": "0.4.3",
54
+ "@gajae-code/agent-core": "0.4.3",
55
+ "@gajae-code/ai": "0.4.3",
56
+ "@gajae-code/natives": "0.4.3",
57
+ "@gajae-code/tui": "0.4.3",
58
+ "@gajae-code/utils": "0.4.3",
59
59
  "@puppeteer/browsers": "^2.13.0",
60
60
  "@types/turndown": "5.0.6",
61
61
  "@xterm/headless": "^6.0.0",