syntaur 0.27.0 → 0.32.0
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/dashboard/dist/assets/{_basePickBy-DPBuiT9A.js → _basePickBy-CV3s3ZBR.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-B5Q4dkW3.js → _baseUniq-BTBb-kpx.js} +1 -1
- package/dashboard/dist/assets/{arc-Bp71QC_v.js → arc-DroCaru_.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-CWHBISZ5.js → architectureDiagram-2XIMDMQ5-hL5g0oNx.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-D0txIHgi.js → blockDiagram-WCTKOSBZ-H-mOZOGQ.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-D_Hpnc38.js → c4Diagram-IC4MRINW-C7JTywql.js} +1 -1
- package/dashboard/dist/assets/channel-X6-lrXLw.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-D0A_A8qn.js → chunk-4BX2VUAB-C5NgL7Ud.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-DuK8QvrD.js → chunk-55IACEB6-CpqlZIZp.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-B5WfIDS6.js → chunk-FMBD7UC4-DOEJuCgN.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-D3jB_ZJP.js → chunk-JSJVCQXG-DTvwZQeC.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-DtxN1mOD.js → chunk-KX2RTZJC-DtM5R3Ro.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-4fQpgivN.js → chunk-NQ4KR5QH-BRf7XeyG.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-BOf9TZCT.js → chunk-QZHKN3VN-CkRK4_hm.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-D9HeEPWL.js → chunk-WL4C6EOR-D40xff82.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-DfkR91Os.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-DfkR91Os.js +1 -0
- package/dashboard/dist/assets/clone--OUSRwbL.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-CpzWcyB7.js → cose-bilkent-S5V4N54A-BzAx8dWI.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-CC9-omFF.js → dagre-KLK3FWXG-DqBzOGFn.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-q_F9KKPz.js → diagram-E7M64L7V-BU3Nv4BP.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-CbYvNpQB.js → diagram-IFDJBPK2-9173qxjV.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-q8XUUKRC.js → diagram-P4PSJMXO-CDO7XNao.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-Q-oL35fO.js → erDiagram-INFDFZHY-DkO9AjCM.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-Cptj-2yF.js → flowDiagram-PKNHOUZH-9Fjhsq_p.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-BYmgXBad.js → ganttDiagram-A5KZAMGK-FL3oGbo9.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-DHF3w-Cn.js → gitGraphDiagram-K3NZZRJ6-FS9HpxFJ.js} +1 -1
- package/dashboard/dist/assets/{graph-Br4uG9xg.js → graph-COu71lol.js} +1 -1
- package/dashboard/dist/assets/index-BohN_jjP.css +1 -0
- package/dashboard/dist/assets/{index-dyJ_mu3x.js → index-D1FxzsMS.js} +84 -83
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Ckb3YLUI.js → infoDiagram-LFFYTUFH-Cb7nqRMJ.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DSXXm4hL.js → ishikawaDiagram-PHBUUO56-DU44jQ_t.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-D4JJ4wn_.js → journeyDiagram-4ABVD52K-Dvf5wmhX.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-DZeWPcIi.js → kanban-definition-K7BYSVSG-NNnzIiBX.js} +1 -1
- package/dashboard/dist/assets/{layout-DU5mcBKh.js → layout-BWL1q6XW.js} +1 -1
- package/dashboard/dist/assets/{linear-h7AvdT63.js → linear-BpjXUE-L.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-DIOnVuDB.js → mermaid.core-C1YuKa7V.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-BVSORv6W.js → mindmap-definition-YRQLILUH-BUS-7SSM.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-BEdO084J.js → pieDiagram-SKSYHLDU-CId0D08y.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-3Dc5mQ7q.js → quadrantDiagram-337W2JSQ-lrdlvDFz.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-eu-8doSY.js → requirementDiagram-Z7DCOOCP-CijOr4BN.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-jA292hzv.js → sankeyDiagram-WA2Y5GQK-Bz63rCum.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-et31a6Tg.js → sequenceDiagram-2WXFIKYE-0ojwsRXQ.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-D6MtTWaR.js → stateDiagram-RAJIS63D-DvTark-k.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CiT1CTy0.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-Oa_SYaCP.js → timeline-definition-YZTLITO2-B4EQprf1.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-vrIbKmuv.js → treemap-KZPCXAKY-ht_xOxVL.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-B3UlkEHW.js → vennDiagram-LZ73GAT5-C4DqZkvq.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BLiVVy6A.js → xychartDiagram-JWTSCODW-eoymvv9D.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +449 -124
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +5766 -3927
- package/dist/index.js.map +1 -1
- package/dist/launch/index.js +1191 -1181
- package/dist/launch/index.js.map +1 -1
- package/package.json +2 -1
- package/platforms/README.md +21 -0
- package/platforms/claude-code/skills/clear-assignment/SKILL.md +2 -2
- package/platforms/claude-code/skills/log-progress/SKILL.md +29 -48
- package/platforms/claude-code/skills/plan-assignment/SKILL.md +20 -1
- package/platforms/claude-code/skills/save-session-summary/SKILL.md +28 -29
- package/platforms/claude-code/skills/set-workspace/SKILL.md +25 -41
- package/platforms/codex/skills/clear-assignment/SKILL.md +2 -2
- package/platforms/codex/skills/log-progress/SKILL.md +29 -48
- package/platforms/codex/skills/plan-assignment/SKILL.md +20 -1
- package/platforms/codex/skills/save-session-summary/SKILL.md +28 -29
- package/platforms/codex/skills/set-workspace/SKILL.md +25 -41
- package/skills/clear-assignment/SKILL.md +2 -2
- package/skills/log-progress/SKILL.md +29 -48
- package/skills/plan-assignment/SKILL.md +20 -1
- package/skills/save-session-summary/SKILL.md +28 -29
- package/skills/set-workspace/SKILL.md +25 -41
- package/dashboard/dist/assets/channel-D41AslDq.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-BnKy62Yt.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BnKy62Yt.js +0 -1
- package/dashboard/dist/assets/clone-Cz7h9axV.js +0 -1
- package/dashboard/dist/assets/index-Ds1-e_jv.css +0 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-sYL-A3ib.js +0 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -1798,9 +1798,11 @@ __export(config_exports, {
|
|
|
1798
1798
|
AgentConfigError: () => AgentConfigError,
|
|
1799
1799
|
BUILTIN_AGENTS: () => BUILTIN_AGENTS,
|
|
1800
1800
|
DEFAULT_ASSIGNMENT_TYPES: () => DEFAULT_ASSIGNMENT_TYPES,
|
|
1801
|
+
DEFAULT_STATUS_COLORS: () => DEFAULT_STATUS_COLORS,
|
|
1801
1802
|
PROMPT_ARG_POSITIONS: () => PROMPT_ARG_POSITIONS,
|
|
1802
1803
|
TERMINAL_CHOICES: () => TERMINAL_CHOICES,
|
|
1803
1804
|
TerminalConfigError: () => TerminalConfigError,
|
|
1805
|
+
buildDefaultStatusConfig: () => buildDefaultStatusConfig,
|
|
1804
1806
|
deleteAgentsConfig: () => deleteAgentsConfig,
|
|
1805
1807
|
deleteHotkeyBindingsConfig: () => deleteHotkeyBindingsConfig,
|
|
1806
1808
|
deleteStatusConfig: () => deleteStatusConfig,
|
|
@@ -1811,8 +1813,11 @@ __export(config_exports, {
|
|
|
1811
1813
|
getAssignmentTypes: () => getAssignmentTypes,
|
|
1812
1814
|
getTerminal: () => getTerminal,
|
|
1813
1815
|
parseAgentCommand: () => parseAgentCommand,
|
|
1816
|
+
parseStatusConfig: () => parseStatusConfig,
|
|
1814
1817
|
parseTerminalConfig: () => parseTerminalConfig,
|
|
1815
1818
|
readConfig: () => readConfig,
|
|
1819
|
+
serializeStatusConfig: () => serializeStatusConfig,
|
|
1820
|
+
toTitleCase: () => toTitleCase,
|
|
1816
1821
|
updateAgentsConfig: () => updateAgentsConfig,
|
|
1817
1822
|
updateBackupConfig: () => updateBackupConfig,
|
|
1818
1823
|
updateIntegrationConfig: () => updateIntegrationConfig,
|
|
@@ -2058,6 +2063,24 @@ function parseStatusConfig(content) {
|
|
|
2058
2063
|
transitions
|
|
2059
2064
|
};
|
|
2060
2065
|
}
|
|
2066
|
+
function toTitleCase(s) {
|
|
2067
|
+
return s.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2068
|
+
}
|
|
2069
|
+
function buildDefaultStatusConfig() {
|
|
2070
|
+
return {
|
|
2071
|
+
statuses: DEFAULT_STATUSES.map((id) => ({
|
|
2072
|
+
id,
|
|
2073
|
+
label: toTitleCase(id),
|
|
2074
|
+
color: DEFAULT_STATUS_COLORS[id] ?? "gray",
|
|
2075
|
+
terminal: id === "completed" || id === "failed"
|
|
2076
|
+
})),
|
|
2077
|
+
order: [...DEFAULT_STATUSES],
|
|
2078
|
+
transitions: Array.from(DEFAULT_TRANSITION_TABLE.entries()).map(([key, to]) => {
|
|
2079
|
+
const [from, command] = key.split(":");
|
|
2080
|
+
return { from, command, to };
|
|
2081
|
+
})
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2061
2084
|
function serializeStatusConfig(statuses) {
|
|
2062
2085
|
const lines = [];
|
|
2063
2086
|
lines.push("statuses:");
|
|
@@ -3127,7 +3150,7 @@ async function updateAgentsConfig(mutation, options = {}) {
|
|
|
3127
3150
|
await writeAgentsConfig(next);
|
|
3128
3151
|
return { previous, next, written: true };
|
|
3129
3152
|
}
|
|
3130
|
-
var DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, AgentConfigError, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
|
|
3153
|
+
var DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, AgentConfigError, DEFAULT_STATUS_COLORS, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
|
|
3131
3154
|
var init_config2 = __esm({
|
|
3132
3155
|
"src/utils/config.ts"() {
|
|
3133
3156
|
"use strict";
|
|
@@ -3135,6 +3158,7 @@ var init_config2 = __esm({
|
|
|
3135
3158
|
init_fs();
|
|
3136
3159
|
init_config();
|
|
3137
3160
|
init_fs_migration();
|
|
3161
|
+
init_lifecycle();
|
|
3138
3162
|
init_hotkeysCatalog();
|
|
3139
3163
|
init_agents_schema();
|
|
3140
3164
|
init_terminal_schema();
|
|
@@ -3182,6 +3206,14 @@ var init_config2 = __esm({
|
|
|
3182
3206
|
AUTO_CREATE_WORKTREE_VALUES = ["skip", "ask", "always"];
|
|
3183
3207
|
AgentConfigError = class extends Error {
|
|
3184
3208
|
};
|
|
3209
|
+
DEFAULT_STATUS_COLORS = {
|
|
3210
|
+
pending: "slate",
|
|
3211
|
+
in_progress: "teal",
|
|
3212
|
+
blocked: "amber",
|
|
3213
|
+
review: "violet",
|
|
3214
|
+
completed: "emerald",
|
|
3215
|
+
failed: "rose"
|
|
3216
|
+
};
|
|
3185
3217
|
KNOWN_AGENT_SCALAR_FIELDS = /* @__PURE__ */ new Set([
|
|
3186
3218
|
"id",
|
|
3187
3219
|
"label",
|
|
@@ -4040,6 +4072,37 @@ function initSessionDb(dbPath) {
|
|
|
4040
4072
|
UPDATE meta SET value = '4' WHERE key = 'schema_version';
|
|
4041
4073
|
`);
|
|
4042
4074
|
}
|
|
4075
|
+
const vBeforeV5 = database.prepare("SELECT value FROM meta WHERE key = 'schema_version'").get()?.value;
|
|
4076
|
+
if (vBeforeV5 === "4") {
|
|
4077
|
+
database.exec(`
|
|
4078
|
+
CREATE TABLE sessions_v5 (
|
|
4079
|
+
session_id TEXT PRIMARY KEY,
|
|
4080
|
+
project_slug TEXT,
|
|
4081
|
+
assignment_slug TEXT,
|
|
4082
|
+
agent TEXT NOT NULL,
|
|
4083
|
+
started TEXT NOT NULL,
|
|
4084
|
+
ended TEXT,
|
|
4085
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
4086
|
+
path TEXT,
|
|
4087
|
+
description TEXT,
|
|
4088
|
+
transcript_path TEXT,
|
|
4089
|
+
pid INTEGER,
|
|
4090
|
+
pid_started_at TEXT,
|
|
4091
|
+
original_head_sha TEXT,
|
|
4092
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
4093
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
4094
|
+
);
|
|
4095
|
+
INSERT INTO sessions_v5
|
|
4096
|
+
SELECT session_id, project_slug, assignment_slug, agent, started, ended, status, path, description, transcript_path, pid, pid_started_at, NULL, created_at, updated_at
|
|
4097
|
+
FROM sessions;
|
|
4098
|
+
DROP TABLE sessions;
|
|
4099
|
+
ALTER TABLE sessions_v5 RENAME TO sessions;
|
|
4100
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_slug);
|
|
4101
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_assignment ON sessions(project_slug, assignment_slug);
|
|
4102
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status);
|
|
4103
|
+
UPDATE meta SET value = '5' WHERE key = 'schema_version';
|
|
4104
|
+
`);
|
|
4105
|
+
}
|
|
4043
4106
|
});
|
|
4044
4107
|
runMigrations.exclusive();
|
|
4045
4108
|
db.exec(POST_MIGRATION_INDEXES_SQL);
|
|
@@ -4131,7 +4194,7 @@ var init_session_db = __esm({
|
|
|
4131
4194
|
init_paths();
|
|
4132
4195
|
init_fs();
|
|
4133
4196
|
db = null;
|
|
4134
|
-
SCHEMA_VERSION = "
|
|
4197
|
+
SCHEMA_VERSION = "5";
|
|
4135
4198
|
SCHEMA_SQL = `
|
|
4136
4199
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
4137
4200
|
session_id TEXT PRIMARY KEY,
|
|
@@ -4146,6 +4209,7 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
4146
4209
|
transcript_path TEXT,
|
|
4147
4210
|
pid INTEGER,
|
|
4148
4211
|
pid_started_at TEXT,
|
|
4212
|
+
original_head_sha TEXT,
|
|
4149
4213
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
4150
4214
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
4151
4215
|
);
|
|
@@ -4175,25 +4239,27 @@ function rowToSession(row) {
|
|
|
4175
4239
|
description: row.description ?? null,
|
|
4176
4240
|
transcriptPath: row.transcript_path ?? null,
|
|
4177
4241
|
pid: row.pid ?? null,
|
|
4178
|
-
pidStartedAt: row.pid_started_at ?? null
|
|
4242
|
+
pidStartedAt: row.pid_started_at ?? null,
|
|
4243
|
+
originalHeadSha: row.original_head_sha ?? null
|
|
4179
4244
|
};
|
|
4180
4245
|
}
|
|
4181
4246
|
async function appendSession(_projectDir, session) {
|
|
4182
4247
|
const db4 = getSessionDb();
|
|
4183
4248
|
db4.prepare(`
|
|
4184
|
-
INSERT INTO sessions (session_id, project_slug, assignment_slug, agent, started, status, path, description, transcript_path, pid, pid_started_at)
|
|
4185
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
4249
|
+
INSERT INTO sessions (session_id, project_slug, assignment_slug, agent, started, status, path, description, transcript_path, pid, pid_started_at, original_head_sha)
|
|
4250
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
4186
4251
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
4187
|
-
project_slug
|
|
4188
|
-
assignment_slug
|
|
4189
|
-
agent
|
|
4190
|
-
status
|
|
4191
|
-
path
|
|
4192
|
-
description
|
|
4193
|
-
transcript_path
|
|
4194
|
-
pid
|
|
4195
|
-
pid_started_at
|
|
4196
|
-
|
|
4252
|
+
project_slug = COALESCE(NULLIF(excluded.project_slug, ''), project_slug),
|
|
4253
|
+
assignment_slug = COALESCE(NULLIF(excluded.assignment_slug, ''), assignment_slug),
|
|
4254
|
+
agent = excluded.agent,
|
|
4255
|
+
status = CASE WHEN status IN ('completed','stopped') THEN status ELSE excluded.status END,
|
|
4256
|
+
path = COALESCE(NULLIF(excluded.path, ''), path),
|
|
4257
|
+
description = COALESCE(NULLIF(excluded.description, ''), description),
|
|
4258
|
+
transcript_path = COALESCE(NULLIF(excluded.transcript_path, ''), transcript_path),
|
|
4259
|
+
pid = COALESCE(excluded.pid, pid),
|
|
4260
|
+
pid_started_at = COALESCE(NULLIF(excluded.pid_started_at, ''), pid_started_at),
|
|
4261
|
+
original_head_sha = COALESCE(NULLIF(original_head_sha, ''), NULLIF(excluded.original_head_sha, '')),
|
|
4262
|
+
updated_at = datetime('now')
|
|
4197
4263
|
`).run(
|
|
4198
4264
|
session.sessionId,
|
|
4199
4265
|
session.projectSlug ?? null,
|
|
@@ -4205,7 +4271,8 @@ async function appendSession(_projectDir, session) {
|
|
|
4205
4271
|
session.description ?? null,
|
|
4206
4272
|
session.transcriptPath ?? null,
|
|
4207
4273
|
session.pid ?? null,
|
|
4208
|
-
session.pidStartedAt ?? null
|
|
4274
|
+
session.pidStartedAt ?? null,
|
|
4275
|
+
session.originalHeadSha ?? null
|
|
4209
4276
|
);
|
|
4210
4277
|
}
|
|
4211
4278
|
async function updateSessionStatus(_projectDir, sessionId, status) {
|
|
@@ -5063,9 +5130,6 @@ async function computeStandaloneRecords(assignmentsDir2) {
|
|
|
5063
5130
|
records.sort((left, right) => compareTimestamps(right.record.updated, left.record.updated));
|
|
5064
5131
|
return records;
|
|
5065
5132
|
}
|
|
5066
|
-
function toTitleCase(s) {
|
|
5067
|
-
return s.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
5068
|
-
}
|
|
5069
5133
|
function getTransitionDefinitions(config) {
|
|
5070
5134
|
if (!config.custom) return DEFAULT_TRANSITION_DEFINITIONS;
|
|
5071
5135
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -5101,19 +5165,12 @@ async function getStatusConfig() {
|
|
|
5101
5165
|
terminalStatuses: terminalSet.size > 0 ? terminalSet : /* @__PURE__ */ new Set(["completed", "failed"])
|
|
5102
5166
|
};
|
|
5103
5167
|
} else {
|
|
5168
|
+
const def = buildDefaultStatusConfig();
|
|
5104
5169
|
_cachedConfig = {
|
|
5105
5170
|
custom: false,
|
|
5106
|
-
statuses:
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
color: DEFAULT_STATUS_COLORS[id] ?? "gray",
|
|
5110
|
-
terminal: id === "completed" || id === "failed"
|
|
5111
|
-
})),
|
|
5112
|
-
order: [...DEFAULT_STATUSES],
|
|
5113
|
-
transitions: Array.from(DEFAULT_TRANSITION_TABLE.entries()).map(([key, to]) => {
|
|
5114
|
-
const [from, command] = key.split(":");
|
|
5115
|
-
return { from, command, to };
|
|
5116
|
-
}),
|
|
5171
|
+
statuses: def.statuses,
|
|
5172
|
+
order: def.order,
|
|
5173
|
+
transitions: def.transitions,
|
|
5117
5174
|
transitionTable: DEFAULT_TRANSITION_TABLE,
|
|
5118
5175
|
terminalStatuses: /* @__PURE__ */ new Set(["completed", "failed"])
|
|
5119
5176
|
};
|
|
@@ -6713,7 +6770,7 @@ async function getPlaybookDetail(playbooksDir2, slug) {
|
|
|
6713
6770
|
enabled
|
|
6714
6771
|
};
|
|
6715
6772
|
}
|
|
6716
|
-
var WorkspaceBlockedError, STALE_ASSIGNMENT_MS, RECENT_PROJECTS_LIMIT, RECENT_ACTIVITY_LIMIT, RECENT_SESSIONS_LIMIT, NEWEST_CREATED_LIMIT, SEGMENT_DISPLAY_CAP, STALE_LIMIT_DEFAULT, STALE_LIMIT_MAX, TERMINAL_STATUSES2, STATUS_TO_SEGMENT, HERO_PRIORITY, projectRecordsCache, standaloneRecordsCache, DEFAULT_TRANSITION_DEFINITIONS,
|
|
6773
|
+
var WorkspaceBlockedError, STALE_ASSIGNMENT_MS, RECENT_PROJECTS_LIMIT, RECENT_ACTIVITY_LIMIT, RECENT_SESSIONS_LIMIT, NEWEST_CREATED_LIMIT, SEGMENT_DISPLAY_CAP, STALE_LIMIT_DEFAULT, STALE_LIMIT_MAX, TERMINAL_STATUSES2, STATUS_TO_SEGMENT, HERO_PRIORITY, projectRecordsCache, standaloneRecordsCache, DEFAULT_TRANSITION_DEFINITIONS, _cachedConfig, REFERENCED_BY_LIMIT, migratedProjectsDirs, DEFAULT_GRAPH_COLORS;
|
|
6717
6774
|
var init_api = __esm({
|
|
6718
6775
|
"src/dashboard/api.ts"() {
|
|
6719
6776
|
"use strict";
|
|
@@ -6828,14 +6885,6 @@ var init_api = __esm({
|
|
|
6828
6885
|
requiresReason: false
|
|
6829
6886
|
}
|
|
6830
6887
|
];
|
|
6831
|
-
DEFAULT_STATUS_COLORS = {
|
|
6832
|
-
pending: "slate",
|
|
6833
|
-
in_progress: "teal",
|
|
6834
|
-
blocked: "amber",
|
|
6835
|
-
review: "violet",
|
|
6836
|
-
completed: "emerald",
|
|
6837
|
-
failed: "rose"
|
|
6838
|
-
};
|
|
6839
6888
|
_cachedConfig = null;
|
|
6840
6889
|
REFERENCED_BY_LIMIT = 50;
|
|
6841
6890
|
migratedProjectsDirs = /* @__PURE__ */ new Set();
|
|
@@ -6991,7 +7040,18 @@ function enrichSessions(sessions, agents, deps) {
|
|
|
6991
7040
|
|
|
6992
7041
|
// src/dashboard/watcher.ts
|
|
6993
7042
|
import { watch } from "chokidar";
|
|
6994
|
-
import { basename as basename2, dirname as dirname3, relative, sep } from "path";
|
|
7043
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, relative, sep } from "path";
|
|
7044
|
+
var defaultPathApi = { relative, isAbsolute: isAbsolute2 };
|
|
7045
|
+
function ignoreDotSegmentsBelow(root, pathApi = defaultPathApi) {
|
|
7046
|
+
return (p) => {
|
|
7047
|
+
const rel = pathApi.relative(root, p);
|
|
7048
|
+
if (!rel) return false;
|
|
7049
|
+
if (pathApi.isAbsolute(rel)) return false;
|
|
7050
|
+
const parts = rel.split(/[\\/]/);
|
|
7051
|
+
if (parts[0] === "..") return false;
|
|
7052
|
+
return parts.some((segment) => segment.startsWith("."));
|
|
7053
|
+
};
|
|
7054
|
+
}
|
|
6995
7055
|
function createWatcher(options) {
|
|
6996
7056
|
const { projectsDir, assignmentsDir: assignmentsDir2, serversDir: serversDir2, playbooksDir: playbooksDir2, todosDir: todosDir2, dbPath, onMessage, debounceMs = 300 } = options;
|
|
6997
7057
|
const pendingEvents = /* @__PURE__ */ new Map();
|
|
@@ -6999,7 +7059,7 @@ function createWatcher(options) {
|
|
|
6999
7059
|
ignoreInitial: true,
|
|
7000
7060
|
persistent: true,
|
|
7001
7061
|
depth: 10,
|
|
7002
|
-
ignored:
|
|
7062
|
+
ignored: ignoreDotSegmentsBelow(projectsDir)
|
|
7003
7063
|
});
|
|
7004
7064
|
function handleProjectChange(filePath) {
|
|
7005
7065
|
const rel = relative(projectsDir, filePath);
|
|
@@ -7068,7 +7128,7 @@ function createWatcher(options) {
|
|
|
7068
7128
|
ignoreInitial: true,
|
|
7069
7129
|
persistent: true,
|
|
7070
7130
|
depth: 5,
|
|
7071
|
-
ignored:
|
|
7131
|
+
ignored: ignoreDotSegmentsBelow(assignmentsDir2)
|
|
7072
7132
|
});
|
|
7073
7133
|
standaloneWatcher.on("change", handleStandaloneChange2);
|
|
7074
7134
|
standaloneWatcher.on("add", handleStandaloneChange2);
|
|
@@ -7097,7 +7157,7 @@ function createWatcher(options) {
|
|
|
7097
7157
|
ignoreInitial: true,
|
|
7098
7158
|
persistent: true,
|
|
7099
7159
|
depth: 1,
|
|
7100
|
-
ignored:
|
|
7160
|
+
ignored: ignoreDotSegmentsBelow(serversDir2)
|
|
7101
7161
|
});
|
|
7102
7162
|
serversWatcher.on("change", handleServerChange2);
|
|
7103
7163
|
serversWatcher.on("add", handleServerChange2);
|
|
@@ -7126,7 +7186,7 @@ function createWatcher(options) {
|
|
|
7126
7186
|
ignoreInitial: true,
|
|
7127
7187
|
persistent: true,
|
|
7128
7188
|
depth: 1,
|
|
7129
|
-
ignored:
|
|
7189
|
+
ignored: ignoreDotSegmentsBelow(playbooksDir2)
|
|
7130
7190
|
});
|
|
7131
7191
|
playbooksWatcher.on("change", handlePlaybookChange2);
|
|
7132
7192
|
playbooksWatcher.on("add", handlePlaybookChange2);
|
|
@@ -7155,7 +7215,7 @@ function createWatcher(options) {
|
|
|
7155
7215
|
ignoreInitial: true,
|
|
7156
7216
|
persistent: true,
|
|
7157
7217
|
depth: 1,
|
|
7158
|
-
ignored:
|
|
7218
|
+
ignored: ignoreDotSegmentsBelow(todosDir2)
|
|
7159
7219
|
});
|
|
7160
7220
|
todosWatcher.on("change", handleTodoChange2);
|
|
7161
7221
|
todosWatcher.on("add", handleTodoChange2);
|
|
@@ -7187,7 +7247,7 @@ function createWatcher(options) {
|
|
|
7187
7247
|
ignoreInitial: true,
|
|
7188
7248
|
persistent: true,
|
|
7189
7249
|
depth: 0,
|
|
7190
|
-
ignored:
|
|
7250
|
+
ignored: ignoreDotSegmentsBelow(dbDir)
|
|
7191
7251
|
});
|
|
7192
7252
|
leasesDbWatcher.on("change", handleDbChange2);
|
|
7193
7253
|
leasesDbWatcher.on("add", handleDbChange2);
|
|
@@ -7909,7 +7969,7 @@ function createDashboardLayoutRouter() {
|
|
|
7909
7969
|
init_lifecycle();
|
|
7910
7970
|
init_slug();
|
|
7911
7971
|
import { Router as Router2 } from "express";
|
|
7912
|
-
import { resolve as resolve18, basename as basename3, isAbsolute as
|
|
7972
|
+
import { resolve as resolve18, basename as basename3, isAbsolute as isAbsolute4 } from "path";
|
|
7913
7973
|
import { rm, readFile as readFile15, open as fsOpen, stat as fsStat, realpath as fsRealpath } from "fs/promises";
|
|
7914
7974
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
7915
7975
|
|
|
@@ -7928,6 +7988,20 @@ init_frontmatter();
|
|
|
7928
7988
|
init_fs();
|
|
7929
7989
|
import { spawn } from "child_process";
|
|
7930
7990
|
import { readFile as readFile13 } from "fs/promises";
|
|
7991
|
+
|
|
7992
|
+
// src/launch/cwd.ts
|
|
7993
|
+
import { existsSync, statSync as statSync2 } from "fs";
|
|
7994
|
+
import { isAbsolute as isAbsolute3 } from "path";
|
|
7995
|
+
function isExistingDir(p) {
|
|
7996
|
+
if (!p || !isAbsolute3(p)) return false;
|
|
7997
|
+
try {
|
|
7998
|
+
return existsSync(p) && statSync2(p).isDirectory();
|
|
7999
|
+
} catch {
|
|
8000
|
+
return false;
|
|
8001
|
+
}
|
|
8002
|
+
}
|
|
8003
|
+
|
|
8004
|
+
// src/utils/git-worktree.ts
|
|
7931
8005
|
function run(command, args, cwd) {
|
|
7932
8006
|
return new Promise((resolvePromise) => {
|
|
7933
8007
|
const child = spawn(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -7962,11 +8036,11 @@ async function createWorktree(opts) {
|
|
|
7962
8036
|
);
|
|
7963
8037
|
}
|
|
7964
8038
|
}
|
|
7965
|
-
async function removeWorktree(repository, worktreePath) {
|
|
7966
|
-
const
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
);
|
|
8039
|
+
async function removeWorktree(repository, worktreePath, opts = {}) {
|
|
8040
|
+
const args = ["-C", repository, "worktree", "remove"];
|
|
8041
|
+
if (opts.force) args.push("--force");
|
|
8042
|
+
args.push(worktreePath);
|
|
8043
|
+
const result = await run("git", args);
|
|
7970
8044
|
return { ok: result.code === 0, stderr: result.stderr };
|
|
7971
8045
|
}
|
|
7972
8046
|
async function deleteBranch(repository, branch) {
|
|
@@ -8007,6 +8081,82 @@ async function detectDefaultBranch(repository) {
|
|
|
8007
8081
|
}
|
|
8008
8082
|
return branches[0] ?? null;
|
|
8009
8083
|
}
|
|
8084
|
+
async function captureHeadSha(dir) {
|
|
8085
|
+
const result = await run("git", ["-C", dir, "rev-parse", "HEAD"]);
|
|
8086
|
+
if (result.code !== 0) return null;
|
|
8087
|
+
const sha = result.stdout.trim();
|
|
8088
|
+
return sha.length > 0 ? sha : null;
|
|
8089
|
+
}
|
|
8090
|
+
async function branchCheckedOutAt(repository, branch) {
|
|
8091
|
+
const result = await run("git", ["-C", repository, "worktree", "list", "--porcelain"]);
|
|
8092
|
+
if (result.code !== 0) return null;
|
|
8093
|
+
let currentPath = null;
|
|
8094
|
+
for (const line of result.stdout.split("\n")) {
|
|
8095
|
+
if (line.startsWith("worktree ")) {
|
|
8096
|
+
currentPath = line.slice("worktree ".length).trim();
|
|
8097
|
+
} else if (line.startsWith("branch ")) {
|
|
8098
|
+
const ref = line.slice("branch ".length).trim();
|
|
8099
|
+
if (ref === `refs/heads/${branch}` && currentPath) return currentPath;
|
|
8100
|
+
}
|
|
8101
|
+
}
|
|
8102
|
+
return null;
|
|
8103
|
+
}
|
|
8104
|
+
async function recreateWorktree(opts) {
|
|
8105
|
+
const { repository, worktreePath, branch } = opts;
|
|
8106
|
+
const originalHeadSha = opts.originalHeadSha ?? null;
|
|
8107
|
+
await run("git", ["-C", repository, "worktree", "prune"]);
|
|
8108
|
+
const add = async (args) => {
|
|
8109
|
+
const result = await run("git", ["-C", repository, "worktree", "add", ...args]);
|
|
8110
|
+
if (result.code !== 0) {
|
|
8111
|
+
throw new GitWorktreeError(
|
|
8112
|
+
`git worktree add failed (exit ${result.code}): ${result.stderr.trim() || "(no stderr)"}`,
|
|
8113
|
+
result.stderr
|
|
8114
|
+
);
|
|
8115
|
+
}
|
|
8116
|
+
};
|
|
8117
|
+
const refExists = async (ref) => {
|
|
8118
|
+
const result = await run("git", [
|
|
8119
|
+
"-C",
|
|
8120
|
+
repository,
|
|
8121
|
+
"rev-parse",
|
|
8122
|
+
"--verify",
|
|
8123
|
+
"--quiet",
|
|
8124
|
+
ref
|
|
8125
|
+
]);
|
|
8126
|
+
return result.code === 0;
|
|
8127
|
+
};
|
|
8128
|
+
if (branch && (await listBranches(repository)).includes(branch)) {
|
|
8129
|
+
const checkedOutAt = await branchCheckedOutAt(repository, branch);
|
|
8130
|
+
if (!checkedOutAt || checkedOutAt === worktreePath || !isExistingDir(checkedOutAt)) {
|
|
8131
|
+
await add([worktreePath, branch]);
|
|
8132
|
+
return { baseUsed: branch, exact: true, branch };
|
|
8133
|
+
}
|
|
8134
|
+
const detachBase = originalHeadSha && await refExists(`${originalHeadSha}^{commit}`) ? originalHeadSha : `refs/heads/${branch}`;
|
|
8135
|
+
await add(["--detach", worktreePath, detachBase]);
|
|
8136
|
+
return { baseUsed: detachBase, exact: detachBase === originalHeadSha, branch: null };
|
|
8137
|
+
}
|
|
8138
|
+
let baseUsed = null;
|
|
8139
|
+
if (originalHeadSha && await refExists(`${originalHeadSha}^{commit}`)) {
|
|
8140
|
+
baseUsed = originalHeadSha;
|
|
8141
|
+
} else if (branch && await refExists(`refs/remotes/origin/${branch}`)) {
|
|
8142
|
+
baseUsed = `refs/remotes/origin/${branch}`;
|
|
8143
|
+
} else {
|
|
8144
|
+
baseUsed = await detectDefaultBranch(repository);
|
|
8145
|
+
}
|
|
8146
|
+
if (!baseUsed) {
|
|
8147
|
+
throw new GitWorktreeError(
|
|
8148
|
+
`recreateWorktree: no base ref to recreate ${worktreePath} (no original sha, no origin/${branch ?? "<none>"}, no default branch)`,
|
|
8149
|
+
""
|
|
8150
|
+
);
|
|
8151
|
+
}
|
|
8152
|
+
const exact = baseUsed === originalHeadSha;
|
|
8153
|
+
if (branch) {
|
|
8154
|
+
await add(["-b", branch, worktreePath, baseUsed]);
|
|
8155
|
+
return { baseUsed, exact, branch };
|
|
8156
|
+
}
|
|
8157
|
+
await add(["--detach", worktreePath, baseUsed]);
|
|
8158
|
+
return { baseUsed, exact, branch: null };
|
|
8159
|
+
}
|
|
8010
8160
|
async function createWorktreeAndRecord(opts) {
|
|
8011
8161
|
const { assignmentPath, repository, branch, worktreePath, parentBranch } = opts;
|
|
8012
8162
|
await createWorktree({ repository, branch, worktreePath, parentBranch });
|
|
@@ -8020,7 +8170,7 @@ async function createWorktreeAndRecord(opts) {
|
|
|
8020
8170
|
});
|
|
8021
8171
|
await writeFileForce(assignmentPath, updated);
|
|
8022
8172
|
} catch (writeErr) {
|
|
8023
|
-
const cleanup = await removeWorktree(repository, worktreePath);
|
|
8173
|
+
const cleanup = await removeWorktree(repository, worktreePath, { force: true });
|
|
8024
8174
|
const branchCleanup = await deleteBranch(repository, branch);
|
|
8025
8175
|
const writeMsg = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
8026
8176
|
throw new Error(
|
|
@@ -8121,6 +8271,154 @@ function validateBranchName(name) {
|
|
|
8121
8271
|
return null;
|
|
8122
8272
|
}
|
|
8123
8273
|
|
|
8274
|
+
// src/dashboard/recreate-target.ts
|
|
8275
|
+
init_api();
|
|
8276
|
+
init_agent_sessions();
|
|
8277
|
+
async function resolveRecreateTarget(deps, target) {
|
|
8278
|
+
const { projectsDir, assignmentsDir: assignmentsDir2 } = deps;
|
|
8279
|
+
if (target.kind === "assignment") {
|
|
8280
|
+
const detail = "id" in target ? await getAssignmentDetailById(projectsDir, assignmentsDir2, target.id) : await getAssignmentDetail(
|
|
8281
|
+
projectsDir,
|
|
8282
|
+
target.projectSlug,
|
|
8283
|
+
target.assignmentSlug
|
|
8284
|
+
);
|
|
8285
|
+
if (!detail) return null;
|
|
8286
|
+
const worktreePath2 = detail.workspace.worktreePath ?? "";
|
|
8287
|
+
const repository2 = detail.workspace.repository ?? null;
|
|
8288
|
+
const branch2 = detail.workspace.branch ?? null;
|
|
8289
|
+
const missing2 = worktreePath2 !== "" && !isExistingDir(worktreePath2);
|
|
8290
|
+
return {
|
|
8291
|
+
kind: "assignment",
|
|
8292
|
+
id: detail.id,
|
|
8293
|
+
projectSlug: detail.projectSlug ?? null,
|
|
8294
|
+
assignmentSlug: detail.slug,
|
|
8295
|
+
worktreePath: worktreePath2,
|
|
8296
|
+
repository: repository2,
|
|
8297
|
+
branch: branch2,
|
|
8298
|
+
originalHeadSha: null,
|
|
8299
|
+
missing: missing2,
|
|
8300
|
+
recreatable: missing2 && isExistingDir(repository2)
|
|
8301
|
+
};
|
|
8302
|
+
}
|
|
8303
|
+
const session = getSessionById(target.id);
|
|
8304
|
+
if (!session) return null;
|
|
8305
|
+
let repository = null;
|
|
8306
|
+
let branch = null;
|
|
8307
|
+
let assignmentWorktreePath = "";
|
|
8308
|
+
if (session.projectSlug && session.assignmentSlug) {
|
|
8309
|
+
const detail = await getAssignmentDetail(
|
|
8310
|
+
projectsDir,
|
|
8311
|
+
session.projectSlug,
|
|
8312
|
+
session.assignmentSlug
|
|
8313
|
+
);
|
|
8314
|
+
if (detail) {
|
|
8315
|
+
repository = detail.workspace.repository ?? null;
|
|
8316
|
+
branch = detail.workspace.branch ?? null;
|
|
8317
|
+
assignmentWorktreePath = detail.workspace.worktreePath ?? "";
|
|
8318
|
+
}
|
|
8319
|
+
} else if (session.assignmentSlug) {
|
|
8320
|
+
const detail = await getAssignmentDetailById(
|
|
8321
|
+
projectsDir,
|
|
8322
|
+
assignmentsDir2,
|
|
8323
|
+
session.assignmentSlug
|
|
8324
|
+
);
|
|
8325
|
+
if (detail) {
|
|
8326
|
+
repository = detail.workspace.repository ?? null;
|
|
8327
|
+
branch = detail.workspace.branch ?? null;
|
|
8328
|
+
assignmentWorktreePath = detail.workspace.worktreePath ?? "";
|
|
8329
|
+
}
|
|
8330
|
+
}
|
|
8331
|
+
const worktreePath = session.path || assignmentWorktreePath;
|
|
8332
|
+
const missing = worktreePath !== "" && !isExistingDir(worktreePath);
|
|
8333
|
+
return {
|
|
8334
|
+
kind: "session",
|
|
8335
|
+
id: session.sessionId,
|
|
8336
|
+
projectSlug: session.projectSlug ?? null,
|
|
8337
|
+
assignmentSlug: session.assignmentSlug ?? null,
|
|
8338
|
+
worktreePath,
|
|
8339
|
+
repository,
|
|
8340
|
+
branch,
|
|
8341
|
+
originalHeadSha: session.originalHeadSha ?? null,
|
|
8342
|
+
missing,
|
|
8343
|
+
recreatable: missing && isExistingDir(repository)
|
|
8344
|
+
};
|
|
8345
|
+
}
|
|
8346
|
+
|
|
8347
|
+
// src/dashboard/worktree-recreate.ts
|
|
8348
|
+
async function recreateForTarget(deps, target) {
|
|
8349
|
+
const t = await resolveRecreateTarget(deps, target);
|
|
8350
|
+
if (!t) return { status: "not-found" };
|
|
8351
|
+
if (t.worktreePath === "") return { status: "no-path" };
|
|
8352
|
+
if (isExistingDir(t.worktreePath)) {
|
|
8353
|
+
return { status: "already-exists", branch: t.branch };
|
|
8354
|
+
}
|
|
8355
|
+
if (!t.repository) return { status: "no-repo" };
|
|
8356
|
+
const repoCheck = await assertRepoRoot(t.repository);
|
|
8357
|
+
if (!repoCheck.ok) {
|
|
8358
|
+
return { status: "bad-repo", httpStatus: repoCheck.status, error: repoCheck.error };
|
|
8359
|
+
}
|
|
8360
|
+
const key = `recreate:${t.worktreePath}`;
|
|
8361
|
+
if (worktreeInFlight.has(key)) return { status: "in-flight" };
|
|
8362
|
+
worktreeInFlight.add(key);
|
|
8363
|
+
try {
|
|
8364
|
+
const r = await recreateWorktree({
|
|
8365
|
+
repository: repoCheck.repo,
|
|
8366
|
+
worktreePath: t.worktreePath,
|
|
8367
|
+
branch: t.branch,
|
|
8368
|
+
originalHeadSha: t.originalHeadSha
|
|
8369
|
+
});
|
|
8370
|
+
return { status: "recreated", baseUsed: r.baseUsed, exact: r.exact, branch: r.branch };
|
|
8371
|
+
} finally {
|
|
8372
|
+
worktreeInFlight.delete(key);
|
|
8373
|
+
}
|
|
8374
|
+
}
|
|
8375
|
+
function recreateOutcomeToHttp(outcome) {
|
|
8376
|
+
switch (outcome.status) {
|
|
8377
|
+
case "not-found":
|
|
8378
|
+
return { httpStatus: 404, body: { error: "Target not found." } };
|
|
8379
|
+
case "no-path":
|
|
8380
|
+
return {
|
|
8381
|
+
httpStatus: 422,
|
|
8382
|
+
body: { error: "No recorded worktree path to recreate." }
|
|
8383
|
+
};
|
|
8384
|
+
case "no-repo":
|
|
8385
|
+
return {
|
|
8386
|
+
httpStatus: 422,
|
|
8387
|
+
body: {
|
|
8388
|
+
error: "Cannot recreate: no repository on record for this worktree."
|
|
8389
|
+
}
|
|
8390
|
+
};
|
|
8391
|
+
case "bad-repo":
|
|
8392
|
+
return { httpStatus: outcome.httpStatus, body: { error: outcome.error } };
|
|
8393
|
+
case "in-flight":
|
|
8394
|
+
return {
|
|
8395
|
+
httpStatus: 409,
|
|
8396
|
+
body: { error: "A recreate is already in progress for this worktree." }
|
|
8397
|
+
};
|
|
8398
|
+
case "already-exists":
|
|
8399
|
+
return {
|
|
8400
|
+
httpStatus: 200,
|
|
8401
|
+
body: {
|
|
8402
|
+
ok: true,
|
|
8403
|
+
alreadyExisted: true,
|
|
8404
|
+
baseUsed: outcome.branch ?? "HEAD",
|
|
8405
|
+
exact: true,
|
|
8406
|
+
branch: outcome.branch
|
|
8407
|
+
}
|
|
8408
|
+
};
|
|
8409
|
+
case "recreated":
|
|
8410
|
+
return {
|
|
8411
|
+
httpStatus: 200,
|
|
8412
|
+
body: {
|
|
8413
|
+
ok: true,
|
|
8414
|
+
baseUsed: outcome.baseUsed,
|
|
8415
|
+
exact: outcome.exact,
|
|
8416
|
+
branch: outcome.branch
|
|
8417
|
+
}
|
|
8418
|
+
};
|
|
8419
|
+
}
|
|
8420
|
+
}
|
|
8421
|
+
|
|
8124
8422
|
// src/dashboard/repository-candidates.ts
|
|
8125
8423
|
init_fs();
|
|
8126
8424
|
init_parser();
|
|
@@ -8807,7 +9105,7 @@ async function assertRepoRoot(repoInput) {
|
|
|
8807
9105
|
return { ok: false, status: 400, error: "`repository` is required." };
|
|
8808
9106
|
}
|
|
8809
9107
|
const repo = repoInput.trim();
|
|
8810
|
-
if (!
|
|
9108
|
+
if (!isAbsolute4(repo)) {
|
|
8811
9109
|
return { ok: false, status: 400, error: "`repository` must be an absolute path." };
|
|
8812
9110
|
}
|
|
8813
9111
|
try {
|
|
@@ -10046,6 +10344,45 @@ ${entry}`;
|
|
|
10046
10344
|
}
|
|
10047
10345
|
}
|
|
10048
10346
|
);
|
|
10347
|
+
router.post(
|
|
10348
|
+
"/api/projects/:slug/assignments/:aslug/worktree/recreate",
|
|
10349
|
+
async (req, res) => {
|
|
10350
|
+
try {
|
|
10351
|
+
const projectSlug = getParam(req.params.slug);
|
|
10352
|
+
const assignmentSlug = getParam(req.params.aslug);
|
|
10353
|
+
const outcome = await recreateForTarget(
|
|
10354
|
+
{ projectsDir, assignmentsDir: assignmentsDir2 ?? "" },
|
|
10355
|
+
{ kind: "assignment", projectSlug, assignmentSlug }
|
|
10356
|
+
);
|
|
10357
|
+
const { httpStatus, body } = recreateOutcomeToHttp(outcome);
|
|
10358
|
+
res.status(httpStatus).json(body);
|
|
10359
|
+
} catch (error) {
|
|
10360
|
+
console.error("Error recreating worktree:", error);
|
|
10361
|
+
res.status(500).json({ error: `Failed to recreate worktree: ${error.message}` });
|
|
10362
|
+
}
|
|
10363
|
+
}
|
|
10364
|
+
);
|
|
10365
|
+
router.post(
|
|
10366
|
+
"/api/assignments/:id/worktree/recreate",
|
|
10367
|
+
async (req, res) => {
|
|
10368
|
+
try {
|
|
10369
|
+
if (!assignmentsDir2) {
|
|
10370
|
+
res.status(501).json({ error: "Standalone assignments not configured on this server" });
|
|
10371
|
+
return;
|
|
10372
|
+
}
|
|
10373
|
+
const id = getParam(req.params.id);
|
|
10374
|
+
const outcome = await recreateForTarget(
|
|
10375
|
+
{ projectsDir, assignmentsDir: assignmentsDir2 },
|
|
10376
|
+
{ kind: "assignment", id }
|
|
10377
|
+
);
|
|
10378
|
+
const { httpStatus, body } = recreateOutcomeToHttp(outcome);
|
|
10379
|
+
res.status(httpStatus).json(body);
|
|
10380
|
+
} catch (error) {
|
|
10381
|
+
console.error("Error recreating worktree:", error);
|
|
10382
|
+
res.status(500).json({ error: `Failed to recreate worktree: ${error.message}` });
|
|
10383
|
+
}
|
|
10384
|
+
}
|
|
10385
|
+
);
|
|
10049
10386
|
router.post("/api/projects/:slug/status-override", async (req, res) => {
|
|
10050
10387
|
try {
|
|
10051
10388
|
const projectSlug = getParam(req.params.slug);
|
|
@@ -11308,6 +11645,7 @@ function createAgentSessionsRouter(projectsDir, broadcast, assignmentsDir2) {
|
|
|
11308
11645
|
const recordedPath = derivedPath ?? path ?? "";
|
|
11309
11646
|
const pid = typeof rawPid === "number" && Number.isFinite(rawPid) && rawPid > 0 ? rawPid : null;
|
|
11310
11647
|
const pidStartedAt = pid !== null ? captureProcessStartedAt(pid) : null;
|
|
11648
|
+
const originalHeadSha = isExistingDir(recordedPath) ? await captureHeadSha(recordedPath) : null;
|
|
11311
11649
|
const session = {
|
|
11312
11650
|
projectSlug: projectSlug || null,
|
|
11313
11651
|
assignmentSlug: assignmentSlug || null,
|
|
@@ -11319,7 +11657,8 @@ function createAgentSessionsRouter(projectsDir, broadcast, assignmentsDir2) {
|
|
|
11319
11657
|
description: description || null,
|
|
11320
11658
|
transcriptPath: transcriptPath || null,
|
|
11321
11659
|
pid,
|
|
11322
|
-
pidStartedAt
|
|
11660
|
+
pidStartedAt,
|
|
11661
|
+
originalHeadSha
|
|
11323
11662
|
};
|
|
11324
11663
|
await appendSession("", session);
|
|
11325
11664
|
broadcast?.({ type: "agent-sessions-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -11328,6 +11667,21 @@ function createAgentSessionsRouter(projectsDir, broadcast, assignmentsDir2) {
|
|
|
11328
11667
|
res.status(500).json({ error: error instanceof Error ? error.message : "Registration failed" });
|
|
11329
11668
|
}
|
|
11330
11669
|
});
|
|
11670
|
+
router.post("/:sessionId/worktree/recreate", async (req, res) => {
|
|
11671
|
+
try {
|
|
11672
|
+
const { sessionId } = req.params;
|
|
11673
|
+
const outcome = await recreateForTarget(
|
|
11674
|
+
{ projectsDir, assignmentsDir: assignmentsDir2 ?? "" },
|
|
11675
|
+
{ kind: "session", id: sessionId }
|
|
11676
|
+
);
|
|
11677
|
+
const { httpStatus, body } = recreateOutcomeToHttp(outcome);
|
|
11678
|
+
res.status(httpStatus).json(body);
|
|
11679
|
+
} catch (error) {
|
|
11680
|
+
res.status(500).json({
|
|
11681
|
+
error: error instanceof Error ? error.message : "Failed to recreate worktree"
|
|
11682
|
+
});
|
|
11683
|
+
}
|
|
11684
|
+
});
|
|
11331
11685
|
router.patch("/:sessionId", async (req, res) => {
|
|
11332
11686
|
try {
|
|
11333
11687
|
const { sessionId } = req.params;
|
|
@@ -11628,7 +11982,7 @@ import { Router as Router6 } from "express";
|
|
|
11628
11982
|
|
|
11629
11983
|
// src/utils/terminal-probe.ts
|
|
11630
11984
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
11631
|
-
import { existsSync } from "fs";
|
|
11985
|
+
import { existsSync as existsSync2 } from "fs";
|
|
11632
11986
|
import { homedir as homedir2 } from "os";
|
|
11633
11987
|
import { join as join2 } from "path";
|
|
11634
11988
|
var APP_BUNDLE_IDS = {
|
|
@@ -11650,12 +12004,12 @@ function defaultApplicationsDirs() {
|
|
|
11650
12004
|
}
|
|
11651
12005
|
function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
|
|
11652
12006
|
const fixed = APP_FIXED_PATHS[terminal];
|
|
11653
|
-
if (fixed &&
|
|
12007
|
+
if (fixed && existsSync2(fixed)) return fixed;
|
|
11654
12008
|
const bundleName = APP_BUNDLE_NAMES[terminal];
|
|
11655
12009
|
if (bundleName) {
|
|
11656
12010
|
for (const dir of dirs) {
|
|
11657
12011
|
const candidate = join2(dir, bundleName);
|
|
11658
|
-
if (
|
|
12012
|
+
if (existsSync2(candidate)) return candidate;
|
|
11659
12013
|
}
|
|
11660
12014
|
}
|
|
11661
12015
|
return null;
|
|
@@ -11692,50 +12046,6 @@ function probeTerminalInstalled(terminal, opts = {}) {
|
|
|
11692
12046
|
return { ok: false, reason: "no-probe-available" };
|
|
11693
12047
|
}
|
|
11694
12048
|
|
|
11695
|
-
// src/dashboard/api-launch-preflight.ts
|
|
11696
|
-
init_api();
|
|
11697
|
-
|
|
11698
|
-
// src/launch/cwd.ts
|
|
11699
|
-
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
11700
|
-
import { isAbsolute as isAbsolute3 } from "path";
|
|
11701
|
-
function isExistingDir(p) {
|
|
11702
|
-
if (!p || !isAbsolute3(p)) return false;
|
|
11703
|
-
try {
|
|
11704
|
-
return existsSync2(p) && statSync2(p).isDirectory();
|
|
11705
|
-
} catch {
|
|
11706
|
-
return false;
|
|
11707
|
-
}
|
|
11708
|
-
}
|
|
11709
|
-
function resolveWorkspaceCwd(input) {
|
|
11710
|
-
const { worktreePath, repository, branch, assignmentSlug } = input;
|
|
11711
|
-
if (isExistingDir(worktreePath)) {
|
|
11712
|
-
return { cwd: worktreePath, fallbackWarning: null, invalidReason: null };
|
|
11713
|
-
}
|
|
11714
|
-
if (isExistingDir(repository)) {
|
|
11715
|
-
const fallbackWarning = worktreePath ? `syntaur: workspace.worktreePath ${worktreePath} is not an existing directory for ${assignmentSlug} \u2014 launching in ${repository}` : formatFallbackCwdWarning({
|
|
11716
|
-
assignmentSlug,
|
|
11717
|
-
workspaceDir: repository,
|
|
11718
|
-
worktreePath,
|
|
11719
|
-
branch
|
|
11720
|
-
});
|
|
11721
|
-
return { cwd: repository, fallbackWarning, invalidReason: null };
|
|
11722
|
-
}
|
|
11723
|
-
const shown = (p) => p && p.trim().length > 0 ? p : "(unset)";
|
|
11724
|
-
return {
|
|
11725
|
-
cwd: null,
|
|
11726
|
-
fallbackWarning: null,
|
|
11727
|
-
invalidReason: `workspace path invalid for ${assignmentSlug}: tried worktreePath ${shown(worktreePath)} and repository ${shown(repository)} \u2014 neither is an existing directory`
|
|
11728
|
-
};
|
|
11729
|
-
}
|
|
11730
|
-
function formatFallbackCwdWarning(opts) {
|
|
11731
|
-
const missing = [];
|
|
11732
|
-
if (!opts.worktreePath) missing.push("worktreePath");
|
|
11733
|
-
if (!opts.branch) missing.push("branch");
|
|
11734
|
-
if (missing.length === 0) return null;
|
|
11735
|
-
const fields = missing.map((m) => `workspace.${m}`).join(" and ");
|
|
11736
|
-
return `syntaur: ${fields} not set for ${opts.assignmentSlug} \u2014 launching in ${opts.workspaceDir}`;
|
|
11737
|
-
}
|
|
11738
|
-
|
|
11739
12049
|
// src/dashboard/api-launch-preflight.ts
|
|
11740
12050
|
function createLaunchPreflightRouter(projectsDir, assignmentsDir2) {
|
|
11741
12051
|
const router = Router6();
|
|
@@ -11763,29 +12073,44 @@ function createLaunchPreflightRouter(projectsDir, assignmentsDir2) {
|
|
|
11763
12073
|
return;
|
|
11764
12074
|
}
|
|
11765
12075
|
const target = body.target;
|
|
11766
|
-
if (target && target.kind === "assignment" && typeof target.id === "string") {
|
|
11767
|
-
const
|
|
11768
|
-
projectsDir,
|
|
11769
|
-
|
|
11770
|
-
target.id
|
|
12076
|
+
if (target && (target.kind === "assignment" || target.kind === "session") && typeof target.id === "string") {
|
|
12077
|
+
const resolved = await resolveRecreateTarget(
|
|
12078
|
+
{ projectsDir, assignmentsDir: assignmentsDir2 },
|
|
12079
|
+
target.kind === "assignment" ? { kind: "assignment", id: target.id } : { kind: "session", id: target.id }
|
|
11771
12080
|
);
|
|
11772
|
-
if (
|
|
11773
|
-
const
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
12081
|
+
if (resolved && resolved.missing) {
|
|
12082
|
+
const response2 = resolved.recreatable ? {
|
|
12083
|
+
ok: false,
|
|
12084
|
+
terminal,
|
|
12085
|
+
reason: "workspace-path-invalid",
|
|
12086
|
+
message: `Worktree ${resolved.worktreePath} was deleted.`,
|
|
12087
|
+
recreate: {
|
|
12088
|
+
kind: resolved.kind,
|
|
12089
|
+
id: resolved.id,
|
|
12090
|
+
projectSlug: resolved.projectSlug,
|
|
12091
|
+
assignmentSlug: resolved.assignmentSlug,
|
|
12092
|
+
deletedPath: resolved.worktreePath,
|
|
12093
|
+
repository: resolved.repository,
|
|
12094
|
+
branch: resolved.branch
|
|
12095
|
+
}
|
|
12096
|
+
} : {
|
|
12097
|
+
ok: false,
|
|
12098
|
+
terminal,
|
|
12099
|
+
reason: "workspace-path-invalid",
|
|
12100
|
+
message: `Worktree ${resolved.worktreePath} was deleted and can't be auto-recreated (no repository on record). Set a valid workspace for this assignment, then try again.`
|
|
12101
|
+
};
|
|
12102
|
+
res.json(response2);
|
|
12103
|
+
return;
|
|
12104
|
+
}
|
|
12105
|
+
if (resolved && resolved.kind === "assignment" && resolved.worktreePath === "" && !isExistingDir(resolved.repository)) {
|
|
12106
|
+
const response2 = {
|
|
12107
|
+
ok: false,
|
|
12108
|
+
terminal,
|
|
12109
|
+
reason: "workspace-path-invalid",
|
|
12110
|
+
message: "This assignment has no valid workspace directory. Set a repository or worktree, then try again."
|
|
12111
|
+
};
|
|
12112
|
+
res.json(response2);
|
|
12113
|
+
return;
|
|
11789
12114
|
}
|
|
11790
12115
|
}
|
|
11791
12116
|
const response = { ok: true, terminal };
|