@gajae-code/coding-agent 0.3.0 → 0.3.1

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 (175) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/types/async/job-manager.d.ts +7 -0
  3. package/dist/types/cli/args.d.ts +1 -1
  4. package/dist/types/commands/deep-interview.d.ts +3 -0
  5. package/dist/types/config/keybindings.d.ts +5 -0
  6. package/dist/types/config/settings-schema.d.ts +4 -4
  7. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  8. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  9. package/dist/types/deep-interview/render-middleware.d.ts +1 -0
  10. package/dist/types/eval/py/executor.d.ts +2 -0
  11. package/dist/types/eval/py/kernel.d.ts +2 -0
  12. package/dist/types/exec/bash-executor.d.ts +10 -0
  13. package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
  14. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
  15. package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
  16. package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
  17. package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
  18. package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
  19. package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
  20. package/dist/types/hooks/skill-state.d.ts +21 -0
  21. package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
  22. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  23. package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
  24. package/dist/types/internal-urls/types.d.ts +4 -0
  25. package/dist/types/lsp/index.d.ts +10 -10
  26. package/dist/types/modes/bridge/auth.d.ts +12 -0
  27. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  28. package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
  29. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  30. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  31. package/dist/types/modes/components/custom-editor.d.ts +6 -0
  32. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  33. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  34. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  35. package/dist/types/modes/components/status-line.d.ts +2 -0
  36. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  37. package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
  38. package/dist/types/modes/index.d.ts +1 -0
  39. package/dist/types/modes/interactive-mode.d.ts +1 -0
  40. package/dist/types/modes/jobs-observer.d.ts +57 -0
  41. package/dist/types/modes/rpc/host-tools.d.ts +1 -16
  42. package/dist/types/modes/rpc/host-uris.d.ts +1 -38
  43. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
  44. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  45. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
  46. package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
  47. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  48. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  49. package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
  50. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  51. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  52. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  53. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  54. package/dist/types/modes/types.d.ts +1 -0
  55. package/dist/types/sdk.d.ts +2 -0
  56. package/dist/types/session/agent-session.d.ts +11 -1
  57. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
  58. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  59. package/dist/types/task/id.d.ts +7 -0
  60. package/dist/types/task/index.d.ts +5 -0
  61. package/dist/types/task/receipt.d.ts +85 -0
  62. package/dist/types/task/spawn-gate.d.ts +38 -0
  63. package/dist/types/task/types.d.ts +143 -11
  64. package/dist/types/tools/cron.d.ts +6 -0
  65. package/dist/types/tools/index.d.ts +2 -0
  66. package/dist/types/tools/path-utils.d.ts +1 -0
  67. package/dist/types/tools/subagent.d.ts +15 -0
  68. package/package.json +7 -7
  69. package/scripts/build-binary.ts +7 -0
  70. package/src/async/job-manager.ts +36 -0
  71. package/src/cli/args.ts +9 -2
  72. package/src/commands/deep-interview.ts +1 -0
  73. package/src/commands/harness.ts +289 -19
  74. package/src/commands/launch.ts +2 -2
  75. package/src/commands/state.ts +2 -1
  76. package/src/commands/team.ts +22 -4
  77. package/src/config/keybindings.ts +6 -0
  78. package/src/config/settings-schema.ts +6 -3
  79. package/src/dap/client.ts +17 -3
  80. package/src/debug/crash-diagnostics.ts +223 -0
  81. package/src/debug/runtime-gauges.ts +20 -0
  82. package/src/deep-interview/render-middleware.ts +6 -0
  83. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  84. package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
  85. package/src/defaults/gjc/skills/ultragoal/SKILL.md +28 -2
  86. package/src/eval/py/executor.ts +21 -1
  87. package/src/eval/py/kernel.ts +15 -0
  88. package/src/exec/bash-executor.ts +41 -0
  89. package/src/gjc-runtime/cli-write-receipt.ts +31 -0
  90. package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
  91. package/src/gjc-runtime/ralplan-runtime.ts +213 -36
  92. package/src/gjc-runtime/state-migrations.ts +54 -7
  93. package/src/gjc-runtime/state-runtime.ts +461 -64
  94. package/src/gjc-runtime/state-schema.ts +192 -0
  95. package/src/gjc-runtime/state-writer.ts +32 -1
  96. package/src/gjc-runtime/team-runtime.ts +177 -105
  97. package/src/gjc-runtime/ultragoal-runtime.ts +114 -26
  98. package/src/gjc-runtime/workflow-command-ref.ts +239 -0
  99. package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
  100. package/src/gjc-runtime/workflow-manifest.ts +3 -1
  101. package/src/harness-control-plane/control-endpoint.ts +19 -8
  102. package/src/harness-control-plane/owner.ts +57 -10
  103. package/src/harness-control-plane/state-machine.ts +2 -1
  104. package/src/hooks/skill-state.ts +176 -26
  105. package/src/internal-urls/agent-protocol.ts +68 -21
  106. package/src/internal-urls/artifact-protocol.ts +12 -17
  107. package/src/internal-urls/docs-index.generated.ts +3 -2
  108. package/src/internal-urls/registry-helpers.ts +19 -16
  109. package/src/internal-urls/types.ts +4 -0
  110. package/src/lsp/client.ts +18 -2
  111. package/src/main.ts +21 -5
  112. package/src/modes/bridge/auth.ts +41 -0
  113. package/src/modes/bridge/bridge-client-bridge.ts +47 -0
  114. package/src/modes/bridge/bridge-mode.ts +520 -0
  115. package/src/modes/bridge/bridge-ui-context.ts +200 -0
  116. package/src/modes/bridge/event-stream.ts +70 -0
  117. package/src/modes/components/custom-editor.ts +101 -0
  118. package/src/modes/components/hook-selector.ts +61 -18
  119. package/src/modes/components/jobs-overlay-model.ts +109 -0
  120. package/src/modes/components/jobs-overlay.ts +172 -0
  121. package/src/modes/components/status-line/presets.ts +7 -5
  122. package/src/modes/components/status-line/segments.ts +25 -0
  123. package/src/modes/components/status-line/types.ts +2 -0
  124. package/src/modes/components/status-line.ts +9 -1
  125. package/src/modes/controllers/extension-ui-controller.ts +39 -3
  126. package/src/modes/controllers/input-controller.ts +97 -9
  127. package/src/modes/controllers/selector-controller.ts +29 -0
  128. package/src/modes/index.ts +1 -0
  129. package/src/modes/interactive-mode.ts +27 -0
  130. package/src/modes/jobs-observer.ts +204 -0
  131. package/src/modes/rpc/host-tools.ts +1 -186
  132. package/src/modes/rpc/host-uris.ts +1 -235
  133. package/src/modes/rpc/rpc-client.ts +25 -10
  134. package/src/modes/rpc/rpc-mode.ts +12 -381
  135. package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
  136. package/src/modes/shared/agent-wire/command-validation.ts +131 -0
  137. package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
  138. package/src/modes/shared/agent-wire/handshake.ts +117 -0
  139. package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
  140. package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
  141. package/src/modes/shared/agent-wire/protocol.ts +96 -0
  142. package/src/modes/shared/agent-wire/responses.ts +17 -0
  143. package/src/modes/shared/agent-wire/scopes.ts +89 -0
  144. package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
  145. package/src/modes/shared/agent-wire/ui-result.ts +48 -0
  146. package/src/modes/types.ts +1 -0
  147. package/src/prompts/tools/subagent.md +12 -7
  148. package/src/prompts/tools/task-summary.md +3 -9
  149. package/src/prompts/tools/task.md +5 -1
  150. package/src/sdk.ts +4 -0
  151. package/src/session/agent-session.ts +214 -38
  152. package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
  153. package/src/skill-state/workflow-state-contract.ts +7 -4
  154. package/src/skill-state/workflow-state-version.ts +3 -0
  155. package/src/slash-commands/builtin-registry.ts +8 -0
  156. package/src/task/executor.ts +29 -5
  157. package/src/task/id.ts +33 -0
  158. package/src/task/index.ts +257 -67
  159. package/src/task/output-manager.ts +5 -4
  160. package/src/task/receipt.ts +297 -0
  161. package/src/task/render.ts +48 -131
  162. package/src/task/spawn-gate.ts +132 -0
  163. package/src/task/types.ts +48 -7
  164. package/src/tools/ask.ts +73 -33
  165. package/src/tools/ast-edit.ts +1 -0
  166. package/src/tools/ast-grep.ts +1 -0
  167. package/src/tools/bash.ts +1 -1
  168. package/src/tools/cron.ts +48 -0
  169. package/src/tools/find.ts +4 -1
  170. package/src/tools/index.ts +2 -0
  171. package/src/tools/path-utils.ts +3 -2
  172. package/src/tools/read.ts +1 -0
  173. package/src/tools/search.ts +1 -0
  174. package/src/tools/skill.ts +6 -1
  175. package/src/tools/subagent.ts +237 -84
@@ -1,25 +1,28 @@
1
1
  /**
2
- * Shared helpers for internal-url protocol handlers that resolve IDs against
3
- * registered agent sessions.
2
+ * Shared helpers for internal-url protocol handlers that resolve session-scoped
3
+ * artifact IDs.
4
4
  */
5
- import { AgentRegistry } from "../registry/agent-registry";
5
+ import * as path from "node:path";
6
+ import type { ResolveContext } from "./types";
7
+
8
+ function addDir(dirs: string[], dir: string | null | undefined): void {
9
+ if (!dir) return;
10
+ const normalized = path.resolve(dir);
11
+ if (!dirs.includes(normalized)) dirs.push(normalized);
12
+ }
6
13
 
7
14
  /**
8
- * Snapshot of artifacts dirs for every registered session, deduped.
15
+ * Snapshot of artifacts dirs explicitly authorized for the calling session.
9
16
  *
10
- * Prefers `sessionManager.getArtifactsDir()` because subagents adopt their
11
- * parent's `ArtifactManager` and report the parent's dir there; dedup then
12
- * collapses parent + N subagents (the whole agent tree) to one entry. Falls
13
- * back to the raw session file (with the `.jsonl` suffix stripped) when no
14
- * live session reference is attached.
17
+ * Normal reads are scoped to the caller's artifacts directory. Parent/child
18
+ * agent tree sharing is allowed only when the caller supplies explicit
19
+ * authorized directories at the ResolveContext boundary. This intentionally
20
+ * does not enumerate AgentRegistry.global(); live but unrelated sessions are
21
+ * not an authorization source.
15
22
  */
16
- export function artifactsDirsFromRegistry(): string[] {
23
+ export function authorizedArtifactsDirsFromContext(context?: ResolveContext): string[] {
17
24
  const dirs: string[] = [];
18
- for (const ref of AgentRegistry.global().list()) {
19
- const dir =
20
- ref.session?.sessionManager.getArtifactsDir() ?? (ref.sessionFile ? ref.sessionFile.slice(0, -6) : null);
21
- if (!dir) continue;
22
- if (!dirs.includes(dir)) dirs.push(dir);
23
- }
25
+ addDir(dirs, context?.getArtifactsDir?.());
26
+ for (const dir of context?.getAuthorizedArtifactsDirs?.() ?? []) addDir(dirs, dir);
24
27
  return dirs;
25
28
  }
@@ -59,6 +59,10 @@ export interface ResolveContext {
59
59
  cwd?: string;
60
60
  /** Settings of the calling session (used by `issue://`/`pr://` for cache TTLs). */
61
61
  settings?: unknown;
62
+ /** Artifacts directory of the calling session. */
63
+ getArtifactsDir?: () => string | null;
64
+ /** Additional artifacts directories explicitly authorized for this caller (for parent/child agent trees). */
65
+ getAuthorizedArtifactsDirs?: () => readonly string[];
62
66
  /** Caller's abort signal. */
63
67
  signal?: AbortSignal;
64
68
  }
package/src/lsp/client.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isEnoent, logger, ptree, untilAborted } from "@gajae-code/utils";
2
+ import { formatCrashDiagnosticNotice, writeCrashReport } from "../debug/crash-diagnostics";
2
3
  import { ToolAbortError, throwIfAborted } from "../tools/tool-errors";
3
4
  import { applyWorkspaceEdit } from "./edits";
4
5
  import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
@@ -486,7 +487,7 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string, initT
486
487
  clients.set(key, client);
487
488
 
488
489
  // Register crash recovery - remove client on process exit
489
- proc.exited.then(() => {
490
+ proc.exited.then(async () => {
490
491
  clients.delete(key);
491
492
  clientLocks.delete(key);
492
493
  client.resolveProjectLoaded();
@@ -501,9 +502,24 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string, initT
501
502
  .filter(line => !/^\[\d{2}:\d{2}:\d{2} (?:INF|DBG|VRB)\]/.test(line))
502
503
  .join("\n")
503
504
  .trim();
505
+ const crashNotice = formatCrashDiagnosticNotice(
506
+ await writeCrashReport(
507
+ {
508
+ kind: "lsp",
509
+ command: [command, ...args],
510
+ exitCode: proc.exitCode,
511
+ stderr,
512
+ protocol: "lsp",
513
+ },
514
+ { cwd },
515
+ ),
516
+ );
517
+ const diagnosticSuffix = crashNotice ? `\n${crashNotice}` : "";
504
518
  const code = proc.exitCode;
505
519
  const err = new Error(
506
- stderr ? `LSP server exited (code ${code}): ${stderr}` : `LSP server exited unexpectedly (code ${code})`,
520
+ stderr
521
+ ? `LSP server exited (code ${code}): ${stderr}${diagnosticSuffix}`
522
+ : `LSP server exited unexpectedly (code ${code})${diagnosticSuffix}`,
507
523
  );
508
524
  for (const pending of client.pendingRequests.values()) {
509
525
  pending.reject(err);
package/src/main.ts CHANGED
@@ -32,7 +32,7 @@ import { getDefault, type SettingPath, Settings, settings } from "./config/setti
32
32
  import { initializeWithSettings } from "./discovery";
33
33
  import { exportFromFile } from "./export/html";
34
34
  import type { ExtensionUIContext } from "./extensibility/extensions/types";
35
- import { InteractiveMode, runAcpMode, runPrintMode, runRpcMode } from "./modes";
35
+ import { InteractiveMode, runAcpMode, runBridgeMode, runPrintMode, runRpcMode } from "./modes";
36
36
  import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
37
37
  import type { SubmittedUserInput } from "./modes/types";
38
38
  import type { MCPManager } from "./runtime-mcp";
@@ -707,21 +707,35 @@ export async function runRootCommand(
707
707
  process.exit(0);
708
708
  }
709
709
 
710
- if ((parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui") && parsedArgs.fileArgs.length > 0) {
711
- process.stderr.write(`${chalk.red("Error: @file arguments are not supported in RPC mode")}\n`);
710
+ if (
711
+ (parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui" || parsedArgs.mode === "bridge") &&
712
+ parsedArgs.fileArgs.length > 0
713
+ ) {
714
+ process.stderr.write(`${chalk.red("Error: @file arguments are not supported in RPC or bridge mode")}\n`);
712
715
  process.exit(1);
713
716
  }
714
717
 
715
718
  const cwd = getProjectDir();
716
719
  const settingsInstance = deps.settings ?? (await logger.time("settings:init", Settings.init, { cwd }));
717
- if (parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui" || parsedArgs.mode === "acp") {
720
+ if (
721
+ parsedArgs.mode === "rpc" ||
722
+ parsedArgs.mode === "rpc-ui" ||
723
+ parsedArgs.mode === "acp" ||
724
+ parsedArgs.mode === "bridge"
725
+ ) {
718
726
  applyRpcDefaultSettingOverrides(settingsInstance);
719
727
  }
720
728
  modelRegistry.applyConfiguredModelBindings(settingsInstance);
721
729
  if (parsedArgs.noPty || parsedArgs.mode === "rpc-ui") {
722
730
  Bun.env.PI_NO_PTY = "1";
723
731
  }
724
- if (parsedArgs.noTitle || parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui" || parsedArgs.mode === "acp") {
732
+ if (
733
+ parsedArgs.noTitle ||
734
+ parsedArgs.mode === "rpc" ||
735
+ parsedArgs.mode === "rpc-ui" ||
736
+ parsedArgs.mode === "acp" ||
737
+ parsedArgs.mode === "bridge"
738
+ ) {
725
739
  Bun.env.PI_NO_TITLE = "1";
726
740
  }
727
741
  const { pipedInput, fileText, fileImages } = await logger.time("prepareInitialMessage", async () => {
@@ -894,6 +908,8 @@ export async function runRootCommand(
894
908
 
895
909
  if (mode === "rpc" || mode === "rpc-ui") {
896
910
  await runRpcMode(session, mode === "rpc-ui" ? setToolUIContext : undefined);
911
+ } else if (mode === "bridge") {
912
+ await runBridgeMode(session, setToolUIContext);
897
913
  } else if (isInteractive) {
898
914
  const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
899
915
  const changelogMarkdown = await logger.time("main:getChangelogForDisplay", getChangelogForDisplay, parsedArgs);
@@ -0,0 +1,41 @@
1
+ import * as crypto from "node:crypto";
2
+
3
+ export interface BridgeAuthConfig {
4
+ token: string;
5
+ }
6
+
7
+ export interface BridgeBindConfig {
8
+ hostname: string;
9
+ port: number;
10
+ tlsConfigured: boolean;
11
+ }
12
+
13
+ export function extractBearerToken(authorization: string | null | undefined): string | undefined {
14
+ if (!authorization) return undefined;
15
+ const trimmed = authorization.trim();
16
+ const match = /^Bearer\s+(.+)$/i.exec(trimmed);
17
+ const token = match?.[1]?.trim();
18
+ return token ? token : undefined;
19
+ }
20
+
21
+ export function isBridgeTokenAuthorized(authorization: string | null | undefined, config: BridgeAuthConfig): boolean {
22
+ const candidate = extractBearerToken(authorization);
23
+ if (candidate === undefined) return false;
24
+ const candidateBytes = Buffer.from(candidate, "utf8");
25
+ const expectedBytes = Buffer.from(config.token, "utf8");
26
+ return candidateBytes.length === expectedBytes.length && crypto.timingSafeEqual(candidateBytes, expectedBytes);
27
+ }
28
+
29
+ export function isLoopbackHost(hostname: string): boolean {
30
+ const normalized = hostname.trim().toLowerCase();
31
+ return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "[::1]";
32
+ }
33
+
34
+ export function assertSafeBridgeBind(config: BridgeBindConfig): void {
35
+ if (!config.tlsConfigured) {
36
+ throw new Error(
37
+ `Refusing to start bridge on ${config.hostname}:${config.port} without TLS configured. ` +
38
+ "Set GJC_BRIDGE_TLS_CERT and GJC_BRIDGE_TLS_KEY.",
39
+ );
40
+ }
41
+ }
@@ -0,0 +1,47 @@
1
+ import type {
2
+ ClientBridge,
3
+ ClientBridgePermissionOption,
4
+ ClientBridgePermissionOutcome,
5
+ ClientBridgePermissionToolCall,
6
+ } from "../../session/client-bridge";
7
+ import type { UiRequestBroker, UiRequestCancelled, UiRequestResolution } from "../shared/agent-wire/ui-request-broker";
8
+
9
+ export interface BridgePermissionRequestPayload {
10
+ kind: "permission";
11
+ toolCall: ClientBridgePermissionToolCall;
12
+ options: ClientBridgePermissionOption[];
13
+ }
14
+
15
+ export type BridgePermissionBroker = UiRequestBroker<BridgePermissionRequestPayload, ClientBridgePermissionOutcome>;
16
+ function isUiRequestCancelled(
17
+ resolution: UiRequestResolution<ClientBridgePermissionOutcome>,
18
+ ): resolution is UiRequestCancelled {
19
+ return "status" in resolution && resolution.status === "cancelled";
20
+ }
21
+
22
+ function toPermissionOutcome(
23
+ resolution: UiRequestResolution<ClientBridgePermissionOutcome>,
24
+ ): ClientBridgePermissionOutcome {
25
+ if (isUiRequestCancelled(resolution)) {
26
+ return { outcome: "cancelled" };
27
+ }
28
+ return resolution;
29
+ }
30
+
31
+ export function createBridgeClientBridge(broker: BridgePermissionBroker): ClientBridge {
32
+ return {
33
+ capabilities: { requestPermission: true },
34
+ deferAgentInitiatedTurns: true,
35
+ async requestPermission(toolCall, options, signal) {
36
+ return toPermissionOutcome(
37
+ await broker.request(
38
+ { kind: "permission", toolCall, options },
39
+ {
40
+ correlationId: toolCall.toolCallId,
41
+ signal,
42
+ },
43
+ ),
44
+ );
45
+ },
46
+ };
47
+ }