summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-26 20:32:25 +0000
committersoryu <soryu@soryu.co>2026-01-26 20:32:25 +0000
commitc5807eda364980645b21727dab4236d16d119a56 (patch)
tree0e69566aae61b6c54a41c8b58914747aa8f24f3a
parentbbbaab80baca6b152ce2edf68a971f29f189cd97 (diff)
downloadsoryu-makima/local-only-mode-pr.tar.gz
soryu-makima/local-only-mode-pr.zip
Add local-only mode toggle to contract creationmakima/local-only-mode-pr
-rw-r--r--makima/frontend/src/components/contracts/ContractDetail.tsx5
-rw-r--r--makima/frontend/src/components/contracts/ContractList.tsx15
-rw-r--r--makima/frontend/src/lib/api.ts6
-rw-r--r--makima/frontend/src/routes/contracts.tsx44
4 files changed, 66 insertions, 4 deletions
diff --git a/makima/frontend/src/components/contracts/ContractDetail.tsx b/makima/frontend/src/components/contracts/ContractDetail.tsx
index 90b6967..6e31c84 100644
--- a/makima/frontend/src/components/contracts/ContractDetail.tsx
+++ b/makima/frontend/src/components/contracts/ContractDetail.tsx
@@ -177,6 +177,11 @@ export function ContractDetail({
>
{statusConfig[contract.status].label}
</span>
+ {contract.localOnly && (
+ <span className="px-2 py-0.5 font-mono text-[10px] uppercase text-amber-400 border border-amber-400/30 bg-amber-400/10">
+ Local-Only
+ </span>
+ )}
</div>
{contract.description && (
<p className="font-mono text-sm text-[#9bc3ff] mb-3">
diff --git a/makima/frontend/src/components/contracts/ContractList.tsx b/makima/frontend/src/components/contracts/ContractList.tsx
index ebde497..98f8ff6 100644
--- a/makima/frontend/src/components/contracts/ContractList.tsx
+++ b/makima/frontend/src/components/contracts/ContractList.tsx
@@ -127,11 +127,18 @@ export function ContractList({
`}
>
<div className="flex items-start justify-between gap-2 mb-2">
- <h3 className="font-mono text-sm text-[#dbe7ff] truncate">
- {contract.name}
- </h3>
+ <div className="flex items-center gap-2 min-w-0">
+ <h3 className="font-mono text-sm text-[#dbe7ff] truncate">
+ {contract.name}
+ </h3>
+ {contract.localOnly && (
+ <span className="px-1.5 py-0.5 font-mono text-[9px] uppercase text-amber-400 border border-amber-400/30 bg-amber-400/10 shrink-0">
+ Local
+ </span>
+ )}
+ </div>
<span
- className={`text-[10px] font-mono uppercase ${
+ className={`text-[10px] font-mono uppercase shrink-0 ${
statusColors[contract.status]
}`}
>
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts
index f15eec0..7c9fcd6 100644
--- a/makima/frontend/src/lib/api.ts
+++ b/makima/frontend/src/lib/api.ts
@@ -1673,6 +1673,8 @@ export interface ContractSummary {
status: ContractStatus;
/** Supervisor task ID for contract orchestration */
supervisorTaskId: string | null;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly: boolean;
fileCount: number;
taskCount: number;
repositoryCount: number;
@@ -1695,6 +1697,8 @@ export interface Contract {
autonomousLoop: boolean;
/** Whether to wait for user confirmation before progressing to the next phase */
phaseGuard: boolean;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly: boolean;
version: number;
createdAt: string;
updatedAt: string;
@@ -1728,6 +1732,8 @@ export interface CreateContractRequest {
contractType?: ContractType;
/** Initial phase to start in (defaults based on contract type) */
initialPhase?: ContractPhase;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly?: boolean;
}
export interface UpdateContractRequest {
diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx
index 36eb980..aa62bd9 100644
--- a/makima/frontend/src/routes/contracts.tsx
+++ b/makima/frontend/src/routes/contracts.tsx
@@ -92,6 +92,7 @@ function ContractsPageContent() {
const [showRepoSuggestions, setShowRepoSuggestions] = useState(false);
const [contractTypes, setContractTypes] = useState<ContractTypeTemplate[]>([]);
const [contractTypesLoading, setContractTypesLoading] = useState(false);
+ const [localOnly, setLocalOnly] = useState(false);
// Fetch contract types when modal opens - merges built-in types with user templates
useEffect(() => {
@@ -263,6 +264,7 @@ function ContractsPageContent() {
description: newContractDescription.trim() || undefined,
contractType: contractType,
initialPhase: initialPhase !== defaultPhaseForType ? initialPhase : undefined,
+ localOnly: localOnly || undefined,
};
try {
@@ -303,6 +305,7 @@ function ContractsPageContent() {
setRepoName("");
setRepoUrl("");
setRepoPath("");
+ setLocalOnly(false);
navigate(`/contracts/${contract.id}`);
}
} catch (err) {
@@ -336,6 +339,7 @@ function ContractsPageContent() {
setRepoName("");
setRepoUrl("");
setRepoPath("");
+ setLocalOnly(false);
setCreateError(null);
}, []);
@@ -661,6 +665,46 @@ function ContractsPageContent() {
</p>
</div>
+ {/* Local-Only Mode */}
+ <div className="space-y-2">
+ <div className="flex items-center space-x-3">
+ <button
+ type="button"
+ onClick={() => setLocalOnly(!localOnly)}
+ className={`w-5 h-5 flex items-center justify-center border transition-colors ${
+ localOnly
+ ? "bg-[#0f3c78] border-[#75aafc] text-[#dbe7ff]"
+ : "bg-[#0d1b2d] border-[#3f6fb3] text-transparent"
+ }`}
+ >
+ {localOnly && (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 24 24"
+ fill="none"
+ stroke="currentColor"
+ strokeWidth="3"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ className="w-3 h-3"
+ >
+ <polyline points="20 6 9 17 4 12" />
+ </svg>
+ )}
+ </button>
+ <label
+ className="font-mono text-sm text-[#dbe7ff] cursor-pointer select-none"
+ onClick={() => setLocalOnly(!localOnly)}
+ >
+ Local-Only Mode
+ </label>
+ </div>
+ <p className="font-mono text-xs text-[#8b949e] pl-8">
+ When enabled, tasks won't automatically push to remote or create PRs.
+ Use patch files to export changes.
+ </p>
+ </div>
+
{/* Repository Configuration */}
<div className="border-t border-[rgba(117,170,252,0.2)] pt-4">
<label className="block font-mono text-xs text-[#75aafc] uppercase mb-3">