summaryrefslogtreecommitdiff
path: root/makima/src/db
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-26 22:12:57 +0000
committerGitHub <noreply@github.com>2026-01-26 22:12:57 +0000
commitd1f5dadb549d499c5aeee9cacf6c9aa0a233c198 (patch)
treea47e3d68a6b25bc39044a52b63099a199dce677d /makima/src/db
parentbc1ce8013bc36a1585be05b928f2386ab56529c2 (diff)
downloadsoryu-d1f5dadb549d499c5aeee9cacf6c9aa0a233c198.tar.gz
soryu-d1f5dadb549d499c5aeee9cacf6c9aa0a233c198.zip
Add local-only mode for contracts with patch export support (#34)
* Add local_only flag to contracts database and models Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint * Skip automatic completion actions in local_only mode Add `local_only` flag to contracts that prevents automatic completion actions (branch, merge, pr) from executing when tasks complete. This allows users to manually handle code changes via patch files or other means when operating in local-only mode. Changes: - Add `local_only` field to Contract model and request types - Add database migration for the new column - Add `local_only` parameter to SpawnTask command in both state.rs and daemon protocol.rs - Modify task manager to skip completion action execution when `local_only` is true, with appropriate logging - Pass `local_only` flag through all task spawning paths: - mesh_supervisor.rs (task spawn, retry, resume) - mesh.rs (task start, reassign, continue) - mesh_chat.rs (run task) - contract_chat.rs (run task) - Update repository create/update functions to handle `local_only` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint * Implement core patch export system Add functionality to create uncompressed, human-readable git patches for export. This enables users to generate patches that can be manually applied or shared, without the compression used for internal checkpoints. Changes: - Add ExportPatchResult struct with patch content, file count, and line stats - Add create_export_patch() function that generates diffs against a base SHA - Add get_head_sha() utility function - Add parse_diff_stat() helper to extract line counts from git output - Add CreateExportPatch command to daemon protocol - Add ExportPatchCreated response message to protocol - Add handler in task manager to process export patch requests - Add server-side handling to broadcast patch results to UI The export patch system automatically finds the merge-base when no base SHA is provided, trying upstream tracking branch first, then common default branches (origin/main, origin/master, main, master). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint * Add GitActionsPanel frontend component * Add WorktreeFilesPanel and PatchesListPanel components * Add local-only mode toggle to contract creation --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/db')
-rw-r--r--makima/src/db/models.rs18
-rw-r--r--makima/src/db/repository.rs19
2 files changed, 30 insertions, 7 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 95517a1..9c2d072 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -1326,6 +1326,11 @@ pub struct Contract {
#[sqlx(json)]
#[serde(default)]
pub completed_deliverables: serde_json::Value,
+ /// Whether this contract operates in local-only mode.
+ /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
+ /// allowing users to manually handle code changes via patch files or other means.
+ #[serde(default)]
+ pub local_only: bool,
pub version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
@@ -1441,6 +1446,9 @@ pub struct ContractSummary {
pub status: String,
/// Supervisor task ID for contract orchestration
pub supervisor_task_id: Option<Uuid>,
+ /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
+ #[serde(default)]
+ pub local_only: bool,
pub file_count: i64,
pub task_count: i64,
pub repository_count: i64,
@@ -1495,6 +1503,11 @@ pub struct CreateContractRequest {
/// phase outputs before progressing to the next phase.
#[serde(default)]
pub phase_guard: Option<bool>,
+ /// Enable local-only mode for this contract.
+ /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
+ /// allowing users to manually handle code changes via patch files or other means.
+ #[serde(default)]
+ pub local_only: Option<bool>,
}
/// Request payload for updating a contract
@@ -1516,6 +1529,11 @@ pub struct UpdateContractRequest {
/// phase outputs before progressing to the next phase.
#[serde(default)]
pub phase_guard: Option<bool>,
+ /// Enable or disable local-only mode for this contract.
+ /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
+ /// allowing users to manually handle code changes via patch files or other means.
+ #[serde(default)]
+ pub local_only: Option<bool>,
/// Version for optimistic locking
pub version: Option<i32>,
}
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs
index b55b05e..6d6642b 100644
--- a/makima/src/db/repository.rs
+++ b/makima/src/db/repository.rs
@@ -2175,11 +2175,12 @@ pub async fn create_contract_for_owner(
let autonomous_loop = req.autonomous_loop.unwrap_or(false);
let phase_guard = req.phase_guard.unwrap_or(false);
+ let local_only = req.local_only.unwrap_or(false);
sqlx::query_as::<_, Contract>(
r#"
- INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop, phase_guard)
- VALUES ($1, $2, $3, $4, $5, $6, $7)
+ INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop, phase_guard, local_only)
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *
"#,
)
@@ -2190,6 +2191,7 @@ pub async fn create_contract_for_owner(
.bind(phase)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.fetch_one(pool)
.await
}
@@ -2222,7 +2224,7 @@ pub async fn list_contracts_for_owner(
r#"
SELECT
c.id, c.name, c.description, c.contract_type, c.phase, c.status,
- c.supervisor_task_id, c.version, c.created_at,
+ c.supervisor_task_id, c.local_only, c.version, c.created_at,
(SELECT COUNT(*) FROM files WHERE contract_id = c.id) as file_count,
(SELECT COUNT(*) FROM tasks WHERE contract_id = c.id) as task_count,
(SELECT COUNT(*) FROM contract_repositories WHERE contract_id = c.id) as repository_count
@@ -2246,7 +2248,7 @@ pub async fn get_contract_summary_for_owner(
r#"
SELECT
c.id, c.name, c.description, c.contract_type, c.phase, c.status,
- c.supervisor_task_id, c.version, c.created_at,
+ c.supervisor_task_id, c.local_only, c.version, c.created_at,
(SELECT COUNT(*) FROM files WHERE contract_id = c.id) as file_count,
(SELECT COUNT(*) FROM tasks WHERE contract_id = c.id) as task_count,
(SELECT COUNT(*) FROM contract_repositories WHERE contract_id = c.id) as repository_count
@@ -2290,14 +2292,15 @@ pub async fn update_contract_for_owner(
let supervisor_task_id = req.supervisor_task_id.or(existing.supervisor_task_id);
let autonomous_loop = req.autonomous_loop.unwrap_or(existing.autonomous_loop);
let phase_guard = req.phase_guard.unwrap_or(existing.phase_guard);
+ let local_only = req.local_only.unwrap_or(existing.local_only);
let result = if req.version.is_some() {
sqlx::query_as::<_, Contract>(
r#"
UPDATE contracts
SET name = $3, description = $4, phase = $5, status = $6,
- supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW()
- WHERE id = $1 AND owner_id = $2 AND version = $10
+ supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, local_only = $10, version = version + 1, updated_at = NOW()
+ WHERE id = $1 AND owner_id = $2 AND version = $11
RETURNING *
"#,
)
@@ -2310,6 +2313,7 @@ pub async fn update_contract_for_owner(
.bind(supervisor_task_id)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.bind(req.version.unwrap())
.fetch_optional(pool)
.await?
@@ -2318,7 +2322,7 @@ pub async fn update_contract_for_owner(
r#"
UPDATE contracts
SET name = $3, description = $4, phase = $5, status = $6,
- supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW()
+ supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, local_only = $10, version = version + 1, updated_at = NOW()
WHERE id = $1 AND owner_id = $2
RETURNING *
"#,
@@ -2332,6 +2336,7 @@ pub async fn update_contract_for_owner(
.bind(supervisor_task_id)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.fetch_optional(pool)
.await?
};