opencode-hive 1.3.1 → 1.3.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/dist/hive-core/src/index.d.ts +4 -0
- package/dist/hive-core/src/services/agentsMdService.d.ts +32 -0
- package/dist/hive-core/src/services/configService.d.ts +78 -0
- package/dist/hive-core/src/services/contextService.d.ts +25 -0
- package/dist/hive-core/src/services/dockerSandboxService.d.ts +76 -0
- package/dist/hive-core/src/services/featureService.d.ts +19 -0
- package/dist/hive-core/src/services/index.d.ts +16 -0
- package/dist/hive-core/src/services/planService.d.ts +15 -0
- package/dist/hive-core/src/services/reviewService.d.ts +12 -0
- package/dist/hive-core/src/services/sessionService.d.ts +18 -0
- package/dist/hive-core/src/services/subtaskService.d.ts +17 -0
- package/dist/hive-core/src/services/taskDependencyGraph.d.ts +41 -0
- package/dist/hive-core/src/services/taskService.d.ts +124 -0
- package/dist/hive-core/src/services/worktreeService.d.ts +66 -0
- package/dist/hive-core/src/types.d.ts +221 -0
- package/dist/hive-core/src/utils/detection.d.ts +14 -0
- package/dist/hive-core/src/utils/paths.d.ts +105 -0
- package/dist/index.js +17007 -16691
- package/dist/{agents → opencode-hive/src/agents}/architect.d.ts +1 -1
- package/dist/opencode-hive/src/agents/hive.d.ts +12 -0
- package/dist/opencode-hive/src/agents/swarm.d.ts +12 -0
- package/package.json +1 -1
- package/skills/writing-plans/SKILL.md +15 -1
- package/dist/agents/hive.d.ts +0 -12
- package/dist/agents/swarm.d.ts +0 -12
- /package/dist/{agents → opencode-hive/src/agents}/custom-agents.d.ts +0 -0
- /package/dist/{agents → opencode-hive/src/agents}/forager.d.ts +0 -0
- /package/dist/{agents → opencode-hive/src/agents}/hygienic.d.ts +0 -0
- /package/dist/{agents → opencode-hive/src/agents}/index.d.ts +0 -0
- /package/dist/{agents → opencode-hive/src/agents}/scout.d.ts +0 -0
- /package/dist/{hooks → opencode-hive/src/hooks}/system-hook.d.ts +0 -0
- /package/dist/{hooks → opencode-hive/src/hooks}/variant-hook.d.ts +0 -0
- /package/dist/{index.d.ts → opencode-hive/src/index.d.ts} +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/ast-grep.d.ts +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/context7.d.ts +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/grep-app.d.ts +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/index.d.ts +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/types.d.ts +0 -0
- /package/dist/{mcp → opencode-hive/src/mcp}/websearch.d.ts +0 -0
- /package/dist/{skills → opencode-hive/src/skills}/builtin.d.ts +0 -0
- /package/dist/{skills → opencode-hive/src/skills}/file-loader.d.ts +0 -0
- /package/dist/{skills → opencode-hive/src/skills}/index.d.ts +0 -0
- /package/dist/{skills → opencode-hive/src/skills}/registry.generated.d.ts +0 -0
- /package/dist/{skills → opencode-hive/src/skills}/types.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/compaction-prompt.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/format.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/prompt-budgeting.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/prompt-file.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/prompt-observability.d.ts +0 -0
- /package/dist/{utils → opencode-hive/src/utils}/worker-prompt.d.ts +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ContextService } from './contextService.js';
|
|
2
|
+
export interface InitResult {
|
|
3
|
+
content: string;
|
|
4
|
+
existed: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface SyncResult {
|
|
7
|
+
proposals: string[];
|
|
8
|
+
diff: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ApplyResult {
|
|
11
|
+
path: string;
|
|
12
|
+
chars: number;
|
|
13
|
+
isNew: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class AgentsMdService {
|
|
16
|
+
private readonly rootDir;
|
|
17
|
+
private readonly contextService;
|
|
18
|
+
constructor(rootDir: string, contextService: ContextService);
|
|
19
|
+
init(): Promise<InitResult>;
|
|
20
|
+
sync(featureName: string): Promise<SyncResult>;
|
|
21
|
+
apply(content: string): ApplyResult;
|
|
22
|
+
private extractFindings;
|
|
23
|
+
private generateProposals;
|
|
24
|
+
private formatDiff;
|
|
25
|
+
private scanAndGenerate;
|
|
26
|
+
private detectProjectInfo;
|
|
27
|
+
private detectPackageManager;
|
|
28
|
+
private detectLanguage;
|
|
29
|
+
private detectTestFramework;
|
|
30
|
+
private detectMonorepo;
|
|
31
|
+
private generateTemplate;
|
|
32
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { AgentModelConfig, HiveConfig, ResolvedCustomAgentConfig } from '../types.js';
|
|
2
|
+
import type { SandboxConfig } from './dockerSandboxService.js';
|
|
3
|
+
/**
|
|
4
|
+
* ConfigService manages user config at ~/.config/opencode/agent_hive.json
|
|
5
|
+
*
|
|
6
|
+
* This is USER config (not project-scoped):
|
|
7
|
+
* - VSCode extension reads/writes this
|
|
8
|
+
* - OpenCode plugin reads this to enable features
|
|
9
|
+
* - Agent does NOT have tools to access this
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConfigService {
|
|
12
|
+
private configPath;
|
|
13
|
+
private cachedConfig;
|
|
14
|
+
private cachedCustomAgentConfigs;
|
|
15
|
+
constructor();
|
|
16
|
+
/**
|
|
17
|
+
* Get config path
|
|
18
|
+
*/
|
|
19
|
+
getPath(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get the full config, merged with defaults.
|
|
22
|
+
*/
|
|
23
|
+
get(): HiveConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Update config (partial merge).
|
|
26
|
+
*/
|
|
27
|
+
set(updates: Partial<HiveConfig>): HiveConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Check if config file exists.
|
|
30
|
+
*/
|
|
31
|
+
exists(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Initialize config with defaults if it doesn't exist.
|
|
34
|
+
*/
|
|
35
|
+
init(): HiveConfig;
|
|
36
|
+
/**
|
|
37
|
+
* Get agent-specific model config
|
|
38
|
+
*/
|
|
39
|
+
getAgentConfig(agent: string): AgentModelConfig | ResolvedCustomAgentConfig;
|
|
40
|
+
getCustomAgentConfigs(): Record<string, ResolvedCustomAgentConfig>;
|
|
41
|
+
hasConfiguredAgent(agent: string): boolean;
|
|
42
|
+
private isBuiltInAgent;
|
|
43
|
+
private isReservedCustomAgentName;
|
|
44
|
+
private isSupportedCustomAgentBase;
|
|
45
|
+
private isPlannerAgent;
|
|
46
|
+
private isObjectRecord;
|
|
47
|
+
private resolveAutoLoadSkills;
|
|
48
|
+
/**
|
|
49
|
+
* Check if OMO-Slim delegation is enabled via user config.
|
|
50
|
+
*/
|
|
51
|
+
isOmoSlimEnabled(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Get list of globally disabled skills.
|
|
54
|
+
*/
|
|
55
|
+
getDisabledSkills(): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Get list of globally disabled MCPs.
|
|
58
|
+
*/
|
|
59
|
+
getDisabledMcps(): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Get sandbox configuration for worker isolation.
|
|
62
|
+
* Returns { mode: 'none' | 'docker', image?: string, persistent?: boolean }
|
|
63
|
+
*/
|
|
64
|
+
getSandboxConfig(): SandboxConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Get hook execution cadence for a specific hook.
|
|
67
|
+
* Returns the configured cadence or 1 (every turn) if not set.
|
|
68
|
+
* Validates cadence values and defaults to 1 for invalid values.
|
|
69
|
+
*
|
|
70
|
+
* @param hookName - The OpenCode hook name (e.g., 'experimental.chat.system.transform')
|
|
71
|
+
* @param options - Optional configuration
|
|
72
|
+
* @param options.safetyCritical - If true, enforces cadence=1 regardless of config
|
|
73
|
+
* @returns Validated cadence value (always >= 1)
|
|
74
|
+
*/
|
|
75
|
+
getHookCadence(hookName: string, options?: {
|
|
76
|
+
safetyCritical?: boolean;
|
|
77
|
+
}): number;
|
|
78
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ContextFile } from '../types.js';
|
|
2
|
+
export type { ContextFile };
|
|
3
|
+
export declare const RESERVED_OVERVIEW_CONTEXT = "overview";
|
|
4
|
+
export declare class ContextService {
|
|
5
|
+
private projectRoot;
|
|
6
|
+
constructor(projectRoot: string);
|
|
7
|
+
write(featureName: string, fileName: string, content: string): string;
|
|
8
|
+
read(featureName: string, fileName: string): string | null;
|
|
9
|
+
list(featureName: string): ContextFile[];
|
|
10
|
+
getOverview(featureName: string): ContextFile | null;
|
|
11
|
+
listExecutionContext(featureName: string): ContextFile[];
|
|
12
|
+
delete(featureName: string, fileName: string): boolean;
|
|
13
|
+
compile(featureName: string): string;
|
|
14
|
+
archive(featureName: string): {
|
|
15
|
+
archived: string[];
|
|
16
|
+
archivePath: string;
|
|
17
|
+
};
|
|
18
|
+
stats(featureName: string): {
|
|
19
|
+
count: number;
|
|
20
|
+
totalChars: number;
|
|
21
|
+
oldest?: string;
|
|
22
|
+
newest?: string;
|
|
23
|
+
};
|
|
24
|
+
private normalizeFileName;
|
|
25
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface SandboxConfig {
|
|
2
|
+
mode: 'none' | 'docker';
|
|
3
|
+
image?: string;
|
|
4
|
+
persistent?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* DockerSandboxService handles Level 1 Docker sandboxing for Hive workers.
|
|
8
|
+
* Uses ephemeral containers (docker run --rm) with volume mounts.
|
|
9
|
+
*
|
|
10
|
+
* Level 1: Lightweight docker run (no devcontainer.json, no persistent containers)
|
|
11
|
+
*/
|
|
12
|
+
export declare class DockerSandboxService {
|
|
13
|
+
/**
|
|
14
|
+
* Detects appropriate Docker image based on project files in worktree.
|
|
15
|
+
*
|
|
16
|
+
* @param worktreePath - Path to the worktree directory
|
|
17
|
+
* @returns Docker image name, or null if Dockerfile exists (user manages their own)
|
|
18
|
+
*/
|
|
19
|
+
static detectImage(worktreePath: string): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Builds docker run command with volume mount and working directory.
|
|
22
|
+
*
|
|
23
|
+
* @param worktreePath - Path to the worktree directory
|
|
24
|
+
* @param command - Command to execute inside container
|
|
25
|
+
* @param image - Docker image to use
|
|
26
|
+
* @returns Complete docker run command string
|
|
27
|
+
*/
|
|
28
|
+
static buildRunCommand(worktreePath: string, command: string, image: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Generates a container name from a worktree path.
|
|
31
|
+
* Extracts feature and task from .hive/.worktrees/<feature>/<task> pattern.
|
|
32
|
+
*
|
|
33
|
+
* @param worktreePath - Path to the worktree directory
|
|
34
|
+
* @returns Container name (e.g., 'hive-my-feature-my-task')
|
|
35
|
+
*/
|
|
36
|
+
static containerName(worktreePath: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Ensures a persistent container exists for the worktree.
|
|
39
|
+
* If container already running, returns its name.
|
|
40
|
+
* Otherwise, creates a new detached container.
|
|
41
|
+
*
|
|
42
|
+
* @param worktreePath - Path to the worktree directory
|
|
43
|
+
* @param image - Docker image to use
|
|
44
|
+
* @returns Container name
|
|
45
|
+
*/
|
|
46
|
+
static ensureContainer(worktreePath: string, image: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Builds a docker exec command for persistent containers.
|
|
49
|
+
*
|
|
50
|
+
* @param containerName - Name of the running container
|
|
51
|
+
* @param command - Command to execute
|
|
52
|
+
* @returns Complete docker exec command string
|
|
53
|
+
*/
|
|
54
|
+
static buildExecCommand(containerName: string, command: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Stops and removes a persistent container for a worktree.
|
|
57
|
+
*
|
|
58
|
+
* @param worktreePath - Path to the worktree directory
|
|
59
|
+
*/
|
|
60
|
+
static stopContainer(worktreePath: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Checks if Docker is available on the system.
|
|
63
|
+
*
|
|
64
|
+
* @returns true if docker is available, false otherwise
|
|
65
|
+
*/
|
|
66
|
+
static isDockerAvailable(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Wraps a command with Docker container execution based on config.
|
|
69
|
+
*
|
|
70
|
+
* @param worktreePath - Path to the worktree directory
|
|
71
|
+
* @param command - Command to execute
|
|
72
|
+
* @param config - Sandbox configuration
|
|
73
|
+
* @returns Wrapped command (or original if no wrapping needed)
|
|
74
|
+
*/
|
|
75
|
+
static wrapCommand(worktreePath: string, command: string, config: SandboxConfig): string;
|
|
76
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FeatureJson, FeatureStatusType, FeatureInfo } from '../types.js';
|
|
2
|
+
export declare class FeatureService {
|
|
3
|
+
private projectRoot;
|
|
4
|
+
private reviewService;
|
|
5
|
+
constructor(projectRoot: string);
|
|
6
|
+
private getReviewService;
|
|
7
|
+
create(name: string, ticket?: string): FeatureJson;
|
|
8
|
+
get(name: string): FeatureJson | null;
|
|
9
|
+
list(): string[];
|
|
10
|
+
getActive(): FeatureJson | null;
|
|
11
|
+
setActive(name: string): void;
|
|
12
|
+
updateStatus(name: string, status: FeatureStatusType): FeatureJson;
|
|
13
|
+
getInfo(name: string): FeatureInfo | null;
|
|
14
|
+
private getTasks;
|
|
15
|
+
complete(name: string): FeatureJson;
|
|
16
|
+
setSession(name: string, sessionId: string): void;
|
|
17
|
+
getSession(name: string): string | undefined;
|
|
18
|
+
private readActiveFeatureName;
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { FeatureService } from './featureService.js';
|
|
2
|
+
export { PlanService } from './planService.js';
|
|
3
|
+
export { TaskService } from './taskService.js';
|
|
4
|
+
export { SubtaskService } from './subtaskService.js';
|
|
5
|
+
export { WorktreeService, createWorktreeService } from './worktreeService.js';
|
|
6
|
+
export type { WorktreeInfo, DiffResult, ApplyResult, CommitResult, MergeResult, WorktreeConfig } from './worktreeService.js';
|
|
7
|
+
export { ContextService } from './contextService.js';
|
|
8
|
+
export { ReviewService } from './reviewService.js';
|
|
9
|
+
export { SessionService } from './sessionService.js';
|
|
10
|
+
export { ConfigService } from './configService.js';
|
|
11
|
+
export { AgentsMdService } from './agentsMdService.js';
|
|
12
|
+
export type { InitResult, SyncResult, ApplyResult as AgentsMdApplyResult } from './agentsMdService.js';
|
|
13
|
+
export { DockerSandboxService } from './dockerSandboxService.js';
|
|
14
|
+
export type { SandboxConfig } from './dockerSandboxService.js';
|
|
15
|
+
export { buildEffectiveDependencies, computeRunnableAndBlocked } from './taskDependencyGraph.js';
|
|
16
|
+
export type { TaskWithDeps, RunnableBlockedResult } from './taskDependencyGraph.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PlanComment, PlanReadResult } from '../types.js';
|
|
2
|
+
export declare class PlanService {
|
|
3
|
+
private projectRoot;
|
|
4
|
+
private reviewService;
|
|
5
|
+
constructor(projectRoot: string);
|
|
6
|
+
private getReviewService;
|
|
7
|
+
write(featureName: string, content: string): string;
|
|
8
|
+
read(featureName: string): PlanReadResult | null;
|
|
9
|
+
approve(featureName: string): void;
|
|
10
|
+
isApproved(featureName: string): boolean;
|
|
11
|
+
revokeApproval(featureName: string): void;
|
|
12
|
+
getComments(featureName: string): PlanComment[];
|
|
13
|
+
addComment(featureName: string, comment: Omit<PlanComment, 'id'>): PlanComment;
|
|
14
|
+
clearComments(featureName: string): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReviewCounts, ReviewDocument, ReviewThread } from '../types.js';
|
|
2
|
+
export declare class ReviewService {
|
|
3
|
+
private projectRoot;
|
|
4
|
+
constructor(projectRoot: string);
|
|
5
|
+
getThreads(featureName: string, document: ReviewDocument): ReviewThread[];
|
|
6
|
+
saveThreads(featureName: string, document: ReviewDocument, threads: ReviewThread[]): void;
|
|
7
|
+
clear(featureName: string, document: ReviewDocument): void;
|
|
8
|
+
countByDocument(featureName: string): ReviewCounts;
|
|
9
|
+
hasUnresolvedThreads(featureName: string, document?: ReviewDocument): boolean;
|
|
10
|
+
private readComments;
|
|
11
|
+
private getCanonicalPath;
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SessionInfo } from '../types.js';
|
|
2
|
+
export declare class SessionService {
|
|
3
|
+
private projectRoot;
|
|
4
|
+
constructor(projectRoot: string);
|
|
5
|
+
private getSessionsPath;
|
|
6
|
+
private getSessions;
|
|
7
|
+
private saveSessions;
|
|
8
|
+
track(featureName: string, sessionId: string, taskFolder?: string): SessionInfo;
|
|
9
|
+
setMaster(featureName: string, sessionId: string): void;
|
|
10
|
+
getMaster(featureName: string): string | undefined;
|
|
11
|
+
list(featureName: string): SessionInfo[];
|
|
12
|
+
get(featureName: string, sessionId: string): SessionInfo | undefined;
|
|
13
|
+
getByTask(featureName: string, taskFolder: string): SessionInfo | undefined;
|
|
14
|
+
remove(featureName: string, sessionId: string): boolean;
|
|
15
|
+
findFeatureBySession(sessionId: string): string | null;
|
|
16
|
+
fork(featureName: string, fromSessionId?: string): SessionInfo;
|
|
17
|
+
fresh(featureName: string, title?: string): SessionInfo;
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Subtask, SubtaskType, TaskStatusType } from '../types.js';
|
|
2
|
+
export declare class SubtaskService {
|
|
3
|
+
private projectRoot;
|
|
4
|
+
constructor(projectRoot: string);
|
|
5
|
+
create(featureName: string, taskFolder: string, name: string, type?: SubtaskType): Subtask;
|
|
6
|
+
update(featureName: string, taskFolder: string, subtaskId: string, status: TaskStatusType): Subtask;
|
|
7
|
+
list(featureName: string, taskFolder: string): Subtask[];
|
|
8
|
+
get(featureName: string, taskFolder: string, subtaskId: string): Subtask | null;
|
|
9
|
+
writeSpec(featureName: string, taskFolder: string, subtaskId: string, content: string): string;
|
|
10
|
+
writeReport(featureName: string, taskFolder: string, subtaskId: string, content: string): string;
|
|
11
|
+
readSpec(featureName: string, taskFolder: string, subtaskId: string): string | null;
|
|
12
|
+
readReport(featureName: string, taskFolder: string, subtaskId: string): string | null;
|
|
13
|
+
delete(featureName: string, taskFolder: string, subtaskId: string): void;
|
|
14
|
+
private listFolders;
|
|
15
|
+
private findFolder;
|
|
16
|
+
private slugify;
|
|
17
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TaskStatusType } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal task info needed for dependency graph computation.
|
|
4
|
+
*/
|
|
5
|
+
export interface TaskWithDeps {
|
|
6
|
+
folder: string;
|
|
7
|
+
status: TaskStatusType;
|
|
8
|
+
dependsOn?: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Result of computing runnable and blocked tasks.
|
|
12
|
+
*/
|
|
13
|
+
export interface RunnableBlockedResult {
|
|
14
|
+
/** Task folders that are pending and have all dependencies satisfied (done) */
|
|
15
|
+
runnable: string[];
|
|
16
|
+
/** Map of task folder -> array of unsatisfied dependency folders */
|
|
17
|
+
blocked: Record<string, string[]>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Compute which pending tasks are runnable (all deps done) and which are blocked.
|
|
21
|
+
*
|
|
22
|
+
* A task is runnable if:
|
|
23
|
+
* - Its status is 'pending'
|
|
24
|
+
* - All its dependencies have status 'done'
|
|
25
|
+
*
|
|
26
|
+
* A task is blocked if:
|
|
27
|
+
* - Its status is 'pending'
|
|
28
|
+
* - At least one dependency does NOT have status 'done'
|
|
29
|
+
*
|
|
30
|
+
* Only 'done' satisfies a dependency. Other statuses (in_progress, cancelled,
|
|
31
|
+
* failed, blocked, partial) do NOT satisfy dependencies.
|
|
32
|
+
*
|
|
33
|
+
* @param tasks - Array of tasks with their status and dependencies
|
|
34
|
+
* @returns Object with runnable task folders and blocked tasks with their missing deps
|
|
35
|
+
*/
|
|
36
|
+
export declare function computeRunnableAndBlocked(tasks: TaskWithDeps[]): RunnableBlockedResult;
|
|
37
|
+
/**
|
|
38
|
+
* Compute effective dependencies for each task, applying legacy numeric
|
|
39
|
+
* sequential fallback when dependsOn is undefined.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildEffectiveDependencies(tasks: TaskWithDeps[]): Map<string, string[]>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { LockOptions } from '../utils/paths.js';
|
|
2
|
+
import { TaskStatus, TaskStatusType, TasksSyncResult, TaskInfo, Subtask, SubtaskType, WorkerSession } from '../types.js';
|
|
3
|
+
/** Current schema version for TaskStatus */
|
|
4
|
+
export declare const TASK_STATUS_SCHEMA_VERSION = 1;
|
|
5
|
+
/** Fields that can be updated by background workers without clobbering completion-owned fields */
|
|
6
|
+
export interface BackgroundPatchFields {
|
|
7
|
+
idempotencyKey?: string;
|
|
8
|
+
workerSession?: Partial<WorkerSession>;
|
|
9
|
+
}
|
|
10
|
+
/** Fields owned by the completion flow (not to be touched by background patches) */
|
|
11
|
+
export interface CompletionFields {
|
|
12
|
+
status?: TaskStatusType;
|
|
13
|
+
summary?: string;
|
|
14
|
+
completedAt?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class TaskService {
|
|
17
|
+
private projectRoot;
|
|
18
|
+
constructor(projectRoot: string);
|
|
19
|
+
sync(featureName: string): TasksSyncResult;
|
|
20
|
+
/**
|
|
21
|
+
* Create a manual task with auto-incrementing index.
|
|
22
|
+
* Folder format: "01-task-name", "02-task-name", etc.
|
|
23
|
+
* Index ensures alphabetical sort = chronological order.
|
|
24
|
+
*/
|
|
25
|
+
create(featureName: string, name: string, order?: number): string;
|
|
26
|
+
private createFromPlan;
|
|
27
|
+
buildSpecContent(params: {
|
|
28
|
+
featureName: string;
|
|
29
|
+
task: {
|
|
30
|
+
folder: string;
|
|
31
|
+
name: string;
|
|
32
|
+
order: number;
|
|
33
|
+
description?: string;
|
|
34
|
+
};
|
|
35
|
+
dependsOn: string[];
|
|
36
|
+
allTasks: Array<{
|
|
37
|
+
folder: string;
|
|
38
|
+
name: string;
|
|
39
|
+
order: number;
|
|
40
|
+
}>;
|
|
41
|
+
planContent?: string | null;
|
|
42
|
+
contextFiles?: Array<{
|
|
43
|
+
name: string;
|
|
44
|
+
content: string;
|
|
45
|
+
}>;
|
|
46
|
+
completedTasks?: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
summary: string;
|
|
49
|
+
}>;
|
|
50
|
+
}): string;
|
|
51
|
+
private extractPlanSection;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve dependency numbers to folder names.
|
|
54
|
+
* - If dependsOnNumbers is null (not specified), apply implicit sequential default (N-1 for N > 1).
|
|
55
|
+
* - If dependsOnNumbers is [] (explicit "none"), return empty array.
|
|
56
|
+
* - Otherwise, map numbers to corresponding task folders.
|
|
57
|
+
*/
|
|
58
|
+
private resolveDependencies;
|
|
59
|
+
/**
|
|
60
|
+
* Validate the dependency graph for errors before creating tasks.
|
|
61
|
+
* Throws descriptive errors pointing the operator to fix plan.md.
|
|
62
|
+
*
|
|
63
|
+
* Checks for:
|
|
64
|
+
* - Unknown task numbers in dependencies
|
|
65
|
+
* - Self-dependencies
|
|
66
|
+
* - Cycles (using DFS topological sort)
|
|
67
|
+
*/
|
|
68
|
+
private validateDependencyGraph;
|
|
69
|
+
/**
|
|
70
|
+
* Detect cycles in the dependency graph using DFS.
|
|
71
|
+
* Throws a descriptive error if a cycle is found.
|
|
72
|
+
*/
|
|
73
|
+
private detectCycles;
|
|
74
|
+
writeSpec(featureName: string, taskFolder: string, content: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Update task status with locked atomic write.
|
|
77
|
+
* Uses file locking to prevent race conditions between concurrent updates.
|
|
78
|
+
*
|
|
79
|
+
* @param featureName - Feature name
|
|
80
|
+
* @param taskFolder - Task folder name
|
|
81
|
+
* @param updates - Fields to update (status, summary, baseCommit)
|
|
82
|
+
* @param lockOptions - Optional lock configuration
|
|
83
|
+
* @returns Updated TaskStatus
|
|
84
|
+
*/
|
|
85
|
+
update(featureName: string, taskFolder: string, updates: Partial<Pick<TaskStatus, 'status' | 'summary' | 'baseCommit'>>, lockOptions?: LockOptions): TaskStatus;
|
|
86
|
+
/**
|
|
87
|
+
* Patch only background-owned fields without clobbering completion-owned fields.
|
|
88
|
+
* Safe for concurrent use by background workers.
|
|
89
|
+
*
|
|
90
|
+
* Uses deep merge for workerSession to allow partial updates like:
|
|
91
|
+
* - patchBackgroundFields(..., { workerSession: { lastHeartbeatAt: '...' } })
|
|
92
|
+
* will update only lastHeartbeatAt, preserving other workerSession fields.
|
|
93
|
+
*
|
|
94
|
+
* @param featureName - Feature name
|
|
95
|
+
* @param taskFolder - Task folder name
|
|
96
|
+
* @param patch - Background-owned fields to update
|
|
97
|
+
* @param lockOptions - Optional lock configuration
|
|
98
|
+
* @returns Updated TaskStatus
|
|
99
|
+
*/
|
|
100
|
+
patchBackgroundFields(featureName: string, taskFolder: string, patch: BackgroundPatchFields, lockOptions?: LockOptions): TaskStatus;
|
|
101
|
+
/**
|
|
102
|
+
* Get raw TaskStatus including all fields (for internal use or debugging).
|
|
103
|
+
*/
|
|
104
|
+
getRawStatus(featureName: string, taskFolder: string): TaskStatus | null;
|
|
105
|
+
get(featureName: string, taskFolder: string): TaskInfo | null;
|
|
106
|
+
list(featureName: string): TaskInfo[];
|
|
107
|
+
writeReport(featureName: string, taskFolder: string, report: string): string;
|
|
108
|
+
private listFolders;
|
|
109
|
+
private deleteTask;
|
|
110
|
+
private getNextOrder;
|
|
111
|
+
private parseTasksFromPlan;
|
|
112
|
+
createSubtask(featureName: string, taskFolder: string, name: string, type?: SubtaskType): Subtask;
|
|
113
|
+
updateSubtask(featureName: string, taskFolder: string, subtaskId: string, status: TaskStatusType): Subtask;
|
|
114
|
+
listSubtasks(featureName: string, taskFolder: string): Subtask[];
|
|
115
|
+
deleteSubtask(featureName: string, taskFolder: string, subtaskId: string): void;
|
|
116
|
+
getSubtask(featureName: string, taskFolder: string, subtaskId: string): Subtask | null;
|
|
117
|
+
writeSubtaskSpec(featureName: string, taskFolder: string, subtaskId: string, content: string): string;
|
|
118
|
+
writeSubtaskReport(featureName: string, taskFolder: string, subtaskId: string, content: string): string;
|
|
119
|
+
readSubtaskSpec(featureName: string, taskFolder: string, subtaskId: string): string | null;
|
|
120
|
+
readSubtaskReport(featureName: string, taskFolder: string, subtaskId: string): string | null;
|
|
121
|
+
private listSubtaskFolders;
|
|
122
|
+
private findSubtaskFolder;
|
|
123
|
+
private slugify;
|
|
124
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface WorktreeInfo {
|
|
2
|
+
path: string;
|
|
3
|
+
branch: string;
|
|
4
|
+
commit: string;
|
|
5
|
+
feature: string;
|
|
6
|
+
step: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DiffResult {
|
|
9
|
+
hasDiff: boolean;
|
|
10
|
+
diffContent: string;
|
|
11
|
+
filesChanged: string[];
|
|
12
|
+
insertions: number;
|
|
13
|
+
deletions: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ApplyResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
error?: string;
|
|
18
|
+
filesAffected: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface CommitResult {
|
|
21
|
+
committed: boolean;
|
|
22
|
+
sha: string;
|
|
23
|
+
message?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MergeResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
merged: boolean;
|
|
28
|
+
sha?: string;
|
|
29
|
+
filesChanged?: string[];
|
|
30
|
+
conflicts?: string[];
|
|
31
|
+
error?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface WorktreeConfig {
|
|
34
|
+
baseDir: string;
|
|
35
|
+
hiveDir: string;
|
|
36
|
+
}
|
|
37
|
+
export declare class WorktreeService {
|
|
38
|
+
private config;
|
|
39
|
+
constructor(config: WorktreeConfig);
|
|
40
|
+
private getGit;
|
|
41
|
+
private getWorktreesDir;
|
|
42
|
+
private getWorktreePath;
|
|
43
|
+
private getStepStatusPath;
|
|
44
|
+
private getBranchName;
|
|
45
|
+
create(feature: string, step: string, baseBranch?: string): Promise<WorktreeInfo>;
|
|
46
|
+
get(feature: string, step: string): Promise<WorktreeInfo | null>;
|
|
47
|
+
getDiff(feature: string, step: string, baseCommit?: string): Promise<DiffResult>;
|
|
48
|
+
exportPatch(feature: string, step: string, baseBranch?: string): Promise<string>;
|
|
49
|
+
applyDiff(feature: string, step: string, baseBranch?: string): Promise<ApplyResult>;
|
|
50
|
+
revertDiff(feature: string, step: string, baseBranch?: string): Promise<ApplyResult>;
|
|
51
|
+
private parseFilesFromDiff;
|
|
52
|
+
revertFromSavedDiff(diffPath: string): Promise<ApplyResult>;
|
|
53
|
+
remove(feature: string, step: string, deleteBranch?: boolean): Promise<void>;
|
|
54
|
+
list(feature?: string): Promise<WorktreeInfo[]>;
|
|
55
|
+
cleanup(feature?: string): Promise<{
|
|
56
|
+
removed: string[];
|
|
57
|
+
pruned: boolean;
|
|
58
|
+
}>;
|
|
59
|
+
checkConflicts(feature: string, step: string, baseBranch?: string): Promise<string[]>;
|
|
60
|
+
checkConflictsFromSavedDiff(diffPath: string, reverse?: boolean): Promise<string[]>;
|
|
61
|
+
commitChanges(feature: string, step: string, message?: string): Promise<CommitResult>;
|
|
62
|
+
merge(feature: string, step: string, strategy?: "merge" | "squash" | "rebase", message?: string): Promise<MergeResult>;
|
|
63
|
+
hasUncommittedChanges(feature: string, step: string): Promise<boolean>;
|
|
64
|
+
private parseConflictsFromError;
|
|
65
|
+
}
|
|
66
|
+
export declare function createWorktreeService(projectDir: string): WorktreeService;
|