@gajae-code/coding-agent 0.6.3 → 0.6.5

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 (140) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +73 -1
  3. package/dist/types/cli/migrate-cli.d.ts +20 -0
  4. package/dist/types/commands/migrate.d.ts +33 -0
  5. package/dist/types/config/keybindings.d.ts +4 -0
  6. package/dist/types/config/settings-schema.d.ts +27 -0
  7. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
  8. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
  9. package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
  10. package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
  11. package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
  12. package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
  13. package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
  14. package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
  15. package/dist/types/gjc-runtime/state-writer.d.ts +36 -7
  16. package/dist/types/gjc-runtime/tmux-sessions.d.ts +2 -0
  17. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +7 -4
  18. package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
  19. package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
  20. package/dist/types/harness-control-plane/storage.d.ts +2 -1
  21. package/dist/types/hooks/skill-state.d.ts +12 -4
  22. package/dist/types/migrate/action-planner.d.ts +11 -0
  23. package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
  24. package/dist/types/migrate/adapters/codex.d.ts +5 -0
  25. package/dist/types/migrate/adapters/index.d.ts +45 -0
  26. package/dist/types/migrate/adapters/opencode.d.ts +2 -0
  27. package/dist/types/migrate/executor.d.ts +2 -0
  28. package/dist/types/migrate/mcp-mapper.d.ts +20 -0
  29. package/dist/types/migrate/report.d.ts +18 -0
  30. package/dist/types/migrate/skill-normalizer.d.ts +27 -0
  31. package/dist/types/migrate/types.d.ts +126 -0
  32. package/dist/types/modes/components/custom-editor.d.ts +1 -1
  33. package/dist/types/modes/components/welcome.d.ts +3 -1
  34. package/dist/types/modes/interactive-mode.d.ts +3 -0
  35. package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -0
  36. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
  37. package/dist/types/research-plan/index.d.ts +1 -0
  38. package/dist/types/research-plan/ledger.d.ts +33 -0
  39. package/dist/types/rlm/artifacts.d.ts +1 -1
  40. package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
  41. package/dist/types/skill-state/active-state.d.ts +6 -11
  42. package/dist/types/skill-state/canonical-skills.d.ts +3 -0
  43. package/dist/types/skill-state/workflow-hud.d.ts +2 -0
  44. package/dist/types/task/spawn-gate.d.ts +1 -10
  45. package/package.json +7 -7
  46. package/src/cli/migrate-cli.ts +106 -0
  47. package/src/cli/setup-cli.ts +14 -1
  48. package/src/cli.ts +1 -0
  49. package/src/commands/deep-interview.ts +2 -2
  50. package/src/commands/launch.ts +1 -1
  51. package/src/commands/migrate.ts +46 -0
  52. package/src/commands/state.ts +2 -1
  53. package/src/commands/team.ts +7 -3
  54. package/src/config/model-registry.ts +9 -2
  55. package/src/config/model-resolver.ts +13 -2
  56. package/src/config/settings-schema.ts +17 -0
  57. package/src/coordinator-mcp/policy.ts +10 -2
  58. package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
  59. package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
  60. package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
  61. package/src/defaults/gjc/skills/team/SKILL.md +51 -47
  62. package/src/defaults/gjc/skills/ultragoal/SKILL.md +17 -13
  63. package/src/exec/bash-executor.ts +3 -1
  64. package/src/extensibility/custom-commands/loader.ts +0 -7
  65. package/src/extensibility/gjc-plugins/injection.ts +23 -4
  66. package/src/extensibility/gjc-plugins/state.ts +16 -1
  67. package/src/gjc-runtime/deep-interview-recorder.ts +43 -18
  68. package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
  69. package/src/gjc-runtime/goal-mode-request.ts +26 -11
  70. package/src/gjc-runtime/launch-tmux.ts +68 -15
  71. package/src/gjc-runtime/ralplan-runtime.ts +79 -50
  72. package/src/gjc-runtime/session-layout.ts +180 -0
  73. package/src/gjc-runtime/session-resolution.ts +217 -0
  74. package/src/gjc-runtime/state-graph.ts +1 -2
  75. package/src/gjc-runtime/state-migrations.ts +1 -0
  76. package/src/gjc-runtime/state-runtime.ts +230 -121
  77. package/src/gjc-runtime/state-schema.ts +2 -0
  78. package/src/gjc-runtime/state-writer.ts +289 -41
  79. package/src/gjc-runtime/team-runtime.ts +43 -19
  80. package/src/gjc-runtime/tmux-sessions.ts +43 -2
  81. package/src/gjc-runtime/ultragoal-guard.ts +45 -2
  82. package/src/gjc-runtime/ultragoal-runtime.ts +121 -41
  83. package/src/gjc-runtime/workflow-command-ref.ts +1 -2
  84. package/src/gjc-runtime/workflow-manifest.ts +1 -2
  85. package/src/harness-control-plane/storage.ts +14 -4
  86. package/src/hooks/native-skill-hook.ts +38 -12
  87. package/src/hooks/skill-state.ts +178 -83
  88. package/src/internal-urls/docs-index.generated.ts +9 -6
  89. package/src/migrate/action-planner.ts +318 -0
  90. package/src/migrate/adapters/claude-code.ts +39 -0
  91. package/src/migrate/adapters/codex.ts +70 -0
  92. package/src/migrate/adapters/index.ts +277 -0
  93. package/src/migrate/adapters/opencode.ts +52 -0
  94. package/src/migrate/executor.ts +81 -0
  95. package/src/migrate/mcp-mapper.ts +152 -0
  96. package/src/migrate/report.ts +104 -0
  97. package/src/migrate/skill-normalizer.ts +80 -0
  98. package/src/migrate/types.ts +163 -0
  99. package/src/modes/bridge/bridge-mode.ts +2 -2
  100. package/src/modes/components/custom-editor.ts +30 -20
  101. package/src/modes/components/welcome.ts +42 -9
  102. package/src/modes/controllers/input-controller.ts +21 -3
  103. package/src/modes/interactive-mode.ts +22 -1
  104. package/src/modes/prompt-action-autocomplete.ts +11 -1
  105. package/src/modes/rpc/rpc-mode.ts +2 -2
  106. package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
  107. package/src/prompts/agents/init.md +1 -1
  108. package/src/prompts/system/plan-mode-active.md +1 -1
  109. package/src/prompts/tools/ast-grep.md +1 -1
  110. package/src/prompts/tools/search.md +1 -1
  111. package/src/prompts/tools/task.md +1 -2
  112. package/src/research-plan/index.ts +1 -0
  113. package/src/research-plan/ledger.ts +177 -0
  114. package/src/rlm/artifacts.ts +12 -3
  115. package/src/rlm/index.ts +7 -0
  116. package/src/runtime-mcp/config-writer.ts +46 -0
  117. package/src/session/agent-session.ts +15 -21
  118. package/src/session/session-manager.ts +19 -2
  119. package/src/setup/hermes/templates/operator-instructions.v1.md +8 -0
  120. package/src/setup/hermes-setup.ts +1 -1
  121. package/src/skill-state/active-state.ts +72 -108
  122. package/src/skill-state/canonical-skills.ts +4 -0
  123. package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
  124. package/src/skill-state/workflow-hud.ts +4 -2
  125. package/src/skill-state/workflow-state-contract.ts +3 -3
  126. package/src/slash-commands/builtin-registry.ts +8 -4
  127. package/src/system-prompt.ts +11 -9
  128. package/src/task/agents.ts +1 -22
  129. package/src/task/index.ts +1 -41
  130. package/src/task/spawn-gate.ts +1 -38
  131. package/src/task/types.ts +1 -1
  132. package/src/tools/ask.ts +34 -12
  133. package/src/tools/computer.ts +58 -4
  134. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
  135. package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
  136. package/src/prompts/agents/explore.md +0 -58
  137. package/src/prompts/agents/plan.md +0 -49
  138. package/src/prompts/agents/reviewer.md +0 -141
  139. package/src/prompts/agents/task.md +0 -16
  140. package/src/prompts/review-request.md +0 -70
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.6.5] - 2026-06-21
6
+
7
+ ### Changed
8
+
9
+ - Scoped all GJC workflow state by session ID: skill state, plans, specs, and ledgers now live under per-session `.gjc/_session-{id}/` directories, so concurrent or resumed sessions no longer collide on shared workflow state.
10
+ - Hardened skill-state hooks with a writer revision policy, a force-ask on Stop, HUD reconciliation, and an fd-duplication guard; forced/authoritative state writes now survive corrupt prior state (#950).
11
+ - Migrated the global debug shortcut into the keybinding registry and added `pasteImage` as a single source of truth with default-collision diagnostics (#925, #939).
12
+ - Added safe import of custom skills and MCP servers via `migrate` (#944).
13
+ - Trimmed the bundled agent roster to the four canonical role agents: planner, architect, critic, and executor (#922).
14
+ - Added a research-plan ledger spike (#933).
15
+
16
+ ### Fixed
17
+
18
+ - Stopped including `bash` in the planning-phase mutation guard. The phase-boundary block (and the always-on `.gjc/**` runtime-owned block) now apply only to the fully-pathed `write`/`edit`/`ast_edit` tools; `bash` is never blocked by any workflow skill (`deep-interview`, `ralplan`, `ultragoal` goal-planning), so read-only shell commands run freely during planning. This reverts the `bash` parity added in 0.6.2; product-code and `.gjc/**` mutation are still gated through the dedicated edit tools (#951).
19
+ - Rejected counterexample-only claims in research-plan regardless of `dropCondition` wording (#942).
20
+ - Bounded computer-use screenshot inline images to avoid oversized payloads.
21
+ - Tolerated missing session env in guard reads (#930).
22
+
23
+ ### Documentation
24
+
25
+ - Documented standalone MCP boundaries (#923).
26
+
27
+ ## [0.6.4] - 2026-06-20
28
+
29
+ ### Changed
30
+
31
+ - Added `startup.welcomeBannerMode = "square"` for a square-corner Unicode welcome-logo fallback, and stopped treating Windows Terminal (`WT_SESSION`) as an automatic ASCII downgrade; `auto` now preserves the rounded Unicode logo while `unicode`, `square`, and `ascii` remain explicit overrides.
32
+
33
+ - Improved image input discoverability by adding an interactive `#paste-image` prompt action and clearer clipboard fallback guidance when no image is available.
34
+
35
+ - Improved skill migration guidance for users moving custom skills onto the current skill system (#899).
36
+
37
+ ### Fixed
38
+
39
+ - Fixed native Windows tmux launch and hardened Windows tmux root launch, and resolved follow-up Windows tmux launch and input regressions (#884, #895, #906).
40
+ - Fixed `EXDEV` failures when moving session artifacts across filesystems (cross-device session artifact moves) (#886).
41
+ - Excluded user context files from the project prompt so file-level context filtering no longer leaks user-scoped files into project context (#885).
42
+ - Fixed a bash cancellation descendant-cleanup race so cancellation now waits for child-process cleanup within a bounded stall prompt (#893).
43
+ - Fixed the TUI dropping the first `/goal set <objective>` command from input history: the typed command is now recorded whenever args are supplied, regardless of prior goal-mode state (#910).
44
+ - Fixed Ctrl+Enter/Ctrl+Shift+Enter newline handling in the editor: idle Ctrl+Enter now falls through to newline insertion while keeping Ctrl+Enter as the busy-session follow-up shortcut, and Ctrl+Shift+Enter inserts a newline (#911).
45
+ - Fixed parsing of psmux modified-enter key sequences in the TUI (#918).
46
+
47
+ ### Documentation
48
+
49
+ - Documented Windows Terminal welcome-logo troubleshooting with Cascadia Mono / Cascadia Mono Nerd Font and the profile `fontFace` setting.
50
+ - Documented CLI `@image` attachments and interactive TUI clipboard image paste fallbacks in the root README.
51
+
52
+ - Documented lifecycle notification hooks (#903).
53
+ - Added a routed GJC session guide for Clawhip/Hermes/OpenClaw visible routed sessions and linked it from the Hermes docs and operator instructions.
54
+
5
55
  ## [0.6.3] - 2026-06-19
6
56
 
7
57
  ### Fixed
package/README.md CHANGED
@@ -11,9 +11,69 @@ Package-specific references:
11
11
  - [DEVELOPMENT](./DEVELOPMENT.md)
12
12
  - [RenderMermaid guide](../../docs/render-mermaid.md)
13
13
 
14
+ ## External lifecycle notifications
15
+
16
+ GJC already exposes public lifecycle events through the extension/hook event contract. External notification integrations for Discord, Hermes, clawhip, or similar channels should be opt-in and subscribe to these events instead of scraping transcripts or logs:
17
+
18
+ - `turn_end` — a model/tool turn finished. The public payload is `{ type: "turn_end", turnIndex, message, toolResults }`.
19
+ - `agent_end` — the agent loop for a submitted prompt reached a terminal boundary. The public payload is `{ type: "agent_end", messages }`.
20
+
21
+ Recommended external mapping:
22
+
23
+ | Notification | Public event | Status guidance |
24
+ |---|---|---|
25
+ | Turn finished | `turn_end` | Use the handler's own sanitized status such as `"finished"`. |
26
+ | Agent stopped/finished | `agent_end` | Treat as terminal for the prompt. |
27
+ | Waiting/blocked/failed | `agent_end` plus a caller-supplied safe summary | Current lifecycle events do not expose a separate structured waiting/blocked reason; inspect only public-safe, integration-owned state. |
28
+
29
+ Forward only a minimal, caller-sanitized payload. Do not include raw prompts, assistant transcripts, hidden prompts, tool outputs, raw logs, host paths, private config, webhook URLs, channel IDs, tokens, or secrets. A safe notification payload should be built by the extension/hook itself, for example:
30
+
31
+ ```ts
32
+ import type { ExtensionAPI } from "@gajae-code/coding-agent";
33
+
34
+ type PublicLifecycleNotification = {
35
+ type: "turn_end" | "agent_end";
36
+ status: "finished" | "stopped" | "failed" | "blocked" | "waiting";
37
+ turnIndex?: number;
38
+ timestamp: string;
39
+ summary: string;
40
+ };
41
+
42
+ export default function lifecycleNotifier(pi: ExtensionAPI) {
43
+ const enabled = process.env.GJC_LIFECYCLE_NOTIFY === "1";
44
+ if (!enabled) return;
45
+
46
+ const send = async (payload: PublicLifecycleNotification) => {
47
+ // POST to Discord/Hermes/clawhip here. Keep target URLs and channel IDs in
48
+ // private config or environment variables; never include them in payloads.
49
+ };
50
+
51
+ pi.on("turn_end", event =>
52
+ send({
53
+ type: "turn_end",
54
+ status: "finished",
55
+ turnIndex: event.turnIndex,
56
+ timestamp: new Date().toISOString(),
57
+ summary: "GJC turn finished",
58
+ }),
59
+ );
60
+
61
+ pi.on("agent_end", () =>
62
+ send({
63
+ type: "agent_end",
64
+ status: "stopped",
65
+ timestamp: new Date().toISOString(),
66
+ summary: "GJC prompt reached a terminal lifecycle boundary",
67
+ }),
68
+ );
69
+ }
70
+ ```
71
+
72
+ This is the supported repo-native lifecycle notification path. It is not Claude Code hook compatibility, and it remains disabled unless the user configures an extension/hook handler and private delivery target.
73
+
14
74
  ## Memory backends
15
75
 
16
- The agent supports three mutually-exclusive memory backends, selected via the `memory.backend` setting (Settings → Memory tab, or `~/.gjc/config.yml`):
76
+ The agent supports three mutually-exclusive memory backends, selected via the `memory.backend` setting (Settings → Memory tab, or `~/.gjc/agent/config.yml`):
17
77
 
18
78
  - `off` (default) — no memory subsystem runs.
19
79
  - `local` — existing rollout-summarisation pipeline; writes `memory_summary.md` and consolidated artifacts under the agent dir.
@@ -35,3 +95,15 @@ Switching backends mid-session is honoured on the next system-prompt rebuild and
35
95
  ## Red-claw TUI theme
36
96
 
37
97
  The interactive TUI defaults to the bundled `red-claw` crustacean theme for dark terminals and the bundled `blue-crab` theme for light-appearance terminals, with matching welcome/icon assets. Three additional bundled migration themes — `claude-code`, `codex`, and `opencode` — mirror the look of those tools for easy eye-migration and are selectable from Settings or `/theme`. Explicit user theme settings still win; set `theme.dark: red-claw` and `theme.light: blue-crab` in `~/.gjc/agent/config.yml` to pin them.
98
+
99
+ ### Welcome banner fonts on Windows Terminal
100
+
101
+ The startup logo defaults to rounded Unicode box drawing. Windows Terminal can render it correctly when the selected profile font has the needed box-drawing glyphs; recommended choices are `Cascadia Mono` or `Cascadia Mono Nerd Font`. In Windows Terminal Settings, set the profile font face to one of those fonts, or add it to the profile JSON:
102
+
103
+ ```json
104
+ "font": {
105
+ "face": "Cascadia Mono"
106
+ }
107
+ ```
108
+
109
+ For terminals or fonts with broken rounded corners, set `startup.welcomeBannerMode` in `~/.gjc/agent/config.yml` to one of `unicode`, `square`, or `ascii`. `square` keeps a Unicode-looking logo using square corners (`┌ ┐ └ ┘`) while `ascii` uses only `+`, `-`, and `|`.
@@ -0,0 +1,20 @@
1
+ import { type MigrateReport, type MigrateSource } from "../migrate/types";
2
+ export interface MigrateCommandArgs {
3
+ from: string[];
4
+ project: boolean;
5
+ force: boolean;
6
+ dryRun: boolean;
7
+ json: boolean;
8
+ /** Test seam: override home dir for source discovery. */
9
+ homeDir?: string;
10
+ /** Test seam: override cwd for project-scope destinations. */
11
+ cwd?: string;
12
+ }
13
+ export declare class MigrateArgsError extends Error {
14
+ }
15
+ /** Expand `all`/repeated `--from`, validate, and return sources in canonical order. */
16
+ export declare function resolveSources(from: string[]): MigrateSource[];
17
+ /** Run the migration and return the report (does not set process.exitCode). */
18
+ export declare function runMigrate(args: MigrateCommandArgs): Promise<MigrateReport>;
19
+ /** CLI entry: run, render, and set the process exit code. */
20
+ export declare function runMigrateCommand(args: MigrateCommandArgs): Promise<void>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Import MCP servers and skills from other coding agents into GJC.
3
+ */
4
+ import { Command } from "@gajae-code/utils/cli";
5
+ export default class Migrate extends Command {
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ from: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
10
+ description: string;
11
+ multiple: true;
12
+ required: true;
13
+ };
14
+ project: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
15
+ description: string;
16
+ default: boolean;
17
+ };
18
+ force: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
19
+ description: string;
20
+ default: boolean;
21
+ };
22
+ "dry-run": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
23
+ description: string;
24
+ default: boolean;
25
+ };
26
+ json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
27
+ char: string;
28
+ description: string;
29
+ default: boolean;
30
+ };
31
+ };
32
+ run(): Promise<void>;
33
+ }
@@ -173,6 +173,10 @@ export declare const KEYBINDINGS: {
173
173
  readonly defaultKeys: ["escape", "ctrl+c"];
174
174
  readonly description: "Cancel selection";
175
175
  };
176
+ readonly "tui.global.debug": {
177
+ readonly defaultKeys: "shift+ctrl+d";
178
+ readonly description: "Toggle debug overlay";
179
+ };
176
180
  readonly "app.interrupt": {
177
181
  readonly defaultKeys: "escape";
178
182
  readonly description: "Interrupt current operation";
@@ -1195,6 +1195,33 @@ export declare const SETTINGS_SCHEMA: {
1195
1195
  readonly description: "Skip welcome screen and startup status messages";
1196
1196
  };
1197
1197
  };
1198
+ readonly "startup.welcomeBannerMode": {
1199
+ readonly type: "enum";
1200
+ readonly values: readonly ["auto", "unicode", "square", "ascii"];
1201
+ readonly default: "auto";
1202
+ readonly ui: {
1203
+ readonly tab: "interaction";
1204
+ readonly label: "Welcome Banner Mode";
1205
+ readonly description: "Logo style for the startup welcome screen";
1206
+ readonly options: readonly [{
1207
+ readonly value: "auto";
1208
+ readonly label: "Auto";
1209
+ readonly description: "Use the rounded Unicode logo";
1210
+ }, {
1211
+ readonly value: "unicode";
1212
+ readonly label: "Unicode";
1213
+ readonly description: "Force the rounded Unicode logo";
1214
+ }, {
1215
+ readonly value: "square";
1216
+ readonly label: "Square Unicode";
1217
+ readonly description: "Force the square-corner Unicode fallback";
1218
+ }, {
1219
+ readonly value: "ascii";
1220
+ readonly label: "ASCII";
1221
+ readonly description: "Force the ASCII-safe logo";
1222
+ }];
1223
+ };
1224
+ };
1198
1225
  readonly "startup.checkUpdate": {
1199
1226
  readonly type: "boolean";
1200
1227
  readonly default: true;
@@ -84,6 +84,8 @@ export declare function ensureDeepInterviewStateShape(value: unknown): DeepInter
84
84
  export declare function projectCompactState(value: unknown, options?: {
85
85
  lastN?: number;
86
86
  }): DeepInterviewCompactState;
87
+ /** Refresh the best-effort HUD cache from persisted deep-interview state. */
88
+ export declare function syncDeepInterviewRecorderHud(cwd: string, statePath: string, sessionId: string | undefined): Promise<void>;
87
89
  /** Record an `answered` shell for one round (append-or-merge by durable key). */
88
90
  export declare function appendOrMergeDeepInterviewRound(cwd: string, statePath: string, input: DeepInterviewAnswerInput, options?: {
89
91
  sessionId?: string;
@@ -13,12 +13,12 @@ export interface DeepInterviewCommandResult {
13
13
  stdout?: string;
14
14
  stderr?: string;
15
15
  }
16
- export declare function deepInterviewStatePath(cwd: string, sessionId: string | undefined): string;
16
+ export declare function deepInterviewStatePath(cwd: string, sessionId?: string): string;
17
17
  export interface ResolvedDeepInterviewSpecWriteArgs {
18
18
  stage: "final";
19
19
  slug: string;
20
20
  spec: string;
21
- sessionId?: string;
21
+ sessionId: string;
22
22
  json: boolean;
23
23
  deliberate: boolean;
24
24
  handoff?: "ralplan";
@@ -30,7 +30,7 @@ export type CurrentSessionGoalModeWriteResult = {
30
30
  sessionFile: string;
31
31
  };
32
32
  export declare function isUltragoalCreateGoalsInvocation(args: readonly string[]): boolean;
33
- export declare function readUltragoalGjcObjective(cwd: string): Promise<{
33
+ export declare function readUltragoalGjcObjective(cwd: string, sessionId?: string | null): Promise<{
34
34
  objective: string;
35
35
  goalsPath: string;
36
36
  }>;
@@ -0,0 +1,59 @@
1
+ export declare const GJC_DIR = ".gjc";
2
+ export declare const GJC_SESSION_PREFIX = "_session-";
3
+ export declare const GJC_SESSION_ACTIVITY_FILE = ".session-activity.json";
4
+ /** Source that produced a resolved GJC session id, for audit/diagnostics. */
5
+ export type GjcSessionSource = "flag" | "payload" | "env" | "latest";
6
+ export interface GjcSessionContext {
7
+ gjcSessionId: string;
8
+ sessionRoot: string;
9
+ source: GjcSessionSource;
10
+ }
11
+ /**
12
+ * Encode a session id into a single safe path segment. Matches the historical
13
+ * encoding used across the runtimes so ids round-trip identically:
14
+ * `encodeURIComponent` plus dot-escaping (dots are legal in filenames but we
15
+ * avoid `.`/`..` traversal ambiguity).
16
+ */
17
+ export declare function encodeSessionSegment(value: string): string;
18
+ /** Inverse of {@link encodeSessionSegment}. */
19
+ export declare function decodeSessionSegment(segment: string): string;
20
+ /** Throw when a session id is missing or blank; never let blank suppress callers. */
21
+ export declare function assertNonEmptyGjcSessionId(value: string | undefined, source: string): asserts value is string;
22
+ /**
23
+ * Assert a value is safe to use as a single path segment: non-blank and free of
24
+ * path separators or `.`/`..` traversal. Use for already-safe identifiers
25
+ * (skill modes, slugs) where we want identical filenames but fail closed on
26
+ * traversal rather than silently normalizing out of the intended directory.
27
+ */
28
+ export declare function assertSafePathComponent(value: string, label: string): void;
29
+ /** The shared `.gjc/` root (holds shared config; never session-scoped). */
30
+ export declare function gjcRoot(cwd: string): string;
31
+ /** The per-session root directory: `<cwd>/.gjc/_session-{encodedId}`. */
32
+ export declare function sessionRoot(cwd: string, gjcSessionId: string): string;
33
+ /** Directory name (no path) for a session id, e.g. `_session-abc`. */
34
+ export declare function sessionDirName(gjcSessionId: string): string;
35
+ /** Return the decoded session id for a `_session-*` directory name, else undefined. */
36
+ export declare function sessionIdFromDirName(name: string): string | undefined;
37
+ /** Authoritative per-session activity marker path. */
38
+ export declare function sessionActivityPath(cwd: string, gjcSessionId: string): string;
39
+ export declare function sessionStateDir(cwd: string, gjcSessionId: string): string;
40
+ export declare function sessionSpecsDir(cwd: string, gjcSessionId: string): string;
41
+ export declare function sessionPlansDir(cwd: string, gjcSessionId: string): string;
42
+ export declare function sessionUltragoalDir(cwd: string, gjcSessionId: string): string;
43
+ export declare function sessionAuditDir(cwd: string, gjcSessionId: string): string;
44
+ export declare function sessionReportsDir(cwd: string, gjcSessionId: string): string;
45
+ export declare function sessionLogsDir(cwd: string, gjcSessionId: string): string;
46
+ export declare function sessionRuntimeDir(cwd: string, gjcSessionId: string): string;
47
+ export declare function sessionRlmDir(cwd: string, gjcSessionId: string): string;
48
+ export declare function activeStateDir(cwd: string, gjcSessionId: string): string;
49
+ export declare function activeSnapshotPath(cwd: string, gjcSessionId: string): string;
50
+ export declare function activeEntryPath(cwd: string, gjcSessionId: string, skill: string): string;
51
+ export declare function modeStatePath(cwd: string, gjcSessionId: string, mode: string): string;
52
+ export declare function auditPath(cwd: string, gjcSessionId: string): string;
53
+ export declare function transactionJournalPath(cwd: string, gjcSessionId: string, mutationId: string): string;
54
+ export declare function teamStateRoot(cwd: string, gjcSessionId: string): string;
55
+ export declare function workflowGatePath(cwd: string, gjcSessionId: string, gateId: string): string;
56
+ export declare function harnessStateRoot(cwd: string, gjcSessionId: string): string;
57
+ export declare function coordinatorMcpStateRoot(cwd: string, gjcSessionId: string): string;
58
+ export declare function tmuxRuntimeSessionPath(cwd: string, gjcSessionId: string, slug: string): string;
59
+ export declare function rlmArtifactRoot(cwd: string, gjcSessionId: string, rlmSessionId: string): string;
@@ -0,0 +1,47 @@
1
+ import { type GjcSessionContext, type GjcSessionSource } from "./session-layout";
2
+ /** Window within which two activity timestamps are treated as an ambiguous tie. */
3
+ export declare const LATEST_SESSION_TIE_WINDOW_MS = 1000;
4
+ export interface SessionIdSources {
5
+ /** Raw `--session-id` value: `undefined` = flag absent; `""` = present-but-blank (invalid). */
6
+ flagValue?: string | undefined;
7
+ payloadSessionId?: unknown;
8
+ envSessionId?: string | undefined;
9
+ }
10
+ export declare class SessionResolutionError extends Error {
11
+ readonly code: "blank_flag" | "no_session" | "ambiguous" | "missing_for_write";
12
+ constructor(message: string, code: "blank_flag" | "no_session" | "ambiguous" | "missing_for_write");
13
+ }
14
+ interface ResolvedFromSources {
15
+ gjcSessionId: string;
16
+ source: GjcSessionSource;
17
+ }
18
+ /**
19
+ * Resolve a session id from explicit sources only (flag -> payload -> env).
20
+ * Returns `undefined` when none is present. A blank explicit flag throws.
21
+ */
22
+ export declare function resolveSessionIdFromSources(sources: SessionIdSources): ResolvedFromSources | undefined;
23
+ /** Resolve session context for a WRITE command. Errors when no explicit id is present. */
24
+ export declare function resolveGjcSessionForWrite(cwd: string, sources: SessionIdSources): GjcSessionContext;
25
+ /**
26
+ * Resolve session context for a READ/STATUS/CLEAR command. Falls back to the
27
+ * latest active session by activity marker when no explicit id is present.
28
+ */
29
+ export declare function resolveGjcSessionForRead(cwd: string, sources: SessionIdSources): Promise<GjcSessionContext>;
30
+ /**
31
+ * Scan `.gjc/_session-*` directories and select the most-recently-active one by
32
+ * its activity marker. Never uses raw directory mtime. Throws on zero candidates
33
+ * or an ambiguous tie.
34
+ */
35
+ export declare function detectLatestSession(cwd: string): Promise<GjcSessionContext>;
36
+ export interface ActivityMarkerInfo {
37
+ writer: string;
38
+ /** Relative generated path that was just written, for diagnostics. */
39
+ path?: string;
40
+ }
41
+ /**
42
+ * Best-effort write of the per-session activity marker. State-command callers
43
+ * MUST treat a thrown error as a command failure (auto-detect depends on it);
44
+ * non-critical writers may swallow it.
45
+ */
46
+ export declare function writeSessionActivityMarker(cwd: string, gjcSessionId: string, info: ActivityMarkerInfo): Promise<void>;
47
+ export {};
@@ -1,4 +1,4 @@
1
- import type { CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
1
+ import { type CanonicalGjcWorkflowSkill } from "../skill-state/canonical-skills";
2
2
  export type StateGraphSkill = CanonicalGjcWorkflowSkill | "all";
3
3
  export type StateGraphFormat = "ascii" | "mermaid" | "dot";
4
4
  export declare function renderStateGraph(skill: StateGraphSkill, format?: string): string;
@@ -2,9 +2,9 @@ import { type CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
2
2
  /**
3
3
  * Native implementation of the `gjc state read|write|clear` command surface.
4
4
  *
5
- * Simple file-receipt operations against `.gjc/state/[sessions/<id>/]<mode>-state.json` and
6
- * `.gjc/state/[sessions/<id>/]skill-active-state.json`. This is the sanctioned CLI mediator for
7
- * the mutation-guarded `.gjc/state` ACL — agents call it instead of editing those files directly.
5
+ * Simple file-receipt operations against session-scoped state under
6
+ * `.gjc/_session-{id}/state/`. This is the sanctioned CLI mediator for
7
+ * mutation-guarded GJC state — agents call it instead of editing those files directly.
8
8
  */
9
9
  export interface StateCommandResult {
10
10
  status: number;
@@ -24,12 +24,13 @@ export interface StateCommandResult {
24
24
  export declare function reconcileWorkflowSkillState(options: {
25
25
  cwd: string;
26
26
  mode: CanonicalGjcWorkflowSkill;
27
- sessionId: string | undefined;
27
+ sessionId?: string;
28
28
  threadId?: string;
29
29
  turnId?: string;
30
30
  active: boolean;
31
31
  phase: string;
32
32
  payload: Record<string, unknown>;
33
+ sourceRevision?: number;
33
34
  }): Promise<{
34
35
  stateFile: string;
35
36
  }>;
@@ -84,6 +84,7 @@ export declare const WorkflowStateEnvelopeSchema: z.ZodObject<{
84
84
  computed_at: z.ZodString;
85
85
  }, z.core.$loose>>;
86
86
  }, z.core.$loose>>;
87
+ state_revision: z.ZodOptional<z.ZodNumber>;
87
88
  }, z.core.$loose>;
88
89
  /**
89
90
  * Strict receipt required on WRITE (post checksum-stamping). Anchored to the
@@ -164,6 +165,7 @@ export declare const RequiredOnWriteEnvelopeSchema: z.ZodObject<{
164
165
  computed_at: z.ZodString;
165
166
  }, z.core.$loose>;
166
167
  }, z.core.$loose>;
168
+ state_revision: z.ZodOptional<z.ZodNumber>;
167
169
  }, z.core.$loose>;
168
170
  /** Per-skill mode state consumed by hooks / the mutation guard. */
169
171
  export declare const ModeStateSchema: z.ZodObject<{
@@ -11,7 +11,7 @@ import { type AuditEntry, type CanonicalGjcWorkflowSkill, type WorkflowStateMuta
11
11
  * supplied mutation context. No lockfiles are used; isolation is by atomic rename,
12
12
  * append, O_EXCL creates, conditional deletes, per-entry active-state files,
13
13
  * and derived active-state snapshots.
14
- * Transaction journals are per mutation id under `.gjc/state/transactions/`;
14
+ * Transaction journals are per mutation id under the session state transactions directory;
15
15
  * they are recovery evidence only, never global locks or waiters, so stale
16
16
  * journals do not block unrelated state reads or writes.
17
17
  */
@@ -24,9 +24,14 @@ export interface StateWriterReceiptContext {
24
24
  sessionId?: string;
25
25
  mutationId?: string;
26
26
  nowIso?: string;
27
+ verb?: string;
28
+ fromPhase?: string;
29
+ toPhase?: string;
30
+ forced?: boolean;
27
31
  }
28
32
  export interface StateWriterAuditContext {
29
33
  cwd?: string;
34
+ sessionId?: string;
30
35
  category: WriterCategory;
31
36
  verb: string;
32
37
  owner: WorkflowStateMutationOwner;
@@ -52,10 +57,25 @@ export interface WorkflowTransactionJournal {
52
57
  paths: string[];
53
58
  steps: string[];
54
59
  }
60
+ export type StateWritePolicy = "source" | "cache";
61
+ export interface GuardedStateWriterOptions extends StateWriterOptions {
62
+ policy: StateWritePolicy;
63
+ expectedRevision?: number;
64
+ sourceRevision?: number;
65
+ }
66
+ export type GuardedWriteResult = {
67
+ path: string;
68
+ written: true;
69
+ } | {
70
+ path: string;
71
+ written: false;
72
+ reason: "stale-skip";
73
+ };
55
74
  export interface StateWriterOptions {
56
75
  cwd?: string;
57
76
  receipt?: StateWriterReceiptContext;
58
77
  audit?: StateWriterAuditContext;
78
+ sourceRevision?: number;
59
79
  /**
60
80
  * Cross-process lock tuning for read-modify-write paths that route through
61
81
  * `withWorkflowStateLock` / `updateJsonAtomic`. Omit for the hardened
@@ -63,6 +83,12 @@ export interface StateWriterOptions {
63
83
  */
64
84
  lock?: FileLockOptions;
65
85
  }
86
+ export declare class StateWriteConflictError extends Error {
87
+ readonly path: string;
88
+ readonly expectedRevision: number;
89
+ readonly persistedRevision: number;
90
+ constructor(path: string, expectedRevision: number, persistedRevision: number);
91
+ }
66
92
  export interface DeleteIfOwnedOptions extends StateWriterOptions {
67
93
  predicate?: (current: unknown) => boolean | Promise<boolean>;
68
94
  }
@@ -113,6 +139,9 @@ export declare function readExistingStateForMutation(filePath: string): Promise<
113
139
  export declare function workflowEnvelopeContentSha256(value: unknown): string;
114
140
  export declare function stampWorkflowEnvelopeChecksum<T>(value: T, filePath: string, computedAt?: string): T;
115
141
  export declare function detectWorkflowEnvelopeIntegrityMismatch(filePath: string): Promise<WorkflowEnvelopeIntegrityMismatch | undefined>;
142
+ export declare function persistedStateRevision(value: unknown): number;
143
+ export declare function writeGuardedJsonAtomic(targetPath: string, value: unknown, options: GuardedStateWriterOptions): Promise<GuardedWriteResult>;
144
+ export declare function writeGuardedWorkflowEnvelopeAtomic(targetPath: string, value: unknown, options: GuardedStateWriterOptions): Promise<GuardedWriteResult>;
116
145
  export declare function writeJsonAtomic(targetPath: string, value: unknown, options?: StateWriterOptions): Promise<string>;
117
146
  export declare function writeWorkflowEnvelopeAtomic(targetPath: string, value: unknown, options?: StateWriterOptions): Promise<string>;
118
147
  export declare function writeTextAtomic(targetPath: string, text: string, options?: StateWriterOptions): Promise<string>;
@@ -178,8 +207,7 @@ export declare function createJsonNoClobber(targetPath: string, value: unknown,
178
207
  export declare function deleteIfOwned(targetPath: string, predicateOrOptions?: ((current: unknown) => boolean | Promise<boolean>) | DeleteIfOwnedOptions): Promise<DeleteResult>;
179
208
  export declare function removeFileAudited(targetPath: string, options?: StateWriterOptions): Promise<DeleteResult>;
180
209
  /**
181
- * Active entry files under `.gjc/state/active/<skill>.json` and
182
- * `.gjc/state/sessions/<id>/active/<skill>.json` are authoritative. The
210
+ * Active entry files under `.gjc/_session-{id}/state/active/<skill>.json` are authoritative. The
183
211
  * adjacent `skill-active-state.json` file is only a derived cache rebuilt from
184
212
  * those entries, so concurrent snapshot rebuilds can race without losing any
185
213
  * writer's per-skill state.
@@ -196,14 +224,15 @@ export declare function softDelete(targetPath: string, meta: Record<string, unkn
196
224
  export declare function hardPruneJson(targetPaths: readonly string[], selector: HardPruneSelector, options?: StateWriterOptions): Promise<string[]>;
197
225
  export declare function hardPrune(targets: readonly GenericHardPruneTarget[], selector: GenericHardPruneSelector, options?: StateWriterOptions): Promise<string[]>;
198
226
  export declare function forceOverwrite(targetPath: string, rawValue: unknown, options?: ForceOverwriteOptions): Promise<string>;
199
- export declare function appendAuditEntry(cwd: string, entry: AuditEntry): Promise<string>;
200
- export declare function readWorkflowTransactionJournal(cwd: string, mutationId: string): Promise<WorkflowTransactionJournal | undefined>;
227
+ export declare function appendAuditEntry(cwd: string, sessionIdOrEntry: string | AuditEntry, maybeEntry?: AuditEntry): Promise<string>;
228
+ export declare function readWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string): Promise<WorkflowTransactionJournal | undefined>;
201
229
  export declare function beginWorkflowTransactionJournal(input: {
202
230
  cwd: string;
231
+ sessionId: string;
203
232
  mutationId: string;
204
233
  caller?: CanonicalGjcWorkflowSkill;
205
234
  callee?: CanonicalGjcWorkflowSkill;
206
235
  paths: string[];
207
236
  }): Promise<string>;
208
- export declare function updateWorkflowTransactionJournal(cwd: string, mutationId: string, patch: Partial<WorkflowTransactionJournal>): Promise<string>;
209
- export declare function completeWorkflowTransactionJournal(cwd: string, mutationId: string): Promise<void>;
237
+ export declare function updateWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string, patch: Partial<WorkflowTransactionJournal>): Promise<string>;
238
+ export declare function completeWorkflowTransactionJournal(cwd: string, sessionId: string, mutationId: string): Promise<void>;
@@ -32,6 +32,8 @@ export declare function listGjcTmuxSessions(env?: NodeJS.ProcessEnv): GjcTmuxSes
32
32
  /** @internal */
33
33
  export declare function listTmuxSessionsForGc(env?: NodeJS.ProcessEnv): GjcTmuxSessionsForGc;
34
34
  export declare function findGjcTmuxSessionByBranch(branch: string, env?: NodeJS.ProcessEnv, project?: string | null): GjcTmuxSessionStatus | undefined;
35
+ export declare function findGjcTmuxSessionByName(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus | undefined;
36
+ export declare function findGjcTmuxSessionByScope(project: string, branch: string | null | undefined, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus | undefined;
35
37
  export declare function statusGjcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
36
38
  export declare function createGjcTmuxSession(env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
37
39
  /** @internal */
@@ -23,6 +23,7 @@ export interface UltragoalPlan {
23
23
  goals: UltragoalGoal[];
24
24
  createdAt: string;
25
25
  updatedAt: string;
26
+ [key: string]: unknown;
26
27
  }
27
28
  export type UltragoalReceiptKind = "per-goal" | "final-aggregate";
28
29
  export interface UltragoalCompletionVerification {
@@ -79,8 +80,8 @@ interface JsonObject {
79
80
  [key: string]: unknown;
80
81
  }
81
82
  export declare function hashStructuredValue(value: unknown): string;
82
- export declare function getUltragoalPaths(cwd: string): UltragoalPaths;
83
- export declare function readUltragoalLedger(cwd: string): Promise<UltragoalLedgerEvent[]>;
83
+ export declare function getUltragoalPaths(cwd: string, sessionId?: string | null): UltragoalPaths;
84
+ export declare function readUltragoalLedger(cwd: string, sessionId?: string | null): Promise<UltragoalLedgerEvent[]>;
84
85
  export declare function computeUltragoalPlanGeneration(input: {
85
86
  plan: UltragoalPlan;
86
87
  ledger: readonly UltragoalLedgerEvent[];
@@ -93,13 +94,14 @@ export declare function computeUltragoalPlanGeneration(input: {
93
94
  planGeneration: string;
94
95
  basis: UltragoalCompletionVerification["basis"];
95
96
  };
96
- export declare function readUltragoalPlan(cwd: string): Promise<UltragoalPlan | null>;
97
- export declare function getUltragoalStatus(cwd: string): Promise<UltragoalStatusSummary>;
97
+ export declare function readUltragoalPlan(cwd: string, sessionId?: string | null): Promise<UltragoalPlan | null>;
98
+ export declare function getUltragoalStatus(cwd: string, sessionId?: string | null): Promise<UltragoalStatusSummary>;
98
99
  export declare function buildUltragoalHudSummary(summary: UltragoalStatusSummary, latestLedger?: UltragoalLedgerEvent): WorkflowHudSummary;
99
100
  export declare function createUltragoalPlan(input: {
100
101
  cwd: string;
101
102
  brief: string;
102
103
  gjcGoalMode?: UltragoalGjcGoalMode;
104
+ sessionId?: string | null;
103
105
  }): Promise<UltragoalPlan>;
104
106
  export interface UltragoalRunCompletionState {
105
107
  requiredGoals: UltragoalGoal[];
@@ -115,6 +117,7 @@ export declare function getUltragoalRunCompletionState(plan: UltragoalPlan, opti
115
117
  export declare function startNextUltragoalGoal(input: {
116
118
  cwd: string;
117
119
  retryFailed?: boolean;
120
+ sessionId?: string | null;
118
121
  }): Promise<{
119
122
  plan: UltragoalPlan;
120
123
  goal?: UltragoalGoal;
@@ -1,4 +1,4 @@
1
- import type { CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
1
+ import { type CanonicalGjcWorkflowSkill } from "../skill-state/canonical-skills";
2
2
  export type CommandRefVisibility = "public" | "hidden" | "planned";
3
3
  export type CommandRefIncludeWhen = "implemented-only" | "planned";
4
4
  export interface CommandRefCommand {
@@ -3,7 +3,7 @@
3
3
  * Any JSON manifest projection is derived from this module and must never be
4
4
  * hand-edited.
5
5
  */
6
- import type { CanonicalGjcWorkflowSkill } from "../skill-state/active-state";
6
+ import { type CanonicalGjcWorkflowSkill } from "../skill-state/canonical-skills";
7
7
  export interface WorkflowState {
8
8
  id: string;
9
9
  initial?: boolean;
@@ -29,11 +29,12 @@ export declare class StorageError extends Error {
29
29
  readonly code: string;
30
30
  constructor(message: string, code: string);
31
31
  }
32
- /** Resolve the harness state root from explicit value, env, or cwd default. */
32
+ /** Resolve the harness state root from explicit value, env, or cwd/session default. */
33
33
  export declare function resolveHarnessRoot(opts?: {
34
34
  root?: string;
35
35
  cwd?: string;
36
36
  env?: NodeJS.ProcessEnv;
37
+ gjcSessionId?: string;
37
38
  }): string;
38
39
  export declare function assertSafeSessionId(id: string): void;
39
40
  export declare function generateSessionId(prefix?: string): string;