@gajae-code/coding-agent 0.6.4 → 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.
- package/CHANGELOG.md +22 -0
- package/dist/types/cli/migrate-cli.d.ts +20 -0
- package/dist/types/commands/migrate.d.ts +33 -0
- package/dist/types/config/keybindings.d.ts +4 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
- package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
- package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
- package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +36 -7
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +7 -4
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
- package/dist/types/harness-control-plane/storage.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +12 -4
- package/dist/types/migrate/action-planner.d.ts +11 -0
- package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
- package/dist/types/migrate/adapters/codex.d.ts +5 -0
- package/dist/types/migrate/adapters/index.d.ts +45 -0
- package/dist/types/migrate/adapters/opencode.d.ts +2 -0
- package/dist/types/migrate/executor.d.ts +2 -0
- package/dist/types/migrate/mcp-mapper.d.ts +20 -0
- package/dist/types/migrate/report.d.ts +18 -0
- package/dist/types/migrate/skill-normalizer.d.ts +27 -0
- package/dist/types/migrate/types.d.ts +126 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
- package/dist/types/research-plan/index.d.ts +1 -0
- package/dist/types/research-plan/ledger.d.ts +33 -0
- package/dist/types/rlm/artifacts.d.ts +1 -1
- package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
- package/dist/types/skill-state/active-state.d.ts +6 -11
- package/dist/types/skill-state/canonical-skills.d.ts +3 -0
- package/dist/types/skill-state/workflow-hud.d.ts +2 -0
- package/dist/types/task/spawn-gate.d.ts +1 -10
- package/package.json +7 -7
- package/src/cli/migrate-cli.ts +106 -0
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +2 -2
- package/src/commands/migrate.ts +46 -0
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +7 -3
- package/src/coordinator-mcp/policy.ts +10 -2
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
- package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
- package/src/defaults/gjc/skills/team/SKILL.md +51 -47
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +17 -13
- package/src/extensibility/custom-commands/loader.ts +0 -7
- package/src/extensibility/gjc-plugins/injection.ts +23 -4
- package/src/extensibility/gjc-plugins/state.ts +16 -1
- package/src/gjc-runtime/deep-interview-recorder.ts +43 -18
- package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
- package/src/gjc-runtime/goal-mode-request.ts +26 -11
- package/src/gjc-runtime/launch-tmux.ts +6 -1
- package/src/gjc-runtime/ralplan-runtime.ts +79 -50
- package/src/gjc-runtime/session-layout.ts +180 -0
- package/src/gjc-runtime/session-resolution.ts +217 -0
- package/src/gjc-runtime/state-graph.ts +1 -2
- package/src/gjc-runtime/state-migrations.ts +1 -0
- package/src/gjc-runtime/state-runtime.ts +230 -121
- package/src/gjc-runtime/state-schema.ts +2 -0
- package/src/gjc-runtime/state-writer.ts +289 -41
- package/src/gjc-runtime/team-runtime.ts +43 -19
- package/src/gjc-runtime/tmux-sessions.ts +7 -1
- package/src/gjc-runtime/ultragoal-guard.ts +45 -2
- package/src/gjc-runtime/ultragoal-runtime.ts +121 -41
- package/src/gjc-runtime/workflow-command-ref.ts +1 -2
- package/src/gjc-runtime/workflow-manifest.ts +1 -2
- package/src/harness-control-plane/storage.ts +14 -4
- package/src/hooks/native-skill-hook.ts +38 -12
- package/src/hooks/skill-state.ts +178 -83
- package/src/internal-urls/docs-index.generated.ts +6 -4
- package/src/migrate/action-planner.ts +318 -0
- package/src/migrate/adapters/claude-code.ts +39 -0
- package/src/migrate/adapters/codex.ts +70 -0
- package/src/migrate/adapters/index.ts +277 -0
- package/src/migrate/adapters/opencode.ts +52 -0
- package/src/migrate/executor.ts +81 -0
- package/src/migrate/mcp-mapper.ts +152 -0
- package/src/migrate/report.ts +104 -0
- package/src/migrate/skill-normalizer.ts +80 -0
- package/src/migrate/types.ts +163 -0
- package/src/modes/bridge/bridge-mode.ts +2 -2
- package/src/modes/components/custom-editor.ts +30 -20
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +1 -2
- package/src/research-plan/index.ts +1 -0
- package/src/research-plan/ledger.ts +177 -0
- package/src/rlm/artifacts.ts +12 -3
- package/src/rlm/index.ts +7 -0
- package/src/runtime-mcp/config-writer.ts +46 -0
- package/src/session/agent-session.ts +15 -21
- package/src/setup/hermes-setup.ts +1 -1
- package/src/skill-state/active-state.ts +72 -108
- package/src/skill-state/canonical-skills.ts +4 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
- package/src/skill-state/workflow-hud.ts +4 -2
- package/src/skill-state/workflow-state-contract.ts +3 -3
- package/src/task/agents.ts +1 -22
- package/src/task/index.ts +1 -41
- package/src/task/spawn-gate.ts +1 -38
- package/src/task/types.ts +1 -1
- package/src/tools/ask.ts +34 -12
- package/src/tools/computer.ts +58 -4
- package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
- package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
- package/src/prompts/agents/explore.md +0 -58
- package/src/prompts/agents/plan.md +0 -49
- package/src/prompts/agents/reviewer.md +0 -141
- package/src/prompts/agents/task.md +0 -16
- package/src/prompts/review-request.md +0 -70
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a skill from another agent into a native GJC `SKILL.md`.
|
|
3
|
+
*
|
|
4
|
+
* GJC derives a skill's loaded name from its directory (`<slug>/SKILL.md`) when no
|
|
5
|
+
* frontmatter `name` is present, and requires a `description`. To guarantee the
|
|
6
|
+
* effective loaded name equals the lowercase-hyphen slug, we drop any frontmatter
|
|
7
|
+
* `name` and place the file at `<slug>/SKILL.md`, synthesizing a `description`
|
|
8
|
+
* when the source lacks one.
|
|
9
|
+
*/
|
|
10
|
+
export interface NormalizeSkillInput {
|
|
11
|
+
/** Raw name from the source (filename stem, frontmatter name, etc.). */
|
|
12
|
+
rawName: string;
|
|
13
|
+
/** Full source markdown (may or may not have frontmatter). */
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
export interface NormalizedSkill {
|
|
17
|
+
slug: string;
|
|
18
|
+
content: string;
|
|
19
|
+
warnings: string[];
|
|
20
|
+
}
|
|
21
|
+
/** Convert an arbitrary name into a lowercase-hyphen slug. */
|
|
22
|
+
export declare function slugify(name: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Produce a `{ slug, content }` pair whose effective GJC-loaded name equals `slug`.
|
|
25
|
+
* Throws only on an unusable name (cannot produce a slug).
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalizeSkill(input: NormalizeSkillInput): NormalizedSkill;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for `gjc migrate`.
|
|
3
|
+
*
|
|
4
|
+
* Imports MCP servers and skills from other coding agents (Claude Code, Codex,
|
|
5
|
+
* OpenCode) into native GJC config. See the consensus plan under
|
|
6
|
+
* `.gjc/plans/ralplan/` for the full taxonomy and force/collision semantics.
|
|
7
|
+
*/
|
|
8
|
+
import type { MCPServerConfig } from "../runtime-mcp/types";
|
|
9
|
+
/** Supported migration sources. */
|
|
10
|
+
export type MigrateSource = "claude-code" | "codex" | "opencode";
|
|
11
|
+
export declare const MIGRATE_SOURCES: readonly MigrateSource[];
|
|
12
|
+
/** Canonical, deterministic ordering used when expanding `--from all` / repeated `--from`. */
|
|
13
|
+
export declare const CANONICAL_SOURCE_ORDER: readonly MigrateSource[];
|
|
14
|
+
/** What kind of thing an action/coverage row is about. */
|
|
15
|
+
export type MigrateItemType = "mcp" | "skill" | "source";
|
|
16
|
+
/**
|
|
17
|
+
* Per-item outcome taxonomy.
|
|
18
|
+
*
|
|
19
|
+
* `skipped_*` outcomes are non-fatal (exit 0). Any `failed_*` outcome sets
|
|
20
|
+
* `ok=false` and a non-zero process exit code.
|
|
21
|
+
*/
|
|
22
|
+
export type MigrationStatus = "imported" | "updated" | "skipped_exists" | "skipped_absent_source" | "skipped_unmappable" | "failed_invalid_source" | "failed_invalid_destination" | "failed_io";
|
|
23
|
+
export declare const MIGRATION_STATUSES: readonly MigrationStatus[];
|
|
24
|
+
/** Statuses that represent a hard failure (drive `ok=false` + non-zero exit). */
|
|
25
|
+
export declare const FAILURE_STATUSES: ReadonlySet<MigrationStatus>;
|
|
26
|
+
export declare function isFailureStatus(status: MigrationStatus): boolean;
|
|
27
|
+
/** Operation the planner decided for an item. */
|
|
28
|
+
export type MigrateOperation = "create" | "update" | "skip" | "fail";
|
|
29
|
+
/** A raw MCP server candidate parsed from a source, before mapping/destination planning. */
|
|
30
|
+
export interface McpCandidate {
|
|
31
|
+
source: MigrateSource;
|
|
32
|
+
name: string;
|
|
33
|
+
/** The raw, unmapped server entry from the source config (mapped by the planner). */
|
|
34
|
+
raw: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** A raw skill candidate parsed from a source, before normalization/destination planning. */
|
|
37
|
+
export interface SkillCandidate {
|
|
38
|
+
source: MigrateSource;
|
|
39
|
+
/** Slug used as the destination directory and effective loaded name. */
|
|
40
|
+
slug: string;
|
|
41
|
+
/** Full SKILL.md content (frontmatter already normalized so loaded name == slug). */
|
|
42
|
+
content: string;
|
|
43
|
+
warnings: string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Source-level diagnostic for a single source/type pair (e.g. "codex mcp config
|
|
47
|
+
* was malformed"). Distinct from per-item actions so absent/unreadable sources
|
|
48
|
+
* are reported once instead of per item.
|
|
49
|
+
*/
|
|
50
|
+
export interface SourceDiagnostic {
|
|
51
|
+
source: MigrateSource;
|
|
52
|
+
type: Exclude<MigrateItemType, "source"> | "source";
|
|
53
|
+
status: Extract<MigrationStatus, "skipped_absent_source" | "failed_invalid_source" | "failed_io">;
|
|
54
|
+
message: string;
|
|
55
|
+
}
|
|
56
|
+
/** Normalized candidates + diagnostics returned by an adapter. */
|
|
57
|
+
export interface AdapterResult {
|
|
58
|
+
mcpCandidates: McpCandidate[];
|
|
59
|
+
skillCandidates: SkillCandidate[];
|
|
60
|
+
diagnostics: SourceDiagnostic[];
|
|
61
|
+
}
|
|
62
|
+
/** A single planned action consumed identically by dry-run and live execution. */
|
|
63
|
+
export interface MigrateAction {
|
|
64
|
+
source: MigrateSource;
|
|
65
|
+
type: MigrateItemType;
|
|
66
|
+
name?: string;
|
|
67
|
+
/** For skills: the effective GJC-loaded name (== slug). */
|
|
68
|
+
effectiveName?: string;
|
|
69
|
+
/** Absolute destination path (mcp.json for MCP, <skillsDir>/<slug>/SKILL.md for skills). */
|
|
70
|
+
destination?: string;
|
|
71
|
+
operation: MigrateOperation;
|
|
72
|
+
status: MigrationStatus;
|
|
73
|
+
reason?: string;
|
|
74
|
+
warnings?: string[];
|
|
75
|
+
/** Resolved payload the executor needs; never serialized to the report. */
|
|
76
|
+
mcp?: {
|
|
77
|
+
config: MCPServerConfig;
|
|
78
|
+
force: boolean;
|
|
79
|
+
};
|
|
80
|
+
skill?: {
|
|
81
|
+
content: string;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export interface MigrateWarning {
|
|
85
|
+
source: MigrateSource;
|
|
86
|
+
type: string;
|
|
87
|
+
name?: string;
|
|
88
|
+
message: string;
|
|
89
|
+
}
|
|
90
|
+
export type StatusCounts = Record<MigrationStatus, number>;
|
|
91
|
+
export interface MigrateDestinations {
|
|
92
|
+
mcpConfigPath: string;
|
|
93
|
+
skillsDir: string;
|
|
94
|
+
}
|
|
95
|
+
/** The full machine-readable report emitted with `--json`. */
|
|
96
|
+
export interface MigrateReport {
|
|
97
|
+
ok: boolean;
|
|
98
|
+
dryRun: boolean;
|
|
99
|
+
project: boolean;
|
|
100
|
+
force: boolean;
|
|
101
|
+
sources: MigrateSource[];
|
|
102
|
+
destinations: MigrateDestinations;
|
|
103
|
+
summary: {
|
|
104
|
+
total: StatusCounts;
|
|
105
|
+
byType: {
|
|
106
|
+
mcp: StatusCounts;
|
|
107
|
+
skill: StatusCounts;
|
|
108
|
+
source: StatusCounts;
|
|
109
|
+
};
|
|
110
|
+
bySource: Record<MigrateSource, StatusCounts>;
|
|
111
|
+
};
|
|
112
|
+
actions: Array<{
|
|
113
|
+
source: MigrateSource;
|
|
114
|
+
type: MigrateItemType;
|
|
115
|
+
name?: string;
|
|
116
|
+
effectiveName?: string;
|
|
117
|
+
destination?: string;
|
|
118
|
+
operation: MigrateOperation;
|
|
119
|
+
status: MigrationStatus;
|
|
120
|
+
reason?: string;
|
|
121
|
+
warnings?: string[];
|
|
122
|
+
}>;
|
|
123
|
+
warnings: MigrateWarning[];
|
|
124
|
+
}
|
|
125
|
+
/** Create a zeroed status-count record. */
|
|
126
|
+
export declare function emptyStatusCounts(): StatusCounts;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Editor, type KeyId } from "@gajae-code/tui";
|
|
2
|
-
import type
|
|
2
|
+
import { type AppKeybinding } from "../../config/keybindings";
|
|
3
3
|
type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.message.queue" | "app.clipboard.pasteImage" | "app.clipboard.copyPrompt">;
|
|
4
4
|
type PastePendingClearReason = "timeout" | "queue-limit";
|
|
5
5
|
/**
|
|
@@ -41,7 +41,7 @@ export interface AuditLogOptions {
|
|
|
41
41
|
now?(): number;
|
|
42
42
|
nextId?(): string;
|
|
43
43
|
}
|
|
44
|
-
export declare function defaultAuditPath(runId: string, root?: string): string;
|
|
44
|
+
export declare function defaultAuditPath(runId: string, root?: string, gjcSessionId?: string): string;
|
|
45
45
|
/** Append-only audit log writer + reader for one unattended run. */
|
|
46
46
|
export declare class UnattendedAuditLog {
|
|
47
47
|
private readonly filePath;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./ledger";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type ResearchPlanConfidence = "low" | "medium" | "high";
|
|
2
|
+
export type ResearchEvidenceVerdict = "support" | "contradict" | "uncertain";
|
|
3
|
+
export interface ResearchPlanItem {
|
|
4
|
+
claim: string;
|
|
5
|
+
confidence: ResearchPlanConfidence;
|
|
6
|
+
unknowns: string[];
|
|
7
|
+
evidenceNeeded: string[];
|
|
8
|
+
counterexampleQueries: string[];
|
|
9
|
+
sourceConflictPolicy: string;
|
|
10
|
+
dropCondition: string;
|
|
11
|
+
verifierChecks: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ResearchEvidenceEntry {
|
|
14
|
+
claim: string;
|
|
15
|
+
source: string;
|
|
16
|
+
confidence: ResearchPlanConfidence;
|
|
17
|
+
verdict: ResearchEvidenceVerdict;
|
|
18
|
+
notes?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ResearchLedgerVerdict {
|
|
21
|
+
claim: string;
|
|
22
|
+
finalVerdict: "accepted" | "rejected" | "uncertain";
|
|
23
|
+
survivingSources: ResearchEvidenceEntry[];
|
|
24
|
+
rejectReason?: string;
|
|
25
|
+
unresolvedUnknowns: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface ResearchPlanValidationResult {
|
|
28
|
+
valid: boolean;
|
|
29
|
+
errors: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare function validateResearchPlanItem(item: Partial<ResearchPlanItem>): ResearchPlanValidationResult;
|
|
32
|
+
export declare function validateResearchEvidenceEntry(entry: Partial<ResearchEvidenceEntry>): ResearchPlanValidationResult;
|
|
33
|
+
export declare function evaluateResearchLedger(item: ResearchPlanItem, evidence: readonly ResearchEvidenceEntry[]): ResearchLedgerVerdict;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RlmArtifactPaths } from "./types";
|
|
2
|
-
export declare const RLM_DIR_SEGMENT
|
|
2
|
+
export declare const RLM_DIR_SEGMENT = "rlm";
|
|
3
3
|
export declare function isValidRlmSessionId(sessionId: string): boolean;
|
|
4
4
|
/** Generate a filesystem-safe, sortable session id (timestamp + random suffix). */
|
|
5
5
|
export declare function generateRlmSessionId(now?: Date): string;
|
|
@@ -28,6 +28,32 @@ export declare function addMCPServer(filePath: string, name: string, config: MCP
|
|
|
28
28
|
* @throws Error if validation fails
|
|
29
29
|
*/
|
|
30
30
|
export declare function updateMCPServer(filePath: string, name: string, config: MCPServerConfig): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Result of an {@link upsertMCPServer} call.
|
|
33
|
+
* - `added`: server did not exist and was written.
|
|
34
|
+
* - `updated`: server existed and was overwritten because `force` was set.
|
|
35
|
+
* - `skipped`: server existed and `force` was not set, so nothing was written.
|
|
36
|
+
*/
|
|
37
|
+
export type UpsertMCPServerResult = {
|
|
38
|
+
status: "added";
|
|
39
|
+
} | {
|
|
40
|
+
status: "updated";
|
|
41
|
+
} | {
|
|
42
|
+
status: "skipped";
|
|
43
|
+
reason: "exists";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Add an MCP server, or overwrite an existing one only when `force` is set.
|
|
47
|
+
*
|
|
48
|
+
* Collision-aware wrapper over {@link addMCPServer} / {@link updateMCPServer} used by
|
|
49
|
+
* `gjc migrate`. Never connects to the server. Reuses the underlying writers so the
|
|
50
|
+
* rest of the config file (including `disabledServers`) is preserved on update.
|
|
51
|
+
*
|
|
52
|
+
* @throws Error if the server name or config is invalid (validated before any write).
|
|
53
|
+
*/
|
|
54
|
+
export declare function upsertMCPServer(filePath: string, name: string, config: MCPServerConfig, options?: {
|
|
55
|
+
force?: boolean;
|
|
56
|
+
}): Promise<UpsertMCPServerResult>;
|
|
31
57
|
/**
|
|
32
58
|
* Remove an MCP server from a config file.
|
|
33
59
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill } from "./canonical-skills";
|
|
1
2
|
import type { WorkflowStateReceipt } from "./workflow-state-contract";
|
|
2
3
|
export declare const SKILL_ACTIVE_STATE_FILE = "skill-active-state.json";
|
|
3
|
-
export
|
|
4
|
-
export type CanonicalGjcWorkflowSkill = (typeof CANONICAL_GJC_WORKFLOW_SKILLS)[number];
|
|
4
|
+
export { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill };
|
|
5
5
|
export type WorkflowHudSeverity = "info" | "warning" | "blocked" | "error" | "success";
|
|
6
6
|
export interface WorkflowHudChip {
|
|
7
7
|
label: string;
|
|
@@ -44,6 +44,7 @@ export interface SkillActiveEntry {
|
|
|
44
44
|
handoff_to?: string;
|
|
45
45
|
handoff_at?: string;
|
|
46
46
|
active_subskills?: ActiveSubskillEntry[];
|
|
47
|
+
source_state_revision?: number;
|
|
47
48
|
}
|
|
48
49
|
export interface SkillActiveState {
|
|
49
50
|
version?: number;
|
|
@@ -65,7 +66,7 @@ export interface SkillActiveState {
|
|
|
65
66
|
}
|
|
66
67
|
export interface SkillActiveStatePaths {
|
|
67
68
|
rootPath: string;
|
|
68
|
-
sessionPath
|
|
69
|
+
sessionPath: string;
|
|
69
70
|
}
|
|
70
71
|
export interface SyncSkillActiveStateOptions {
|
|
71
72
|
cwd: string;
|
|
@@ -83,6 +84,7 @@ export interface SyncSkillActiveStateOptions {
|
|
|
83
84
|
handoff_to?: string;
|
|
84
85
|
handoff_at?: string;
|
|
85
86
|
active_subskills?: ActiveSubskillEntry[];
|
|
87
|
+
sourceRevision?: number;
|
|
86
88
|
}
|
|
87
89
|
export declare function normalizeWorkflowHudSummary(raw: unknown): WorkflowHudSummary | undefined;
|
|
88
90
|
export declare function isCanonicalGjcWorkflowSkill(skill: string): skill is CanonicalGjcWorkflowSkill;
|
|
@@ -102,13 +104,6 @@ export interface ApplyHandoffOptions {
|
|
|
102
104
|
strict?: boolean;
|
|
103
105
|
}
|
|
104
106
|
/**
|
|
105
|
-
* Atomically apply a workflow-skill handoff to
|
|
106
|
-
* root `skill-active-state.json` files in a single write per file.
|
|
107
|
-
*
|
|
108
|
-
* Write order: **session first, root last**. The session file is the
|
|
109
|
-
* source of truth for HUD; the root aggregate must never lead the session
|
|
110
|
-
* during a handoff window. Each file is rewritten once with caller demoted
|
|
111
|
-
* to `active:false` (preserving `handoff_to`/`handoff_at` lineage) and
|
|
112
|
-
* callee promoted to `active:true` (with `handoff_from`/`handoff_at`).
|
|
107
|
+
* Atomically apply a workflow-skill handoff to the session-scoped active state.
|
|
113
108
|
*/
|
|
114
109
|
export declare function applyHandoffToActiveState(options: ApplyHandoffOptions): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** The hard, locked batch threshold enforced by the runtime gate. */
|
|
2
2
|
export declare const DEFAULT_SPAWN_THRESHOLD = 4;
|
|
3
|
-
/** The justification a large batch
|
|
3
|
+
/** The justification a large batch must supply to pass the hard gate. */
|
|
4
4
|
export interface SpawnPlanReceipt {
|
|
5
5
|
whyParallel: string;
|
|
6
6
|
whyNotLocal: string;
|
|
@@ -14,14 +14,6 @@ export interface SpawnGateRequest {
|
|
|
14
14
|
/** The spawn-plan receipt, when provided. */
|
|
15
15
|
plan?: SpawnPlanReceipt;
|
|
16
16
|
}
|
|
17
|
-
export interface ReviewerExploreGateRequest {
|
|
18
|
-
/** Agent type/name doing the spawning, when known. */
|
|
19
|
-
spawningAgentType?: string | null;
|
|
20
|
-
/** Target agent type/name requested by the task call. */
|
|
21
|
-
targetAgent: string;
|
|
22
|
-
/** The spawn-plan receipt, when provided. */
|
|
23
|
-
plan?: SpawnPlanReceipt;
|
|
24
|
-
}
|
|
25
17
|
export type SpawnGateOutcome = "allowed" | "rejected";
|
|
26
18
|
export interface SpawnGateDecision {
|
|
27
19
|
outcome: SpawnGateOutcome;
|
|
@@ -35,4 +27,3 @@ export interface SpawnGateDecision {
|
|
|
35
27
|
export declare function findMissingPlanFields(plan: SpawnPlanReceipt | undefined): string[];
|
|
36
28
|
export declare function decide(childCount: number, threshold: number, plan: SpawnPlanReceipt | undefined): SpawnGateDecision;
|
|
37
29
|
export declare function evaluateSpawnGate(request: SpawnGateRequest): SpawnGateDecision;
|
|
38
|
-
export declare function evaluateReviewerExploreGate(request: ReviewerExploreGateRequest): SpawnGateDecision;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.5",
|
|
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",
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
52
52
|
"@babel/parser": "^7.29.3",
|
|
53
53
|
"@mozilla/readability": "^0.6.0",
|
|
54
|
-
"@gajae-code/stats": "0.6.
|
|
55
|
-
"@gajae-code/agent-core": "0.6.
|
|
56
|
-
"@gajae-code/ai": "0.6.
|
|
57
|
-
"@gajae-code/natives": "0.6.
|
|
58
|
-
"@gajae-code/tui": "0.6.
|
|
59
|
-
"@gajae-code/utils": "0.6.
|
|
54
|
+
"@gajae-code/stats": "0.6.5",
|
|
55
|
+
"@gajae-code/agent-core": "0.6.5",
|
|
56
|
+
"@gajae-code/ai": "0.6.5",
|
|
57
|
+
"@gajae-code/natives": "0.6.5",
|
|
58
|
+
"@gajae-code/tui": "0.6.5",
|
|
59
|
+
"@gajae-code/utils": "0.6.5",
|
|
60
60
|
"@puppeteer/browsers": "^2.13.0",
|
|
61
61
|
"@types/turndown": "5.0.6",
|
|
62
62
|
"@xterm/headless": "^6.0.0",
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gjc migrate` — import MCP servers and skills from other coding agents.
|
|
3
|
+
*/
|
|
4
|
+
import * as os from "node:os";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { getAgentDir, getMCPConfigPath, getProjectAgentDir, getProjectDir } from "@gajae-code/utils";
|
|
7
|
+
import { planMigration } from "../migrate/action-planner";
|
|
8
|
+
import { getAdapter } from "../migrate/adapters/index";
|
|
9
|
+
import { executeActions } from "../migrate/executor";
|
|
10
|
+
import { buildReport, renderHuman } from "../migrate/report";
|
|
11
|
+
import {
|
|
12
|
+
type AdapterResult,
|
|
13
|
+
CANONICAL_SOURCE_ORDER,
|
|
14
|
+
MIGRATE_SOURCES,
|
|
15
|
+
type MigrateDestinations,
|
|
16
|
+
type MigrateReport,
|
|
17
|
+
type MigrateSource,
|
|
18
|
+
} from "../migrate/types";
|
|
19
|
+
|
|
20
|
+
export interface MigrateCommandArgs {
|
|
21
|
+
from: string[];
|
|
22
|
+
project: boolean;
|
|
23
|
+
force: boolean;
|
|
24
|
+
dryRun: boolean;
|
|
25
|
+
json: boolean;
|
|
26
|
+
/** Test seam: override home dir for source discovery. */
|
|
27
|
+
homeDir?: string;
|
|
28
|
+
/** Test seam: override cwd for project-scope destinations. */
|
|
29
|
+
cwd?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class MigrateArgsError extends Error {}
|
|
33
|
+
|
|
34
|
+
/** Expand `all`/repeated `--from`, validate, and return sources in canonical order. */
|
|
35
|
+
export function resolveSources(from: string[]): MigrateSource[] {
|
|
36
|
+
if (from.length === 0) {
|
|
37
|
+
throw new MigrateArgsError("No source selected. Use --from <claude-code|codex|opencode|all> (repeatable).");
|
|
38
|
+
}
|
|
39
|
+
const selected = new Set<MigrateSource>();
|
|
40
|
+
for (const raw of from) {
|
|
41
|
+
const value = raw.trim().toLowerCase();
|
|
42
|
+
if (value === "all") {
|
|
43
|
+
for (const s of MIGRATE_SOURCES) selected.add(s);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!(MIGRATE_SOURCES as readonly string[]).includes(value)) {
|
|
47
|
+
throw new MigrateArgsError(`Unknown source "${raw}". Valid: ${MIGRATE_SOURCES.join(", ")}, all.`);
|
|
48
|
+
}
|
|
49
|
+
selected.add(value as MigrateSource);
|
|
50
|
+
}
|
|
51
|
+
return CANONICAL_SOURCE_ORDER.filter(s => selected.has(s));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolveDestinations(project: boolean, cwd: string): MigrateDestinations {
|
|
55
|
+
const scope = project ? "project" : "user";
|
|
56
|
+
const skillsDir = project ? path.join(getProjectAgentDir(cwd), "skills") : path.join(getAgentDir(), "skills");
|
|
57
|
+
return { mcpConfigPath: getMCPConfigPath(scope, cwd), skillsDir };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Run the migration and return the report (does not set process.exitCode). */
|
|
61
|
+
export async function runMigrate(args: MigrateCommandArgs): Promise<MigrateReport> {
|
|
62
|
+
const sources = resolveSources(args.from);
|
|
63
|
+
const cwd = args.cwd ?? getProjectDir();
|
|
64
|
+
const homeDir = args.homeDir ?? os.homedir();
|
|
65
|
+
const destinations = resolveDestinations(args.project, cwd);
|
|
66
|
+
|
|
67
|
+
const results: AdapterResult[] = [];
|
|
68
|
+
for (const source of sources) {
|
|
69
|
+
results.push(await getAdapter(source).collect({ homeDir }));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { actions, warnings } = await planMigration({ results, destinations, force: args.force });
|
|
73
|
+
const finalActions = args.dryRun ? actions : await executeActions(actions);
|
|
74
|
+
|
|
75
|
+
return buildReport({
|
|
76
|
+
actions: finalActions,
|
|
77
|
+
warnings,
|
|
78
|
+
sources,
|
|
79
|
+
destinations,
|
|
80
|
+
dryRun: args.dryRun,
|
|
81
|
+
project: args.project,
|
|
82
|
+
force: args.force,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** CLI entry: run, render, and set the process exit code. */
|
|
87
|
+
export async function runMigrateCommand(args: MigrateCommandArgs): Promise<void> {
|
|
88
|
+
let report: MigrateReport;
|
|
89
|
+
try {
|
|
90
|
+
report = await runMigrate(args);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof MigrateArgsError) {
|
|
93
|
+
process.stderr.write(`${error.message}\n`);
|
|
94
|
+
process.exitCode = 2;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (args.json) {
|
|
101
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
102
|
+
} else {
|
|
103
|
+
process.stdout.write(`${renderHuman(report)}\n`);
|
|
104
|
+
}
|
|
105
|
+
process.exitCode = report.ok ? 0 : 1;
|
|
106
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -43,6 +43,7 @@ const commands: CommandEntry[] = [
|
|
|
43
43
|
load: () => import("./commands/contribution-prep").then(m => m.default),
|
|
44
44
|
},
|
|
45
45
|
{ name: "deep-interview", load: () => import("./commands/deep-interview").then(m => m.default) },
|
|
46
|
+
{ name: "migrate", load: () => import("./commands/migrate").then(m => m.default) },
|
|
46
47
|
{ name: "rlm", load: () => import("./commands/rlm").then(m => m.default) },
|
|
47
48
|
{ name: "update", load: () => import("./commands/update").then(m => m.default) },
|
|
48
49
|
{ name: "launch", load: () => import("./commands/launch").then(m => m.default) },
|
|
@@ -11,11 +11,11 @@ export default class DeepInterview extends Command {
|
|
|
11
11
|
threshold: Flags.string({ description: "Override ambiguity threshold for kickoff" }),
|
|
12
12
|
"threshold-source": Flags.string({ description: "Describe the threshold override source" }),
|
|
13
13
|
"session-id": Flags.string({
|
|
14
|
-
description: "Route state/spec handoff through a session-scoped .gjc
|
|
14
|
+
description: "Route state/spec handoff through a session-scoped .gjc/_session-{sessionid} directory",
|
|
15
15
|
}),
|
|
16
16
|
write: Flags.boolean({ description: "Persist a final deep-interview spec through the sanctioned GJC CLI/API" }),
|
|
17
17
|
stage: Flags.string({ description: 'Spec stage for --write (currently "final")' }),
|
|
18
|
-
slug: Flags.string({ description: "Safe slug for .gjc/specs/deep-interview-<slug>.md" }),
|
|
18
|
+
slug: Flags.string({ description: "Safe slug for .gjc/_session-{sessionid}/specs/deep-interview-<slug>.md" }),
|
|
19
19
|
spec: Flags.string({ description: "Final spec markdown or a path to the final spec markdown" }),
|
|
20
20
|
handoff: Flags.string({ description: 'After --write, hand off to a workflow target (currently "ralplan")' }),
|
|
21
21
|
deliberate: Flags.boolean({
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import MCP servers and skills from other coding agents into GJC.
|
|
3
|
+
*/
|
|
4
|
+
import { Command, Flags } from "@gajae-code/utils/cli";
|
|
5
|
+
import { type MigrateCommandArgs, runMigrateCommand } from "../cli/migrate-cli";
|
|
6
|
+
|
|
7
|
+
export default class Migrate extends Command {
|
|
8
|
+
static description = "Import MCP servers and skills from Claude Code, Codex, or OpenCode";
|
|
9
|
+
|
|
10
|
+
static examples = [
|
|
11
|
+
"gjc migrate --from claude-code",
|
|
12
|
+
"gjc migrate --from codex --from opencode",
|
|
13
|
+
"gjc migrate --from all --dry-run --json",
|
|
14
|
+
"gjc migrate --from claude-code --project --force",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
static flags = {
|
|
18
|
+
from: Flags.string({
|
|
19
|
+
description: "Source agent to import from (repeatable): claude-code | codex | opencode | all",
|
|
20
|
+
multiple: true,
|
|
21
|
+
required: true,
|
|
22
|
+
}),
|
|
23
|
+
project: Flags.boolean({
|
|
24
|
+
description: "Write to the project scope (./.gjc) instead of the user scope (~/.gjc)",
|
|
25
|
+
default: false,
|
|
26
|
+
}),
|
|
27
|
+
force: Flags.boolean({
|
|
28
|
+
description: "Overwrite existing skills/MCP servers instead of skipping them",
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
31
|
+
"dry-run": Flags.boolean({ description: "Preview the migration without writing anything", default: false }),
|
|
32
|
+
json: Flags.boolean({ char: "j", description: "Emit a machine-readable JSON report", default: false }),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
async run(): Promise<void> {
|
|
36
|
+
const { flags } = await this.parse(Migrate);
|
|
37
|
+
const cmd: MigrateCommandArgs = {
|
|
38
|
+
from: flags.from ?? [],
|
|
39
|
+
project: flags.project,
|
|
40
|
+
force: flags.force,
|
|
41
|
+
dryRun: flags["dry-run"],
|
|
42
|
+
json: flags.json,
|
|
43
|
+
};
|
|
44
|
+
await runMigrateCommand(cmd);
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/commands/state.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { Command } from "@gajae-code/utils/cli";
|
|
|
2
2
|
import { runNativeStateCommand } from "../gjc-runtime/state-runtime";
|
|
3
3
|
|
|
4
4
|
export default class State extends Command {
|
|
5
|
-
static description =
|
|
5
|
+
static description =
|
|
6
|
+
"Read or update current-session GJC workflow state receipts under .gjc/_session-{sessionid}/state";
|
|
6
7
|
static strict = false;
|
|
7
8
|
static examples = [
|
|
8
9
|
'$ gjc state read --input \'{"mode":"deep-interview"}\' --json',
|
package/src/commands/team.ts
CHANGED
|
@@ -75,7 +75,7 @@ function parseInputFlag(argv: string[]): Record<string, unknown> {
|
|
|
75
75
|
|
|
76
76
|
export default class Team extends Command {
|
|
77
77
|
static description =
|
|
78
|
-
"Run native GJC tmux team orchestration from inside an existing tmux/GJC --tmux session; --dry-run writes ephemeral .gjc/state/team state only";
|
|
78
|
+
"Run native GJC tmux team orchestration from inside an existing tmux/GJC --tmux session; --dry-run writes ephemeral .gjc/_session-{sessionid}/state/team state only";
|
|
79
79
|
static strict = false;
|
|
80
80
|
|
|
81
81
|
static args = {
|
|
@@ -89,7 +89,7 @@ export default class Team extends Command {
|
|
|
89
89
|
json: Flags.boolean({ char: "j", description: "Emit machine-readable JSON", default: false }),
|
|
90
90
|
"dry-run": Flags.boolean({
|
|
91
91
|
description:
|
|
92
|
-
"Create ephemeral .gjc/state/team state without starting tmux panes; do not commit generated state",
|
|
92
|
+
"Create ephemeral .gjc/_session-{sessionid}/state/team state without starting tmux panes; do not commit generated state",
|
|
93
93
|
default: false,
|
|
94
94
|
}),
|
|
95
95
|
};
|
|
@@ -210,7 +210,11 @@ export default class Team extends Command {
|
|
|
210
210
|
`tmux: ${snapshot.tmux_session}`,
|
|
211
211
|
`state: ${snapshot.state_dir}`,
|
|
212
212
|
`workers: ${snapshot.workers.length}`,
|
|
213
|
-
...(dryRun
|
|
213
|
+
...(dryRun
|
|
214
|
+
? [
|
|
215
|
+
"dry-run: wrote ephemeral .gjc/_session-{sessionid}/state/team state only; do not commit generated .gjc state",
|
|
216
|
+
]
|
|
217
|
+
: []),
|
|
214
218
|
]);
|
|
215
219
|
}
|
|
216
220
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { coordinatorMcpStateRoot, gjcRoot } from "../gjc-runtime/session-layout";
|
|
3
4
|
|
|
4
5
|
export type CoordinatorMutationClass = "sessions" | "questions" | "reports";
|
|
5
6
|
|
|
@@ -73,9 +74,16 @@ function cleanScope(value: string | undefined): string | null {
|
|
|
73
74
|
return trimmed.replace(/[^a-zA-Z0-9_.-]+/g, "-").slice(0, 100) || null;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
function defaultCoordinatorMcpStateRoot(cwd: string, gjcSessionId?: string): string {
|
|
78
|
+
return gjcSessionId
|
|
79
|
+
? coordinatorMcpStateRoot(cwd, gjcSessionId)
|
|
80
|
+
: path.join(gjcRoot(cwd), "state", "coordinator-mcp");
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
export function buildCoordinatorMcpConfig(env: NodeJS.ProcessEnv = process.env): CoordinatorMcpConfig {
|
|
77
|
-
const
|
|
78
|
-
|
|
84
|
+
const stateRootOverride = env.GJC_COORDINATOR_MCP_STATE_ROOT?.trim();
|
|
85
|
+
const gjcSessionId = env.GJC_SESSION_ID?.trim();
|
|
86
|
+
const stateRoot = stateRootOverride || defaultCoordinatorMcpStateRoot(process.cwd(), gjcSessionId);
|
|
79
87
|
return {
|
|
80
88
|
allowedRoots: parseRootList(env.GJC_COORDINATOR_MCP_WORKDIR_ROOTS).map(root => path.resolve(root)),
|
|
81
89
|
mutationClasses: parseMutationClasses(
|