Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
356fd61
Integrate harness-aware execution handoff
codydeny Mar 27, 2026
7bb14d8
Update repo instructions and GitHub metadata
codydeny Mar 27, 2026
3d8ae36
Fix batch completion runtime state access
codydeny Mar 27, 2026
a3fa249
Make raw dev installer default to dev ref
codydeny Mar 27, 2026
8150fc9
Fix Claude skill and hook installation
codydeny Mar 27, 2026
4a50195
Merge origin/main into dev
codydeny Mar 27, 2026
ad87cdc
Route Superplan artifact writes through CLI
codydeny Mar 27, 2026
5eb9a1e
refactor(init): overhaul Superplan CLI architecture for global-first …
ishashankmi Mar 28, 2026
7c220a6
updated remove and added uninstall command
ishashankmi Mar 28, 2026
d3430d1
updated sh command to install superplan globally
ishashankmi Mar 28, 2026
729d40d
fix: remove install_path from cleanup_paths to prevent skills deletion
ishashankmi Mar 28, 2026
1c9ca98
fix: create agent directory before installing skills
ishashankmi Mar 28, 2026
f4e0bbc
fix: init
codydeny Mar 28, 2026
ff117d5
Merge branch 'dev' of https://github.com/superplan-md/cli into dev
codydeny Mar 28, 2026
e7f629f
Refresh CLI guidance for updated Superplan layout
codydeny Mar 28, 2026
2f17268
fix: remove agents claude files
codydeny Mar 28, 2026
c618a0e
Fix Claude skill and hook installation
codydeny Mar 27, 2026
d78a9b0
Route Superplan artifact writes through CLI
codydeny Mar 27, 2026
8859b47
fix: init
codydeny Mar 28, 2026
66b0c3e
refactor(init): overhaul Superplan CLI architecture for global-first …
ishashankmi Mar 28, 2026
06067d6
updated remove and added uninstall command
ishashankmi Mar 28, 2026
fe79611
updated sh command to install superplan globally
ishashankmi Mar 28, 2026
e2cae48
fix: remove install_path from cleanup_paths to prevent skills deletion
ishashankmi Mar 28, 2026
6405056
fix: create agent directory before installing skills
ishashankmi Mar 28, 2026
180ed43
Refresh CLI guidance for updated Superplan layout
codydeny Mar 28, 2026
4f9da92
fix: remove agents claude files
codydeny Mar 28, 2026
b933c84
feat: improve plan guidance and overlay runtime
codydeny Mar 28, 2026
eeae0bb
feat: improve plan guidance and overlay runtime
codydeny Mar 28, 2026
2257216
Merge pull request #10 from superplan-md/codex/plan-guidance-overlay-…
codydeny Mar 28, 2026
a4a8977
Add multi-workspace overlay runtime board
codydeny Mar 28, 2026
689b609
Merge origin/dev into dev
codydeny Mar 28, 2026
45702f2
Merge branch 'codex/plan-guidance-overlay-runtime' into dev
codydeny Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions .github/copilot-instructions.md

This file was deleted.

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ changes
.cursor
.opencode
.github

# Superplan - AI agent configurations
.agents/
.amazonq/
AGENTS.md
37 changes: 0 additions & 37 deletions AGENTS.md

This file was deleted.

149 changes: 142 additions & 7 deletions apps/overlay-desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,128 @@ use tauri_nspanel::{
};

fn overlay_runtime_file_path_for_workspace(workspace_root: &Path, file_name: &str) -> PathBuf {
workspace_root.join(".superplan/runtime").join(file_name)
overlay_runtime_dir_for_workspace(workspace_root).join(file_name)
}

fn overlay_runtime_root_dir() -> PathBuf {
let home_dir = env::var_os("HOME")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("."));

home_dir.join(".config").join("superplan").join("runtime")
}

fn overlay_runtime_dir_for_workspace(workspace_root: &Path) -> PathBuf {
workspace_root.join(".superplan/runtime")
let workspace_name = workspace_root
.file_name()
.and_then(|value| value.to_str())
.unwrap_or("root")
.to_lowercase()
.chars()
.map(|character| if character.is_ascii_alphanumeric() { character } else { '-' })
.collect::<String>();

overlay_runtime_root_dir()
.join(format!("workspace-{}", if workspace_name.is_empty() { "root" } else { &workspace_name }))
}

fn load_runtime_json_payloads(file_name: &str) -> Result<Vec<serde_json::Value>, String> {
let runtime_root = overlay_runtime_root_dir();
let runtime_entries = match fs::read_dir(&runtime_root) {
Ok(entries) => entries,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
Err(error) => {
return Err(format!(
"failed to read overlay runtime directory at {}: {error}",
runtime_root.display()
));
}
};

let mut payloads = Vec::new();

for entry in runtime_entries {
let entry = entry.map_err(|error| {
format!(
"failed to read an entry from overlay runtime directory at {}: {error}",
runtime_root.display()
)
})?;
let entry_path = entry.path();
if !entry_path.is_dir() {
continue;
}

let payload_path = entry_path.join(file_name);
if !payload_path.is_file() {
continue;
}

let payload = match fs::read_to_string(&payload_path) {
Ok(payload) => payload,
Err(error) => {
eprintln!(
"skipping unreadable overlay runtime payload at {}: {error}",
payload_path.display()
);
continue;
}
};
let payload_value: serde_json::Value = match serde_json::from_str(&payload) {
Ok(payload_value) => payload_value,
Err(error) => {
eprintln!(
"skipping invalid overlay runtime payload at {}: {error}",
payload_path.display()
);
continue;
}
};
payloads.push(payload_value);
}

payloads.sort_by(|left, right| {
let left_attention = left
.get("attention_state")
.and_then(|value| value.as_str())
.unwrap_or("normal");
let right_attention = right
.get("attention_state")
.and_then(|value| value.as_str())
.unwrap_or("normal");
let attention_rank = |value: &str| match value {
"needs_feedback" => 0,
"all_tasks_done" => 2,
_ => 1,
};

attention_rank(left_attention)
.cmp(&attention_rank(right_attention))
.then_with(|| {
let left_updated = left
.get("updated_at")
.and_then(|value| value.as_str())
.unwrap_or("");
let right_updated = right
.get("updated_at")
.and_then(|value| value.as_str())
.unwrap_or("");
right_updated.cmp(left_updated)
})
.then_with(|| {
let left_workspace = left
.get("workspace_path")
.and_then(|value| value.as_str())
.unwrap_or("");
let right_workspace = right
.get("workspace_path")
.and_then(|value| value.as_str())
.unwrap_or("");
left_workspace.cmp(right_workspace)
})
});

Ok(payloads)
}

#[derive(Default)]
Expand Down Expand Up @@ -136,7 +253,7 @@ fn apply_secondary_launch(
#[tauri::command]
fn load_overlay_snapshot(app_handle: tauri::AppHandle) -> Result<String, String> {
let snapshot_path = resolve_overlay_snapshot_path(&app_handle)?.ok_or_else(|| {
"failed to locate .superplan/runtime/overlay.json from explicit launch workspace, SUPERPLAN_OVERLAY_WORKSPACE, current working directory, or app manifest ancestors".to_string()
"failed to locate the global workspace-scoped overlay snapshot from explicit launch workspace, SUPERPLAN_OVERLAY_WORKSPACE, current working directory, or app manifest ancestors".to_string()
})?;

fs::read_to_string(&snapshot_path).map_err(|error| {
Expand All @@ -147,6 +264,12 @@ fn load_overlay_snapshot(app_handle: tauri::AppHandle) -> Result<String, String>
})
}

#[tauri::command]
fn load_overlay_snapshots() -> Result<String, String> {
serde_json::to_string(&load_runtime_json_payloads("overlay.json")?)
.map_err(|error| format!("failed to serialize overlay snapshots: {error}"))
}

#[tauri::command]
fn load_overlay_control_state(app_handle: tauri::AppHandle) -> Result<Option<String>, String> {
let control_path = match resolve_overlay_control_path(&app_handle)? {
Expand All @@ -164,6 +287,12 @@ fn load_overlay_control_state(app_handle: tauri::AppHandle) -> Result<Option<Str
})
}

#[tauri::command]
fn load_overlay_control_states() -> Result<String, String> {
serde_json::to_string(&load_runtime_json_payloads("overlay-control.json")?)
.map_err(|error| format!("failed to serialize overlay control states: {error}"))
}

// Bug #1 fix: manifest_dir (CARGO_MANIFEST_DIR) was baked in at compile time
// and pointed to the developer's machine path. It is now removed entirely from
// workspace discovery — the correct path must come from --workspace or
Expand Down Expand Up @@ -389,6 +518,7 @@ fn persist_overlay_requested_action(
requested_action: String,
updated_at: String,
visible: bool,
workspace_path: Option<String>,
) -> Result<(), String> {
let requested_action = requested_action.trim().to_ascii_lowercase();
if requested_action != "ensure" && requested_action != "show" && requested_action != "hide" {
Expand All @@ -397,9 +527,12 @@ fn persist_overlay_requested_action(
));
}

let workspace_root = resolve_overlay_workspace_root(&app_handle)?.ok_or_else(|| {
"failed to resolve overlay workspace root for control state persistence".to_string()
})?;
let workspace_root = workspace_path
.map(PathBuf::from)
.or(resolve_overlay_workspace_root(&app_handle)?)
.ok_or_else(|| {
"failed to resolve overlay workspace root for control state persistence".to_string()
})?;
let runtime_dir = overlay_runtime_dir_for_workspace(workspace_root.as_path());
let control_path = runtime_dir.join("overlay-control.json");

Expand Down Expand Up @@ -550,7 +683,9 @@ pub fn run() {
.manage(OverlayWorkspaceState::default())
.invoke_handler(tauri::generate_handler![
load_overlay_snapshot,
load_overlay_snapshots,
load_overlay_control_state,
load_overlay_control_states,
persist_overlay_requested_action,
set_overlay_visibility,
exit_overlay_application,
Expand Down Expand Up @@ -611,7 +746,7 @@ mod tests {
}

fn create_runtime_file(workspace_root: &Path, file_name: &str) -> PathBuf {
let runtime_file = workspace_root.join(".superplan/runtime").join(file_name);
let runtime_file = super::overlay_runtime_file_path_for_workspace(workspace_root, file_name);
fs::create_dir_all(runtime_file.parent().expect("runtime file parent"))
.expect("create runtime dir");
fs::write(&runtime_file, "{\"visible\":true}").expect("write runtime file");
Expand Down
3 changes: 3 additions & 0 deletions apps/overlay-desktop/src/lib/prototype-state.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export type PrototypeMode = 'compact' | 'expanded';

export interface PrototypeTask {
task_id: string;
change_id?: string;
task_ref?: string;
title: string;
description?: string;
status: string;
Expand Down Expand Up @@ -44,6 +46,7 @@ export interface PrototypeSnapshot {
workspace_path: string;
session_id: string;
updated_at: string;
tracked_changes: PrototypeFocusedChange[];
focused_change: PrototypeFocusedChange | null;
active_task: PrototypeTask | null;
board: PrototypeBoard;
Expand Down
9 changes: 7 additions & 2 deletions apps/overlay-desktop/src/lib/prototype-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,16 @@ function getPrimaryTask(snapshot) {
}

function getFocusedChange(snapshot) {
if (!snapshot.focused_change || snapshot.focused_change.status === 'done') {
const change = snapshot.focused_change
?? snapshot.tracked_changes?.find(candidate => candidate.status !== 'done')
?? snapshot.tracked_changes?.[0]
?? null;

if (!change || change.status === 'done') {
return null;
}

return snapshot.focused_change;
return change;
}

function createColumnCounts(board) {
Expand Down
Loading