@gajae-code/coding-agent 0.8.1 → 0.8.2
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 +34 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +12 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/notifications/config.d.ts +8 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +15 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +10 -0
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +7 -7
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +37 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/notify-cli.ts +91 -7
- package/src/cli.ts +3 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-registry.ts +14 -2
- package/src/config/settings.ts +22 -0
- package/src/coordinator-mcp/server.ts +34 -8
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +38 -5
- package/src/defaults/gjc/skills/ralplan/SKILL.md +15 -11
- package/src/defaults/gjc/skills/team/SKILL.md +1 -1
- package/src/extensibility/extensions/runner.ts +2 -0
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
- package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
- package/src/gjc-runtime/deep-interview-state.ts +13 -0
- package/src/gjc-runtime/session-state-sidecar.ts +59 -11
- package/src/gjc-runtime/state-runtime.ts +12 -2
- package/src/gjc-runtime/team-runtime.ts +23 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +73 -19
- package/src/hooks/native-skill-hook.ts +29 -0
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/main.ts +52 -41
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/welcome.ts +160 -44
- package/src/modes/controllers/command-controller.ts +1 -2
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +179 -17
- package/src/modes/controllers/selector-controller.ts +122 -27
- package/src/modes/interactive-mode.ts +43 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +21 -20
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +2 -2
- package/src/notifications/config.ts +9 -1
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +39 -9
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-control.ts +3 -1
- package/src/notifications/telegram-daemon.ts +217 -43
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/tools/computer.md +2 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +20 -6
- package/src/session/agent-session.ts +225 -31
- package/src/session/agent-storage.ts +4 -0
- package/src/session/session-manager.ts +44 -2
- package/src/slash-commands/builtin-registry.ts +153 -71
- package/src/task/executor.ts +7 -4
- package/src/task/index.ts +9 -3
- package/src/task/output-manager.ts +16 -6
- package/src/task/receipt.ts +26 -7
- package/src/tools/computer.ts +246 -43
- package/src/tools/telegram-send.ts +6 -0
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- package/src/workflow/workflow-intent-report.ts +135 -0
|
@@ -23,6 +23,12 @@ export declare function isGloballyConfigured(cfg: NotificationConfig): boolean;
|
|
|
23
23
|
export declare function shouldRegisterNotificationsExtension(input: {
|
|
24
24
|
env: NodeJS.ProcessEnv;
|
|
25
25
|
cfg?: NotificationConfig;
|
|
26
|
+
/** Task recursion depth; helper/subagent sessions must not spawn remote surfaces. */
|
|
27
|
+
taskDepth?: number;
|
|
28
|
+
/** Parent subagent id/prefix; present for helper/subagent sessions even when depth is omitted. */
|
|
29
|
+
parentTaskPrefix?: string;
|
|
30
|
+
/** Role-agent type/name; present for task sessions even if depth metadata is lost. */
|
|
31
|
+
currentAgentType?: string;
|
|
26
32
|
}): boolean;
|
|
27
33
|
/**
|
|
28
34
|
* Resolve whether THIS session should run notifications.
|
|
@@ -61,7 +67,8 @@ export interface RedactableAction {
|
|
|
61
67
|
* When redact is false, return the action unchanged.
|
|
62
68
|
*
|
|
63
69
|
* Redaction still applies to streamed content frames (turn_stream, context_update,
|
|
64
|
-
* image_attachment) which are suppressed at their emit sites, not here.
|
|
70
|
+
* image_attachment) which are suppressed at their emit sites, not here. Explicit
|
|
71
|
+
* `telegram_send` file attachments are rejected before the file is read or forwarded.
|
|
65
72
|
*/
|
|
66
73
|
export declare function buildRedactedAction(action: RedactableAction, opts: {
|
|
67
74
|
redact: boolean;
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* Enable with Settings notifications config, `GJC_NOTIFICATIONS=1` (a token is
|
|
18
18
|
* generated), or `GJC_NOTIFICATIONS_TOKEN`.
|
|
19
19
|
*/
|
|
20
|
-
import
|
|
20
|
+
import { Settings } from "../config/settings";
|
|
21
|
+
import type { ExtensionAPI } from "../extensibility/extensions";
|
|
21
22
|
/** Where a `session_create` should run. Discriminated by `kind`. */
|
|
22
23
|
export type SessionCreateTarget = {
|
|
23
24
|
kind: "existing_path";
|
|
@@ -69,7 +70,7 @@ export interface SessionCloseFrame {
|
|
|
69
70
|
chatId: string;
|
|
70
71
|
token: string;
|
|
71
72
|
target: SessionCloseTarget;
|
|
72
|
-
/**
|
|
73
|
+
/** Required force-only close flag; false/omitted is rejected by daemon policy. */
|
|
73
74
|
force?: boolean;
|
|
74
75
|
}
|
|
75
76
|
/** Resume a session (reattach if alive, else cold-restart from history). */
|
|
@@ -173,4 +174,6 @@ export interface SessionReadyFrame {
|
|
|
173
174
|
*/
|
|
174
175
|
export declare function readGitRepoName(cwd: string): string | undefined;
|
|
175
176
|
export declare function notificationsEnabled(): boolean;
|
|
176
|
-
export declare
|
|
177
|
+
export declare function createNotificationsExtension(api: ExtensionAPI, options?: {
|
|
178
|
+
settings?: Settings;
|
|
179
|
+
}): void;
|
|
@@ -23,8 +23,13 @@ export type ParsedLifecycleCommand = {
|
|
|
23
23
|
} | {
|
|
24
24
|
kind: "none";
|
|
25
25
|
};
|
|
26
|
-
/** True when the text begins
|
|
27
|
-
export declare function
|
|
26
|
+
/** True when the text begins with any /session_* token, regardless of addressability. */
|
|
27
|
+
export declare function isLifecycleCommandLikeText(text: string | undefined): boolean;
|
|
28
|
+
/** True when the text begins an addressable /session_* command (cheap pre-gate). */
|
|
29
|
+
export declare function isLifecycleCommandText(text: string | undefined, ctx?: {
|
|
30
|
+
chatType?: string;
|
|
31
|
+
botUsername?: string;
|
|
32
|
+
}): boolean;
|
|
28
33
|
/**
|
|
29
34
|
* Parse a paired-chat message into a lifecycle command. Returns `none` for
|
|
30
35
|
* non-lifecycle text, `usage`/`reject` for malformed input (no side effect), or
|
|
@@ -33,7 +38,10 @@ export declare function isLifecycleCommandText(text: string | undefined): boolea
|
|
|
33
38
|
* The caller MUST have already enforced paired-chat authorization; this function
|
|
34
39
|
* performs grammar + target validation only.
|
|
35
40
|
*/
|
|
36
|
-
export declare function parseLifecycleCommand(text: string | undefined
|
|
41
|
+
export declare function parseLifecycleCommand(text: string | undefined, ctx?: {
|
|
42
|
+
chatType?: string;
|
|
43
|
+
botUsername?: string;
|
|
44
|
+
}): ParsedLifecycleCommand;
|
|
37
45
|
/** The canonical usage text (exported for the daemon's help replies). */
|
|
38
46
|
export declare function lifecycleUsage(): string;
|
|
39
47
|
/**
|
|
@@ -3,8 +3,8 @@ import type { Settings } from "../config/settings";
|
|
|
3
3
|
import type { DaemonRuntimeInfo } from "../daemon/control-types";
|
|
4
4
|
import { type ControlServerLike, type LifecycleControlServerFactory } from "./lifecycle-control-runtime";
|
|
5
5
|
import { NotificationOperatorRuntime, OperatorBackoffPolicy } from "./operator-runtime";
|
|
6
|
-
import { type AliasTable, type CallbackRoute
|
|
7
|
-
export type EnsureDaemonResult = "owner_spawned" | "attached" | "disabled";
|
|
6
|
+
import { type AliasTable, type CallbackRoute } from "./telegram-reference";
|
|
7
|
+
export type EnsureDaemonResult = "owner_spawned" | "attached" | "disabled" | "blocked";
|
|
8
8
|
export interface DaemonState {
|
|
9
9
|
pid: number;
|
|
10
10
|
ownerId: string;
|
|
@@ -95,6 +95,8 @@ export declare function acquireDaemonOwnership(input: {
|
|
|
95
95
|
acquired: boolean;
|
|
96
96
|
ownerId?: string;
|
|
97
97
|
attached?: boolean;
|
|
98
|
+
blocked?: boolean;
|
|
99
|
+
reason?: "identity_mismatch";
|
|
98
100
|
}>;
|
|
99
101
|
export declare function renewDaemonHeartbeat(input: {
|
|
100
102
|
settings: Settings;
|
|
@@ -276,6 +278,8 @@ export declare class TelegramNotificationDaemon {
|
|
|
276
278
|
private readonly flatIdentitySent;
|
|
277
279
|
/** Cached result of whether the paired chat is a private chat (flat-fallback gate). */
|
|
278
280
|
private pairedChatPrivate;
|
|
281
|
+
/** Bot username from getMe, cached once at owner startup for group/forum command targeting. */
|
|
282
|
+
private botUsername;
|
|
279
283
|
/** Sessions whose agent loop is currently busy (drives the typing indicator). */
|
|
280
284
|
private get busy();
|
|
281
285
|
/** Inbound update id → originating Telegram message, for delivery reactions. */
|
|
@@ -317,12 +321,17 @@ export declare class TelegramNotificationDaemon {
|
|
|
317
321
|
/** Build an authenticated lifecycle frame from a parsed command + identity. */
|
|
318
322
|
private buildLifecycleFrame;
|
|
319
323
|
private handleLifecycleCommand;
|
|
324
|
+
private refreshBotIdentity;
|
|
320
325
|
/** Map a lifecycle response/error to a user-facing message (G010 surfacing). */
|
|
321
326
|
private formatLifecycleResponse;
|
|
322
327
|
constructor(opts: TelegramDaemonOptions);
|
|
323
328
|
private createSessionRouter;
|
|
324
329
|
loadAliases(): Promise<void>;
|
|
325
330
|
persistAliases(): Promise<void>;
|
|
331
|
+
loadSeenUpdateIds(): Promise<void>;
|
|
332
|
+
persistSeenUpdateIds(): Promise<void>;
|
|
333
|
+
private pruneSeenUpdateIds;
|
|
334
|
+
private rememberSeenUpdateId;
|
|
326
335
|
scanRoots(): Promise<void>;
|
|
327
336
|
connectSession(sessionId: string, url: string, token: string): void;
|
|
328
337
|
/**
|
|
@@ -340,12 +349,15 @@ export declare class TelegramNotificationDaemon {
|
|
|
340
349
|
* the socket. `scanRoots()` then reconnects the session.
|
|
341
350
|
*/
|
|
342
351
|
private dropSession;
|
|
352
|
+
private deleteMessageRoutes;
|
|
343
353
|
private static readonly THREADED_FRAMES;
|
|
344
354
|
private topicNameFor;
|
|
345
355
|
private topicIdentityKey;
|
|
346
356
|
private topicIdentityBase;
|
|
347
357
|
private topicOwnerForIdentity;
|
|
358
|
+
private sessionCanClaimIdentity;
|
|
348
359
|
private submitThreadedFrame;
|
|
360
|
+
private existingTopicForPrivateChat;
|
|
349
361
|
private rememberPendingThreadedFrame;
|
|
350
362
|
private flushPendingThreadedFrames;
|
|
351
363
|
private ensureTopic;
|
|
@@ -376,7 +388,7 @@ export declare class TelegramNotificationDaemon {
|
|
|
376
388
|
private startTypingTimer;
|
|
377
389
|
private stopTypingTimer;
|
|
378
390
|
handleSessionMessage(session: SessionSocket, msg: any): Promise<void>;
|
|
379
|
-
|
|
391
|
+
private answerCallbackQueryBestEffort;
|
|
380
392
|
private sendStaleGuidance;
|
|
381
393
|
handleTelegramUpdate(update: unknown): Promise<void>;
|
|
382
394
|
pollOnce(signal?: AbortSignal): Promise<number>;
|
|
@@ -81,14 +81,9 @@ export type RouteDecision = ({
|
|
|
81
81
|
} | {
|
|
82
82
|
kind: "ignore";
|
|
83
83
|
};
|
|
84
|
-
export interface PendingAsk {
|
|
85
|
-
sessionId: string;
|
|
86
|
-
actionId: string;
|
|
87
|
-
}
|
|
88
84
|
export interface RouteInboundContext {
|
|
89
85
|
aliasTable: Pick<AliasTable, "get">;
|
|
90
86
|
messageRoutes: Map<string | number, CallbackRoute | Omit<CallbackRoute, "answer">>;
|
|
91
|
-
pendingBySession: (sessionId?: string) => PendingAsk[];
|
|
92
87
|
pairedChatId: string;
|
|
93
88
|
}
|
|
94
89
|
/** Route a Telegram update to a session/action without I/O. Fail closed under ambiguity. */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface RuntimeApiKeyTarget {
|
|
2
|
+
setRuntimeApiKey(provider: string, apiKey: string): void;
|
|
3
|
+
}
|
|
4
|
+
export interface RuntimeApiKeyModel {
|
|
5
|
+
provider: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function applyCliRuntimeApiKeyOverride(target: RuntimeApiKeyTarget, apiKey: string | undefined, model: RuntimeApiKeyModel | undefined): void;
|
|
@@ -317,6 +317,13 @@ export interface SessionStats {
|
|
|
317
317
|
premiumRequests: number;
|
|
318
318
|
cost: number;
|
|
319
319
|
}
|
|
320
|
+
export type QueuedMessageEditMode = "steer" | "followUp";
|
|
321
|
+
export interface QueuedMessageEditEntry {
|
|
322
|
+
id: string;
|
|
323
|
+
text: string;
|
|
324
|
+
mode: QueuedMessageEditMode;
|
|
325
|
+
label: string;
|
|
326
|
+
}
|
|
320
327
|
/** A custom message contributed at the before-agent-start point. */
|
|
321
328
|
export type BeforeAgentStartInternalMessage = Pick<CustomMessage, "customType" | "content" | "display" | "details" | "attribution">;
|
|
322
329
|
/**
|
|
@@ -670,6 +677,9 @@ export declare class AgentSession {
|
|
|
670
677
|
steering: readonly string[];
|
|
671
678
|
followUp: readonly string[];
|
|
672
679
|
};
|
|
680
|
+
getQueuedMessageEntries(): QueuedMessageEditEntry[];
|
|
681
|
+
removeQueuedMessageForEditing(id: string): string | undefined;
|
|
682
|
+
moveQueuedMessageForEditing(id: string, direction: "up" | "down"): boolean;
|
|
673
683
|
/**
|
|
674
684
|
* Pop the newest queued message across steering and follow-up queues.
|
|
675
685
|
* Used by dequeue keybinding to restore messages to editor one at a time.
|
|
@@ -93,6 +93,7 @@ export declare class AgentStorage {
|
|
|
93
93
|
* Sets a cached value with expiry time (unix seconds).
|
|
94
94
|
*/
|
|
95
95
|
setCache(key: string, value: string, expiresAtSec: number): void;
|
|
96
|
+
deleteCachePrefix(prefix: string): void;
|
|
96
97
|
/**
|
|
97
98
|
* Deletes expired cache entries. Call periodically for cleanup.
|
|
98
99
|
*/
|
|
@@ -51,6 +51,8 @@ export interface ExecutorOptions {
|
|
|
51
51
|
artifactsDir?: string;
|
|
52
52
|
/** Path to parent conversation context file */
|
|
53
53
|
contextFile?: string;
|
|
54
|
+
/** Whether the parent runtime actually exposes IRC coordination. */
|
|
55
|
+
ircAvailable?: boolean;
|
|
54
56
|
eventBus?: EventBus;
|
|
55
57
|
contextFiles?: ContextFileEntry[];
|
|
56
58
|
skills?: Skill[];
|
|
@@ -238,7 +238,7 @@ export interface ComputerScreenshotDetails {
|
|
|
238
238
|
scaleY?: number;
|
|
239
239
|
originX?: number;
|
|
240
240
|
originY?: number;
|
|
241
|
-
displayEpoch?:
|
|
241
|
+
displayEpoch?: number;
|
|
242
242
|
captureId?: string;
|
|
243
243
|
pngBytes?: number;
|
|
244
244
|
path?: string;
|
|
@@ -281,7 +281,7 @@ type NativeScreenshot = {
|
|
|
281
281
|
scaleY?: number;
|
|
282
282
|
originX?: number;
|
|
283
283
|
originY?: number;
|
|
284
|
-
displayEpoch?:
|
|
284
|
+
displayEpoch?: number;
|
|
285
285
|
captureId?: string;
|
|
286
286
|
};
|
|
287
287
|
export type ComputerControllerFactory = () => NativeController;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { type WorkflowClaimsLedger, type WorkflowConsensusReport } from "./workflow-intent-report";
|
|
1
2
|
export declare const WORKFLOW_INTENT_DIFF_CUSTOM_TYPE = "workflow-intent-diff";
|
|
2
|
-
export
|
|
3
|
+
export declare const WORKFLOW_INTENT_ROUTES: readonly ["direct", "deep-interview", "ralplan", "ultragoal", "team"];
|
|
4
|
+
export declare const WORKFLOW_ESCALATION_ROUTES: readonly ["deep-interview", "ralplan", "ultragoal", "team"];
|
|
5
|
+
export type WorkflowIntentRoute = (typeof WORKFLOW_INTENT_ROUTES)[number];
|
|
6
|
+
export type WorkflowEscalationRoute = (typeof WORKFLOW_ESCALATION_ROUTES)[number];
|
|
3
7
|
export type DirectTrackingMode = "custom-entry-only" | "not-direct";
|
|
4
8
|
export type RootCausePhaseStatus = "active" | "inactive";
|
|
5
9
|
export interface WorkflowIntentDiff {
|
|
@@ -7,13 +11,15 @@ export interface WorkflowIntentDiff {
|
|
|
7
11
|
readonly route: WorkflowIntentRoute;
|
|
8
12
|
readonly reason: string;
|
|
9
13
|
readonly directTracking: DirectTrackingMode;
|
|
10
|
-
readonly recommendedSkill?:
|
|
14
|
+
readonly recommendedSkill?: WorkflowEscalationRoute;
|
|
11
15
|
readonly recommendedInvocation?: string;
|
|
12
16
|
readonly triggers: readonly string[];
|
|
13
17
|
readonly rootCausePhase: {
|
|
14
18
|
readonly status: RootCausePhaseStatus;
|
|
15
19
|
readonly triggers: readonly string[];
|
|
16
20
|
};
|
|
21
|
+
readonly claimsLedger: WorkflowClaimsLedger;
|
|
22
|
+
readonly consensusReport: WorkflowConsensusReport;
|
|
17
23
|
readonly promptPreview: string;
|
|
18
24
|
}
|
|
19
25
|
export declare function buildWorkflowIntentDiff(text: string): WorkflowIntentDiff | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SessionEntry } from "../session/session-manager";
|
|
2
|
+
import { type WorkflowIntentDiff, type WorkflowIntentRoute } from "./workflow-intent-diff";
|
|
3
|
+
import type { WorkflowSignalObserver } from "./workflow-intent-report";
|
|
4
|
+
export type WorkflowConsumerConfidence = "none" | "low" | "medium" | "high";
|
|
5
|
+
export interface WorkflowRouteCounts {
|
|
6
|
+
readonly direct: number;
|
|
7
|
+
readonly "deep-interview": number;
|
|
8
|
+
readonly ralplan: number;
|
|
9
|
+
readonly ultragoal: number;
|
|
10
|
+
readonly team: number;
|
|
11
|
+
}
|
|
12
|
+
export interface WorkflowIntentReportEntry {
|
|
13
|
+
readonly entryId: string;
|
|
14
|
+
readonly timestamp: string;
|
|
15
|
+
readonly intent: WorkflowIntentDiff;
|
|
16
|
+
}
|
|
17
|
+
export interface WorkflowIntentReportTotals {
|
|
18
|
+
readonly total: number;
|
|
19
|
+
readonly byRoute: WorkflowRouteCounts;
|
|
20
|
+
readonly escalationRequired: number;
|
|
21
|
+
readonly rootCauseActive: number;
|
|
22
|
+
}
|
|
23
|
+
export interface WorkflowIntentReportCollection {
|
|
24
|
+
readonly entries: readonly WorkflowIntentReportEntry[];
|
|
25
|
+
readonly latest: WorkflowIntentReportEntry | undefined;
|
|
26
|
+
readonly totals: WorkflowIntentReportTotals;
|
|
27
|
+
}
|
|
28
|
+
export interface WorkflowObserverSignalSummary {
|
|
29
|
+
readonly observer: WorkflowSignalObserver;
|
|
30
|
+
readonly conclusion: string;
|
|
31
|
+
readonly count: number;
|
|
32
|
+
}
|
|
33
|
+
export interface WorkflowConsensusSummary {
|
|
34
|
+
readonly total: number;
|
|
35
|
+
readonly dominantRoute: WorkflowIntentRoute | undefined;
|
|
36
|
+
readonly confidence: WorkflowConsumerConfidence;
|
|
37
|
+
readonly escalationGate: {
|
|
38
|
+
readonly required: boolean;
|
|
39
|
+
readonly count: number;
|
|
40
|
+
readonly latestReason: string | undefined;
|
|
41
|
+
};
|
|
42
|
+
readonly rootCausePhase: {
|
|
43
|
+
readonly active: boolean;
|
|
44
|
+
readonly count: number;
|
|
45
|
+
readonly triggers: readonly string[];
|
|
46
|
+
};
|
|
47
|
+
readonly observerSignals: readonly WorkflowObserverSignalSummary[];
|
|
48
|
+
}
|
|
49
|
+
export declare function collectWorkflowIntentReports(entries: readonly SessionEntry[]): WorkflowIntentReportCollection;
|
|
50
|
+
export declare function summarizeWorkflowConsensus(intents: readonly WorkflowIntentDiff[]): WorkflowConsensusSummary;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { RootCausePhaseStatus, WorkflowIntentRoute } from "./workflow-intent-diff";
|
|
2
|
+
export type WorkflowConfidence = "high";
|
|
3
|
+
export type WorkflowClaimStatus = "confirmed";
|
|
4
|
+
export type WorkflowEscalationGateStatus = "required" | "not-required";
|
|
5
|
+
export type WorkflowSignalObserver = "intent-router" | "root-cause-schema" | "escalation-gate";
|
|
6
|
+
export interface WorkflowClaim {
|
|
7
|
+
readonly id: "workflow-route" | "root-cause-phase" | "escalation-gate";
|
|
8
|
+
readonly statement: string;
|
|
9
|
+
readonly status: WorkflowClaimStatus;
|
|
10
|
+
readonly confidence: WorkflowConfidence;
|
|
11
|
+
readonly evidence: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
export interface WorkflowClaimsLedger {
|
|
14
|
+
readonly version: 1;
|
|
15
|
+
readonly claims: readonly WorkflowClaim[];
|
|
16
|
+
}
|
|
17
|
+
export interface WorkflowObserverSignal {
|
|
18
|
+
readonly observer: WorkflowSignalObserver;
|
|
19
|
+
readonly conclusion: string;
|
|
20
|
+
readonly evidence: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
export interface WorkflowConsensusReport {
|
|
23
|
+
readonly version: 1;
|
|
24
|
+
readonly route: WorkflowIntentRoute;
|
|
25
|
+
readonly confidence: WorkflowConfidence;
|
|
26
|
+
readonly summary: string;
|
|
27
|
+
readonly observerSignals: readonly WorkflowObserverSignal[];
|
|
28
|
+
readonly escalationGate: {
|
|
29
|
+
readonly status: WorkflowEscalationGateStatus;
|
|
30
|
+
readonly reason: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface WorkflowIntentReport {
|
|
34
|
+
readonly claimsLedger: WorkflowClaimsLedger;
|
|
35
|
+
readonly consensusReport: WorkflowConsensusReport;
|
|
36
|
+
}
|
|
37
|
+
export interface WorkflowIntentReportInput {
|
|
38
|
+
readonly route: WorkflowIntentRoute;
|
|
39
|
+
readonly reason: string;
|
|
40
|
+
readonly direct: boolean;
|
|
41
|
+
readonly recommendedInvocation?: string;
|
|
42
|
+
readonly triggers: readonly string[];
|
|
43
|
+
readonly rootCausePhase: {
|
|
44
|
+
readonly status: RootCausePhaseStatus;
|
|
45
|
+
readonly triggers: readonly string[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export declare function buildWorkflowIntentReport(input: WorkflowIntentReportInput): WorkflowIntentReport;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.2",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
53
53
|
"@babel/parser": "^7.29.3",
|
|
54
54
|
"@mozilla/readability": "^0.6.0",
|
|
55
|
-
"@gajae-code/stats": "0.8.
|
|
56
|
-
"@gajae-code/agent-core": "0.8.
|
|
57
|
-
"@gajae-code/ai": "0.8.
|
|
58
|
-
"@gajae-code/natives": "0.8.
|
|
59
|
-
"@gajae-code/tui": "0.8.
|
|
60
|
-
"@gajae-code/utils": "0.8.
|
|
55
|
+
"@gajae-code/stats": "0.8.2",
|
|
56
|
+
"@gajae-code/agent-core": "0.8.2",
|
|
57
|
+
"@gajae-code/ai": "0.8.2",
|
|
58
|
+
"@gajae-code/natives": "0.8.2",
|
|
59
|
+
"@gajae-code/tui": "0.8.2",
|
|
60
|
+
"@gajae-code/utils": "0.8.2",
|
|
61
61
|
"@puppeteer/browsers": "^2.13.0",
|
|
62
62
|
"@types/turndown": "5.0.6",
|
|
63
63
|
"@xterm/headless": "^6.0.0",
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import type { ArgDescriptor, CommandCtor, CommandEntry, FlagDescriptor } from "@gajae-code/utils/cli";
|
|
5
|
+
|
|
6
|
+
export type FigName = string | string[];
|
|
7
|
+
|
|
8
|
+
export interface FigArg {
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
isOptional?: boolean;
|
|
12
|
+
isVariadic?: boolean;
|
|
13
|
+
suggestions?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FigOption {
|
|
17
|
+
name: FigName;
|
|
18
|
+
description?: string;
|
|
19
|
+
args?: FigArg;
|
|
20
|
+
isRepeatable?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FigSubcommand {
|
|
24
|
+
name: FigName;
|
|
25
|
+
description?: string;
|
|
26
|
+
options?: FigOption[];
|
|
27
|
+
args?: FigArg | FigArg[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface FigSpec extends FigSubcommand {
|
|
31
|
+
name: string;
|
|
32
|
+
subcommands?: FigSubcommand[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type InshellisenseIndexStatus = "created" | "updated" | "already-compatible" | "overwritten";
|
|
36
|
+
|
|
37
|
+
export interface InstallGjcInshellisenseSpecOptions {
|
|
38
|
+
dir?: string;
|
|
39
|
+
force?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface InstallGjcInshellisenseSpecResult {
|
|
43
|
+
directory: string;
|
|
44
|
+
specPath: string;
|
|
45
|
+
indexPath: string;
|
|
46
|
+
indexStatus: InshellisenseIndexStatus;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const GENERATED_INDEX_MARKER = "// Generated by gjc completion inshellisense";
|
|
50
|
+
const BUILTIN_ROOT_OPTIONS: FigOption[] = [
|
|
51
|
+
{ name: ["-h", "--help"], description: "Show help" },
|
|
52
|
+
{ name: ["-v", "--version"], description: "Show version" },
|
|
53
|
+
];
|
|
54
|
+
const BUILTIN_COMMAND_OPTIONS: FigOption[] = [{ name: ["-h", "--help"], description: "Show help" }];
|
|
55
|
+
|
|
56
|
+
export function defaultInshellisenseSpecDir(homeDir: string = os.homedir()): string {
|
|
57
|
+
return path.join(homeDir, ".fig", "autocomplete", "build");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function nameList(name: FigName): string[] {
|
|
61
|
+
return Array.isArray(name) ? name : [name];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function optionKey(option: FigOption): string {
|
|
65
|
+
return nameList(option.name).join("\u0000");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function combineOptions(primary: FigOption[], secondary: FigOption[]): FigOption[] {
|
|
69
|
+
const seen = new Set<string>();
|
|
70
|
+
const combined: FigOption[] = [];
|
|
71
|
+
for (const option of [...primary, ...secondary]) {
|
|
72
|
+
const key = optionKey(option);
|
|
73
|
+
if (seen.has(key)) continue;
|
|
74
|
+
seen.add(key);
|
|
75
|
+
combined.push(option);
|
|
76
|
+
}
|
|
77
|
+
return combined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function commandEntryName(entry: CommandEntry): FigName {
|
|
81
|
+
const names = [entry.name, ...(entry.aliases ?? [])];
|
|
82
|
+
return names.length === 1 ? names[0]! : names;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function flagName(name: string, descriptor: FlagDescriptor): FigName {
|
|
86
|
+
const longName = `--${name}`;
|
|
87
|
+
if (!descriptor.char) return longName;
|
|
88
|
+
return [`-${descriptor.char}`, longName];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function argSuggestions(options: readonly string[] | undefined): string[] | undefined {
|
|
92
|
+
return options && options.length > 0 ? [...options] : undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function optionArgName(name: string, descriptor: FlagDescriptor): string {
|
|
96
|
+
if (descriptor.options && descriptor.options.length > 0) return name;
|
|
97
|
+
return descriptor.kind === "integer" ? "int" : "value";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function figOptionFromFlag(name: string, descriptor: FlagDescriptor): FigOption {
|
|
101
|
+
const option: FigOption = {
|
|
102
|
+
name: flagName(name, descriptor),
|
|
103
|
+
};
|
|
104
|
+
if (descriptor.description) option.description = descriptor.description;
|
|
105
|
+
if (descriptor.multiple) option.isRepeatable = true;
|
|
106
|
+
if (descriptor.kind !== "boolean") {
|
|
107
|
+
const arg: FigArg = { name: optionArgName(name, descriptor) };
|
|
108
|
+
const suggestions = argSuggestions(descriptor.options);
|
|
109
|
+
if (suggestions) arg.suggestions = suggestions;
|
|
110
|
+
option.args = arg;
|
|
111
|
+
}
|
|
112
|
+
return option;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function figOptionsFromFlags(flags: Record<string, FlagDescriptor> | undefined): FigOption[] {
|
|
116
|
+
if (!flags) return [];
|
|
117
|
+
return Object.entries(flags).map(([name, descriptor]) => figOptionFromFlag(name, descriptor));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function figArgFromDescriptor(name: string, descriptor: ArgDescriptor): FigArg {
|
|
121
|
+
const arg: FigArg = { name };
|
|
122
|
+
if (descriptor.description) arg.description = descriptor.description;
|
|
123
|
+
if (!descriptor.required) arg.isOptional = true;
|
|
124
|
+
if (descriptor.multiple) arg.isVariadic = true;
|
|
125
|
+
const suggestions = argSuggestions(descriptor.options);
|
|
126
|
+
if (suggestions) arg.suggestions = suggestions;
|
|
127
|
+
return arg;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function figArgsFromDescriptors(args: Record<string, ArgDescriptor> | undefined): FigArg | FigArg[] | undefined {
|
|
131
|
+
if (!args) return undefined;
|
|
132
|
+
const values = Object.entries(args).map(([name, descriptor]) => figArgFromDescriptor(name, descriptor));
|
|
133
|
+
if (values.length === 0) return undefined;
|
|
134
|
+
return values.length === 1 ? values[0] : values;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function commandToSubcommand(entry: CommandEntry, command: CommandCtor): FigSubcommand {
|
|
138
|
+
const subcommand: FigSubcommand = { name: commandEntryName(entry) };
|
|
139
|
+
if (command.description) subcommand.description = command.description;
|
|
140
|
+
const options = combineOptions(BUILTIN_COMMAND_OPTIONS, figOptionsFromFlags(command.flags));
|
|
141
|
+
if (options.length > 0) subcommand.options = options;
|
|
142
|
+
const args = figArgsFromDescriptors(command.args);
|
|
143
|
+
if (args) subcommand.args = args;
|
|
144
|
+
return subcommand;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function buildGjcFigSpec(entries: CommandEntry[], rootCommandOverride?: CommandCtor): Promise<FigSpec> {
|
|
148
|
+
const subcommands: FigSubcommand[] = [];
|
|
149
|
+
let rootCommand: CommandCtor | undefined = rootCommandOverride;
|
|
150
|
+
|
|
151
|
+
for (const entry of entries) {
|
|
152
|
+
if (entry.name === "launch" && rootCommandOverride) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
let command: CommandCtor;
|
|
156
|
+
try {
|
|
157
|
+
command = await entry.load();
|
|
158
|
+
} catch {
|
|
159
|
+
if (entry.name !== "launch") {
|
|
160
|
+
subcommands.push({ name: commandEntryName(entry) });
|
|
161
|
+
}
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (entry.name === "launch") {
|
|
165
|
+
rootCommand = command;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (command.hidden) continue;
|
|
169
|
+
subcommands.push(commandToSubcommand(entry, command));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const spec: FigSpec = {
|
|
173
|
+
name: "gjc",
|
|
174
|
+
description: rootCommand?.description ?? "Gajae Code CLI",
|
|
175
|
+
};
|
|
176
|
+
const rootOptions = combineOptions(BUILTIN_ROOT_OPTIONS, figOptionsFromFlags(rootCommand?.flags));
|
|
177
|
+
if (rootOptions.length > 0) spec.options = rootOptions;
|
|
178
|
+
const rootArgs = figArgsFromDescriptors(rootCommand?.args);
|
|
179
|
+
if (rootArgs) spec.args = rootArgs;
|
|
180
|
+
if (subcommands.length > 0) spec.subcommands = subcommands;
|
|
181
|
+
return spec;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function renderFigSpecModule(spec: FigSpec): string {
|
|
185
|
+
return `const completionSpec = ${JSON.stringify(spec, null, "\t")};\n\nexport default completionSpec;\n`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function renderInshellisenseIndexModule(): string {
|
|
189
|
+
return `${GENERATED_INDEX_MARKER}\n\nexport default ["gjc"];\nexport const diffVersionedCompletions = [];\n`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function fileTextIfExists(filePath: string): Promise<string | undefined> {
|
|
193
|
+
try {
|
|
194
|
+
return await Bun.file(filePath).text();
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return undefined;
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function indexDeclaresGjc(content: string): boolean {
|
|
202
|
+
return /["']gjc["']/.test(content);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function resolveIndexStatus(indexPath: string, force: boolean | undefined): Promise<InshellisenseIndexStatus> {
|
|
206
|
+
const existing = await fileTextIfExists(indexPath);
|
|
207
|
+
if (existing === undefined) return "created";
|
|
208
|
+
if (existing.includes(GENERATED_INDEX_MARKER)) {
|
|
209
|
+
return existing === renderInshellisenseIndexModule() ? "already-compatible" : "updated";
|
|
210
|
+
}
|
|
211
|
+
if (indexDeclaresGjc(existing)) return "already-compatible";
|
|
212
|
+
if (force) return "overwritten";
|
|
213
|
+
throw new Error(
|
|
214
|
+
`inshellisense index already exists at ${indexPath} and does not list gjc; rerun with --force to overwrite it or pass --dir to install into a GJC-only specs directory`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function installGjcInshellisenseSpec(
|
|
219
|
+
spec: FigSpec,
|
|
220
|
+
options: InstallGjcInshellisenseSpecOptions = {},
|
|
221
|
+
): Promise<InstallGjcInshellisenseSpecResult> {
|
|
222
|
+
const directory = path.resolve(options.dir ?? defaultInshellisenseSpecDir());
|
|
223
|
+
const specPath = path.join(directory, "gjc.js");
|
|
224
|
+
const indexPath = path.join(directory, "index.js");
|
|
225
|
+
const indexStatus = await resolveIndexStatus(indexPath, options.force);
|
|
226
|
+
|
|
227
|
+
await fs.mkdir(directory, { recursive: true });
|
|
228
|
+
await Bun.write(specPath, renderFigSpecModule(spec));
|
|
229
|
+
if (indexStatus !== "already-compatible") {
|
|
230
|
+
await Bun.write(indexPath, renderInshellisenseIndexModule());
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return { directory, specPath, indexPath, indexStatus };
|
|
234
|
+
}
|