@intrect/openswarm 0.5.0 → 0.8.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/LICENSE +21 -674
- package/README.md +97 -35
- package/config.example.yaml +8 -2
- package/dist/adapters/agenticLoop.d.ts +15 -1
- package/dist/adapters/agenticLoop.d.ts.map +1 -1
- package/dist/adapters/agenticLoop.js +62 -4
- package/dist/adapters/agenticLoop.js.map +1 -1
- package/dist/adapters/chatStream.d.ts +55 -0
- package/dist/adapters/chatStream.d.ts.map +1 -0
- package/dist/adapters/chatStream.js +116 -0
- package/dist/adapters/chatStream.js.map +1 -0
- package/dist/adapters/codex.d.ts +6 -0
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/codex.js +27 -1
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/codexModels.d.ts +20 -0
- package/dist/adapters/codexModels.d.ts.map +1 -0
- package/dist/adapters/codexModels.js +195 -0
- package/dist/adapters/codexModels.js.map +1 -0
- package/dist/adapters/codexResponses.d.ts +97 -0
- package/dist/adapters/codexResponses.d.ts.map +1 -0
- package/dist/adapters/codexResponses.js +302 -0
- package/dist/adapters/codexResponses.js.map +1 -0
- package/dist/adapters/gpt.d.ts.map +1 -1
- package/dist/adapters/gpt.js +17 -131
- package/dist/adapters/gpt.js.map +1 -1
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +11 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/local.d.ts.map +1 -1
- package/dist/adapters/local.js +17 -125
- package/dist/adapters/local.js.map +1 -1
- package/dist/adapters/openrouter.d.ts +5 -24
- package/dist/adapters/openrouter.d.ts.map +1 -1
- package/dist/adapters/openrouter.js +20 -121
- package/dist/adapters/openrouter.js.map +1 -1
- package/dist/adapters/resultParsing.d.ts +6 -0
- package/dist/adapters/resultParsing.d.ts.map +1 -0
- package/dist/adapters/resultParsing.js +139 -0
- package/dist/adapters/resultParsing.js.map +1 -0
- package/dist/adapters/tools.d.ts +0 -6
- package/dist/adapters/tools.d.ts.map +1 -1
- package/dist/adapters/tools.js +57 -3
- package/dist/adapters/tools.js.map +1 -1
- package/dist/adapters/types.d.ts +21 -1
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/webTools.d.ts +9 -0
- package/dist/adapters/webTools.d.ts.map +1 -0
- package/dist/adapters/webTools.js +195 -0
- package/dist/adapters/webTools.js.map +1 -0
- package/dist/agents/pairPipeline.d.ts +26 -1
- package/dist/agents/pairPipeline.d.ts.map +1 -1
- package/dist/agents/pairPipeline.js +82 -14
- package/dist/agents/pairPipeline.js.map +1 -1
- package/dist/agents/reflection.d.ts +56 -0
- package/dist/agents/reflection.d.ts.map +1 -0
- package/dist/agents/reflection.js +120 -0
- package/dist/agents/reflection.js.map +1 -0
- package/dist/agents/worker.d.ts +2 -0
- package/dist/agents/worker.d.ts.map +1 -1
- package/dist/agents/worker.js +1 -0
- package/dist/agents/worker.js.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/linearPkce.d.ts +22 -0
- package/dist/auth/linearPkce.d.ts.map +1 -0
- package/dist/auth/linearPkce.js +208 -0
- package/dist/auth/linearPkce.js.map +1 -0
- package/dist/auth/oauthPkce.d.ts.map +1 -1
- package/dist/auth/oauthPkce.js +18 -5
- package/dist/auth/oauthPkce.js.map +1 -1
- package/dist/auth/oauthStore.d.ts.map +1 -1
- package/dist/auth/oauthStore.js +10 -2
- package/dist/auth/oauthStore.js.map +1 -1
- package/dist/automation/autonomousRunner.d.ts +6 -6
- package/dist/automation/autonomousRunner.d.ts.map +1 -1
- package/dist/automation/autonomousRunner.js +15 -13
- package/dist/automation/autonomousRunner.js.map +1 -1
- package/dist/automation/backlogGrooming.d.ts +21 -0
- package/dist/automation/backlogGrooming.d.ts.map +1 -0
- package/dist/automation/backlogGrooming.js +80 -0
- package/dist/automation/backlogGrooming.js.map +1 -0
- package/dist/automation/localCI.d.ts +24 -0
- package/dist/automation/localCI.d.ts.map +1 -0
- package/dist/automation/localCI.js +84 -0
- package/dist/automation/localCI.js.map +1 -0
- package/dist/automation/runnerExecution.d.ts +33 -7
- package/dist/automation/runnerExecution.d.ts.map +1 -1
- package/dist/automation/runnerExecution.js +202 -154
- package/dist/automation/runnerExecution.js.map +1 -1
- package/dist/automation/runnerTypes.d.ts +5 -1
- package/dist/automation/runnerTypes.d.ts.map +1 -1
- package/dist/automation/taskSource.d.ts +101 -0
- package/dist/automation/taskSource.d.ts.map +1 -0
- package/dist/automation/taskSource.js +136 -0
- package/dist/automation/taskSource.js.map +1 -0
- package/dist/automation/workerAuditLog.d.ts +29 -0
- package/dist/automation/workerAuditLog.d.ts.map +1 -0
- package/dist/automation/workerAuditLog.js +82 -0
- package/dist/automation/workerAuditLog.js.map +1 -0
- package/dist/cli/authHandler.d.ts +6 -0
- package/dist/cli/authHandler.d.ts.map +1 -1
- package/dist/cli/authHandler.js +37 -2
- package/dist/cli/authHandler.js.map +1 -1
- package/dist/cli/daemon.d.ts +5 -0
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +13 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/doctorHandler.d.ts +2 -0
- package/dist/cli/doctorHandler.d.ts.map +1 -0
- package/dist/cli/doctorHandler.js +114 -0
- package/dist/cli/doctorHandler.js.map +1 -0
- package/dist/cli/initWizard.d.ts +13 -0
- package/dist/cli/initWizard.d.ts.map +1 -0
- package/dist/cli/initWizard.js +334 -0
- package/dist/cli/initWizard.js.map +1 -0
- package/dist/cli.js +110 -37
- package/dist/cli.js.map +1 -1
- package/dist/core/config.d.ts +50 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +69 -10
- package/dist/core/config.js.map +1 -1
- package/dist/core/envFile.d.ts +6 -0
- package/dist/core/envFile.d.ts.map +1 -1
- package/dist/core/envFile.js +39 -1
- package/dist/core/envFile.js.map +1 -1
- package/dist/core/providerOverride.d.ts +6 -0
- package/dist/core/providerOverride.d.ts.map +1 -0
- package/dist/core/providerOverride.js +37 -0
- package/dist/core/providerOverride.js.map +1 -0
- package/dist/core/service.d.ts.map +1 -1
- package/dist/core/service.js +41 -18
- package/dist/core/service.js.map +1 -1
- package/dist/core/types.d.ts +16 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/discord/discordHandlers.d.ts.map +1 -1
- package/dist/discord/discordHandlers.js +15 -12
- package/dist/discord/discordHandlers.js.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/issues/sqliteStore.d.ts.map +1 -1
- package/dist/issues/sqliteStore.js +7 -2
- package/dist/issues/sqliteStore.js.map +1 -1
- package/dist/knowledge/scanner.d.ts.map +1 -1
- package/dist/knowledge/scanner.js +5 -0
- package/dist/knowledge/scanner.js.map +1 -1
- package/dist/linear/linear.d.ts +45 -2
- package/dist/linear/linear.d.ts.map +1 -1
- package/dist/linear/linear.js +154 -3
- package/dist/linear/linear.js.map +1 -1
- package/dist/locale/prompts/en.d.ts.map +1 -1
- package/dist/locale/prompts/en.js +14 -2
- package/dist/locale/prompts/en.js.map +1 -1
- package/dist/locale/prompts/ko.d.ts.map +1 -1
- package/dist/locale/prompts/ko.js +14 -2
- package/dist/locale/prompts/ko.js.map +1 -1
- package/dist/mcp/mcpClient.d.ts +27 -0
- package/dist/mcp/mcpClient.d.ts.map +1 -0
- package/dist/mcp/mcpClient.js +145 -0
- package/dist/mcp/mcpClient.js.map +1 -0
- package/dist/memory/memoryCore.d.ts.map +1 -1
- package/dist/memory/memoryCore.js +8 -2
- package/dist/memory/memoryCore.js.map +1 -1
- package/dist/notify/notifier.d.ts +26 -0
- package/dist/notify/notifier.d.ts.map +1 -0
- package/dist/notify/notifier.js +131 -0
- package/dist/notify/notifier.js.map +1 -0
- package/dist/orchestration/conflictDetector.d.ts +5 -2
- package/dist/orchestration/conflictDetector.d.ts.map +1 -1
- package/dist/orchestration/conflictDetector.js +35 -6
- package/dist/orchestration/conflictDetector.js.map +1 -1
- package/dist/orchestration/decisionEngine.d.ts +20 -0
- package/dist/orchestration/decisionEngine.d.ts.map +1 -1
- package/dist/orchestration/decisionEngine.js +45 -0
- package/dist/orchestration/decisionEngine.js.map +1 -1
- package/dist/support/banner.d.ts +7 -0
- package/dist/support/banner.d.ts.map +1 -0
- package/dist/support/banner.js +32 -0
- package/dist/support/banner.js.map +1 -0
- package/dist/support/chat.js +28 -5
- package/dist/support/chat.js.map +1 -1
- package/dist/support/chatBackend.d.ts +6 -0
- package/dist/support/chatBackend.d.ts.map +1 -1
- package/dist/support/chatBackend.js +68 -0
- package/dist/support/chatBackend.js.map +1 -1
- package/dist/support/chatTui.d.ts.map +1 -1
- package/dist/support/chatTui.js +202 -9
- package/dist/support/chatTui.js.map +1 -1
- package/dist/support/colors.d.ts +15 -0
- package/dist/support/colors.d.ts.map +1 -0
- package/dist/support/colors.js +23 -0
- package/dist/support/colors.js.map +1 -0
- package/dist/support/planCommand.d.ts +17 -0
- package/dist/support/planCommand.d.ts.map +1 -0
- package/dist/support/planCommand.js +114 -0
- package/dist/support/planCommand.js.map +1 -0
- package/dist/support/planner.d.ts +9 -2
- package/dist/support/planner.d.ts.map +1 -1
- package/dist/support/planner.js +43 -111
- package/dist/support/planner.js.map +1 -1
- package/dist/support/promptHelper.d.ts +24 -0
- package/dist/support/promptHelper.d.ts.map +1 -0
- package/dist/support/promptHelper.js +94 -0
- package/dist/support/promptHelper.js.map +1 -0
- package/dist/support/rateLimiter.d.ts.map +1 -1
- package/dist/support/rateLimiter.js +6 -0
- package/dist/support/rateLimiter.js.map +1 -1
- package/dist/support/repoMetadata.d.ts +7 -0
- package/dist/support/repoMetadata.d.ts.map +1 -1
- package/dist/support/repoMetadata.js +13 -1
- package/dist/support/repoMetadata.js.map +1 -1
- package/dist/support/web.d.ts.map +1 -1
- package/dist/support/web.js +143 -65
- package/dist/support/web.js.map +1 -1
- package/dist/support/worktreeManager.d.ts +6 -1
- package/dist/support/worktreeManager.d.ts.map +1 -1
- package/dist/support/worktreeManager.js +23 -1
- package/dist/support/worktreeManager.js.map +1 -1
- package/dist/taskState/store.d.ts +1 -0
- package/dist/taskState/store.d.ts.map +1 -1
- package/dist/taskState/store.js +22 -1
- package/dist/taskState/store.js.map +1 -1
- package/package.json +4 -2
|
@@ -3,14 +3,19 @@ import type { TaskItem, DecisionResult } from '../orchestration/decisionEngine.j
|
|
|
3
3
|
import type { ExecutorResult } from '../orchestration/workflow.js';
|
|
4
4
|
import type { PipelineResult } from '../agents/pairPipeline.js';
|
|
5
5
|
import type { DefaultRolesConfig, JobProfile } from '../core/types.js';
|
|
6
|
+
import type { SubTask } from '../support/planner.js';
|
|
6
7
|
import { type DraftAnalysis } from '../agents/draftAnalyzer.js';
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import type { Notifier } from '../notify/notifier.js';
|
|
9
|
+
import type { ITaskSource } from './taskSource.js';
|
|
10
|
+
export declare function setNotifier(n: Notifier): void;
|
|
11
|
+
/**
|
|
12
|
+
* Send an outbound notification. Name kept for call-site stability — it is now
|
|
13
|
+
* backend-agnostic (routes to the configured Notifier, not necessarily Discord).
|
|
14
|
+
*/
|
|
11
15
|
export declare function reportToDiscord(message: string | EmbedBuilder): Promise<void>;
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
export declare function setTaskSource(source: ITaskSource): void;
|
|
17
|
+
/** Accessor for callers outside this module (autonomousRunner). */
|
|
18
|
+
export declare function getTaskSource(): ITaskSource | null;
|
|
14
19
|
export declare function fetchLinearTasks(): Promise<{
|
|
15
20
|
tasks: TaskItem[];
|
|
16
21
|
error?: string;
|
|
@@ -40,9 +45,31 @@ export interface ExecutionContext {
|
|
|
40
45
|
scheduleNextHeartbeat?: () => void;
|
|
41
46
|
/** Pipeline guards configuration */
|
|
42
47
|
guards?: Partial<import('../core/types.js').PipelineGuardsConfig>;
|
|
48
|
+
/** Max objective self-repair attempts (lint/bs/test) before giving up (default: 3) */
|
|
49
|
+
maxReflections?: number;
|
|
43
50
|
}
|
|
44
51
|
export declare function resolveProjectPath(ctx: ExecutionContext, task: TaskItem): Promise<string | null>;
|
|
45
52
|
export declare function isValidProjectPath(path: string): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Create Linear sub-issues from an (approved) decomposition: create each
|
|
55
|
+
* sub-issue, register tracking for limits, wire dependencies
|
|
56
|
+
* (ready→Todo / blocked→Backlog), sync state comments, and trigger an immediate
|
|
57
|
+
* heartbeat. Shared by the autonomous `decomposeTask` path and the TUI `/plan`
|
|
58
|
+
* dispatch endpoint so both behave identically (no logic fork). The caller must
|
|
59
|
+
* have already created the parent issue (`parentIssueId`).
|
|
60
|
+
*/
|
|
61
|
+
export declare function createSubIssuesWithDependencies(parentIssueId: string, task: {
|
|
62
|
+
title: string;
|
|
63
|
+
issueIdentifier?: string;
|
|
64
|
+
parentId?: string;
|
|
65
|
+
linearProject?: {
|
|
66
|
+
id?: string;
|
|
67
|
+
name?: string;
|
|
68
|
+
};
|
|
69
|
+
}, subTasks: SubTask[], totalEstimatedMinutes: number, ctx: {
|
|
70
|
+
reportToDiscord: (msg: string) => Promise<void> | void;
|
|
71
|
+
scheduleNextHeartbeat?: () => void;
|
|
72
|
+
}, taskId: string, dailyLimit: number): Promise<boolean>;
|
|
46
73
|
export declare function decomposeTask(ctx: ExecutionContext, task: TaskItem, projectPath: string, targetMinutes: number, draftAnalysis?: DraftAnalysis): Promise<boolean | 'no-decomp'>;
|
|
47
74
|
export declare function executePipeline(ctx: ExecutionContext, task: TaskItem, projectPath: string): Promise<PipelineResult>;
|
|
48
75
|
export declare function requestApproval(decision: DecisionResult, reportFn: (message: string | EmbedBuilder) => Promise<void>): Promise<void>;
|
|
@@ -50,5 +77,4 @@ export declare function reportExecutionResult(task: TaskItem, result: ExecutorRe
|
|
|
50
77
|
export declare function reconcileCompletionState(task: TaskItem): Promise<void>;
|
|
51
78
|
export declare function syncFailureState(task: TaskItem, reason: string): Promise<void>;
|
|
52
79
|
export declare function syncSuccessState(task: TaskItem, confidence?: number): Promise<void>;
|
|
53
|
-
export {};
|
|
54
80
|
//# sourceMappingURL=runnerExecution.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runnerExecution.d.ts","sourceRoot":"","sources":["../../src/automation/runnerExecution.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAiB,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAUtF,OAAO,
|
|
1
|
+
{"version":3,"file":"runnerExecution.d.ts","sourceRoot":"","sources":["../../src/automation/runnerExecution.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
// ============================================
|
|
5
5
|
import { EmbedBuilder } from 'discord.js';
|
|
6
6
|
import { createPipelineFromConfig, buildTaskPrefix } from '../agents/pairPipeline.js';
|
|
7
|
+
import { buildWorkerStartComment, buildWorkerCompleteComment } from './workerAuditLog.js';
|
|
7
8
|
import { formatParsedTaskSummary, loadParsedTask } from '../orchestration/taskParser.js';
|
|
8
9
|
import { saveCognitiveMemory } from '../memory/index.js';
|
|
9
10
|
import * as workerAgent from '../agents/worker.js';
|
|
10
11
|
import * as reviewerAgent from '../agents/reviewer.js';
|
|
11
12
|
import * as projectMapper from '../support/projectMapper.js';
|
|
12
|
-
import * as linear from '../linear/index.js';
|
|
13
13
|
import * as planner from '../support/planner.js';
|
|
14
14
|
import { analyzeIssue } from '../knowledge/index.js';
|
|
15
15
|
import { runDraftAnalysis } from '../agents/draftAnalyzer.js';
|
|
@@ -18,49 +18,45 @@ import { broadcastEvent } from '../core/eventHub.js';
|
|
|
18
18
|
import { buildBranchName, createWorktree, commitAndCreatePR, removeWorktree, } from '../support/worktreeManager.js';
|
|
19
19
|
import { getDecompositionDepth, getChildrenCount, getDailyCreationCount, canCreateMoreIssues, registerDecomposition, } from './runnerState.js';
|
|
20
20
|
import { buildTaskStateSyncComment, completeParentIfChildrenDone, markTaskBlocked, markTaskDecomposed, markTaskDone, markTaskInProgress, releaseDependentTasks, upsertTaskState, } from '../taskState/store.js';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Notifier (outbound notifications — Discord/Slack/Telegram/webhook, INT-1576)
|
|
22
|
+
let notifier = null;
|
|
23
|
+
export function setNotifier(n) {
|
|
24
|
+
notifier = n;
|
|
25
|
+
console.log('[AutonomousRunner] Notifier registered');
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Send an outbound notification. Name kept for call-site stability — it is now
|
|
29
|
+
* backend-agnostic (routes to the configured Notifier, not necessarily Discord).
|
|
30
|
+
*/
|
|
26
31
|
export async function reportToDiscord(message) {
|
|
27
|
-
if (!
|
|
28
|
-
console.log('[AutonomousRunner] No
|
|
32
|
+
if (!notifier) {
|
|
33
|
+
console.log('[AutonomousRunner] No notifier, logging instead:', typeof message === 'string' ? message : message.data.title);
|
|
29
34
|
return;
|
|
30
35
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
await discordSend({ embeds: [message] });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
console.error('[AutonomousRunner] Discord report failed:', error);
|
|
46
|
-
}
|
|
36
|
+
await notifier.notify(message);
|
|
37
|
+
}
|
|
38
|
+
// Task source (Linear OR local SQLite — INT-1577). Injected at service start;
|
|
39
|
+
// the runner routes all task tracking through it instead of importing linear.* .
|
|
40
|
+
let taskSource = null;
|
|
41
|
+
export function setTaskSource(source) {
|
|
42
|
+
taskSource = source;
|
|
43
|
+
console.log(`[AutonomousRunner] Task source registered (${source.kind})`);
|
|
47
44
|
}
|
|
48
|
-
|
|
49
|
-
export function
|
|
50
|
-
|
|
51
|
-
console.log('[AutonomousRunner] Linear fetcher registered');
|
|
45
|
+
/** Accessor for callers outside this module (autonomousRunner). */
|
|
46
|
+
export function getTaskSource() {
|
|
47
|
+
return taskSource;
|
|
52
48
|
}
|
|
53
49
|
// Track consecutive fetch failures for visibility
|
|
54
50
|
let fetchFailureCount = 0;
|
|
55
51
|
export async function fetchLinearTasks() {
|
|
56
|
-
if (!
|
|
57
|
-
console.log('[AutonomousRunner] No
|
|
58
|
-
return { tasks: [], error: 'No
|
|
52
|
+
if (!taskSource) {
|
|
53
|
+
console.log('[AutonomousRunner] No task source registered');
|
|
54
|
+
return { tasks: [], error: 'No task source registered' };
|
|
59
55
|
}
|
|
60
56
|
try {
|
|
61
|
-
const tasks = await
|
|
57
|
+
const tasks = await taskSource.fetchTasks();
|
|
62
58
|
if (fetchFailureCount > 0) {
|
|
63
|
-
console.log(`[AutonomousRunner]
|
|
59
|
+
console.log(`[AutonomousRunner] Task fetch recovered after ${fetchFailureCount} failures`);
|
|
64
60
|
}
|
|
65
61
|
fetchFailureCount = 0;
|
|
66
62
|
return { tasks };
|
|
@@ -68,7 +64,7 @@ export async function fetchLinearTasks() {
|
|
|
68
64
|
catch (error) {
|
|
69
65
|
fetchFailureCount++;
|
|
70
66
|
const msg = error instanceof Error ? error.message : String(error);
|
|
71
|
-
console.error(`[AutonomousRunner]
|
|
67
|
+
console.error(`[AutonomousRunner] Task fetch failed (${fetchFailureCount}x consecutive): ${msg}`);
|
|
72
68
|
return { tasks: [], error: msg };
|
|
73
69
|
}
|
|
74
70
|
}
|
|
@@ -141,6 +137,127 @@ export async function isValidProjectPath(path) {
|
|
|
141
137
|
}
|
|
142
138
|
}
|
|
143
139
|
// Task Decomposition
|
|
140
|
+
/**
|
|
141
|
+
* Create Linear sub-issues from an (approved) decomposition: create each
|
|
142
|
+
* sub-issue, register tracking for limits, wire dependencies
|
|
143
|
+
* (ready→Todo / blocked→Backlog), sync state comments, and trigger an immediate
|
|
144
|
+
* heartbeat. Shared by the autonomous `decomposeTask` path and the TUI `/plan`
|
|
145
|
+
* dispatch endpoint so both behave identically (no logic fork). The caller must
|
|
146
|
+
* have already created the parent issue (`parentIssueId`).
|
|
147
|
+
*/
|
|
148
|
+
export async function createSubIssuesWithDependencies(parentIssueId, task, subTasks, totalEstimatedMinutes, ctx, taskId, dailyLimit) {
|
|
149
|
+
const createdSubIssues = [];
|
|
150
|
+
for (const [index, subTask] of subTasks.entries()) {
|
|
151
|
+
const depsStr = subTask.dependencies?.length
|
|
152
|
+
? `\n\n${t('runner.decomposition.prerequisite', { deps: subTask.dependencies.join(', ') })}`
|
|
153
|
+
: '';
|
|
154
|
+
const fileScope = (subTask.fileScope ?? []).filter((f) => typeof f === 'string' && f.trim().length > 0);
|
|
155
|
+
const scopeStr = fileScope.length
|
|
156
|
+
? `\n\nFile scope: ${fileScope.join(', ')}`
|
|
157
|
+
: '';
|
|
158
|
+
const subDescription = `${subTask.description}\n\n` +
|
|
159
|
+
`${t('runner.decomposition.estimatedTime', { n: String(subTask.estimatedMinutes) })}${depsStr}${scopeStr}\n\n` +
|
|
160
|
+
t('runner.decomposition.autoDecomposed', { parentTitle: task.title });
|
|
161
|
+
const subResult = taskSource
|
|
162
|
+
? await taskSource.createSubIssue(parentIssueId, subTask.title, subDescription, {
|
|
163
|
+
priority: subTask.priority,
|
|
164
|
+
projectId: task.linearProject?.id,
|
|
165
|
+
estimatedMinutes: subTask.estimatedMinutes,
|
|
166
|
+
})
|
|
167
|
+
: { error: 'No task source registered' };
|
|
168
|
+
if ('error' in subResult) {
|
|
169
|
+
console.error(`[AutonomousRunner] Failed to create sub-issue: ${subResult.error}`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
createdSubIssues.push({
|
|
173
|
+
id: subResult.id,
|
|
174
|
+
identifier: subResult.identifier,
|
|
175
|
+
title: subResult.title,
|
|
176
|
+
dependencies: subTask.dependencies || [],
|
|
177
|
+
topoRank: index,
|
|
178
|
+
estimatedMinutes: subTask.estimatedMinutes,
|
|
179
|
+
fileScope,
|
|
180
|
+
});
|
|
181
|
+
console.log(`[AutonomousRunner] Created sub-issue: ${subResult.identifier}`);
|
|
182
|
+
}
|
|
183
|
+
if (createdSubIssues.length === 0) {
|
|
184
|
+
console.error('[AutonomousRunner] No sub-issues created');
|
|
185
|
+
broadcastEvent({ type: 'pipeline:stage', data: { taskId, stage: 'decompose', status: 'fail' } });
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
// Register decomposition in tracking (for limits)
|
|
189
|
+
registerDecomposition(parentIssueId, task.parentId, // Parent ID if this task is also a sub-issue
|
|
190
|
+
createdSubIssues.map(s => s.id));
|
|
191
|
+
console.log(`[AutonomousRunner] Registered decomposition: parent=${parentIssueId}, children=${createdSubIssues.length}, daily=${getDailyCreationCount()}/${dailyLimit}`);
|
|
192
|
+
await taskSource?.markAsDecomposed(parentIssueId, createdSubIssues.length, totalEstimatedMinutes);
|
|
193
|
+
const childIdByTitle = new Map(createdSubIssues.map((subIssue) => [subIssue.title, subIssue.id]));
|
|
194
|
+
const parentState = markTaskDecomposed(parentIssueId, {
|
|
195
|
+
issueIdentifier: task.issueIdentifier,
|
|
196
|
+
title: task.title,
|
|
197
|
+
projectId: task.linearProject?.id,
|
|
198
|
+
projectName: task.linearProject?.name,
|
|
199
|
+
parentIssueId: task.parentId,
|
|
200
|
+
childIssueIds: createdSubIssues.map((subIssue) => subIssue.id),
|
|
201
|
+
});
|
|
202
|
+
await taskSource?.addComment(parentIssueId, buildTaskStateSyncComment(parentState, 'Parent task decomposed'));
|
|
203
|
+
const subIssueList = createdSubIssues
|
|
204
|
+
.map((s, i) => `${i + 1}. ${s.identifier}: ${s.title}`)
|
|
205
|
+
.join('\n');
|
|
206
|
+
await ctx.reportToDiscord(t('runner.decomposition.completed', {
|
|
207
|
+
original: task.issueIdentifier || parentIssueId || '',
|
|
208
|
+
count: String(createdSubIssues.length),
|
|
209
|
+
list: subIssueList,
|
|
210
|
+
totalMinutes: String(totalEstimatedMinutes),
|
|
211
|
+
}));
|
|
212
|
+
broadcastEvent({ type: 'pipeline:stage', data: { taskId, stage: 'decompose', status: 'complete' } });
|
|
213
|
+
// Log each sub-issue as a log line for the dashboard
|
|
214
|
+
for (const s of createdSubIssues) {
|
|
215
|
+
broadcastEvent({ type: 'log', data: { taskId, stage: 'decompose', line: `↳ ${s.identifier}: ${s.title}` } });
|
|
216
|
+
}
|
|
217
|
+
console.log(`[AutonomousRunner] Decomposition complete: ${createdSubIssues.length} sub-issues created`);
|
|
218
|
+
for (const subIssue of createdSubIssues) {
|
|
219
|
+
const dependencyIssueIds = subIssue.dependencies
|
|
220
|
+
.map((title) => childIdByTitle.get(title))
|
|
221
|
+
.filter((value) => Boolean(value));
|
|
222
|
+
const isReady = dependencyIssueIds.length === 0;
|
|
223
|
+
const childState = upsertTaskState(subIssue.id, {
|
|
224
|
+
issueIdentifier: subIssue.identifier,
|
|
225
|
+
title: subIssue.title,
|
|
226
|
+
projectId: task.linearProject?.id,
|
|
227
|
+
projectName: task.linearProject?.name,
|
|
228
|
+
parentIssueId: parentIssueId,
|
|
229
|
+
dependencyIssueIds,
|
|
230
|
+
dependencyTitles: subIssue.dependencies,
|
|
231
|
+
fileScope: subIssue.fileScope,
|
|
232
|
+
topoRank: subIssue.topoRank,
|
|
233
|
+
execution: {
|
|
234
|
+
status: isReady ? 'todo' : 'blocked',
|
|
235
|
+
blockedReason: isReady ? undefined : `Waiting on dependencies: ${dependencyIssueIds.join(', ')}`,
|
|
236
|
+
retryCount: 0,
|
|
237
|
+
},
|
|
238
|
+
linearState: isReady ? 'Todo' : 'Backlog',
|
|
239
|
+
});
|
|
240
|
+
try {
|
|
241
|
+
if (isReady) {
|
|
242
|
+
await taskSource?.updateState(subIssue.id, 'Todo');
|
|
243
|
+
console.log(`[AutonomousRunner] Moved ${subIssue.identifier} to Todo`);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.log(`[AutonomousRunner] Keeping ${subIssue.identifier} in Backlog until dependencies resolve`);
|
|
247
|
+
}
|
|
248
|
+
await taskSource?.addComment(subIssue.id, buildTaskStateSyncComment(childState, isReady ? 'Task ready after decomposition' : 'Task blocked by decomposition dependency'));
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
console.warn(`[AutonomousRunner] Failed to initialize ${subIssue.identifier} state:`, err);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Trigger immediate heartbeat to pick up newly created sub-issues
|
|
255
|
+
if (ctx.scheduleNextHeartbeat) {
|
|
256
|
+
console.log('[AutonomousRunner] Scheduling immediate heartbeat to process sub-issues...');
|
|
257
|
+
ctx.scheduleNextHeartbeat();
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
144
261
|
export async function decomposeTask(ctx, task, projectPath, targetMinutes, draftAnalysis) {
|
|
145
262
|
console.log(`[AutonomousRunner] Decomposing task: ${task.title}`);
|
|
146
263
|
const taskId = task.issueId || task.id;
|
|
@@ -158,8 +275,8 @@ export async function decomposeTask(ctx, task, projectPath, targetMinutes, draft
|
|
|
158
275
|
console.log(`[AutonomousRunner] Decomposition depth limit reached: ${currentDepth}/${maxDepth}`);
|
|
159
276
|
if (autoBacklog && task.issueId) {
|
|
160
277
|
try {
|
|
161
|
-
await
|
|
162
|
-
await
|
|
278
|
+
await taskSource?.updateState(task.issueId, 'Backlog');
|
|
279
|
+
await taskSource?.addComment(task.issueId, `⚠️ **Auto-moved to Backlog**\n\n` +
|
|
163
280
|
`Reason: Decomposition depth limit reached (${currentDepth}/${maxDepth})\n\n` +
|
|
164
281
|
`This task has been nested too deeply. Please review and simplify the task structure, ` +
|
|
165
282
|
`or handle it manually.`);
|
|
@@ -177,8 +294,8 @@ export async function decomposeTask(ctx, task, projectPath, targetMinutes, draft
|
|
|
177
294
|
console.log(`[AutonomousRunner] Children count limit reached: ${childrenCount}/${maxChildren}`);
|
|
178
295
|
if (autoBacklog) {
|
|
179
296
|
try {
|
|
180
|
-
await
|
|
181
|
-
await
|
|
297
|
+
await taskSource?.updateState(task.issueId, 'Backlog');
|
|
298
|
+
await taskSource?.addComment(task.issueId, `⚠️ **Auto-moved to Backlog**\n\n` +
|
|
182
299
|
`Reason: Too many sub-issues already created (${childrenCount}/${maxChildren})\n\n` +
|
|
183
300
|
`This task has generated too many sub-issues. Please review the decomposition strategy, ` +
|
|
184
301
|
`or handle it manually.`);
|
|
@@ -223,7 +340,9 @@ export async function decomposeTask(ctx, task, projectPath, targetMinutes, draft
|
|
|
223
340
|
projectPath,
|
|
224
341
|
projectName: task.linearProject?.name,
|
|
225
342
|
targetMinutes,
|
|
226
|
-
|
|
343
|
+
// Planner runs through the configured adapter loop now (not claude -p);
|
|
344
|
+
// leave model unset to use the adapter default when no planner model is configured.
|
|
345
|
+
model: ctx.plannerModel,
|
|
227
346
|
timeoutMs: ctx.plannerTimeoutMs ?? 600000,
|
|
228
347
|
onLog: (line) => broadcastEvent({ type: 'log', data: { taskId, stage: 'decompose', line } }),
|
|
229
348
|
impactAnalysis: impactAnalysis ?? undefined,
|
|
@@ -253,109 +372,7 @@ export async function decomposeTask(ctx, task, projectPath, targetMinutes, draft
|
|
|
253
372
|
console.error('[AutonomousRunner] Cannot create sub-issues: no parent issueId');
|
|
254
373
|
return false;
|
|
255
374
|
}
|
|
256
|
-
|
|
257
|
-
for (const [index, subTask] of result.subTasks.entries()) {
|
|
258
|
-
const depsStr = subTask.dependencies?.length
|
|
259
|
-
? `\n\n${t('runner.decomposition.prerequisite', { deps: subTask.dependencies.join(', ') })}`
|
|
260
|
-
: '';
|
|
261
|
-
const subDescription = `${subTask.description}\n\n` +
|
|
262
|
-
`${t('runner.decomposition.estimatedTime', { n: String(subTask.estimatedMinutes) })}${depsStr}\n\n` +
|
|
263
|
-
t('runner.decomposition.autoDecomposed', { parentTitle: task.title });
|
|
264
|
-
const subResult = await linear.createSubIssue(task.issueId, subTask.title, subDescription, {
|
|
265
|
-
priority: subTask.priority,
|
|
266
|
-
projectId: task.linearProject?.id,
|
|
267
|
-
estimatedMinutes: subTask.estimatedMinutes,
|
|
268
|
-
});
|
|
269
|
-
if ('error' in subResult) {
|
|
270
|
-
console.error(`[AutonomousRunner] Failed to create sub-issue: ${subResult.error}`);
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
createdSubIssues.push({
|
|
274
|
-
id: subResult.id,
|
|
275
|
-
identifier: subResult.identifier,
|
|
276
|
-
title: subResult.title,
|
|
277
|
-
dependencies: subTask.dependencies || [],
|
|
278
|
-
topoRank: index,
|
|
279
|
-
estimatedMinutes: subTask.estimatedMinutes,
|
|
280
|
-
});
|
|
281
|
-
console.log(`[AutonomousRunner] Created sub-issue: ${subResult.identifier}`);
|
|
282
|
-
}
|
|
283
|
-
if (createdSubIssues.length === 0) {
|
|
284
|
-
console.error('[AutonomousRunner] No sub-issues created');
|
|
285
|
-
broadcastEvent({ type: 'pipeline:stage', data: { taskId, stage: 'decompose', status: 'fail' } });
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
// Register decomposition in tracking (for limits)
|
|
289
|
-
registerDecomposition(task.issueId, task.parentId, // Parent ID if this task is also a sub-issue
|
|
290
|
-
createdSubIssues.map(s => s.id));
|
|
291
|
-
console.log(`[AutonomousRunner] Registered decomposition: parent=${task.issueId}, children=${createdSubIssues.length}, daily=${getDailyCreationCount()}/${dailyLimit}`);
|
|
292
|
-
await linear.markAsDecomposed(task.issueId, createdSubIssues.length, result.totalEstimatedMinutes);
|
|
293
|
-
const childIdByTitle = new Map(createdSubIssues.map((subIssue) => [subIssue.title, subIssue.id]));
|
|
294
|
-
const parentState = markTaskDecomposed(task.issueId, {
|
|
295
|
-
issueIdentifier: task.issueIdentifier,
|
|
296
|
-
title: task.title,
|
|
297
|
-
projectId: task.linearProject?.id,
|
|
298
|
-
projectName: task.linearProject?.name,
|
|
299
|
-
parentIssueId: task.parentId,
|
|
300
|
-
childIssueIds: createdSubIssues.map((subIssue) => subIssue.id),
|
|
301
|
-
});
|
|
302
|
-
await linear.addComment(task.issueId, buildTaskStateSyncComment(parentState, 'Parent task decomposed'));
|
|
303
|
-
const subIssueList = createdSubIssues
|
|
304
|
-
.map((s, i) => `${i + 1}. ${s.identifier}: ${s.title}`)
|
|
305
|
-
.join('\n');
|
|
306
|
-
await ctx.reportToDiscord(t('runner.decomposition.completed', {
|
|
307
|
-
original: task.issueIdentifier || task.issueId || '',
|
|
308
|
-
count: String(createdSubIssues.length),
|
|
309
|
-
list: subIssueList,
|
|
310
|
-
totalMinutes: String(result.totalEstimatedMinutes),
|
|
311
|
-
}));
|
|
312
|
-
broadcastEvent({ type: 'pipeline:stage', data: { taskId, stage: 'decompose', status: 'complete' } });
|
|
313
|
-
// Log each sub-issue as a log line for the dashboard
|
|
314
|
-
for (const s of createdSubIssues) {
|
|
315
|
-
broadcastEvent({ type: 'log', data: { taskId, stage: 'decompose', line: `↳ ${s.identifier}: ${s.title}` } });
|
|
316
|
-
}
|
|
317
|
-
console.log(`[AutonomousRunner] Decomposition complete: ${createdSubIssues.length} sub-issues created`);
|
|
318
|
-
for (const subIssue of createdSubIssues) {
|
|
319
|
-
const dependencyIssueIds = subIssue.dependencies
|
|
320
|
-
.map((title) => childIdByTitle.get(title))
|
|
321
|
-
.filter((value) => Boolean(value));
|
|
322
|
-
const isReady = dependencyIssueIds.length === 0;
|
|
323
|
-
const childState = upsertTaskState(subIssue.id, {
|
|
324
|
-
issueIdentifier: subIssue.identifier,
|
|
325
|
-
title: subIssue.title,
|
|
326
|
-
projectId: task.linearProject?.id,
|
|
327
|
-
projectName: task.linearProject?.name,
|
|
328
|
-
parentIssueId: task.issueId,
|
|
329
|
-
dependencyIssueIds,
|
|
330
|
-
dependencyTitles: subIssue.dependencies,
|
|
331
|
-
topoRank: subIssue.topoRank,
|
|
332
|
-
execution: {
|
|
333
|
-
status: isReady ? 'todo' : 'blocked',
|
|
334
|
-
blockedReason: isReady ? undefined : `Waiting on dependencies: ${dependencyIssueIds.join(', ')}`,
|
|
335
|
-
retryCount: 0,
|
|
336
|
-
},
|
|
337
|
-
linearState: isReady ? 'Todo' : 'Backlog',
|
|
338
|
-
});
|
|
339
|
-
try {
|
|
340
|
-
if (isReady) {
|
|
341
|
-
await linear.updateIssueState(subIssue.id, 'Todo');
|
|
342
|
-
console.log(`[AutonomousRunner] Moved ${subIssue.identifier} to Todo`);
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
console.log(`[AutonomousRunner] Keeping ${subIssue.identifier} in Backlog until dependencies resolve`);
|
|
346
|
-
}
|
|
347
|
-
await linear.addComment(subIssue.id, buildTaskStateSyncComment(childState, isReady ? 'Task ready after decomposition' : 'Task blocked by decomposition dependency'));
|
|
348
|
-
}
|
|
349
|
-
catch (err) {
|
|
350
|
-
console.warn(`[AutonomousRunner] Failed to initialize ${subIssue.identifier} state:`, err);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
// Trigger immediate heartbeat to pick up newly created sub-issues
|
|
354
|
-
if (ctx.scheduleNextHeartbeat) {
|
|
355
|
-
console.log('[AutonomousRunner] Scheduling immediate heartbeat to process sub-issues...');
|
|
356
|
-
ctx.scheduleNextHeartbeat();
|
|
357
|
-
}
|
|
358
|
-
return true;
|
|
375
|
+
return createSubIssuesWithDependencies(task.issueId, task, result.subTasks, result.totalEstimatedMinutes, ctx, taskId, dailyLimit);
|
|
359
376
|
}
|
|
360
377
|
// Pipeline Execution
|
|
361
378
|
export async function executePipeline(ctx, task, projectPath) {
|
|
@@ -446,19 +463,50 @@ export async function executePipeline(ctx, task, projectPath) {
|
|
|
446
463
|
projectStats: draftResult.projectStats,
|
|
447
464
|
impactAnalysis: draftResult.impactAnalysis,
|
|
448
465
|
registrySnapshot: draftResult.registrySnapshot,
|
|
449
|
-
} : undefined);
|
|
466
|
+
} : undefined, ctx.maxReflections);
|
|
450
467
|
const taskPrefix = buildTaskPrefix(task, actualPath);
|
|
451
|
-
pipeline.on('stage:start', ({ stage }) => {
|
|
468
|
+
pipeline.on('stage:start', ({ stage, context, model }) => {
|
|
452
469
|
console.log(`[${taskPrefix}] Stage started: ${stage}`);
|
|
470
|
+
// Audit trail: comment the worker instruction (prompt summary, target
|
|
471
|
+
// files, model/effort) on each worker run. Non-blocking — fire & forget.
|
|
472
|
+
if (stage === 'worker' && task.issueId) {
|
|
473
|
+
const draft = context?.config?.draftAnalysis;
|
|
474
|
+
const body = buildWorkerStartComment({
|
|
475
|
+
attempt: context?.currentIteration ?? 1,
|
|
476
|
+
maxAttempts: ctx.pairMaxAttempts ?? 3,
|
|
477
|
+
taskTitle: task.title,
|
|
478
|
+
taskGoal: draft?.intentSummary || task.description,
|
|
479
|
+
targetFiles: draft?.relevantFiles,
|
|
480
|
+
model: model || context?.config?.roles?.worker?.model,
|
|
481
|
+
maxTurns: context?.config?.roles?.worker?.maxTurns,
|
|
482
|
+
isRevision: (context?.currentIteration ?? 1) > 1,
|
|
483
|
+
});
|
|
484
|
+
void taskSource?.addComment(task.issueId, body).catch((err) => console.error(`[${taskPrefix}] Worker start audit comment failed:`, err));
|
|
485
|
+
}
|
|
453
486
|
});
|
|
454
487
|
const taskReportCtx = {
|
|
455
488
|
issueIdentifier: task.issueIdentifier || task.issueId,
|
|
456
489
|
projectName: task.linearProject?.name,
|
|
457
490
|
projectPath: actualPath,
|
|
458
491
|
};
|
|
459
|
-
pipeline.on('stage:complete', async ({ stage, result }) => {
|
|
492
|
+
pipeline.on('stage:complete', async ({ stage, result, context }) => {
|
|
460
493
|
console.log(`[${taskPrefix}] Stage completed: ${stage}, success=${result.success}`);
|
|
461
494
|
await reportStageResult(stage, result, ctx.reportToDiscord, taskReportCtx);
|
|
495
|
+
// Audit trail: comment the actions taken (files changed, commands run,
|
|
496
|
+
// confidence, halt reason) on each worker run.
|
|
497
|
+
if (stage === 'worker' && task.issueId) {
|
|
498
|
+
try {
|
|
499
|
+
await taskSource?.addComment(task.issueId, buildWorkerCompleteComment({
|
|
500
|
+
attempt: context?.currentIteration ?? 1,
|
|
501
|
+
maxAttempts: ctx.pairMaxAttempts ?? 3,
|
|
502
|
+
result: result.result,
|
|
503
|
+
durationSec: Math.floor((result.duration ?? 0) / 1000),
|
|
504
|
+
}));
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
console.error(`[${taskPrefix}] Worker complete audit comment failed:`, err);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
462
510
|
});
|
|
463
511
|
pipeline.on('revision:start', ({ stage }) => {
|
|
464
512
|
void ctx.reportToDiscord(t('runner.pipeline.revisionNeeded', { stage }));
|
|
@@ -469,7 +517,7 @@ export async function executePipeline(ctx, task, projectPath) {
|
|
|
469
517
|
// Report to Linear
|
|
470
518
|
if (task.issueId && ctx.guards?.haltToLinear) {
|
|
471
519
|
try {
|
|
472
|
-
await
|
|
520
|
+
await taskSource?.logHalt(task.issueId, sessionId, confidence, iteration, haltReason);
|
|
473
521
|
}
|
|
474
522
|
catch (err) {
|
|
475
523
|
console.error(`[${taskPrefix}] Linear logHalt failed:`, err);
|
|
@@ -507,13 +555,13 @@ export async function executePipeline(ctx, task, projectPath) {
|
|
|
507
555
|
branchName: worktreeInfo?.branchName,
|
|
508
556
|
worktreePath: actualPath,
|
|
509
557
|
});
|
|
510
|
-
await
|
|
511
|
-
await
|
|
558
|
+
await taskSource?.logPairStart(task.issueId, sessionId, projectPath);
|
|
559
|
+
await taskSource?.addComment(task.issueId, buildTaskStateSyncComment(inProgressState, 'Task execution started'));
|
|
512
560
|
}
|
|
513
561
|
catch (err) {
|
|
514
562
|
console.error(`[${taskPrefix}] Linear logPairStart failed:`, err);
|
|
515
563
|
// Continue pipeline even if this fails
|
|
516
|
-
await
|
|
564
|
+
await taskSource?.updateState(task.issueId, 'In Progress');
|
|
517
565
|
}
|
|
518
566
|
}
|
|
519
567
|
// Run pipeline in worktree path
|
|
@@ -657,8 +705,8 @@ export async function reconcileCompletionState(task) {
|
|
|
657
705
|
const released = releaseDependentTasks(task.issueId);
|
|
658
706
|
for (const child of released) {
|
|
659
707
|
try {
|
|
660
|
-
await
|
|
661
|
-
await
|
|
708
|
+
await taskSource?.updateState(child.issueId, 'Todo');
|
|
709
|
+
await taskSource?.addComment(child.issueId, buildTaskStateSyncComment(child, 'Task unblocked and ready'));
|
|
662
710
|
}
|
|
663
711
|
catch (err) {
|
|
664
712
|
console.warn(`[AutonomousRunner] Failed to release dependent task ${child.issueId}:`, err);
|
|
@@ -668,8 +716,8 @@ export async function reconcileCompletionState(task) {
|
|
|
668
716
|
if (!parent)
|
|
669
717
|
return;
|
|
670
718
|
try {
|
|
671
|
-
await
|
|
672
|
-
await
|
|
719
|
+
await taskSource?.updateState(parent.issueId, 'Done');
|
|
720
|
+
await taskSource?.addComment(parent.issueId, buildTaskStateSyncComment(parent, 'All child tasks completed'));
|
|
673
721
|
}
|
|
674
722
|
catch (err) {
|
|
675
723
|
console.warn(`[AutonomousRunner] Failed to complete parent task ${parent.issueId}:`, err);
|
|
@@ -680,7 +728,7 @@ export async function syncFailureState(task, reason) {
|
|
|
680
728
|
return;
|
|
681
729
|
const state = markTaskBlocked(task.issueId, reason, task.blockedBy || [], task.linearState);
|
|
682
730
|
try {
|
|
683
|
-
await
|
|
731
|
+
await taskSource?.addComment(task.issueId, buildTaskStateSyncComment(state, 'Task blocked'));
|
|
684
732
|
}
|
|
685
733
|
catch (err) {
|
|
686
734
|
console.warn(`[AutonomousRunner] Failed to sync blocked state for ${task.issueId}:`, err);
|
|
@@ -695,7 +743,7 @@ export async function syncSuccessState(task, confidence) {
|
|
|
695
743
|
confidence,
|
|
696
744
|
});
|
|
697
745
|
try {
|
|
698
|
-
await
|
|
746
|
+
await taskSource?.addComment(task.issueId, buildTaskStateSyncComment(state, 'Task completed'));
|
|
699
747
|
}
|
|
700
748
|
catch (err) {
|
|
701
749
|
console.warn(`[AutonomousRunner] Failed to sync success state for ${task.issueId}:`, err);
|