@gajae-code/coding-agent 0.5.0 → 0.5.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 +36 -0
- package/README.md +1 -1
- package/dist/types/async/job-manager.d.ts +26 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/list-models.d.ts +6 -0
- package/dist/types/cli/setup-cli.d.ts +8 -1
- package/dist/types/commands/gc.d.ts +26 -0
- package/dist/types/commands/setup.d.ts +7 -0
- package/dist/types/config/file-lock-gc.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +29 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +62 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/defaults/gjc/extensions/grok-build/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
- package/dist/types/defaults/gjc-grok-cli.d.ts +5 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +103 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +112 -0
- package/dist/types/gjc-runtime/gc-render.d.ts +6 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +134 -0
- package/dist/types/gjc-runtime/ledger-event-renderer.d.ts +68 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +64 -2
- package/dist/types/gjc-runtime/team-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +11 -0
- package/dist/types/gjc-runtime/tmux-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
- package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
- package/dist/types/harness-control-plane/owner.d.ts +7 -0
- package/dist/types/harness-control-plane/storage.d.ts +20 -0
- package/dist/types/modes/components/hook-selector.d.ts +7 -1
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +72 -2
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +13 -0
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/theme/defaults/index.d.ts +302 -0
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +39 -3
- package/dist/types/session/history-storage.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +10 -1
- package/dist/types/setup/credential-import.d.ts +79 -0
- package/dist/types/skill-state/workflow-hud.d.ts +14 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/render.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +15 -1
- package/dist/types/tools/subagent-render.d.ts +7 -1
- package/dist/types/tools/subagent.d.ts +27 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
- package/dist/types/web/search/index.d.ts +4 -4
- package/dist/types/web/search/provider.d.ts +16 -20
- package/dist/types/web/search/providers/base.d.ts +2 -1
- package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +14 -2
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +52 -0
- package/src/cli/args.ts +5 -0
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/fast-help.ts +2 -0
- package/src/cli/list-models.ts +13 -1
- package/src/cli/setup-cli.ts +138 -3
- package/src/cli.ts +1 -0
- package/src/commands/gc.ts +22 -0
- package/src/commands/harness.ts +7 -3
- package/src/commands/setup.ts +5 -1
- package/src/commands/ultragoal.ts +3 -1
- package/src/config/file-lock-gc.ts +193 -0
- package/src/config/file-lock.ts +66 -10
- package/src/config/model-profile-activation.ts +15 -3
- package/src/config/model-profiles.ts +39 -30
- package/src/config/model-registry.ts +21 -1
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +62 -0
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/server.ts +459 -3
- package/src/defaults/gjc/agent.models.grok-cli.yml +36 -0
- package/src/defaults/gjc/extensions/grok-build/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-build/package.json +7 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +39 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/package.json +8 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +131 -113
- package/src/defaults/gjc/skills/deep-interview/lateral-review-panel.md +49 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +30 -8
- package/src/defaults/gjc-defaults.ts +7 -0
- package/src/defaults/gjc-grok-cli.ts +22 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +457 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +18 -26
- package/src/gjc-runtime/deep-interview-state.ts +324 -0
- package/src/gjc-runtime/gc-render.ts +70 -0
- package/src/gjc-runtime/gc-runtime.ts +403 -0
- package/src/gjc-runtime/launch-tmux.ts +3 -4
- package/src/gjc-runtime/ledger-event-renderer.ts +164 -0
- package/src/gjc-runtime/ralplan-runtime.ts +232 -19
- package/src/gjc-runtime/state-renderer.ts +12 -3
- package/src/gjc-runtime/state-runtime.ts +48 -30
- package/src/gjc-runtime/state-writer.ts +254 -7
- package/src/gjc-runtime/team-gc.ts +49 -0
- package/src/gjc-runtime/team-runtime.ts +179 -2
- package/src/gjc-runtime/tmux-common.ts +14 -0
- package/src/gjc-runtime/tmux-gc.ts +177 -0
- package/src/gjc-runtime/tmux-sessions.ts +49 -1
- package/src/gjc-runtime/ultragoal-guard.ts +155 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1239 -31
- package/src/gjc-runtime/workflow-manifest.generated.json +44 -0
- package/src/gjc-runtime/workflow-manifest.ts +12 -0
- package/src/harness-control-plane/gc-adapter.ts +184 -0
- package/src/harness-control-plane/owner.ts +14 -2
- package/src/harness-control-plane/rpc-adapter.ts +1 -1
- package/src/harness-control-plane/storage.ts +70 -0
- package/src/hooks/skill-state.ts +121 -2
- package/src/internal-urls/docs-index.generated.ts +22 -12
- package/src/lsp/defaults.json +1 -0
- package/src/main.ts +18 -3
- package/src/modes/acp/acp-agent.ts +4 -2
- package/src/modes/bridge/bridge-mode.ts +2 -1
- package/src/modes/components/history-search.ts +5 -2
- package/src/modes/components/hook-selector.ts +19 -0
- package/src/modes/components/model-selector.ts +51 -8
- package/src/modes/components/provider-onboarding-selector.ts +6 -1
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/controllers/command-controller.ts +25 -6
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/selector-controller.ts +81 -1
- package/src/modes/interactive-mode.ts +11 -1
- package/src/modes/rpc/rpc-mode.ts +266 -34
- package/src/modes/shared/agent-wire/command-dispatch.ts +281 -261
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +30 -1
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +3 -0
- package/src/modes/shared/agent-wire/session-registry.ts +109 -0
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +24 -0
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +23 -3
- package/src/modes/shared/agent-wire/unattended-session.ts +32 -2
- package/src/modes/theme/defaults/claude-code.json +100 -0
- package/src/modes/theme/defaults/codex.json +100 -0
- package/src/modes/theme/defaults/index.ts +6 -0
- package/src/modes/theme/defaults/opencode.json +102 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/types.ts +1 -1
- package/src/prompts/agents/executor.md +5 -2
- package/src/sdk.ts +29 -4
- package/src/session/agent-session.ts +99 -19
- package/src/session/blob-store.ts +59 -3
- package/src/session/history-storage.ts +32 -11
- package/src/session/session-manager.ts +72 -20
- package/src/setup/credential-import.ts +429 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +7 -1
- package/src/skill-state/deep-interview-mutation-guard.ts +2 -1
- package/src/skill-state/workflow-hud.ts +106 -10
- package/src/slash-commands/builtin-registry.ts +3 -2
- package/src/task/executor.ts +16 -1
- package/src/task/render.ts +18 -7
- package/src/tools/ask.ts +59 -2
- package/src/tools/cron.ts +1 -1
- package/src/tools/job.ts +3 -2
- package/src/tools/monitor.ts +36 -1
- package/src/tools/subagent-render.ts +128 -29
- package/src/tools/subagent.ts +173 -9
- package/src/tools/ultragoal-ask-guard.ts +39 -0
- package/src/web/search/index.ts +25 -25
- package/src/web/search/provider.ts +178 -87
- package/src/web/search/providers/base.ts +2 -1
- package/src/web/search/providers/openai-compatible.ts +151 -0
- package/src/web/search/types.ts +47 -22
|
@@ -168,6 +168,50 @@ interface CoordinatorSessionState {
|
|
|
168
168
|
reason: string | null;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
type CoordinatorEventKind =
|
|
172
|
+
| "session.registered"
|
|
173
|
+
| "session.started"
|
|
174
|
+
| "session.state_changed"
|
|
175
|
+
| "turn.queued"
|
|
176
|
+
| "turn.delivering"
|
|
177
|
+
| "turn.active"
|
|
178
|
+
| "turn.waiting_for_answer"
|
|
179
|
+
| "turn.completed"
|
|
180
|
+
| "turn.failed"
|
|
181
|
+
| "turn.cancelled"
|
|
182
|
+
| "turn.superseded"
|
|
183
|
+
| "question.opened"
|
|
184
|
+
| "question.answered"
|
|
185
|
+
| "report.written"
|
|
186
|
+
| "tmux.delivery_succeeded"
|
|
187
|
+
| "tmux.delivery_failed";
|
|
188
|
+
|
|
189
|
+
interface CoordinatorEvent {
|
|
190
|
+
schema_version: 1;
|
|
191
|
+
seq: number;
|
|
192
|
+
id: string;
|
|
193
|
+
timestamp: string;
|
|
194
|
+
kind: CoordinatorEventKind;
|
|
195
|
+
session_id?: string;
|
|
196
|
+
turn_id?: string;
|
|
197
|
+
question_id?: string;
|
|
198
|
+
report_id?: string;
|
|
199
|
+
summary: string;
|
|
200
|
+
payload_ref?: string;
|
|
201
|
+
metadata?: Record<string, string | number | boolean | null>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
interface CoordinatorEventInput {
|
|
205
|
+
kind: CoordinatorEventKind;
|
|
206
|
+
sessionId?: string | null;
|
|
207
|
+
turnId?: string | null;
|
|
208
|
+
questionId?: string | null;
|
|
209
|
+
reportId?: string | null;
|
|
210
|
+
summary: string;
|
|
211
|
+
payloadRef?: string | null;
|
|
212
|
+
metadata?: Record<string, string | number | boolean | null>;
|
|
213
|
+
}
|
|
214
|
+
|
|
171
215
|
const MISSING_FINAL_RESPONSE_ADVISORY = "completion_missing_final_response";
|
|
172
216
|
const ACTIVE_TURN_STATUSES = new Set<TurnStatus>(["delivering", "active", "waiting_for_answer", "completing"]);
|
|
173
217
|
const TERMINAL_TURN_STATUSES = new Set<TurnStatus>(["completed", "failed", "cancelled", "superseded"]);
|
|
@@ -351,6 +395,22 @@ function toolSchema(name: CoordinatorToolName): {
|
|
|
351
395
|
if (name === "gjc_coordinator_read_coordination_status") {
|
|
352
396
|
return { name, description: "Read coordinator coordination reports.", inputSchema: common };
|
|
353
397
|
}
|
|
398
|
+
if (name === "gjc_coordinator_watch_events") {
|
|
399
|
+
return {
|
|
400
|
+
name,
|
|
401
|
+
description: "Long-poll the durable coordinator event journal for new bounded event records.",
|
|
402
|
+
inputSchema: {
|
|
403
|
+
type: "object",
|
|
404
|
+
properties: {
|
|
405
|
+
after_seq: { type: "number" },
|
|
406
|
+
session_id: sessionId,
|
|
407
|
+
event_types: { type: "array", items: { type: "string" } },
|
|
408
|
+
timeout_ms: { type: "number" },
|
|
409
|
+
limit: { type: "number" },
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
}
|
|
354
414
|
return { name, description: "List known scoped GJC coordinator bridge sessions.", inputSchema: common };
|
|
355
415
|
}
|
|
356
416
|
|
|
@@ -393,6 +453,218 @@ async function listJsonFiles(dir: string): Promise<unknown[]> {
|
|
|
393
453
|
}
|
|
394
454
|
}
|
|
395
455
|
|
|
456
|
+
const COORDINATOR_STATUS_EVENT_LIMIT = 100;
|
|
457
|
+
|
|
458
|
+
function jsonRecords(values: unknown[]): Array<Record<string, unknown>> {
|
|
459
|
+
return values.map(value => asRecord(value)).filter((value): value is Record<string, unknown> => value !== null);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function firstString(record: Record<string, unknown>, keys: string[]): string | null {
|
|
463
|
+
for (const key of keys) {
|
|
464
|
+
const value = record[key];
|
|
465
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function eventTimestamp(record: Record<string, unknown>): string | null {
|
|
471
|
+
return firstString(record, ["updated_at", "completed_at", "answered_at", "created_at", "registered_at"]);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function canonicalCoordinatorEvent(
|
|
475
|
+
event_type: "session_state" | "turn_state" | "question_state" | "coordination_report",
|
|
476
|
+
record: Record<string, unknown>,
|
|
477
|
+
): Record<string, unknown> {
|
|
478
|
+
return {
|
|
479
|
+
schema_version: 1,
|
|
480
|
+
event_type,
|
|
481
|
+
session_id: firstString(record, ["session_id", "sessionId"]),
|
|
482
|
+
turn_id: firstString(record, ["turn_id", "turnId", "current_turn_id", "last_turn_id"]),
|
|
483
|
+
question_id: event_type === "question_state" ? firstString(record, ["id", "question_id"]) : null,
|
|
484
|
+
status: firstString(record, ["status", "state"]),
|
|
485
|
+
source: firstString(record, ["source"]),
|
|
486
|
+
reason: firstString(record, ["reason"]),
|
|
487
|
+
updated_at: eventTimestamp(record),
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function sortNewestFirst(records: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
492
|
+
return [...records].sort((left, right) => {
|
|
493
|
+
const leftTime = eventTimestamp(left) ?? "";
|
|
494
|
+
const rightTime = eventTimestamp(right) ?? "";
|
|
495
|
+
return rightTime.localeCompare(leftTime);
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function buildCanonicalCoordinatorEvents(input: {
|
|
500
|
+
sessionStates: Array<Record<string, unknown>>;
|
|
501
|
+
turns: Array<Record<string, unknown>>;
|
|
502
|
+
questions: Array<Record<string, unknown>>;
|
|
503
|
+
reports: Array<Record<string, unknown>>;
|
|
504
|
+
}): Array<Record<string, unknown>> {
|
|
505
|
+
return sortNewestFirst([
|
|
506
|
+
...input.sessionStates.map(record => canonicalCoordinatorEvent("session_state", record)),
|
|
507
|
+
...input.turns.map(record => canonicalCoordinatorEvent("turn_state", record)),
|
|
508
|
+
...input.questions.map(record => canonicalCoordinatorEvent("question_state", record)),
|
|
509
|
+
...input.reports.map(record => canonicalCoordinatorEvent("coordination_report", record)),
|
|
510
|
+
]).slice(0, COORDINATOR_STATUS_EVENT_LIMIT);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function activeSessionStates(sessionStates: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
514
|
+
return sessionStates.filter(record => {
|
|
515
|
+
const state = record.state;
|
|
516
|
+
return state === "booting" || state === "running" || state === "needs_user_input" || state === "stale";
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function eventsDir(namespaceDir: string): string {
|
|
521
|
+
return path.join(namespaceDir, "events");
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function eventJournalFile(namespaceDir: string): string {
|
|
525
|
+
return path.join(eventsDir(namespaceDir), "event-journal.jsonl");
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function eventSequenceFile(namespaceDir: string): string {
|
|
529
|
+
return path.join(eventsDir(namespaceDir), "latest-seq.json");
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function boundSummary(value: string): string {
|
|
533
|
+
const normalized = value
|
|
534
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
535
|
+
.replace(/\s+/g, " ")
|
|
536
|
+
.trim();
|
|
537
|
+
return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function readLatestEventSeq(namespaceDir: string): Promise<number> {
|
|
541
|
+
const sequence = asRecord(await readJsonFile(eventSequenceFile(namespaceDir)));
|
|
542
|
+
const seq = sequence?.seq;
|
|
543
|
+
if (typeof seq === "number" && Number.isInteger(seq) && seq >= 0) return seq;
|
|
544
|
+
let latestSeq = 0;
|
|
545
|
+
for (const event of await readCoordinatorEvents(namespaceDir)) latestSeq = Math.max(latestSeq, event.seq);
|
|
546
|
+
return latestSeq;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const eventAppendQueues = new Map<string, Promise<unknown>>();
|
|
550
|
+
|
|
551
|
+
async function appendCoordinatorEvent(namespaceDir: string, input: CoordinatorEventInput): Promise<CoordinatorEvent> {
|
|
552
|
+
const previous = eventAppendQueues.get(namespaceDir) ?? Promise.resolve();
|
|
553
|
+
let release!: () => void;
|
|
554
|
+
const current = new Promise<void>(resolve => {
|
|
555
|
+
release = resolve;
|
|
556
|
+
});
|
|
557
|
+
const queued = previous.then(
|
|
558
|
+
() => current,
|
|
559
|
+
() => current,
|
|
560
|
+
);
|
|
561
|
+
eventAppendQueues.set(namespaceDir, queued);
|
|
562
|
+
|
|
563
|
+
await previous.catch(() => undefined);
|
|
564
|
+
try {
|
|
565
|
+
const latestSeq = await readLatestEventSeq(namespaceDir);
|
|
566
|
+
const seq = latestSeq + 1;
|
|
567
|
+
const timestamp = new Date().toISOString();
|
|
568
|
+
const event: CoordinatorEvent = {
|
|
569
|
+
schema_version: 1,
|
|
570
|
+
seq,
|
|
571
|
+
id: `event-${seq.toString().padStart(12, "0")}`,
|
|
572
|
+
timestamp,
|
|
573
|
+
kind: input.kind,
|
|
574
|
+
summary: boundSummary(input.summary),
|
|
575
|
+
...(input.sessionId ? { session_id: input.sessionId } : {}),
|
|
576
|
+
...(input.turnId ? { turn_id: input.turnId } : {}),
|
|
577
|
+
...(input.questionId ? { question_id: input.questionId } : {}),
|
|
578
|
+
...(input.reportId ? { report_id: input.reportId } : {}),
|
|
579
|
+
...(input.payloadRef ? { payload_ref: input.payloadRef } : {}),
|
|
580
|
+
...(input.metadata ? { metadata: input.metadata } : {}),
|
|
581
|
+
};
|
|
582
|
+
await ensureDir(eventsDir(namespaceDir));
|
|
583
|
+
await fs.appendFile(eventJournalFile(namespaceDir), `${JSON.stringify(event)}\n`);
|
|
584
|
+
await writeJsonFile(eventSequenceFile(namespaceDir), { seq, updated_at: timestamp });
|
|
585
|
+
return event;
|
|
586
|
+
} finally {
|
|
587
|
+
release();
|
|
588
|
+
if (eventAppendQueues.get(namespaceDir) === queued) eventAppendQueues.delete(namespaceDir);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function parseCoordinatorEvent(line: string): CoordinatorEvent | null {
|
|
593
|
+
try {
|
|
594
|
+
const event = JSON.parse(line) as CoordinatorEvent;
|
|
595
|
+
if (typeof event.seq !== "number" || typeof event.kind !== "string") return null;
|
|
596
|
+
return event;
|
|
597
|
+
} catch {
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
async function readCoordinatorEvents(namespaceDir: string): Promise<CoordinatorEvent[]> {
|
|
603
|
+
try {
|
|
604
|
+
const content = await fs.readFile(eventJournalFile(namespaceDir), "utf8");
|
|
605
|
+
return content
|
|
606
|
+
.split("\n")
|
|
607
|
+
.map(line => line.trim())
|
|
608
|
+
.filter(Boolean)
|
|
609
|
+
.map(parseCoordinatorEvent)
|
|
610
|
+
.filter((event): event is CoordinatorEvent => event !== null)
|
|
611
|
+
.sort((left, right) => left.seq - right.seq);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
|
|
614
|
+
throw error;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function boundedEventLimit(value: unknown): number {
|
|
619
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
620
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return 100;
|
|
621
|
+
return Math.min(parsed, 100);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function eventTypeFilter(value: unknown): Set<string> | null {
|
|
625
|
+
if (!Array.isArray(value)) return null;
|
|
626
|
+
const types = value.filter((item): item is string => typeof item === "string" && item.length > 0);
|
|
627
|
+
return types.length > 0 ? new Set(types) : null;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function filterCoordinatorEvents(
|
|
631
|
+
events: CoordinatorEvent[],
|
|
632
|
+
args: Record<string, unknown>,
|
|
633
|
+
limit: number,
|
|
634
|
+
): CoordinatorEvent[] {
|
|
635
|
+
const afterSeq =
|
|
636
|
+
typeof args.after_seq === "number" ? args.after_seq : Number.parseInt(String(args.after_seq ?? "0"), 10);
|
|
637
|
+
const safeAfterSeq = Number.isFinite(afterSeq) && afterSeq > 0 ? afterSeq : 0;
|
|
638
|
+
const sessionId = args.session_id == null ? null : safeExternalId("session", args.session_id);
|
|
639
|
+
const eventTypes = eventTypeFilter(args.event_types);
|
|
640
|
+
return events
|
|
641
|
+
.filter(event => event.seq > safeAfterSeq)
|
|
642
|
+
.filter(event => !sessionId || event.session_id === sessionId)
|
|
643
|
+
.filter(event => !eventTypes || eventTypes.has(event.kind))
|
|
644
|
+
.slice(0, limit);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function eventSummaries(
|
|
648
|
+
events: CoordinatorEvent[],
|
|
649
|
+
): Array<
|
|
650
|
+
Pick<
|
|
651
|
+
CoordinatorEvent,
|
|
652
|
+
"seq" | "id" | "timestamp" | "kind" | "session_id" | "turn_id" | "question_id" | "report_id" | "summary"
|
|
653
|
+
>
|
|
654
|
+
> {
|
|
655
|
+
return events.map(event => ({
|
|
656
|
+
seq: event.seq,
|
|
657
|
+
id: event.id,
|
|
658
|
+
timestamp: event.timestamp,
|
|
659
|
+
kind: event.kind,
|
|
660
|
+
...(event.session_id ? { session_id: event.session_id } : {}),
|
|
661
|
+
...(event.turn_id ? { turn_id: event.turn_id } : {}),
|
|
662
|
+
...(event.question_id ? { question_id: event.question_id } : {}),
|
|
663
|
+
...(event.report_id ? { report_id: event.report_id } : {}),
|
|
664
|
+
summary: event.summary,
|
|
665
|
+
}));
|
|
666
|
+
}
|
|
667
|
+
|
|
396
668
|
function safeExternalId(kind: "session" | "question", value: unknown): string {
|
|
397
669
|
if (typeof value !== "string" || !SAFE_EXTERNAL_ID_PATTERN.test(value)) throw new Error(`invalid_${kind}_id`);
|
|
398
670
|
return value;
|
|
@@ -449,8 +721,36 @@ async function readTurnRecord(namespaceDir: string, turnId: unknown): Promise<Tu
|
|
|
449
721
|
return (await readJsonFile(turnFile(namespaceDir, safeTurnId(turnId)))) as TurnRecord | null;
|
|
450
722
|
}
|
|
451
723
|
|
|
724
|
+
function turnEventKind(status: TurnStatus): CoordinatorEventKind | null {
|
|
725
|
+
if (status === "queued") return "turn.queued";
|
|
726
|
+
if (status === "delivering") return "turn.delivering";
|
|
727
|
+
if (status === "active") return "turn.active";
|
|
728
|
+
if (status === "waiting_for_answer") return "turn.waiting_for_answer";
|
|
729
|
+
if (status === "completed") return "turn.completed";
|
|
730
|
+
if (status === "failed") return "turn.failed";
|
|
731
|
+
if (status === "cancelled") return "turn.cancelled";
|
|
732
|
+
if (status === "superseded") return "turn.superseded";
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
|
|
452
736
|
async function writeTurnRecord(namespaceDir: string, turn: TurnRecord): Promise<void> {
|
|
737
|
+
const previous = (await readJsonFile(turnFile(namespaceDir, turn.turn_id))) as TurnRecord | null;
|
|
453
738
|
await writeJsonFile(turnFile(namespaceDir, turn.turn_id), turn);
|
|
739
|
+
const kind = previous?.status === turn.status ? null : turnEventKind(turn.status);
|
|
740
|
+
if (kind) {
|
|
741
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
742
|
+
kind,
|
|
743
|
+
sessionId: turn.session_id,
|
|
744
|
+
turnId: turn.turn_id,
|
|
745
|
+
summary: `Turn ${turn.turn_id} is ${turn.status}`,
|
|
746
|
+
payloadRef: path.relative(namespaceDir, turnFile(namespaceDir, turn.turn_id)),
|
|
747
|
+
metadata: {
|
|
748
|
+
status: turn.status,
|
|
749
|
+
queued: turn.delivery.queued,
|
|
750
|
+
tmux_keys_sent: turn.delivery.tmux_keys_sent ?? null,
|
|
751
|
+
},
|
|
752
|
+
});
|
|
753
|
+
}
|
|
454
754
|
}
|
|
455
755
|
|
|
456
756
|
async function readActiveTurn(namespaceDir: string, sessionId: string): Promise<TurnRecord | null> {
|
|
@@ -505,6 +805,28 @@ async function writeSessionState(
|
|
|
505
805
|
reason: options.reason ?? null,
|
|
506
806
|
};
|
|
507
807
|
await writeJsonFile(sessionStateFile(namespaceDir, sessionId), payload);
|
|
808
|
+
if (
|
|
809
|
+
!previous ||
|
|
810
|
+
previous.state !== payload.state ||
|
|
811
|
+
previous.current_turn_id !== payload.current_turn_id ||
|
|
812
|
+
previous.last_turn_id !== payload.last_turn_id ||
|
|
813
|
+
previous.live !== payload.live ||
|
|
814
|
+
previous.reason !== payload.reason
|
|
815
|
+
) {
|
|
816
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
817
|
+
kind: "session.state_changed",
|
|
818
|
+
sessionId,
|
|
819
|
+
turnId: payload.current_turn_id ?? payload.last_turn_id,
|
|
820
|
+
summary: `Session ${sessionId} state changed to ${payload.state}`,
|
|
821
|
+
payloadRef: path.relative(namespaceDir, sessionStateFile(namespaceDir, sessionId)),
|
|
822
|
+
metadata: {
|
|
823
|
+
state: payload.state,
|
|
824
|
+
ready_for_input: payload.ready_for_input,
|
|
825
|
+
live: payload.live,
|
|
826
|
+
reason: payload.reason,
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
}
|
|
508
830
|
return payload;
|
|
509
831
|
}
|
|
510
832
|
|
|
@@ -880,6 +1202,31 @@ function waitForTurnStateChange(namespaceDir: string, turn: TurnRecord, timeoutM
|
|
|
880
1202
|
return deferred.promise;
|
|
881
1203
|
}
|
|
882
1204
|
|
|
1205
|
+
async function waitForCoordinatorEvents(namespaceDir: string, timeoutMs: number): Promise<void> {
|
|
1206
|
+
const deferred = Promise.withResolvers<void>();
|
|
1207
|
+
const watchers: nodeFs.FSWatcher[] = [];
|
|
1208
|
+
let settled = false;
|
|
1209
|
+
const finish = () => {
|
|
1210
|
+
if (settled) return;
|
|
1211
|
+
settled = true;
|
|
1212
|
+
for (const watcher of watchers) watcher.close();
|
|
1213
|
+
clearTimeout(timer);
|
|
1214
|
+
deferred.resolve();
|
|
1215
|
+
};
|
|
1216
|
+
const timer = setTimeout(finish, Math.max(timeoutMs, 0));
|
|
1217
|
+
timer.unref?.();
|
|
1218
|
+
await ensureDir(eventsDir(namespaceDir));
|
|
1219
|
+
try {
|
|
1220
|
+
const watcher = nodeFs.watch(eventsDir(namespaceDir), (_eventType, filename) => {
|
|
1221
|
+
if (filename === "event-journal.jsonl" || filename === "latest-seq.json") finish();
|
|
1222
|
+
});
|
|
1223
|
+
watchers.push(watcher);
|
|
1224
|
+
} catch {
|
|
1225
|
+
// Directory may not exist yet; the timeout remains a bounded fallback.
|
|
1226
|
+
}
|
|
1227
|
+
return deferred.promise;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
883
1230
|
function decodeUtf8WithinByteCap(bytes: Buffer, byteCap: number): string {
|
|
884
1231
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
885
1232
|
for (let end = Math.min(bytes.length, byteCap); end >= 0; end--) {
|
|
@@ -1032,6 +1379,16 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1032
1379
|
reason: tmuxKeysSent ? null : "tmux_delivery_unavailable",
|
|
1033
1380
|
});
|
|
1034
1381
|
}
|
|
1382
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1383
|
+
kind: tmuxKeysSent ? "tmux.delivery_succeeded" : "tmux.delivery_failed",
|
|
1384
|
+
sessionId: activeTurn.session_id,
|
|
1385
|
+
turnId: activeTurn.turn_id,
|
|
1386
|
+
summary: tmuxKeysSent
|
|
1387
|
+
? `Tmux delivery succeeded for turn ${activeTurn.turn_id}`
|
|
1388
|
+
: `Tmux delivery failed for turn ${activeTurn.turn_id}`,
|
|
1389
|
+
payloadRef: path.relative(namespaceDir, turnFile(namespaceDir, activeTurn.turn_id)),
|
|
1390
|
+
metadata: { target: typeof target === "string" ? target : null, live },
|
|
1391
|
+
});
|
|
1035
1392
|
return activeTurn;
|
|
1036
1393
|
}
|
|
1037
1394
|
|
|
@@ -1130,6 +1487,14 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1130
1487
|
sessionFile(sessionId),
|
|
1131
1488
|
commandRunner,
|
|
1132
1489
|
);
|
|
1490
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1491
|
+
kind: "session.registered",
|
|
1492
|
+
sessionId,
|
|
1493
|
+
summary: `Session ${sessionId} registered for coordinator control`,
|
|
1494
|
+
payloadRef: path.relative(namespaceDir, sessionFile(sessionId)),
|
|
1495
|
+
metadata: { source: optionalString(args.source) ?? "register_session", visible: args.visible !== false },
|
|
1496
|
+
});
|
|
1497
|
+
|
|
1133
1498
|
return {
|
|
1134
1499
|
ok: true,
|
|
1135
1500
|
session: registered.session,
|
|
@@ -1169,8 +1534,59 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1169
1534
|
if (name === "gjc_coordinator_list_artifacts") return { ok: true, roots: config.allowedRoots };
|
|
1170
1535
|
if (name === "gjc_coordinator_read_artifact")
|
|
1171
1536
|
return await readCoordinatorArtifact(config, { path: args.path });
|
|
1172
|
-
if (name === "gjc_coordinator_read_coordination_status")
|
|
1173
|
-
|
|
1537
|
+
if (name === "gjc_coordinator_read_coordination_status") {
|
|
1538
|
+
const sessions = jsonRecords(await listSessions());
|
|
1539
|
+
const sessionStates = jsonRecords(await listJsonFiles(path.join(namespaceDir, "session-states")));
|
|
1540
|
+
const turns = jsonRecords(await listJsonFiles(turnsDir(namespaceDir)));
|
|
1541
|
+
const questions = jsonRecords(await listQuestions(args));
|
|
1542
|
+
const reports = jsonRecords(await listJsonFiles(path.join(namespaceDir, "reports")));
|
|
1543
|
+
const events = await readCoordinatorEvents(namespaceDir);
|
|
1544
|
+
return {
|
|
1545
|
+
ok: true,
|
|
1546
|
+
schema_version: 1,
|
|
1547
|
+
namespace: config.namespace,
|
|
1548
|
+
state_root: namespaceDir,
|
|
1549
|
+
transport: { mcp: "polling", push_subscriptions: false },
|
|
1550
|
+
summary: {
|
|
1551
|
+
sessions: sessions.length,
|
|
1552
|
+
active_sessions: activeSessionStates(sessionStates).length,
|
|
1553
|
+
turns: turns.length,
|
|
1554
|
+
active_turns: turns.filter(turn => ACTIVE_TURN_STATUSES.has(turn.status as TurnStatus)).length,
|
|
1555
|
+
queued_turns: turns.filter(turn => turn.status === "queued").length,
|
|
1556
|
+
terminal_turns: turns.filter(turn => TERMINAL_TURN_STATUSES.has(turn.status as TurnStatus)).length,
|
|
1557
|
+
open_questions: questions.filter(question => question.status === "open").length,
|
|
1558
|
+
reports: reports.length,
|
|
1559
|
+
},
|
|
1560
|
+
sessions,
|
|
1561
|
+
session_states: sessionStates,
|
|
1562
|
+
turns,
|
|
1563
|
+
questions,
|
|
1564
|
+
reports,
|
|
1565
|
+
events: buildCanonicalCoordinatorEvents({ sessionStates, turns, questions, reports }),
|
|
1566
|
+
latest_event_seq: await readLatestEventSeq(namespaceDir),
|
|
1567
|
+
recent_events: eventSummaries(events.slice(-10)),
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
if (name === "gjc_coordinator_watch_events") {
|
|
1571
|
+
const limit = boundedEventLimit(args.limit);
|
|
1572
|
+
const timeoutMs = boundedTimeoutMs(args.timeout_ms);
|
|
1573
|
+
let events = await readCoordinatorEvents(namespaceDir);
|
|
1574
|
+
let matched = filterCoordinatorEvents(events, args, limit);
|
|
1575
|
+
let timedOut = false;
|
|
1576
|
+
if (matched.length === 0 && timeoutMs > 0) {
|
|
1577
|
+
await waitForCoordinatorEvents(namespaceDir, timeoutMs);
|
|
1578
|
+
events = await readCoordinatorEvents(namespaceDir);
|
|
1579
|
+
matched = filterCoordinatorEvents(events, args, limit);
|
|
1580
|
+
timedOut = matched.length === 0;
|
|
1581
|
+
}
|
|
1582
|
+
return {
|
|
1583
|
+
ok: true,
|
|
1584
|
+
events: matched,
|
|
1585
|
+
latest_seq: await readLatestEventSeq(namespaceDir),
|
|
1586
|
+
timed_out: timedOut,
|
|
1587
|
+
transport: { mcp: "long_poll", push_subscriptions: false },
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1174
1590
|
if (name === "gjc_coordinator_start_session") {
|
|
1175
1591
|
requireCoordinatorMutation(config, "sessions", args);
|
|
1176
1592
|
const cwd = await assertCoordinatorWorkdir(config, args.cwd);
|
|
@@ -1187,6 +1603,13 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1187
1603
|
if (!startedRecord) throw new Error("coordinator_session_command_required");
|
|
1188
1604
|
const session = normalizeSession(startedRecord);
|
|
1189
1605
|
await writeJsonFile(sessionFile(session.session_id), session);
|
|
1606
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1607
|
+
kind: "session.started",
|
|
1608
|
+
sessionId: String(session.session_id),
|
|
1609
|
+
summary: `Session ${String(session.session_id)} started by coordinator`,
|
|
1610
|
+
payloadRef: path.relative(namespaceDir, sessionFile(session.session_id)),
|
|
1611
|
+
metadata: { prompted: typeof args.prompt === "string" && args.prompt.length > 0 },
|
|
1612
|
+
});
|
|
1190
1613
|
const live = hasTmuxIdentity(session) ? await hasTmuxSession(session, commandRunner) : null;
|
|
1191
1614
|
let sessionState = await writeSessionState(namespaceDir, String(session.session_id), "ready_for_input", {
|
|
1192
1615
|
live,
|
|
@@ -1335,6 +1758,25 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1335
1758
|
answered_at: new Date().toISOString(),
|
|
1336
1759
|
};
|
|
1337
1760
|
await writeJsonFile(questionPath, answered);
|
|
1761
|
+
if (question.status === "open") {
|
|
1762
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1763
|
+
kind: "question.opened",
|
|
1764
|
+
sessionId: typeof question.session_id === "string" ? question.session_id : null,
|
|
1765
|
+
turnId: typeof question.turn_id === "string" ? question.turn_id : null,
|
|
1766
|
+
questionId,
|
|
1767
|
+
summary: `Question ${questionId} opened`,
|
|
1768
|
+
payloadRef: path.relative(namespaceDir, questionPath),
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1772
|
+
kind: "question.answered",
|
|
1773
|
+
sessionId: typeof question.session_id === "string" ? question.session_id : null,
|
|
1774
|
+
turnId: typeof question.turn_id === "string" ? question.turn_id : null,
|
|
1775
|
+
questionId,
|
|
1776
|
+
summary: `Question ${questionId} answered`,
|
|
1777
|
+
payloadRef: path.relative(namespaceDir, questionPath),
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1338
1780
|
let turn: TurnRecord | null = null;
|
|
1339
1781
|
if (answeredTurnId) {
|
|
1340
1782
|
turn = await readTurnRecord(namespaceDir, answeredTurnId);
|
|
@@ -1433,7 +1875,21 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
1433
1875
|
promotedTurn = await promoteNextQueuedTurn(turn.session_id);
|
|
1434
1876
|
}
|
|
1435
1877
|
}
|
|
1436
|
-
|
|
1878
|
+
const reportId = `report-${Date.now()}`;
|
|
1879
|
+
const reportPath = path.join(namespaceDir, "reports", `${reportId}.json`);
|
|
1880
|
+
await writeJsonFile(reportPath, report);
|
|
1881
|
+
await appendCoordinatorEvent(namespaceDir, {
|
|
1882
|
+
kind: "report.written",
|
|
1883
|
+
sessionId,
|
|
1884
|
+
turnId: typeof args.turn_id === "string" ? args.turn_id : null,
|
|
1885
|
+
reportId,
|
|
1886
|
+
summary:
|
|
1887
|
+
typeof args.summary === "string"
|
|
1888
|
+
? args.summary
|
|
1889
|
+
: `Report ${String(args.status ?? "unknown")} written`,
|
|
1890
|
+
payloadRef: path.relative(namespaceDir, reportPath),
|
|
1891
|
+
metadata: { status: typeof args.status === "string" ? args.status : null },
|
|
1892
|
+
});
|
|
1437
1893
|
return {
|
|
1438
1894
|
ok: true,
|
|
1439
1895
|
report,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Merge into ~/.gjc/agent/models.yml (or use as reference)
|
|
2
|
+
# Remove global x-grok-model-override when using multiple Grok Build models.
|
|
3
|
+
|
|
4
|
+
providers:
|
|
5
|
+
grok-build:
|
|
6
|
+
baseUrl: https://cli-chat-proxy.grok.com/v1
|
|
7
|
+
apiKeyEnv: GROK_CLI_OAUTH_TOKEN
|
|
8
|
+
api: grok-cli-responses
|
|
9
|
+
auth: oauth
|
|
10
|
+
headers:
|
|
11
|
+
x-xai-token-auth: xai-grok-cli
|
|
12
|
+
x-grok-client-identifier: gjc-grok-cli
|
|
13
|
+
x-grok-client-version: 0.2.33
|
|
14
|
+
models:
|
|
15
|
+
- id: grok-composer-2.5-fast
|
|
16
|
+
name: Composer 2.5 Fast
|
|
17
|
+
reasoning: false
|
|
18
|
+
input: [text, image]
|
|
19
|
+
contextWindow: 200000
|
|
20
|
+
maxTokens: 30000
|
|
21
|
+
cost:
|
|
22
|
+
input: 3
|
|
23
|
+
output: 15
|
|
24
|
+
cacheRead: 0.5
|
|
25
|
+
cacheWrite: 0
|
|
26
|
+
- id: grok-build
|
|
27
|
+
name: Grok Build
|
|
28
|
+
reasoning: true
|
|
29
|
+
input: [text, image]
|
|
30
|
+
contextWindow: 512000
|
|
31
|
+
maxTokens: 30000
|
|
32
|
+
cost:
|
|
33
|
+
input: 1
|
|
34
|
+
output: 2
|
|
35
|
+
cacheRead: 0.2
|
|
36
|
+
cacheWrite: 0.2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../grok-cli-vendor/src/index.js";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
|
|
3
|
+
"root": false,
|
|
4
|
+
"vcs": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"clientKind": "git",
|
|
7
|
+
"useIgnoreFile": true
|
|
8
|
+
},
|
|
9
|
+
"files": {
|
|
10
|
+
"ignoreUnknown": false
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "space",
|
|
15
|
+
"indentWidth": 2,
|
|
16
|
+
"lineWidth": 100
|
|
17
|
+
},
|
|
18
|
+
"linter": {
|
|
19
|
+
"enabled": true,
|
|
20
|
+
"rules": {
|
|
21
|
+
"recommended": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"javascript": {
|
|
25
|
+
"formatter": {
|
|
26
|
+
"quoteStyle": "single",
|
|
27
|
+
"trailingCommas": "all",
|
|
28
|
+
"semicolons": "always"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"assist": {
|
|
32
|
+
"enabled": true,
|
|
33
|
+
"actions": {
|
|
34
|
+
"source": {
|
|
35
|
+
"organizeImports": "on"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './provider/register.js';
|