oh-my-opencode 4.0.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +28 -3
- package/README.ko.md +28 -3
- package/README.md +28 -3
- package/README.ru.md +28 -3
- package/README.zh-cn.md +28 -3
- package/dist/agents/atlas/agent.d.ts +7 -12
- package/dist/agents/atlas/default-prompt-sections.d.ts +5 -5
- package/dist/agents/atlas/gemini-prompt-sections.d.ts +4 -4
- package/dist/agents/atlas/gpt-prompt-sections.d.ts +5 -5
- package/dist/agents/atlas/kimi-prompt-sections.d.ts +6 -0
- package/dist/agents/atlas/kimi.d.ts +2 -0
- package/dist/agents/atlas/opus-4-7-prompt-sections.d.ts +6 -0
- package/dist/agents/atlas/opus-4-7.d.ts +2 -0
- package/dist/agents/atlas/shared-prompt.d.ts +1 -1
- package/dist/agents/prometheus/plan-generation.d.ts +1 -1
- package/dist/cli/boulder/boulder.d.ts +2 -0
- package/dist/cli/boulder/formatter.d.ts +5 -0
- package/dist/cli/boulder/index.d.ts +1 -0
- package/dist/cli/boulder/types.d.ts +30 -0
- package/dist/cli/doctor/checks/system-binary.d.ts +2 -0
- package/dist/cli/index.js +1122 -456
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +1 -0
- package/dist/create-hooks.d.ts +1 -0
- package/dist/create-managers.d.ts +2 -0
- package/dist/features/background-agent/manager.d.ts +10 -0
- package/dist/features/background-agent/spawner.d.ts +4 -2
- package/dist/features/background-agent/task-poller.d.ts +1 -0
- package/dist/features/background-agent/types.d.ts +1 -0
- package/dist/features/boulder-state/format-duration.d.ts +1 -0
- package/dist/features/boulder-state/index.d.ts +1 -0
- package/dist/features/boulder-state/storage.d.ts +39 -1
- package/dist/features/boulder-state/types.d.ts +43 -0
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/team-mode/team-runtime/session-cleanup.d.ts +21 -0
- package/dist/features/team-mode/team-runtime/session-team-run-registry.d.ts +4 -0
- package/dist/features/tmux-subagent/cleanup.d.ts +10 -0
- package/dist/features/tmux-subagent/session-created-handler.d.ts +23 -0
- package/dist/features/tmux-subagent/session-deleted-handler.d.ts +16 -0
- package/dist/hooks/atlas/boulder-continuation-injector.d.ts +1 -1
- package/dist/hooks/atlas/system-reminder-templates.d.ts +1 -0
- package/dist/hooks/atlas/tool-execute-after.d.ts +1 -0
- package/dist/hooks/atlas/tool-execute-before.d.ts +1 -0
- package/dist/hooks/atlas/types.d.ts +2 -0
- package/dist/hooks/compaction-context-injector/recovery.d.ts +1 -1
- package/dist/hooks/compaction-context-injector/types.d.ts +1 -0
- package/dist/hooks/compaction-todo-preserver/hook.d.ts +11 -0
- package/dist/hooks/fsync-skip-warning/index.d.ts +18 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/ralph-loop/continuation-prompt-injector.d.ts +7 -1
- package/dist/hooks/ralph-loop/iteration-continuation.d.ts +9 -1
- package/dist/hooks/ralph-loop/loop-state-controller.d.ts +1 -0
- package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +3 -0
- package/dist/hooks/ralph-loop/ralph-loop-event-handler.d.ts +2 -0
- package/dist/hooks/ralph-loop/types.d.ts +1 -0
- package/dist/hooks/ralph-loop/verification-failure-handler.d.ts +3 -1
- package/dist/hooks/shared/session-idle-settle.d.ts +11 -0
- package/dist/hooks/team-session-events/team-idle-wake-hint.d.ts +5 -1
- package/dist/hooks/todo-description-override/description.d.ts +1 -1
- package/dist/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.d.ts +2 -0
- package/dist/index.js +5600 -2333
- package/dist/oh-my-opencode.schema.json +8 -0
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
- package/dist/plugin/session-compacting.d.ts +31 -0
- package/dist/plugin-dispose.d.ts +13 -0
- package/dist/plugin-handlers/agent-priority-order.d.ts +6 -6
- package/dist/shared/agent-ordering.d.ts +8 -0
- package/dist/shared/agent-sort-shim.d.ts +8 -8
- package/dist/shared/agent-tool-restrictions.d.ts +5 -1
- package/dist/shared/bun-file-shim.d.ts +8 -0
- package/dist/shared/bun-hash-shim.d.ts +1 -0
- package/dist/shared/bun-which-shim.d.ts +1 -0
- package/dist/shared/classify-path-environment.d.ts +3 -0
- package/dist/shared/event-session-id.d.ts +2 -0
- package/dist/shared/extract-semver.d.ts +1 -0
- package/dist/shared/fsync-skip-tracker.d.ts +12 -0
- package/dist/shared/fsync-skip-warning-formatter.d.ts +2 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/internal-initiator-marker.d.ts +8 -0
- package/dist/shared/model-capability-heuristics.d.ts +1 -0
- package/dist/shared/opencode-version.d.ts +14 -1
- package/dist/shared/session-route.d.ts +18 -0
- package/dist/shared/tmux/cmux-detect.d.ts +8 -0
- package/dist/shared/tmux/index.d.ts +1 -0
- package/dist/shared/tolerant-fsync.d.ts +5 -0
- package/dist/shared/write-file-atomically.d.ts +4 -1
- package/dist/tools/call-omo-agent/agent-resolver.d.ts +5 -12
- package/dist/tools/call-omo-agent/constants.d.ts +2 -2
- package/dist/tools/delegate-task/model-string-parser.d.ts +9 -0
- package/dist/tools/delegate-task/resolve-call-id.d.ts +2 -0
- package/dist/tools/delegate-task/sync-prompt-sender.d.ts +1 -0
- package/dist/tools/delegate-task/sync-result-fetcher.d.ts +3 -1
- package/dist/tools/interactive-bash/constants.d.ts +1 -0
- package/dist/tools/interactive-bash/tmux-path-resolver.d.ts +1 -0
- package/package.json +21 -15
- package/dist/hooks/ralph-loop/completion-promise-detector-test-input.d.ts +0 -11
|
@@ -52,6 +52,7 @@ export declare const HookNameSchema: z.ZodEnum<{
|
|
|
52
52
|
"read-image-resizer": "read-image-resizer";
|
|
53
53
|
"todo-description-override": "todo-description-override";
|
|
54
54
|
"webfetch-redirect-guard": "webfetch-redirect-guard";
|
|
55
|
+
"fsync-skip-warning": "fsync-skip-warning";
|
|
55
56
|
"legacy-plugin-toast": "legacy-plugin-toast";
|
|
56
57
|
}>;
|
|
57
58
|
export type HookName = z.infer<typeof HookNameSchema>;
|
|
@@ -3,6 +3,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
3
3
|
$schema: z.ZodOptional<z.ZodString>;
|
|
4
4
|
new_task_system_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
5
5
|
default_run_agent: z.ZodOptional<z.ZodString>;
|
|
6
|
+
agent_order: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
6
7
|
agent_definitions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
7
8
|
disabled_mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
8
9
|
disabled_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
package/dist/create-hooks.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export declare function createHooks(args: {
|
|
|
60
60
|
readImageResizer: ReturnType<typeof import("./hooks").createReadImageResizerHook> | null;
|
|
61
61
|
todoDescriptionOverride: ReturnType<typeof import("./hooks").createTodoDescriptionOverrideHook> | null;
|
|
62
62
|
webfetchRedirectGuard: ReturnType<typeof import("./hooks").createWebFetchRedirectGuardHook> | null;
|
|
63
|
+
fsyncSkipWarning: ReturnType<typeof import("./hooks").createFsyncSkipWarningHook> | null;
|
|
63
64
|
teamToolGating: ReturnType<typeof import("./hooks").createTeamToolGating> | null;
|
|
64
65
|
contextWindowMonitor: ReturnType<typeof import("./hooks").createContextWindowMonitorHook> | null;
|
|
65
66
|
preemptiveCompaction: ReturnType<typeof import("./hooks").createPreemptiveCompactionHook> | null;
|
|
@@ -3,6 +3,7 @@ import type { ModelCacheState } from "./plugin-state";
|
|
|
3
3
|
import type { PluginContext, TmuxConfig } from "./plugin/types";
|
|
4
4
|
import { BackgroundManager } from "./features/background-agent";
|
|
5
5
|
import { SkillMcpManager } from "./features/skill-mcp-manager";
|
|
6
|
+
import { cleanupSessionTeamRuns } from "./features/team-mode/team-runtime/session-cleanup";
|
|
6
7
|
import { initTaskToastManager } from "./features/task-toast-manager";
|
|
7
8
|
import { TmuxSessionManager } from "./features/tmux-subagent";
|
|
8
9
|
import { registerManagerForCleanup } from "./features/background-agent/process-cleanup";
|
|
@@ -15,6 +16,7 @@ type CreateManagersDeps = {
|
|
|
15
16
|
TmuxSessionManagerClass: typeof TmuxSessionManager;
|
|
16
17
|
initTaskToastManagerFn: typeof initTaskToastManager;
|
|
17
18
|
registerManagerForCleanupFn: typeof registerManagerForCleanup;
|
|
19
|
+
cleanupSessionTeamRunsFn: typeof cleanupSessionTeamRuns;
|
|
18
20
|
createConfigHandlerFn: typeof createConfigHandler;
|
|
19
21
|
markServerRunningInProcessFn: typeof markServerRunningInProcess;
|
|
20
22
|
};
|
|
@@ -9,6 +9,7 @@ interface EventProperties {
|
|
|
9
9
|
sessionID?: string;
|
|
10
10
|
info?: {
|
|
11
11
|
id?: string;
|
|
12
|
+
sessionID?: string;
|
|
12
13
|
};
|
|
13
14
|
[key: string]: unknown;
|
|
14
15
|
}
|
|
@@ -51,9 +52,12 @@ export declare class BackgroundManager {
|
|
|
51
52
|
private queuesByKey;
|
|
52
53
|
private processingKeys;
|
|
53
54
|
private completionTimers;
|
|
55
|
+
private completedTaskArchive;
|
|
54
56
|
private completedTaskSummaries;
|
|
55
57
|
private idleDeferralTimers;
|
|
56
58
|
private notificationQueueByParent;
|
|
59
|
+
private pendingParentWakes;
|
|
60
|
+
private pendingParentWakeTimers;
|
|
57
61
|
private observedOutputSessions;
|
|
58
62
|
private observedIncompleteTodosBySession;
|
|
59
63
|
private rootDescendantCounts;
|
|
@@ -80,6 +84,7 @@ export declare class BackgroundManager {
|
|
|
80
84
|
private rollbackPreStartDescendantReservation;
|
|
81
85
|
private addTask;
|
|
82
86
|
private removeTask;
|
|
87
|
+
private archiveCompletedTask;
|
|
83
88
|
private updateTaskParent;
|
|
84
89
|
private removeTaskFromParentIndex;
|
|
85
90
|
launch(input: LaunchInput): Promise<BackgroundTask>;
|
|
@@ -167,6 +172,11 @@ export declare class BackgroundManager {
|
|
|
167
172
|
*/
|
|
168
173
|
private tryCompleteTask;
|
|
169
174
|
private notifyParentSession;
|
|
175
|
+
private isSessionActive;
|
|
176
|
+
private queuePendingParentWake;
|
|
177
|
+
private flushPendingParentWake;
|
|
178
|
+
private schedulePendingParentWakeFlush;
|
|
179
|
+
private clearPendingParentWakeTimer;
|
|
170
180
|
private hasRunningTasks;
|
|
171
181
|
private pruneStaleTasksAndNotifications;
|
|
172
182
|
private checkAndInterruptStaleTasks;
|
|
@@ -3,7 +3,9 @@ import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./cons
|
|
|
3
3
|
import type { ConcurrencyManager } from "./concurrency";
|
|
4
4
|
export declare const FALLBACK_AGENT = "general";
|
|
5
5
|
export declare function isAgentNotFoundError(error: unknown): boolean;
|
|
6
|
-
export declare function buildFallbackBody(originalBody: Record<string, unknown>, fallbackAgent: string
|
|
6
|
+
export declare function buildFallbackBody(originalBody: Record<string, unknown>, fallbackAgent: string, options?: {
|
|
7
|
+
includeTeamToolDenylist?: boolean;
|
|
8
|
+
}): Record<string, unknown>;
|
|
7
9
|
export interface SpawnerContext {
|
|
8
10
|
client: OpencodeClient;
|
|
9
11
|
directory: string;
|
|
@@ -14,4 +16,4 @@ export interface SpawnerContext {
|
|
|
14
16
|
}
|
|
15
17
|
export declare function createTask(input: LaunchInput): BackgroundTask;
|
|
16
18
|
export declare function startTask(item: QueueItem, ctx: SpawnerContext): Promise<void>;
|
|
17
|
-
export declare function resumeTask(task: BackgroundTask, input: ResumeInput, ctx: Pick<SpawnerContext, "client" | "concurrencyManager" | "onTaskError">): Promise<void>;
|
|
19
|
+
export declare function resumeTask(task: BackgroundTask, input: ResumeInput, ctx: Pick<SpawnerContext, "client" | "concurrencyManager" | "directory" | "onTaskError">): Promise<void>;
|
|
@@ -7,6 +7,7 @@ export declare function pruneStaleTasksAndNotifications(args: {
|
|
|
7
7
|
notifications: Map<string, BackgroundTask[]>;
|
|
8
8
|
onTaskPruned: (taskId: string, task: BackgroundTask, errorMessage: string) => void;
|
|
9
9
|
taskTtlMs?: number;
|
|
10
|
+
sessionStatuses?: SessionStatusMap;
|
|
10
11
|
}): void;
|
|
11
12
|
export type SessionStatusMap = Record<string, {
|
|
12
13
|
type: string;
|
|
@@ -68,6 +68,7 @@ export interface BackgroundTask {
|
|
|
68
68
|
isUnstableAgent?: boolean;
|
|
69
69
|
/** Category used for this task (e.g., 'quick', 'visual-engineering') */
|
|
70
70
|
category?: string;
|
|
71
|
+
onSessionCreated?: (sessionId: string) => void | Promise<void>;
|
|
71
72
|
/** Pending retry notification details for the next spawned retry session */
|
|
72
73
|
retryNotification?: {
|
|
73
74
|
previousSessionID?: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatDurationHuman(milliseconds: number): string;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles reading/writing boulder.json for active plan tracking.
|
|
5
5
|
*/
|
|
6
|
-
import type { BoulderState, PlanProgress, TaskSessionState } from "./types";
|
|
6
|
+
import type { BoulderSessionOrigin, BoulderState, BoulderWorkResumeOption, BoulderWorkState, PlanProgress, TaskSessionState } from "./types";
|
|
7
7
|
export declare function getBoulderFilePath(directory: string): string;
|
|
8
8
|
export declare function resolveBoulderPlanPath(directory: string, state: Pick<BoulderState, "active_plan" | "worktree_path">): string;
|
|
9
9
|
export declare function readBoulderState(directory: string): BoulderState | null;
|
|
@@ -43,3 +43,41 @@ export declare function getPlanName(planPath: string): string;
|
|
|
43
43
|
* Create a new boulder state for a plan.
|
|
44
44
|
*/
|
|
45
45
|
export declare function createBoulderState(planPath: string, sessionId: string, agent?: string, worktreePath?: string): BoulderState;
|
|
46
|
+
export declare function generateWorkId(planName: string): string;
|
|
47
|
+
export declare function getBoulderWorks(state: BoulderState): BoulderWorkState[];
|
|
48
|
+
export declare function getActiveWorks(directory: string): BoulderWorkState[];
|
|
49
|
+
export declare function getWorkById(directory: string, workId: string): BoulderWorkState | null;
|
|
50
|
+
export declare function getWorkByPlanName(directory: string, planName: string, options?: {
|
|
51
|
+
worktreePath?: string;
|
|
52
|
+
}): BoulderWorkState | null;
|
|
53
|
+
export declare function getWorkForSession(directory: string, sessionId: string): BoulderWorkState | null;
|
|
54
|
+
export declare function resolveBoulderPlanPathForWork(directory: string, work: Pick<BoulderWorkState, "active_plan" | "worktree_path">): string;
|
|
55
|
+
export declare function getWorkResumeOptions(directory: string): BoulderWorkResumeOption[];
|
|
56
|
+
export declare function selectActiveWork(directory: string, workId: string): BoulderState | null;
|
|
57
|
+
export declare function addBoulderWork(directory: string, input: {
|
|
58
|
+
planPath: string;
|
|
59
|
+
sessionId: string;
|
|
60
|
+
agent?: string;
|
|
61
|
+
worktreePath?: string;
|
|
62
|
+
startedAt?: string;
|
|
63
|
+
}): BoulderState | null;
|
|
64
|
+
export declare function appendSessionIdForWork(directory: string, workId: string, sessionId: string, origin?: BoulderSessionOrigin): BoulderState | null;
|
|
65
|
+
export declare function upsertTaskSessionStateForWork(directory: string, workId: string, input: {
|
|
66
|
+
taskKey: string;
|
|
67
|
+
taskLabel: string;
|
|
68
|
+
taskTitle: string;
|
|
69
|
+
sessionId: string;
|
|
70
|
+
agent?: string;
|
|
71
|
+
category?: string;
|
|
72
|
+
}): BoulderState | null;
|
|
73
|
+
export declare function startTaskTimer(directory: string, workId: string, input: {
|
|
74
|
+
taskKey: string;
|
|
75
|
+
taskLabel: string;
|
|
76
|
+
taskTitle: string;
|
|
77
|
+
sessionId: string;
|
|
78
|
+
agent?: string;
|
|
79
|
+
category?: string;
|
|
80
|
+
startedAt?: string;
|
|
81
|
+
}): BoulderState | null;
|
|
82
|
+
export declare function endTaskTimer(directory: string, workId: string, taskKey: string, endedAt?: string): BoulderState | null;
|
|
83
|
+
export declare function completeBoulder(directory: string, workId?: string, endedAt?: string): BoulderState | null;
|
|
@@ -5,10 +5,17 @@
|
|
|
5
5
|
* Named after Sisyphus's boulder - the eternal task that must be rolled.
|
|
6
6
|
*/
|
|
7
7
|
export interface BoulderState {
|
|
8
|
+
schema_version?: 2;
|
|
9
|
+
active_work_id?: string;
|
|
10
|
+
works?: Record<string, BoulderWorkState>;
|
|
8
11
|
/** Absolute path to the active plan file */
|
|
9
12
|
active_plan: string;
|
|
10
13
|
/** ISO timestamp when work started */
|
|
11
14
|
started_at: string;
|
|
15
|
+
ended_at?: string;
|
|
16
|
+
elapsed_ms?: number;
|
|
17
|
+
status?: BoulderWorkStatus;
|
|
18
|
+
updated_at?: string;
|
|
12
19
|
/** Session IDs that have worked on this plan */
|
|
13
20
|
session_ids: string[];
|
|
14
21
|
session_origins?: Record<string, "direct" | "appended">;
|
|
@@ -21,6 +28,24 @@ export interface BoulderState {
|
|
|
21
28
|
/** Preferred reusable subagent sessions keyed by current top-level plan task */
|
|
22
29
|
task_sessions?: Record<string, TaskSessionState>;
|
|
23
30
|
}
|
|
31
|
+
export type BoulderSessionOrigin = "direct" | "appended";
|
|
32
|
+
export type BoulderWorkStatus = "active" | "completed" | "paused" | "abandoned";
|
|
33
|
+
export type BoulderTaskStatus = "running" | "completed" | "cancelled";
|
|
34
|
+
export interface BoulderWorkState {
|
|
35
|
+
work_id: string;
|
|
36
|
+
active_plan: string;
|
|
37
|
+
plan_name: string;
|
|
38
|
+
status?: BoulderWorkStatus;
|
|
39
|
+
started_at: string;
|
|
40
|
+
ended_at?: string;
|
|
41
|
+
elapsed_ms?: number;
|
|
42
|
+
updated_at?: string;
|
|
43
|
+
session_ids: string[];
|
|
44
|
+
session_origins?: Record<string, BoulderSessionOrigin>;
|
|
45
|
+
agent?: string;
|
|
46
|
+
worktree_path?: string;
|
|
47
|
+
task_sessions?: Record<string, TaskSessionState>;
|
|
48
|
+
}
|
|
24
49
|
export interface PlanProgress {
|
|
25
50
|
/** Total number of checkboxes */
|
|
26
51
|
total: number;
|
|
@@ -42,9 +67,27 @@ export interface TaskSessionState {
|
|
|
42
67
|
agent?: string;
|
|
43
68
|
/** Category associated with the task session, when known */
|
|
44
69
|
category?: string;
|
|
70
|
+
started_at?: string;
|
|
71
|
+
ended_at?: string;
|
|
72
|
+
elapsed_ms?: number;
|
|
73
|
+
status?: BoulderTaskStatus;
|
|
45
74
|
/** Last update timestamp */
|
|
46
75
|
updated_at: string;
|
|
47
76
|
}
|
|
77
|
+
export interface BoulderWorkResumeOption {
|
|
78
|
+
work_id: string;
|
|
79
|
+
plan_name: string;
|
|
80
|
+
active_plan: string;
|
|
81
|
+
worktree_path?: string;
|
|
82
|
+
status: BoulderWorkStatus;
|
|
83
|
+
started_at: string;
|
|
84
|
+
updated_at: string;
|
|
85
|
+
ended_at?: string;
|
|
86
|
+
elapsed_ms?: number;
|
|
87
|
+
session_count: number;
|
|
88
|
+
progress: PlanProgress;
|
|
89
|
+
is_current_mirror: boolean;
|
|
90
|
+
}
|
|
48
91
|
export interface TopLevelTaskRef {
|
|
49
92
|
/** Stable identifier for the current top-level plan task */
|
|
50
93
|
key: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const START_WORK_TEMPLATE = "You are starting a Sisyphus work session.\n\n## ARGUMENTS\n\n- `/start-work [plan-name] [--worktree <path>]`\n - `plan-name` (optional): name or partial match of the plan to start\n - `--worktree <path>` (optional): absolute path to an existing git worktree to work in\n - If specified and valid: hook pre-sets worktree_path in boulder.json\n - If specified but invalid: you must run `git worktree add <path> <branch>` first\n - If omitted: work directly in the current project directory (no worktree)\n\n## WHAT TO DO\n\n1. **Find available plans**: Search for Prometheus-generated plan files at `.sisyphus/plans/`\n\n2. **Check for active boulder state**: Read `.sisyphus/boulder.json` if it exists\n\n3. **Decision logic**:\n - If
|
|
1
|
+
export declare const START_WORK_TEMPLATE = "You are starting a Sisyphus work session.\n\n## ARGUMENTS\n\n- `/start-work [plan-name] [--worktree <path>]`\n - `plan-name` (optional): name or partial match of the plan to start\n - `--worktree <path>` (optional): absolute path to an existing git worktree to work in\n - If specified and valid: hook pre-sets worktree_path in boulder.json\n - If specified but invalid: you must run `git worktree add <path> <branch>` first\n - If omitted: work directly in the current project directory (no worktree)\n\n## WHAT TO DO\n\n1. **Find available plans**: Search for Prometheus-generated plan files at `.sisyphus/plans/`\n\n2. **Check for active boulder state**: Read `.sisyphus/boulder.json` if it exists\n\n3. **Decision logic**:\n - If multiple active works are listed in your context:\n - This means boulder.json has more than one work with status: `active` or `paused`\n - Use the Question tool to ask the user which plan to resume\n - Resume by running `/start-work {plan-name}` for the selected plan\n - If the user says \"start a new plan\", continue with cold-start auto-selection logic\n - If exactly one active work is listed and the user did not name a plan:\n - Auto-resume that single active work\n - If no active plan OR plan is complete:\n - List available plan files\n - If ONE plan: auto-select it\n - If MULTIPLE plans: show list with timestamps, ask user to select\n\n4. **Worktree Setup** (ONLY when `--worktree` was explicitly specified and `worktree_path` not already set in boulder.json):\n 1. `git worktree list --porcelain` - see available worktrees\n 2. Create: `git worktree add <absolute-path> <branch-or-HEAD>`\n 3. Update boulder.json to add `\"worktree_path\": \"<absolute-path>\"`\n 4. All work happens inside that worktree directory\n\n5. **Create/Update boulder.json**:\n ```json\n {\n \"active_plan\": \"/absolute/path/to/plan.md\",\n \"started_at\": \"ISO_TIMESTAMP\",\n \"session_ids\": [\"session_id_1\", \"session_id_2\"],\n \"plan_name\": \"plan-name\",\n \"worktree_path\": \"/absolute/path/to/git/worktree\"\n }\n ```\n\n6. **Read the plan file** and start executing tasks according to atlas workflow\n\n## OUTPUT FORMAT\n\nWhen listing plans for selection:\n```\nAvailable Work Plans\n\nCurrent Time: {ISO timestamp}\nSession ID: {current session id}\n\n1. [plan-name-1.md] - Modified: {date} - Progress: 3/10 tasks\n2. [plan-name-2.md] - Modified: {date} - Progress: 0/5 tasks\n\nWhich plan would you like to work on? (Enter number or plan name)\n```\n\nWhen resuming existing work:\n```\nResuming Work Session\n\nActive Plan: {plan-name}\nProgress: {completed}/{total} tasks\nSessions: {count} (appending current session)\nWorktree: {worktree_path}\n\nReading plan and continuing from last incomplete task...\n```\n\nWhen auto-selecting single plan:\n```\nStarting Work Session\n\nPlan: {plan-name}\nSession ID: {session_id}\nStarted: {timestamp}\nWorktree: {worktree_path}\n\nReading plan and beginning execution...\n```\n\n## CRITICAL\n\n- The session_id is injected by the hook - use it directly\n- Always update boulder.json BEFORE starting work\n- If worktree_path is set in boulder.json, all work happens inside that worktree directory\n- Read the FULL plan file before delegating any tasks\n- Follow atlas delegation protocols (7-section format)\n\n## TASK BREAKDOWN (MANDATORY)\n\nAfter reading the plan file, you MUST decompose every plan task into granular, implementation-level sub-steps and register ALL of them as task/todo items BEFORE starting any work.\n\n**How to break down**:\n- Each plan checkbox item (e.g., `- [ ] Add user authentication`) must be split into concrete, actionable sub-tasks\n- Sub-tasks should be specific enough that each one touches a clear set of files/functions\n- Include: file to modify, what to change, expected behavior, and how to verify\n- Do NOT leave any task vague - \"implement feature X\" is NOT acceptable; \"add validateToken() to src/auth/middleware.ts that checks JWT expiry and returns 401\" IS acceptable\n\n**Example breakdown**:\nPlan task: `- [ ] Add rate limiting to API`\n\u2192 Todo items:\n 1. Create `src/middleware/rate-limiter.ts` with sliding window algorithm (max 100 req/min per IP)\n 2. Add RateLimiter middleware to `src/app.ts` router chain, before auth middleware\n 3. Add rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining) to response in `rate-limiter.ts`\n 4. Add test: verify 429 response after exceeding limit in `src/middleware/rate-limiter.test.ts`\n 5. Add test: verify headers are present on normal responses\n\nRegister these as task/todo items so progress is tracked and visible throughout the session.\n\n## WORKTREE COMPLETION\n\nWhen working in a worktree (`worktree_path` is set in boulder.json) and ALL plan tasks are complete:\n1. Commit all remaining changes in the worktree\n2. **Sync .sisyphus state back**: Copy `.sisyphus/` from the worktree to the main repo before removal.\n This is CRITICAL when `.sisyphus/` is gitignored - state written during worktree execution would otherwise be lost.\n ```bash\n cp -r <worktree-path>/.sisyphus/* <main-repo>/.sisyphus/ 2>/dev/null || true\n ```\n3. Switch to the main working directory (the original repo, NOT the worktree)\n4. Merge the worktree branch into the current branch: `git merge <worktree-branch>`\n5. If merge succeeds, clean up: `git worktree remove <worktree-path>`\n6. Remove the boulder.json state\n\nThis is the DEFAULT behavior when `--worktree` was used. Skip merge only if the user explicitly instructs otherwise (e.g., asks to create a PR instead).";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TeamModeConfig } from "../../../config/schema/team-mode";
|
|
2
|
+
import { log } from "../../../shared/logger";
|
|
3
|
+
import type { BackgroundManager } from "../../background-agent/manager";
|
|
4
|
+
import type { TmuxSessionManager } from "../../tmux-subagent/manager";
|
|
5
|
+
import { deleteTeam } from "./delete-team";
|
|
6
|
+
export { clearSessionTeamRunCleanupRegistry, getSessionCreatedTeamRunIds, registerTeamRunForSessionCleanup, unregisterTeamRunForSessionCleanup, } from "./session-team-run-registry";
|
|
7
|
+
export type SessionTeamCleanupReport = {
|
|
8
|
+
cleanedTeamRunIds: string[];
|
|
9
|
+
removedLayoutTeamRunIds: string[];
|
|
10
|
+
errors: string[];
|
|
11
|
+
};
|
|
12
|
+
export type SessionTeamCleanupDeps = {
|
|
13
|
+
deleteTeam: typeof deleteTeam;
|
|
14
|
+
log: typeof log;
|
|
15
|
+
};
|
|
16
|
+
export declare function cleanupSessionTeamRuns(args: {
|
|
17
|
+
config: TeamModeConfig;
|
|
18
|
+
tmuxMgr?: TmuxSessionManager;
|
|
19
|
+
bgMgr?: BackgroundManager;
|
|
20
|
+
deps?: SessionTeamCleanupDeps;
|
|
21
|
+
}): Promise<SessionTeamCleanupReport>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function registerTeamRunForSessionCleanup(teamRunId: string): void;
|
|
2
|
+
export declare function unregisterTeamRunForSessionCleanup(teamRunId: string): void;
|
|
3
|
+
export declare function getSessionCreatedTeamRunIds(): string[];
|
|
4
|
+
export declare function clearSessionTeamRunCleanupRegistry(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TmuxConfig } from "../../config/schema";
|
|
2
|
+
import type { TrackedSession } from "./types";
|
|
3
|
+
export declare function cleanupTmuxSessions(params: {
|
|
4
|
+
tmuxConfig: TmuxConfig;
|
|
5
|
+
directory: string;
|
|
6
|
+
serverUrl: string;
|
|
7
|
+
sourcePaneId: string | undefined;
|
|
8
|
+
sessions: Map<string, TrackedSession>;
|
|
9
|
+
stopPolling: () => void;
|
|
10
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
import type { TmuxConfig } from "../../config/schema";
|
|
3
|
+
import type { CapacityConfig, TrackedSession } from "./types";
|
|
4
|
+
import { type SessionMapping } from "./decision-engine";
|
|
5
|
+
import type { SessionCreatedEvent } from "./session-created-event";
|
|
6
|
+
type OpencodeClient = PluginInput["client"];
|
|
7
|
+
export interface SessionCreatedHandlerDeps {
|
|
8
|
+
client: OpencodeClient;
|
|
9
|
+
tmuxConfig: TmuxConfig;
|
|
10
|
+
directory: string;
|
|
11
|
+
serverUrl: string;
|
|
12
|
+
sourcePaneId: string | undefined;
|
|
13
|
+
sessions: Map<string, TrackedSession>;
|
|
14
|
+
pendingSessions: Set<string>;
|
|
15
|
+
isInsideTmux: () => boolean;
|
|
16
|
+
isEnabled: () => boolean;
|
|
17
|
+
getCapacityConfig: () => CapacityConfig;
|
|
18
|
+
getSessionMappings: () => SessionMapping[];
|
|
19
|
+
waitForSessionReady: (sessionId: string) => Promise<boolean>;
|
|
20
|
+
startPolling: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function handleSessionCreated(deps: SessionCreatedHandlerDeps, event: SessionCreatedEvent): Promise<void>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TmuxConfig } from "../../config/schema";
|
|
2
|
+
import type { TrackedSession } from "./types";
|
|
3
|
+
import { type SessionMapping } from "./decision-engine";
|
|
4
|
+
export interface SessionDeletedHandlerDeps {
|
|
5
|
+
tmuxConfig: TmuxConfig;
|
|
6
|
+
directory: string;
|
|
7
|
+
serverUrl: string;
|
|
8
|
+
sourcePaneId: string | undefined;
|
|
9
|
+
sessions: Map<string, TrackedSession>;
|
|
10
|
+
isEnabled: () => boolean;
|
|
11
|
+
getSessionMappings: () => SessionMapping[];
|
|
12
|
+
stopPolling: () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function handleSessionDeleted(deps: SessionDeletedHandlerDeps, event: {
|
|
15
|
+
sessionID: string;
|
|
16
|
+
}): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
2
|
import type { BackgroundTaskStatusProvider, SessionState } from "./types";
|
|
3
|
-
export type BoulderContinuationResult = "injected" | "skipped_background_tasks" | "skipped_agent_unavailable" | "failed";
|
|
3
|
+
export type BoulderContinuationResult = "injected" | "skipped_active_session" | "skipped_background_tasks" | "skipped_agent_unavailable" | "failed";
|
|
4
4
|
export declare function injectBoulderContinuation(input: {
|
|
5
5
|
ctx: PluginInput;
|
|
6
6
|
sessionID: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const DIRECT_WORK_REMINDER: string;
|
|
2
2
|
export declare const BOULDER_CONTINUATION_PROMPT: string;
|
|
3
|
+
export declare const BOULDER_COMPLETE_PROMPT = "<system-reminder>\nBOULDER COMPLETE: plan \"{PLAN_NAME}\" is fully checked.\n\nTotal elapsed: {ELAPSED_HUMAN}\n\nPer-task breakdown:\n{TASK_BREAKDOWN}\n\nPer your <boulder_completion_response> instructions, print the final ORCHESTRATION COMPLETE summary in your next turn. This nudge fires at most once.\n</system-reminder>";
|
|
3
4
|
export declare const VERIFICATION_REMINDER = "**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE. THEY ARE PROBABLY LYING.**\n\nSubagents say \"done\" when code has errors, tests pass trivially, logic is wrong,\nor they quietly added features nobody asked for. This happens EVERY TIME.\nAssume the work is broken until YOU prove otherwise.\n\n---\n\n**PHASE 1: READ THE CODE FIRST (before running anything)**\n\nDo NOT run tests yet. Read the code FIRST so you know what you're testing.\n\n1. `Bash(\"git diff --stat -- ':!node_modules'\")` - see exactly which files changed. Any file outside expected scope = scope creep.\n2. `Read` EVERY changed file - no exceptions, no skimming.\n3. For EACH file, critically ask:\n - Does this code ACTUALLY do what the task required? (Re-read the task, compare line by line)\n - Any stubs, TODOs, placeholders, hardcoded values? (`Grep` for TODO, FIXME, HACK, xxx)\n - Logic errors? Trace the happy path AND the error path in your head.\n - Anti-patterns? (`Grep` for `as any`, `@ts-ignore`, empty catch, console.log in changed files)\n - Scope creep? Did the subagent touch things or add features NOT in the task spec?\n4. Cross-check every claim:\n - Said \"Updated X\" - READ X. Actually updated, or just superficially touched?\n - Said \"Added tests\" - READ the tests. Do they test REAL behavior or just `expect(true).toBe(true)`?\n - Said \"Follows patterns\" - OPEN a reference file. Does it ACTUALLY match?\n\n**If you cannot explain what every changed line does, you have NOT reviewed it.**\n\n**PHASE 2: RUN AUTOMATED CHECKS (targeted, then broad)**\n\nNow that you understand the code, verify mechanically:\n1. `lsp_diagnostics` on EACH changed file - ZERO new errors\n2. Run tests for changed modules FIRST, then full suite\n3. Build/typecheck - exit 0\n\nIf Phase 1 found issues but Phase 2 passes: Phase 2 is WRONG. The code has bugs that tests don't cover. Fix the code.\n\n**PHASE 3: HANDS-ON QA - ACTUALLY RUN IT (MANDATORY for user-facing changes)**\n\nTests and linters CANNOT catch: visual bugs, wrong CLI output, broken user flows, API response shape issues.\n\n**If this task produced anything a user would SEE or INTERACT with, you MUST launch it and verify yourself.**\n\n- **Frontend/UI**: `/playwright` skill - load the page, click through the flow, check console. Verify: page loads, interactions work, console clean, responsive.\n- **TUI/CLI**: `interactive_bash` - run the command, try good input, try bad input, try --help. Verify: command runs, output correct, error messages helpful, edge inputs handled.\n- **API/Backend**: `Bash` with curl - hit the endpoint, check response body, send malformed input. Verify: returns 200, body correct, error cases return proper errors.\n- **Config/Build**: Actually start the service or import the config. Verify: loads without error, backward compatible.\n\nThis is NOT optional \"if applicable\". If the deliverable is user-facing and you did not run it, you are shipping untested work.\n\n**PHASE 4: GATE DECISION - Should you proceed to the next task?**\n\nAnswer honestly:\n1. Can I explain what EVERY changed line does? (If no - back to Phase 1)\n2. Did I SEE it work with my own eyes? (If user-facing and no - back to Phase 3)\n3. Am I confident nothing existing is broken? (If no - run broader tests)\n\nALL three must be YES. \"Probably\" = NO. \"I think so\" = NO. Investigate until CERTAIN.\n\n- **All 3 YES** - Proceed: mark task complete, move to next.\n- **Any NO** - Reject: resume session with `session_id`, fix the specific issue.\n- **Unsure** - Reject: \"unsure\" = \"no\". Investigate until you have a definitive answer.\n\n**DO NOT proceed to the next task until all 4 phases are complete and the gate passes.**";
|
|
4
5
|
export declare const VERIFICATION_REMINDER_GEMINI = "**THE SUBAGENT HAS FINISHED. THEIR WORK IS EXTREMELY SUSPICIOUS.**\n\nThe subagent CLAIMS this task is done. Based on thousands of executions, subagent claims are FALSE more often than true.\nThey ROUTINELY:\n- Ship code with syntax errors they didn't bother to check\n- Create stub implementations with TODOs and call it \"done\"\n- Write tests that pass trivially (testing nothing meaningful)\n- Implement logic that does NOT match what was requested\n- Add features nobody asked for and call it \"improvement\"\n- Report \"all tests pass\" when they didn't run any tests\n\n**This is NOT a theoretical warning. This WILL happen on this task. Assume the work is BROKEN.**\n\n**YOU MUST VERIFY WITH ACTUAL TOOL CALLS. NOT REASONING. TOOL CALLS.**\nThinking \"it looks correct\" is NOT verification. Running `lsp_diagnostics` IS.\n\n---\n\n**PHASE 1: READ THE CODE FIRST (DO NOT SKIP - DO NOT RUN TESTS YET)**\n\nRead the code FIRST so you know what you're testing.\n\n1. `Bash(\"git diff --stat -- ':!node_modules'\")` - see exactly which files changed.\n2. `Read` EVERY changed file - no exceptions, no skimming.\n3. For EACH file:\n - Does this code ACTUALLY do what the task required? RE-READ the task spec.\n - Any stubs, TODOs, placeholders? `Grep` for TODO, FIXME, HACK, xxx\n - Anti-patterns? `Grep` for `as any`, `@ts-ignore`, empty catch\n - Scope creep? Did the subagent add things NOT in the task spec?\n4. Cross-check EVERY claim against actual code.\n\n**If you cannot explain what every changed line does, GO BACK AND READ AGAIN.**\n\n**PHASE 2: RUN AUTOMATED CHECKS**\n\n1. `lsp_diagnostics` on EACH changed file - ZERO new errors. ACTUALLY RUN THIS.\n2. Run tests for changed modules, then full suite. ACTUALLY RUN THESE.\n3. Build/typecheck - exit 0.\n\nIf Phase 1 found issues but Phase 2 passes: Phase 2 is WRONG. Fix the code.\n\n**PHASE 3: HANDS-ON QA (MANDATORY for user-facing changes)**\n\n- **Frontend/UI**: `/playwright`\n- **TUI/CLI**: `interactive_bash`\n- **API/Backend**: `Bash` with curl\n\n**If user-facing and you did not run it, you are shipping UNTESTED BROKEN work.**\n\n**PHASE 4: GATE DECISION**\n\n1. Can I explain what EVERY changed line does? (If no \u2192 Phase 1)\n2. Did I SEE it work via tool calls? (If user-facing and no \u2192 Phase 3)\n3. Am I confident nothing is broken? (If no \u2192 broader tests)\n\nALL three must be YES. \"Probably\" = NO. \"I think so\" = NO.\n\n**DO NOT proceed to the next task until all 4 phases are complete.**";
|
|
5
6
|
export declare const ORCHESTRATOR_DELEGATION_REQUIRED: string;
|
|
@@ -5,6 +5,7 @@ export declare function createToolExecuteAfterHandler(input: {
|
|
|
5
5
|
ctx: PluginInput;
|
|
6
6
|
pendingFilePaths: Map<string, string>;
|
|
7
7
|
pendingTaskRefs: Map<string, PendingTaskRef>;
|
|
8
|
+
pendingPlanSnapshots?: Map<string, string>;
|
|
8
9
|
autoCommit: boolean;
|
|
9
10
|
getState: (sessionID: string) => SessionState;
|
|
10
11
|
isCallerOrchestrator?: (sessionID: string | undefined) => Promise<boolean>;
|
|
@@ -4,6 +4,7 @@ export declare function createToolExecuteBeforeHandler(input: {
|
|
|
4
4
|
ctx: PluginInput;
|
|
5
5
|
pendingFilePaths: Map<string, string>;
|
|
6
6
|
pendingTaskRefs: Map<string, PendingTaskRef>;
|
|
7
|
+
pendingPlanSnapshots?: Map<string, string>;
|
|
7
8
|
isCallerOrchestrator?: (sessionID: string | undefined) => Promise<boolean>;
|
|
8
9
|
}): (toolInput: {
|
|
9
10
|
tool: string;
|
|
@@ -16,6 +16,7 @@ export interface AtlasHookOptions {
|
|
|
16
16
|
isContinuationStopped?: (sessionID: string) => boolean;
|
|
17
17
|
isCallerOrchestrator?: (sessionID: string | undefined) => Promise<boolean>;
|
|
18
18
|
agentOverrides?: AgentOverrides;
|
|
19
|
+
idleSettleMs?: number;
|
|
19
20
|
/** Enable auto-commit after each atomic task completion (default: true) */
|
|
20
21
|
autoCommit?: boolean;
|
|
21
22
|
}
|
|
@@ -52,4 +53,5 @@ export interface SessionState {
|
|
|
52
53
|
waitingForFinalWaveApproval?: boolean;
|
|
53
54
|
pendingFinalWaveTaskCount?: number;
|
|
54
55
|
approvedFinalWaveTaskCount?: number;
|
|
56
|
+
boulderCompletionNudgedAt?: Record<string, number>;
|
|
55
57
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CompactionContextClient } from "./types";
|
|
2
2
|
import type { TailMonitorState } from "./tail-monitor";
|
|
3
3
|
export declare function createRecoveryLogic(ctx: CompactionContextClient | undefined, getTailState: (sessionID: string) => TailMonitorState): {
|
|
4
|
-
recoverCheckpointedAgentConfig: (sessionID: string, reason: "session.compacted" | "no-text-tail") => Promise<boolean>;
|
|
4
|
+
recoverCheckpointedAgentConfig: (sessionID: string, reason: "compaction.autocontinue" | "session.compacted" | "no-text-tail") => Promise<boolean>;
|
|
5
5
|
maybeWarnAboutNoTextTail: (sessionID: string) => Promise<void>;
|
|
6
6
|
};
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
type ToolExecuteBeforeInput = {
|
|
3
|
+
tool: string;
|
|
4
|
+
sessionID: string;
|
|
5
|
+
callID: string;
|
|
6
|
+
};
|
|
7
|
+
type ToolExecuteBeforeOutput = {
|
|
8
|
+
args: Record<string, unknown>;
|
|
9
|
+
};
|
|
2
10
|
export interface CompactionTodoPreserver {
|
|
3
11
|
capture: (sessionID: string) => Promise<void>;
|
|
12
|
+
restore: (sessionID: string) => Promise<void>;
|
|
4
13
|
event: (input: {
|
|
5
14
|
event: {
|
|
6
15
|
type: string;
|
|
7
16
|
properties?: unknown;
|
|
8
17
|
};
|
|
9
18
|
}) => Promise<void>;
|
|
19
|
+
"tool.execute.before": (input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput) => Promise<void>;
|
|
10
20
|
}
|
|
11
21
|
export declare function createCompactionTodoPreserverHook(ctx: PluginInput): CompactionTodoPreserver;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type ToolExecuteInput = {
|
|
2
|
+
tool: string;
|
|
3
|
+
sessionID: string;
|
|
4
|
+
callID: string;
|
|
5
|
+
};
|
|
6
|
+
type ToolBeforeOutput = {
|
|
7
|
+
args: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
type ToolAfterOutput = {
|
|
10
|
+
title: string;
|
|
11
|
+
output: string;
|
|
12
|
+
metadata: unknown;
|
|
13
|
+
};
|
|
14
|
+
export declare function createFsyncSkipWarningHook(): {
|
|
15
|
+
"tool.execute.before": (input: ToolExecuteInput, _output: ToolBeforeOutput) => Promise<void>;
|
|
16
|
+
"tool.execute.after": (input: ToolExecuteInput, output: ToolAfterOutput) => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -55,3 +55,4 @@ export { createReadImageResizerHook } from "./read-image-resizer";
|
|
|
55
55
|
export { createTodoDescriptionOverrideHook } from "./todo-description-override";
|
|
56
56
|
export { createWebFetchRedirectGuardHook } from "./webfetch-redirect-guard";
|
|
57
57
|
export { createLegacyPluginToastHook } from "./legacy-plugin-toast";
|
|
58
|
+
export { createFsyncSkipWarningHook } from "./fsync-skip-warning";
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export type ContinuationPromptResult = {
|
|
3
|
+
status: "dispatched";
|
|
4
|
+
} | {
|
|
5
|
+
status: "rejected";
|
|
6
|
+
error: Error;
|
|
7
|
+
};
|
|
2
8
|
export declare function injectContinuationPrompt(ctx: PluginInput, options: {
|
|
3
9
|
sessionID: string;
|
|
4
10
|
prompt: string;
|
|
5
11
|
directory: string;
|
|
6
12
|
apiTimeoutMs: number;
|
|
7
13
|
inheritFromSessionID?: string;
|
|
8
|
-
}): Promise<
|
|
14
|
+
}): Promise<ContinuationPromptResult>;
|
|
@@ -8,5 +8,13 @@ type ContinuationOptions = {
|
|
|
8
8
|
setSessionID: (sessionID: string) => RalphLoopState | null;
|
|
9
9
|
};
|
|
10
10
|
};
|
|
11
|
-
export
|
|
11
|
+
export type ContinuationResult = {
|
|
12
|
+
status: "dispatched";
|
|
13
|
+
} | {
|
|
14
|
+
status: "session_creation_rejected";
|
|
15
|
+
} | {
|
|
16
|
+
status: "dispatch_rejected";
|
|
17
|
+
error: unknown;
|
|
18
|
+
};
|
|
19
|
+
export declare function continueIteration(ctx: PluginInput, state: RalphLoopState, options: ContinuationOptions): Promise<ContinuationResult>;
|
|
12
20
|
export {};
|
|
@@ -20,4 +20,5 @@ export declare function createLoopStateController(options: {
|
|
|
20
20
|
markVerificationPending(sessionID: string): RalphLoopState | null;
|
|
21
21
|
setVerificationSessionID(sessionID: string, verificationSessionID: string): RalphLoopState | null;
|
|
22
22
|
restartAfterFailedVerification(sessionID: string, messageCountAtStart?: number): RalphLoopState | null;
|
|
23
|
+
clearVerificationState(sessionID: string, messageCountAtStart?: number): RalphLoopState | null;
|
|
23
24
|
};
|
|
@@ -2,6 +2,9 @@ import type { PluginInput } from "@opencode-ai/plugin";
|
|
|
2
2
|
import type { RalphLoopState } from "./types";
|
|
3
3
|
type LoopStateController = {
|
|
4
4
|
restartAfterFailedVerification: (sessionID: string, messageCountAtStart?: number) => RalphLoopState | null;
|
|
5
|
+
clearVerificationState: (sessionID: string, messageCountAtStart?: number) => RalphLoopState | null;
|
|
6
|
+
incrementIteration: () => RalphLoopState | null;
|
|
7
|
+
clear: () => boolean;
|
|
5
8
|
setVerificationSessionID: (sessionID: string, verificationSessionID: string) => RalphLoopState | null;
|
|
6
9
|
};
|
|
7
10
|
export declare function handlePendingVerification(ctx: PluginInput, input: {
|
|
@@ -8,10 +8,12 @@ type LoopStateController = {
|
|
|
8
8
|
markVerificationPending: (sessionID: string) => RalphLoopState | null;
|
|
9
9
|
setVerificationSessionID: (sessionID: string, verificationSessionID: string) => RalphLoopState | null;
|
|
10
10
|
restartAfterFailedVerification: (sessionID: string, messageCountAtStart?: number) => RalphLoopState | null;
|
|
11
|
+
clearVerificationState: (sessionID: string, messageCountAtStart?: number) => RalphLoopState | null;
|
|
11
12
|
};
|
|
12
13
|
type RalphLoopEventHandlerOptions = {
|
|
13
14
|
directory: string;
|
|
14
15
|
apiTimeoutMs: number;
|
|
16
|
+
idleSettleMs: number;
|
|
15
17
|
getTranscriptPath: (sessionID: string) => string | undefined;
|
|
16
18
|
checkSessionExists?: RalphLoopOptions["checkSessionExists"];
|
|
17
19
|
backgroundManager?: RalphLoopOptions["backgroundManager"];
|
|
@@ -19,6 +19,7 @@ export interface RalphLoopOptions {
|
|
|
19
19
|
config?: RalphLoopConfig;
|
|
20
20
|
getTranscriptPath?: (sessionId: string) => string;
|
|
21
21
|
apiTimeout?: number;
|
|
22
|
+
idleSettleMs?: number;
|
|
22
23
|
checkSessionExists?: (sessionId: string) => Promise<boolean>;
|
|
23
24
|
backgroundManager?: {
|
|
24
25
|
getTasksByParentSession: (sessionId: string) => Array<{
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
2
|
import type { RalphLoopState } from "./types";
|
|
3
3
|
type LoopStateController = {
|
|
4
|
-
|
|
4
|
+
clearVerificationState: (sessionID: string, messageCountAtStart?: number) => RalphLoopState | null;
|
|
5
|
+
incrementIteration: () => RalphLoopState | null;
|
|
6
|
+
clear: () => boolean;
|
|
5
7
|
};
|
|
6
8
|
export declare function handleFailedVerification(ctx: PluginInput, input: {
|
|
7
9
|
state: RalphLoopState;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const DEFAULT_SESSION_IDLE_SETTLE_MS = 150;
|
|
2
|
+
export declare function settleAfterSessionIdle(ms?: number): Promise<void>;
|
|
3
|
+
type SessionStatusClient = {
|
|
4
|
+
session?: {
|
|
5
|
+
status?: () => Promise<unknown>;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export declare function isActiveSessionStatusType(statusType: string): boolean;
|
|
9
|
+
export declare function isSessionActive(client: SessionStatusClient, sessionID: string): Promise<boolean>;
|
|
10
|
+
export declare function shouldPromptAfterSessionIdle(client: SessionStatusClient, sessionID: string, settleMs?: number): Promise<boolean>;
|
|
11
|
+
export {};
|
|
@@ -24,6 +24,7 @@ type TeamIdleWakeHintContext = {
|
|
|
24
24
|
client: {
|
|
25
25
|
session: {
|
|
26
26
|
promptAsync?: (input: PromptAsyncInput) => Promise<unknown>;
|
|
27
|
+
status?: () => Promise<unknown>;
|
|
27
28
|
};
|
|
28
29
|
};
|
|
29
30
|
};
|
|
@@ -34,5 +35,8 @@ type HookInput = {
|
|
|
34
35
|
};
|
|
35
36
|
};
|
|
36
37
|
export type HookImpl = (input: HookInput) => Promise<void>;
|
|
37
|
-
|
|
38
|
+
type TeamIdleWakeHintOptions = {
|
|
39
|
+
idleSettleMs?: number;
|
|
40
|
+
};
|
|
41
|
+
export declare function createTeamIdleWakeHint(ctx: TeamIdleWakeHintContext, config: TeamModeConfig, options?: TeamIdleWakeHintOptions): HookImpl;
|
|
38
42
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const TODOWRITE_DESCRIPTION = "Use this tool to create and manage a structured task list for tracking progress on multi-step work.\n\n## Todo Format (MANDATORY)\n\nEach todo title MUST encode four elements: WHERE, WHY, HOW, and EXPECTED RESULT.\n\nFormat: \"[WHERE] [HOW] to [WHY] - expect [RESULT]\"\n\nGOOD:\n- \"src/utils/validation.ts: Add validateEmail() for input sanitization - returns boolean\"\n- \"UserService.create(): Call validateEmail() before DB insert - rejects invalid emails with 400\"\n- \"validation.test.ts: Add test for missing @ sign - expect validateEmail('foo') to return false\"\n\nBAD:\n- \"Implement email validation\" (where? how? what result?)\n- \"Add dark mode\" (feature, not a todo)\n- \"Fix auth\" (what file? what changes? what's expected?)\n\n## Granularity Rules\n\nEach todo MUST be a single atomic action completable in 1-3 tool calls. If it needs more, split it.\n\n**Size test**: Can you complete this todo by editing one file or running one command? If not, it's too big.\n\n## Task Management\n- One in_progress at a time. Complete it before starting the next.\n- Mark completed immediately after finishing each item.\n- Skip this tool for single trivial tasks (one-step, obvious action).";
|
|
1
|
+
export declare const TODOWRITE_DESCRIPTION = "Use this tool to create and manage a structured task list for tracking progress on multi-step work.\n\n## OpenCode Schema Contract\n\nThe upstream OpenCode `todowrite` schema expects each todo item to include:\n\n- `content`: string\n- `status`: string, one of `pending`, `in_progress`, `completed`, `cancelled`\n- `priority`: string, one of `high`, `medium`, `low`\n\n`priority` is a string field. Never send numeric priorities such as `0`, `1`, `2`, or labels such as `P0`, `P1`, `P2`.\n\n## Todo Format (MANDATORY)\n\nEach todo title MUST encode four elements: WHERE, WHY, HOW, and EXPECTED RESULT.\n\nFormat: \"[WHERE] [HOW] to [WHY] - expect [RESULT]\"\n\nGOOD:\n- \"src/utils/validation.ts: Add validateEmail() for input sanitization - returns boolean\"\n- \"UserService.create(): Call validateEmail() before DB insert - rejects invalid emails with 400\"\n- \"validation.test.ts: Add test for missing @ sign - expect validateEmail('foo') to return false\"\n\nBAD:\n- \"Implement email validation\" (where? how? what result?)\n- \"Add dark mode\" (feature, not a todo)\n- \"Fix auth\" (what file? what changes? what's expected?)\n\n## Granularity Rules\n\nEach todo MUST be a single atomic action completable in 1-3 tool calls. If it needs more, split it.\n\n**Size test**: Can you complete this todo by editing one file or running one command? If not, it's too big.\n\n## Task Management\n- One in_progress at a time. Complete it before starting the next.\n- Mark completed immediately after finishing each item.\n- Skip this tool for single trivial tasks (one-step, obvious action).";
|