cli: remove insomnia-pod binary output

This commit is contained in:
Keisuke Hirata 2026-05-31 14:59:22 +09:00
parent fd32805c30
commit 0d7d3c7bf1
No known key found for this signature in database
14 changed files with 58 additions and 102 deletions

View File

@ -1,4 +1,4 @@
use std::ffi::{OsStr, OsString}; use std::ffi::OsString;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -28,21 +28,15 @@ impl PodRuntimeCommand {
} }
pub fn for_executable(program: impl Into<PathBuf>) -> Self { pub fn for_executable(program: impl Into<PathBuf>) -> Self {
let program = program.into(); Self::new(program, vec![OsString::from("pod")])
let prefix_args = if is_legacy_pod_binary(&program) {
Vec::new()
} else {
vec![OsString::from("pod")]
};
Self::new(program, prefix_args)
} }
/// Resolve the Pod runtime command used for subprocess launches. /// Resolve the Pod runtime command used for subprocess launches.
/// ///
/// `INSOMNIA_POD_COMMAND` is intentionally executable-only: its value is /// `INSOMNIA_POD_COMMAND` is intentionally executable-only: its value is
/// used as the program path without shell parsing and without the unified /// used as the program path without shell parsing and without the unified
/// `pod` prefix arg. That keeps existing development/test overrides safe /// `pod` prefix arg. That keeps development/test overrides safe while the
/// while the default path moves to `current_exe() + ["pod"]`. /// default path is always `current_exe() + ["pod"]`.
pub fn resolve() -> io::Result<Self> { pub fn resolve() -> io::Result<Self> {
if let Some(command) = Self::from_override_env() { if let Some(command) = Self::from_override_env() {
return Ok(command); return Ok(command);
@ -87,14 +81,6 @@ impl fmt::Display for PodRuntimeCommand {
} }
} }
fn is_legacy_pod_binary(program: &Path) -> bool {
let Some(file_name) = program.file_name().and_then(OsStr::to_str) else {
return false;
};
let stem = file_name.strip_suffix(".exe").unwrap_or(file_name);
stem == "insomnia-pod"
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -137,17 +123,17 @@ mod tests {
} }
#[test] #[test]
fn legacy_wrapper_keeps_executable_only_command() { fn any_runtime_executable_gets_pod_prefix() {
let command = PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia-pod"); let command = PodRuntimeCommand::for_executable("/opt/insomnia/bin/custom-runtime");
assert_eq!( assert_eq!(
command.program(), command.program(),
Path::new("/opt/insomnia/bin/insomnia-pod") Path::new("/opt/insomnia/bin/custom-runtime")
); );
assert!(command.prefix_args().is_empty()); assert_eq!(command.prefix_args(), [OsString::from("pod")]);
assert_eq!( assert_eq!(
command.argv_with(["--pod", "agent"]), command.argv_with(["--pod", "agent"]),
vec!["--pod", "agent"] vec!["pod", "--pod", "agent"]
.into_iter() .into_iter()
.map(OsString::from) .map(OsString::from)
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@ -3,10 +3,7 @@ name = "pod"
version = "0.1.0" version = "0.1.0"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
autobins = false
[[bin]]
name = "insomnia-pod"
path = "src/main.rs"
[dependencies] [dependencies]
async-trait = { workspace = true } async-trait = { workspace = true }

View File

@ -191,7 +191,7 @@ fn load_single_manifest(
} }
pub async fn run_cli() -> ExitCode { pub async fn run_cli() -> ExitCode {
run_cli_from("insomnia-pod", std::env::args_os().skip(1)).await run_cli_from("insomnia pod", std::env::args_os().skip(1)).await
} }
pub async fn run_cli_from<I, T>(bin_name: &'static str, args: I) -> ExitCode pub async fn run_cli_from<I, T>(bin_name: &'static str, args: I) -> ExitCode
@ -444,7 +444,7 @@ permission = "write"
#[test] #[test]
fn user_manifest_flag_is_not_accepted() { fn user_manifest_flag_is_not_accepted() {
let err = let err =
Cli::try_parse_from(["insomnia-pod", "--user-manifest", "manifest.toml"]).unwrap_err(); Cli::try_parse_from(["insomnia pod", "--user-manifest", "manifest.toml"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
} }
@ -460,7 +460,7 @@ permission = "write"
#[test] #[test]
fn manifest_conflicts_with_project() { fn manifest_conflicts_with_project() {
let project_err = Cli::try_parse_from([ let project_err = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--manifest", "--manifest",
"manifest.toml", "manifest.toml",
"--project", "--project",
@ -472,7 +472,7 @@ permission = "write"
#[test] #[test]
fn overlay_flag_is_not_accepted() { fn overlay_flag_is_not_accepted() {
let err = Cli::try_parse_from(["insomnia-pod", "--overlay", "pod.name = 'x'"]).unwrap_err(); let err = Cli::try_parse_from(["insomnia pod", "--overlay", "pod.name = 'x'"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
} }
@ -481,7 +481,7 @@ permission = "write"
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let manifest = tmp.path().join("manifest.toml"); let manifest = tmp.path().join("manifest.toml");
write(&manifest, &manifest_toml("single", tmp.path())); write(&manifest, &manifest_toml("single", tmp.path()));
let cli = Cli::try_parse_from(["insomnia-pod", "--manifest", manifest.to_str().unwrap()]) let cli = Cli::try_parse_from(["insomnia pod", "--manifest", manifest.to_str().unwrap()])
.unwrap(); .unwrap();
let (manifest, loader) = resolve_manifest(&cli).unwrap(); let (manifest, loader) = resolve_manifest(&cli).unwrap();
@ -496,7 +496,7 @@ permission = "write"
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let profile = tmp.path().join("profile.lua"); let profile = tmp.path().join("profile.lua");
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--profile", "--profile",
profile.to_str().unwrap(), profile.to_str().unwrap(),
"--profile-pod-name", "--profile-pod-name",
@ -529,7 +529,7 @@ permission = "write"
fn profile_accepts_source_qualified_discovered_name() { fn profile_accepts_source_qualified_discovered_name() {
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--profile", "--profile",
"project:coder", "project:coder",
"--profile-pod-name", "--profile-pod-name",
@ -564,7 +564,7 @@ permission = "write"
#[test] #[test]
fn normal_startup_uses_default_profile() { fn normal_startup_uses_default_profile() {
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from(["insomnia-pod"]).unwrap(); let cli = Cli::try_parse_from(["insomnia pod"]).unwrap();
let mut called = false; let mut called = false;
let (manifest, _loader) = let (manifest, _loader) =
@ -585,7 +585,7 @@ permission = "write"
#[test] #[test]
fn project_flag_no_longer_enables_ambient_manifest_cascade() { fn project_flag_no_longer_enables_ambient_manifest_cascade() {
let cli = Cli::try_parse_from(["insomnia-pod", "--project", "."]).unwrap(); let cli = Cli::try_parse_from(["insomnia pod", "--project", "."]).unwrap();
let err = resolve_manifest_with_profile_loader(&cli, |_, _| { let err = resolve_manifest_with_profile_loader(&cli, |_, _| {
panic!("default profile loader must not run when deprecated --project is present") panic!("default profile loader must not run when deprecated --project is present")
}) })
@ -597,7 +597,7 @@ permission = "write"
fn pod_flag_conflicts_with_session() { fn pod_flag_conflicts_with_session() {
let segment_id = session_store::new_segment_id(); let segment_id = session_store::new_segment_id();
let segment_id = segment_id.to_string(); let segment_id = segment_id.to_string();
let err = Cli::try_parse_from(["insomnia-pod", "--pod", "agent", "--session", &segment_id]) let err = Cli::try_parse_from(["insomnia pod", "--pod", "agent", "--session", &segment_id])
.unwrap_err(); .unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict); assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
} }
@ -608,7 +608,7 @@ permission = "write"
let manifest = tmp.path().join("manifest.toml"); let manifest = tmp.path().join("manifest.toml");
write(&manifest, &manifest_toml("from-file", tmp.path())); write(&manifest, &manifest_toml("from-file", tmp.path()));
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--manifest", "--manifest",
manifest.to_str().unwrap(), manifest.to_str().unwrap(),
"--pod", "--pod",
@ -640,7 +640,7 @@ permission = "write"
"#, "#,
); );
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--manifest", "--manifest",
manifest.to_str().unwrap(), manifest.to_str().unwrap(),
"--pod", "--pod",
@ -657,7 +657,7 @@ permission = "write"
#[test] #[test]
fn pod_flag_with_no_manifest_creates_from_default_profile_with_typed_name() { fn pod_flag_with_no_manifest_creates_from_default_profile_with_typed_name() {
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from(["insomnia-pod", "--pod", "agent"]).unwrap(); let cli = Cli::try_parse_from(["insomnia pod", "--pod", "agent"]).unwrap();
let mut called = false; let mut called = false;
let (manifest, _loader) = let (manifest, _loader) =
@ -683,10 +683,10 @@ permission = "write"
fn profile_conflicts_with_manifest_and_restore_modes() { fn profile_conflicts_with_manifest_and_restore_modes() {
let segment_id = session_store::new_segment_id().to_string(); let segment_id = session_store::new_segment_id().to_string();
for args in [ for args in [
vec!["insomnia-pod", "--profile", "p.lua", "--manifest", "m.toml"], vec!["insomnia pod", "--profile", "p.lua", "--manifest", "m.toml"],
vec!["insomnia-pod", "--profile", "p.lua", "--pod", "agent"], vec!["insomnia pod", "--profile", "p.lua", "--pod", "agent"],
vec![ vec![
"insomnia-pod", "insomnia pod",
"--profile", "--profile",
"p.lua", "p.lua",
"--session", "--session",
@ -700,14 +700,14 @@ permission = "write"
#[test] #[test]
fn profile_pod_name_requires_profile() { fn profile_pod_name_requires_profile() {
let err = Cli::try_parse_from(["insomnia-pod", "--profile-pod-name", "agent"]).unwrap_err(); let err = Cli::try_parse_from(["insomnia pod", "--profile-pod-name", "agent"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument); assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument);
} }
#[test] #[test]
fn profile_pod_name_is_not_restore_pod_flag() { fn profile_pod_name_is_not_restore_pod_flag() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--profile", "--profile",
"p.lua", "p.lua",
"--profile-pod-name", "--profile-pod-name",
@ -726,7 +726,7 @@ permission = "write"
std::fs::create_dir_all(tmp.path().join("prompts")).unwrap(); std::fs::create_dir_all(tmp.path().join("prompts")).unwrap();
std::fs::create_dir_all(tmp.path().join(".insomnia").join("prompts")).unwrap(); std::fs::create_dir_all(tmp.path().join(".insomnia").join("prompts")).unwrap();
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"insomnia-pod", "insomnia pod",
"--manifest", "--manifest",
single_manifest.to_str().unwrap(), single_manifest.to_str().unwrap(),
]) ])

View File

@ -1,6 +0,0 @@
use std::process::ExitCode;
#[tokio::main]
async fn main() -> ExitCode {
pod::entrypoint::run_cli().await
}

View File

@ -2,7 +2,7 @@
//! //!
//! These tests exercise the tool's pod-registry delegation, subprocess //! These tests exercise the tool's pod-registry delegation, subprocess
//! launch, socket handoff, and `spawned_pods.json` write without relying //! launch, socket handoff, and `spawned_pods.json` write without relying
//! on the real `insomnia-pod` binary. `INSOMNIA_POD_COMMAND` is pointed at //! on the real Pod runtime executable. `INSOMNIA_POD_COMMAND` is pointed at
//! `/bin/true` (which exits immediately) while a test-owned Unix //! `/bin/true` (which exits immediately) while a test-owned Unix
//! listener pre-binds the predicted socket path, so the tool sees the //! listener pre-binds the predicted socket path, so the tool sees the
//! "child" as live. //! "child" as live.

View File

@ -1,23 +1,4 @@
{ pkgs }: { pkgs }:
let
# Dev-only wrapper. tui の spawn 経路は `insomnia-pod` バイナリを直に exec し、
# stderr の `INSOMNIA-READY` 行で握手するので、cargo の進捗や rustc の
# warning が混ざると tail に余計な行が積もり本当のエラーが押し出される。
# ここで一度ビルドを切り離し、成功時はビルド出力を一切捨てて素のバイナリ
# を exec、失敗時のみ build log を stderr に流して exit する。
pod-dev = pkgs.writeShellScriptBin "insomnia-pod" ''
set -u
buildlog=$(mktemp)
trap 'rm -f "$buildlog"' EXIT
if ! cargo build --quiet -p pod 2>"$buildlog"; then
cat "$buildlog" >&2
exit 1
fi
manifest=$(cargo locate-project --workspace --message-format plain 2>/dev/null)
target_dir=''${CARGO_TARGET_DIR:-$(dirname "$manifest")/target}
exec "$target_dir/debug/insomnia-pod" "$@"
'';
in
pkgs.mkShell { pkgs.mkShell {
packages = with pkgs; [ packages = with pkgs; [
nixfmt nixfmt
@ -25,7 +6,6 @@ pkgs.mkShell {
git git
rustc rustc
cargo cargo
pod-dev
]; ];
buildInputs = with pkgs; [ buildInputs = with pkgs; [
pkg-config pkg-config

View File

@ -103,7 +103,7 @@ permission = "write"
通常の Pod 起動は Lua profile discovery/default から `PodManifest` を生成する。bundled `builtin:default` が fallback default で、user/project `profiles.toml` は profile registry と default selection だけを担う。user/project `manifest.toml` の ambient cascade は通常起動では使わない。 通常の Pod 起動は Lua profile discovery/default から `PodManifest` を生成する。bundled `builtin:default` が fallback default で、user/project `profiles.toml` は profile registry と default selection だけを担う。user/project `manifest.toml` の ambient cascade は通常起動では使わない。
`insomnia-pod --manifest <PATH>` は explicit one-file compatibility/debug input で、指定 TOML 1 枚だけに builtin defaults を merge し、`PodManifestConfig -> PodManifest` の required validation を通す。 `insomnia pod --manifest <PATH>` は explicit one-file compatibility/debug input で、指定 TOML 1 枚だけに builtin defaults を merge し、`PodManifestConfig -> PodManifest` の required validation を通す。
`PodFactory` の user/project/overlay API は低レベル構成部品として残るが、CLI の通常起動 path では generic TOML overlay を公開しない。 `PodFactory` の user/project/overlay API は低レベル構成部品として残るが、CLI の通常起動 path では generic TOML overlay を公開しない。

View File

@ -26,14 +26,14 @@ return profile {
Run an explicit path with: Run an explicit path with:
```sh ```sh
insomnia-pod --profile ./coder.lua insomnia pod --profile ./coder.lua
# or through the TUI fresh-spawn dialog # or through the TUI fresh-spawn dialog
insomnia --profile ./coder.lua insomnia --profile ./coder.lua
``` ```
`--profile` accepts an explicit path, `path:<path>`, a discovered profile name, `default`, or a source-qualified name such as `project:coder`, `user:coder`, or `builtin:coder`. Path-like values containing `/`, starting with `.`, or ending in `.lua` are explicit paths. ``.nix` paths are no longer supported as profiles and fail with a diagnostic that points users at Lua profiles or `--manifest`. `--profile` accepts an explicit path, `path:<path>`, a discovered profile name, `default`, or a source-qualified name such as `project:coder`, `user:coder`, or `builtin:coder`. Path-like values containing `/`, starting with `.`, or ending in `.lua` are explicit paths. ``.nix` paths are no longer supported as profiles and fail with a diagnostic that points users at Lua profiles or `--manifest`.
`--profile` conflicts with `insomnia-pod --manifest` and with restore/session/adopt modes. Use `--profile-pod-name <name>` when a launcher needs a creation-time Pod name override without invoking `--pod` restore semantics. Profile evaluation is a creation-time path; Pod resume restores saved Pod state/resolved snapshots rather than re-evaluating the profile source. `--profile` conflicts with `insomnia pod --manifest` and with restore/session/adopt modes. Use `--profile-pod-name <name>` when a launcher needs a creation-time Pod name override without invoking `--pod` restore semantics. Profile evaluation is a creation-time path; Pod resume restores saved Pod state/resolved snapshots rather than re-evaluating the profile source.
## Controlled Lua environment ## Controlled Lua environment
@ -81,7 +81,7 @@ The fresh-spawn TUI also uses discovery. The new Pod dialog defaults to the sele
## One-file manifests ## One-file manifests
`insomnia-pod --manifest <PATH>` remains as an explicit compatibility/debug path. It reads exactly that TOML file, resolves relative paths against the file's parent directory, merges builtin defaults, and validates through the same `PodManifestConfig -> PodManifest` boundary as profile artifacts. It does not load user or project `manifest.toml` files and conflicts with `--profile`. `insomnia pod --manifest <PATH>` remains as an explicit compatibility/debug path. It reads exactly that TOML file, resolves relative paths against the file's parent directory, merges builtin defaults, and validates through the same `PodManifestConfig -> PodManifest` boundary as profile artifacts. It does not load user or project `manifest.toml` files and conflicts with `--profile`.
Ambient user/project `manifest.toml` cascade startup has been removed. Normal fresh spawns use profile discovery/default selection, with `profiles.toml` acting only as a profile registry/default selector. Ambient user/project `manifest.toml` cascade startup has been removed. Normal fresh spawns use profile discovery/default selection, with `profiles.toml` acting only as a profile registry/default selector.

View File

@ -5,7 +5,7 @@
# #
# このファイル形式は低レベル runtime manifest。通常起動は profile discovery/default # このファイル形式は低レベル runtime manifest。通常起動は profile discovery/default
# (`profiles.toml` と bundled builtin profile) から manifest を生成する。 # (`profiles.toml` と bundled builtin profile) から manifest を生成する。
# `insomnia-pod --manifest <path>` の one-file compatibility/debug mode では、 # `insomnia pod --manifest <path>` の one-file compatibility/debug mode では、
# 指定した TOML 1 枚に builtin defaults を merge し、required validation を行う。 # 指定した TOML 1 枚に builtin defaults を merge し、required validation を行う。
# user/project `manifest.toml` を暗黙に merge する通常起動 cascade は使わない。 # user/project `manifest.toml` を暗黙に merge する通常起動 cascade は使わない。
# #

View File

@ -1,6 +1,6 @@
# Nix package # Nix package
INSOMNIA provides a flake package for installing the user-facing Pod CLI and TUI binaries without relying on a source checkout at runtime. INSOMNIA provides a flake package for installing the user-facing `insomnia` command without relying on a source checkout at runtime. The Pod runtime still runs as a separate process through `insomnia pod ...`; the installed package does not expose a separate `insomnia-pod` command.
## Build ## Build
@ -10,12 +10,11 @@ From the repository root:
nix build .# nix build .#
``` ```
The default package is implemented by `package.nix` and builds the Cargo packages `pod` and `tui` as installed binaries `insomnia-pod` and `insomnia`. The derivation uses the checked-in `Cargo.lock`, so Cargo dependencies are fetched by the normal Nix Rust packaging path instead of by network access during the build. The default package is implemented by `package.nix` and builds the Cargo package `tui` as the installed binary `insomnia`. The `pod` crate remains a library dependency that provides the Pod runtime entrypoint used by `insomnia pod ...`. The derivation uses the checked-in `Cargo.lock`, so Cargo dependencies are fetched by the normal Nix Rust packaging path instead of by network access during the build.
The package output contains: The package output contains:
- `bin/insomnia-pod` — Pod CLI / runtime process. - `bin/insomnia` — terminal UI and `insomnia pod ...` runtime entrypoint.
- `bin/insomnia` — terminal UI.
- `share/insomnia/resources/` — bundled runtime resources, including `resources/prompts/`. - `share/insomnia/resources/` — bundled runtime resources, including `resources/prompts/`.
- `share/doc/insomnia/nix.md` — this document. - `share/doc/insomnia/nix.md` — this document.
@ -24,7 +23,7 @@ The package output contains:
After `nix build`: After `nix build`:
```sh ```sh
./result/bin/insomnia-pod --help ./result/bin/insomnia pod --help
./result/bin/insomnia ./result/bin/insomnia
``` ```
@ -32,14 +31,14 @@ With flakes:
```sh ```sh
nix run .#insomnia nix run .#insomnia
nix run .#insomnia-pod -- --help nix run .#insomnia -- pod --help
``` ```
`nix run .#` defaults to the TUI. `nix run .#` defaults to the TUI.
## Configuration discovery ## Configuration discovery
The Nix package does not put user configuration, sessions, sockets, or other mutable state in the Nix store. The installed binaries keep the same path semantics as non-Nix builds: The Nix package does not put user configuration, sessions, sockets, or other mutable state in the Nix store. The installed binary keeps the same path semantics as non-Nix builds:
| Purpose | Override | `INSOMNIA_HOME` fallback | XDG / default fallback | | Purpose | Override | `INSOMNIA_HOME` fallback | XDG / default fallback |
| --- | --- | --- | --- | | --- | --- | --- | --- |
@ -47,14 +46,15 @@ The Nix package does not put user configuration, sessions, sockets, or other mut
| Persistent data (`sessions/`, Pod metadata) | `INSOMNIA_DATA_DIR` | `$INSOMNIA_HOME` | `$HOME/.insomnia` | | Persistent data (`sessions/`, Pod metadata) | `INSOMNIA_DATA_DIR` | `$INSOMNIA_HOME` | `$HOME/.insomnia` |
| Runtime state (sockets, lock files, live registry) | `INSOMNIA_RUNTIME_DIR` | `$INSOMNIA_HOME/run` | `$XDG_RUNTIME_DIR/insomnia`, then `$HOME/.insomnia/run` | | Runtime state (sockets, lock files, live registry) | `INSOMNIA_RUNTIME_DIR` | `$INSOMNIA_HOME/run` | `$XDG_RUNTIME_DIR/insomnia`, then `$HOME/.insomnia/run` |
Normal fresh startup is profile-based. The package ships a builtin default profile, user/project `profiles.toml` files may select or define profiles, and `insomnia-pod --manifest <PATH>` remains a one-file compatibility/debug input. `INSOMNIA_USER_MANIFEST` and ambient `.insomnia/manifest.toml` discovery are not part of normal Pod/TUI startup. Normal fresh startup is profile-based. The package ships a builtin default profile, user/project `profiles.toml` files may select or define profiles, and `insomnia pod --manifest <PATH>` remains a one-file compatibility/debug input. `INSOMNIA_USER_MANIFEST` and ambient `.insomnia/manifest.toml` discovery are not part of normal Pod/TUI startup.
## Validation ## Validation
The package derivation has a credential-free install check that verifies: The package derivation has a credential-free install check that verifies:
- `insomnia-pod --help` starts successfully. - `insomnia pod --help` starts successfully.
- `insomnia` is installed and reaches argument parsing. - `insomnia` is installed and reaches argument parsing.
- `bin/insomnia-pod` is not installed.
- bundled prompt resources and this Nix usage document are present in the output. - bundled prompt resources and this Nix usage document are present in the output.
For full validation before handing changes to review, run: For full validation before handing changes to review, run:
@ -63,12 +63,13 @@ For full validation before handing changes to review, run:
nix build .# nix build .#
nix flake check nix flake check
cargo fmt --check cargo fmt --check
cargo check -p tui -p pod -p client
``` ```
This packaging change does not require provider credentials. A Rust `cargo check` is only needed if Rust source or runtime path semantics are changed. These checks do not require provider credentials.
## Known limitations ## Known limitations
- The package currently installs the TUI and Pod CLI only; development-only wrappers from `devshell.nix` are not part of the installable package. - The package currently installs only the `insomnia` command; development-only wrappers from `devshell.nix` are not part of the installable package.
- The TUI does not currently expose a conventional `--help` / `--version` CLI path, so the package smoke check uses an argument-parse failure path for the TUI rather than launching an interactive session. - The TUI does not currently expose a conventional `--help` / `--version` CLI path, so the package smoke check uses an argument-parse failure path for the TUI rather than launching an interactive session.
- Bundled resources are installed under `share/insomnia/resources/` for packaging completeness and inspection. Built-in prompt/resource loading remains governed by the existing application code and user/project override rules. - Bundled resources are installed under `share/insomnia/resources/` for packaging completeness and inspection. Built-in prompt/resource loading remains governed by the existing application code and user/project override rules.

View File

@ -172,7 +172,7 @@ unique であれば workspace を指定しなくて済む。
## Daemon-less リモート Pod 生成SSH-only モデル) ## Daemon-less リモート Pod 生成SSH-only モデル)
リモートホスト上の Pod 生成は **daemon 無しで SSH だけで成立する** リモートホスト上の Pod 生成は **daemon 無しで SSH だけで成立する**
remote 側に必要なのは `insomnia-pod` バイナリと SSH アクセスのみ。 remote 側に必要なのは `insomnia` バイナリと SSH アクセスのみ。
### 前提 ### 前提
@ -182,7 +182,7 @@ remote 側に必要なのは `insomnia-pod` バイナリと SSH アクセスの
- insomnia が転送するのは**セッション(会話履歴)と manifest overlay** - insomnia が転送するのは**セッション(会話履歴)と manifest overlay**
だけ。コードベースの同期は外部に委ねる だけ。コードベースの同期は外部に委ねる
- コンテナ内で動かすか bare metal で動かすかも insomnia は問わない。 - コンテナ内で動かすか bare metal で動かすかも insomnia は問わない。
`insomnia-pod` バイナリが動くホストの fs 上で活動する主体がある、 `insomnia` バイナリが動くホストの fs 上で活動する主体がある、
それだけが前提 それだけが前提
### フロー ### フロー
@ -193,7 +193,7 @@ host_a (spawner) host_b (remote)
├── ssh: session データを転送 ────────→ ファイル書き込み ├── ssh: session データを転送 ────────→ ファイル書き込み
├── ssh: profile / one-file manifest 入力を転送 ─→ 必要ならファイル書き込み ├── ssh: profile / one-file manifest 入力を転送 ─→ 必要ならファイル書き込み
├── ssh: `insomnia-pod --profile ... &` ───────→ Pod プロセス起動、socket 作成 ├── ssh: `insomnia pod --profile ... &` ───────→ Pod プロセス起動、socket 作成
├── ssh -L: socket を tunnel ─────────→ Pod B の unix socket ├── ssh -L: socket を tunnel ─────────→ Pod B の unix socket
└── localhost:tunnel に接続 ──────────→ Method::Run / Event stream └── localhost:tunnel に接続 ──────────→ Method::Run / Event stream
@ -209,7 +209,7 @@ tar cz session/ | ssh insomnia@host-b "tar xz -C ~/workspaces/task-123/store"
scp profile.lua insomnia@host-b:~/workspaces/task-123/profile.lua scp profile.lua insomnia@host-b:~/workspaces/task-123/profile.lua
# 2. Pod を起動detach # 2. Pod を起動detach
ssh insomnia@host-b "insomnia-pod --store ~/workspaces/task-123/store \ ssh insomnia@host-b "insomnia pod --store ~/workspaces/task-123/store \
--profile ~/workspaces/task-123/profile.lua &" --profile ~/workspaces/task-123/profile.lua &"
# 3. socket を tunnel で引っ張る # 3. socket を tunnel で引っ張る

View File

@ -156,12 +156,12 @@ Profile and one-file Manifest CLI paths currently use builtin prompt assets only
The rendered instruction body is followed by fixed Rust-provided sections for working boundaries and, when present, `AGENTS.md`. User templates cannot remove the scope section. The rendered instruction body is followed by fixed Rust-provided sections for working boundaries and, when present, `AGENTS.md`. User templates cannot remove the scope section.
## `insomnia-pod` CLI ## `insomnia pod` CLI
Normal fresh startup uses profile discovery/default selection: Normal fresh startup uses profile discovery/default selection:
```text ```text
insomnia-pod [--profile <selector>] [--profile-pod-name <name>] [-s/--store <path>] insomnia pod [--profile <selector>] [--profile-pod-name <name>] [-s/--store <path>]
``` ```
| Flag | Description | | Flag | Description |
@ -173,8 +173,8 @@ insomnia-pod [--profile <selector>] [--profile-pod-name <name>] [-s/--store <pat
Restore/attach uses Pod/session state and does not re-evaluate profile sources. Restore/attach uses Pod/session state and does not re-evaluate profile sources.
```text ```text
insomnia-pod --pod <name> insomnia pod --pod <name>
insomnia-pod --session <uuid> insomnia pod --session <uuid>
``` ```
Spawn children use hidden `--spawn-config-json`, `--adopt`, and `--callback <path>` flags. These are internal handoff details used by `SpawnPod` after the parent has allocated scope and prepared the child config. Spawn children use hidden `--spawn-config-json`, `--adopt`, and `--callback <path>` flags. These are internal handoff details used by `SpawnPod` after the parent has allocated scope and prepared the child config.

View File

@ -29,7 +29,6 @@
apps.default = mkApp "insomnia" "Run the INSOMNIA terminal UI"; apps.default = mkApp "insomnia" "Run the INSOMNIA terminal UI";
apps.insomnia = mkApp "insomnia" "Run the INSOMNIA terminal UI"; apps.insomnia = mkApp "insomnia" "Run the INSOMNIA terminal UI";
apps.insomnia-pod = mkApp "insomnia-pod" "Run the INSOMNIA Pod CLI";
checks.default = insomnia; checks.default = insomnia;

View File

@ -40,7 +40,7 @@ rustPlatform.buildRustPackage rec {
filter = sourceFilter; filter = sourceFilter;
}; };
cargoHash = "sha256-8TAJLV7+7Th4o5Jpsyqz+n9kiuB0FO6qxGi559otfko="; cargoHash = "sha256-fisV77ZqAPsI0eLZIqw06HTj1CfmnL3NBHhjruZPZUE=";
depsExtraArgs = { depsExtraArgs = {
# nixpkgs 25.11's fetchCargoVendor still uses crates.io's API # nixpkgs 25.11's fetchCargoVendor still uses crates.io's API
@ -82,8 +82,6 @@ rustPlatform.buildRustPackage rec {
); );
cargoBuildFlags = [ cargoBuildFlags = [
"-p"
"pod"
"-p" "-p"
"tui" "tui"
]; ];
@ -103,8 +101,9 @@ rustPlatform.buildRustPackage rec {
installCheckPhase = '' installCheckPhase = ''
runHook preInstallCheck runHook preInstallCheck
"$out/bin/insomnia-pod" --help >/dev/null "$out/bin/insomnia" pod --help >/dev/null
test -x "$out/bin/insomnia" test -x "$out/bin/insomnia"
test ! -e "$out/bin/insomnia-pod"
if "$out/bin/insomnia" --session not-a-uuid 2>insomnia.err; then if "$out/bin/insomnia" --session not-a-uuid 2>insomnia.err; then
echo "insomnia unexpectedly accepted an invalid --session value" >&2 echo "insomnia unexpectedly accepted an invalid --session value" >&2
exit 1 exit 1