Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 428c70beaa | |||
| 1c6dbcede8 | |||
| 3e59a257dc | |||
| 93da9b42a2 | |||
| 0dd5f2317b | |||
| ab93863ea9 | |||
| 85627793b4 | |||
| 8b6a4f7712 | |||
| bf698b3ff2 | |||
| d5119f29f6 | |||
| 563ff13969 | |||
| 39bac24100 | |||
| 889c598129 | |||
| ac56c5e391 | |||
| 17f4e91a84 | |||
| b3f47310c3 | |||
| 972dae64f2 | |||
| cbd5533adf | |||
| 6e419f815d | |||
| 4f4939406f | |||
| f47cf27720 | |||
| 6559c2a1d9 | |||
| 5d5b39bec1 | |||
| 38d116dcf7 | |||
| da3f8da3ac | |||
| 454a7845bb | |||
| 50e3af0d91 | |||
| 8e1af41cd3 | |||
| 355b471067 | |||
| a2f0847aad | |||
| 82ff8b8801 | |||
| a6ad8268b9 | |||
| 3358af57c2 | |||
| 6a61669294 | |||
| 29e48cdb65 | |||
| ed1f7805f6 | |||
| 1d345eba32 | |||
| e35e605914 | |||
| 94137c6586 | |||
| 1658767cf4 | |||
| 83928d0f02 | |||
| 8f648264f1 | |||
| b26ed7c3e4 | |||
| 6e33e8e4e9 | |||
| f0ae9483f3 | |||
| 90992e46a8 | |||
| 41f9427224 | |||
| 089d802f1d | |||
| a4e6c46a47 | |||
| 47de2a0133 | |||
| bd94cc9bbf | |||
| fe82a248ec | |||
| c8db6ce933 | |||
| 896674195c | |||
| ddd92e3dd4 | |||
| b4203a4a09 | |||
| 5fc8e035e6 | |||
| e6114ed18c | |||
| ac9f7a9299 | |||
| 84cf423684 | |||
| 4c14966ae3 | |||
| 6c31ef9577 | |||
| a12d6a8169 | |||
| 13b3c60abc | |||
| 23fc0a6b82 | |||
| 8b15689fb3 | |||
| 98d4393387 | |||
| 35f0a3ea2e | |||
| 1ae8d0e45f | |||
| 025ccc5817 | |||
| 350b393457 |
@@ -2,7 +2,7 @@
|
|||||||
dir: .claude
|
dir: .claude
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Configuration directory for Claude AI assistant integration and custom instructions.
|
Configuration directory for Claude AI assistant settings and custom instructions.
|
||||||
## parent
|
## parent
|
||||||
index: ./.pi-map.index.md
|
index: ./.pi-map.index.md
|
||||||
map: ./.pi-map.md
|
map: ./.pi-map.md
|
||||||
|
|||||||
+2
-2
@@ -4,10 +4,10 @@ dir: .claude
|
|||||||
index: .claude/.pi-map.index.md
|
index: .claude/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Configuration directory for Claude AI assistant integration and custom instructions.
|
Configuration directory for Claude AI assistant settings and custom instructions.
|
||||||
## files
|
## files
|
||||||
## arch
|
## arch
|
||||||
Project-specific AI tooling configuration using convention-based file organization for assistant context and behavior customization.
|
Simple flat-file configuration storage with no executable code, using human-readable text files for AI behavior customization.
|
||||||
## tags
|
## tags
|
||||||
-
|
-
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .claude/skills
|
dir: .claude/skills
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains reusable AI skill definitions and prompt templates that configure Claude's specialized capabilities for specific development tasks.
|
Contains skill definitions and configuration files for the Claude AI assistant to extend its capabilities with specialized behaviors and domain-specific expertise.
|
||||||
## parent
|
## parent
|
||||||
index: .claude/.pi-map.index.md
|
index: .claude/.pi-map.index.md
|
||||||
map: .claude/.pi-map.md
|
map: .claude/.pi-map.md
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ dir: .claude/skills
|
|||||||
index: .claude/skills/.pi-map.index.md
|
index: .claude/skills/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains reusable AI skill definitions and prompt templates that configure Claude's specialized capabilities for specific development tasks.
|
Contains skill definitions and configuration files for the Claude AI assistant to extend its capabilities with specialized behaviors and domain-specific expertise.
|
||||||
## files
|
## files
|
||||||
## arch
|
## arch
|
||||||
Modular skill-based architecture using declarative configuration files (likely YAML/JSON) to define context-specific behaviors, tool access patterns, and system prompts for different operational modes.
|
Declarative skill configuration system using structured metadata files (likely YAML/JSON) that define prompts, tools, and context boundaries for modular AI capability extensions.
|
||||||
## tags
|
## tags
|
||||||
-
|
-
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .claude/skills/sift-backlog
|
dir: .claude/skills/sift-backlog
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool.
|
Provides a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool.
|
||||||
## parent
|
## parent
|
||||||
index: .claude/skills/.pi-map.index.md
|
index: .claude/skills/.pi-map.index.md
|
||||||
map: .claude/skills/.pi-map.md
|
map: .claude/skills/.pi-map.md
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ dir: .claude/skills/sift-backlog
|
|||||||
index: .claude/skills/sift-backlog/.pi-map.index.md
|
index: .claude/skills/sift-backlog/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool.
|
Provides a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool.
|
||||||
## files
|
## files
|
||||||
- SKILL.md | Defines a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool. | dep: sf (custom CLI tool), task management system, plan management system
|
- SKILL.md | Defines a workflow skill for triaging, organizing, and activating backlog tasks into actionable plans using a custom CLI tool. | dep: sf CLI (task, plan, dependency, update subcommands)
|
||||||
## arch
|
## arch
|
||||||
Documentation-driven skill definition using structured markdown with command specifications, workflow stages, and integration patterns for Claude CLI tooling.
|
Skill-based workflow automation using markdown-defined CLI tooling and structured task management patterns.
|
||||||
## tags
|
## tags
|
||||||
skill, defines, workflow, triaging, organizing, activating, backlog, tasks
|
skill, defines, workflow, triaging, organizing, activating, backlog, tasks
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode
|
dir: .opencode
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Hidden directory for OpenCode IDE/editor configuration and workspace metadata
|
This appears to be a configuration or metadata directory for the OpenCode AI coding assistant tool.
|
||||||
## parent
|
## parent
|
||||||
index: ./.pi-map.index.md
|
index: ./.pi-map.index.md
|
||||||
map: ./.pi-map.md
|
map: ./.pi-map.md
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ dir: .opencode
|
|||||||
index: .opencode/.pi-map.index.md
|
index: .opencode/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Hidden directory for OpenCode IDE/editor configuration and workspace metadata
|
This appears to be a configuration or metadata directory for the OpenCode AI coding assistant tool.
|
||||||
## files
|
## files
|
||||||
## arch
|
## arch
|
||||||
IDE-specific dot-directory pattern, no active code architecture; stores tool preferences and ephemeral state
|
Hidden directory storing tool-specific state; no discernible software architecture as it contains no source files.
|
||||||
## tags
|
## tags
|
||||||
-
|
-
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/commands
|
dir: .opencode/commands
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines experimental workflow skills and AI assistant stances for an OpenSpec-based development system with structured change management.
|
Defines AI assistant command workflows for an OpenSpec-based development system, covering task execution, change archival, exploratory analysis, and new change proposal generation.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/.pi-map.index.md
|
index: .opencode/.pi-map.index.md
|
||||||
map: .opencode/.pi-map.md
|
map: .opencode/.pi-map.md
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ dir: .opencode/commands
|
|||||||
index: .opencode/commands/.pi-map.index.md
|
index: .opencode/commands/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines experimental workflow skills and AI assistant stances for an OpenSpec-based development system with structured change management.
|
Defines AI assistant command workflows for an OpenSpec-based development system, covering task execution, change archival, exploratory analysis, and new change proposal generation.
|
||||||
## files
|
## files
|
||||||
- opsx-apply.md | Defines an experimental workflow skill for implementing tasks from an OpenSpec change through a structured, interactive process with CLI integration and progress tracking. | dep: openspec CLI, AskUserQuestion tool, filesystem (for reading context files)
|
- opsx-apply.md | Implement tasks from an OpenSpec change by selecting a change, reading context files, and executing pending tasks in a loop until completion or blocked. | dep: openspec CLI, AskUserQuestion tool, filesystem access
|
||||||
- opsx-archive.md | Defines a workflow for archiving completed changes in an experimental openspec-based development system | dep: openspec CLI, AskUserQuestion tool, Task tool, Skill tool, filesystem (mkdir, mv), JSON parsing
|
- opsx-archive.md | Defines a workflow for archiving completed changes in an experimental openspec-based development system, including validation, spec sync assessment, and user confirmation steps. | dep: openspec CLI, AskUserQuestion tool, Task tool, Skill tool, filesystem operations
|
||||||
- opsx-explore.md | Defines the "explore mode" stance for an AI assistant - a thinking/discovery mode for investigating problems and clarifying requirements without implementing code | dep: OpenSpec system
|
- opsx-explore.md | Defines the "explore mode" stance and guidelines for an AI assistant to think through ideas, investigate problems, and clarify requirements without implementing code. | dep: OpenSpec system, ASCII diagrams, codebase investigation tools
|
||||||
- opsx-propose.md | Defines a workflow for proposing new changes in the openspec system by creating a change directory and generating all required artifacts (proposal.md, design.md, tasks.md) in dependency order | dep: openspec CLI, AskUserQuestion tool, TodoWrite tool, JSON parsing
|
- opsx-propose.md | Defines an AI assistant workflow for proposing new changes by creating a scaffolded change directory and generating all required artifacts (proposal.md, design.md, tasks.md) in dependency order using the openspec CLI tool. | dep: openspec CLI, AskUserQuestion tool, TodoWrite tool
|
||||||
## arch
|
## arch
|
||||||
Markdown-based command definitions using a workflow pattern with interactive CLI integration, progress tracking, and dependency-ordered artifact generation across explore/propose/apply/archive lifecycle phases.
|
Markdown-based command specifications using a structured workflow pattern with sequential steps, file I/O operations, CLI tool integration (openspec), and human-in-the-loop decision points for validation and confirmation.
|
||||||
## tags
|
## tags
|
||||||
opsx, defines, workflow, openspec, openspec cli, askuserquestion tool, explore, experimental
|
opsx, tasks, openspec, change, openspec cli, askuserquestion tool, defines, explore
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/skills
|
dir: .opencode/skills
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains reusable AI skill modules that provide specialized capabilities for the OpenCode assistant.
|
Contains custom AI agent skills or capabilities that extend the base functionality of the OpenCode framework with specialized tools and behaviors.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/.pi-map.index.md
|
index: .opencode/.pi-map.index.md
|
||||||
map: .opencode/.pi-map.md
|
map: .opencode/.pi-map.md
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ dir: .opencode/skills
|
|||||||
index: .opencode/skills/.pi-map.index.md
|
index: .opencode/skills/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains reusable AI skill modules that provide specialized capabilities for the OpenCode assistant.
|
Contains custom AI agent skills or capabilities that extend the base functionality of the OpenCode framework with specialized tools and behaviors.
|
||||||
## files
|
## files
|
||||||
## arch
|
## arch
|
||||||
Modular plugin-based architecture where each skill is a self-contained module with defined interfaces, enabling dynamic loading and composition of AI capabilities.
|
Modular skill plugin architecture where individual capabilities are registered as discrete, composable units that can be dynamically loaded and invoked by the agent system.
|
||||||
## tags
|
## tags
|
||||||
-
|
-
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/skills/openspec-apply-change
|
dir: .opencode/skills/openspec-apply-change
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines an AI assistant skill that implements OpenSpec changes through a spec-driven workflow with structured planning, validation, and execution phases.
|
Provides an AI assistant skill that automates implementation of OpenSpec specification changes through a structured, CLI-driven workflow.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/skills/.pi-map.index.md
|
index: .opencode/skills/.pi-map.index.md
|
||||||
map: .opencode/skills/.pi-map.md
|
map: .opencode/skills/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: .opencode/skills/openspec-apply-change
|
|||||||
index: .opencode/skills/openspec-apply-change/.pi-map.index.md
|
index: .opencode/skills/openspec-apply-change/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines an AI assistant skill that implements OpenSpec changes through a spec-driven workflow with structured planning, validation, and execution phases.
|
Provides an AI assistant skill that automates implementation of OpenSpec specification changes through a structured, CLI-driven workflow.
|
||||||
## files
|
## files
|
||||||
- SKILL.md | Defines an AI assistant skill for implementing tasks from an OpenSpec change using a spec-driven workflow | dep: openspec CLI, AskUserQuestion tool, filesystem access
|
- SKILL.md | Defines an AI assistant skill for implementing tasks from an OpenSpec change using a spec-driven workflow with the openspec CLI. | dep: openspec CLI, AskUserQuestion tool, filesystem access
|
||||||
## arch
|
## arch
|
||||||
Template-based skill definition using markdown documentation with structured workflow phases (planning, validation, execution) and integration points for external tools (OpenSpec CLI, OpenCode agent).
|
Skill-based plugin architecture using markdown-defined capabilities with structured workflow steps (analyze, plan, implement, verify) and external CLI tool integration.
|
||||||
## tags
|
## tags
|
||||||
skill, defines, assistant, implementing, tasks, openspec, change, spec
|
skill, openspec, defines, assistant, implementing, tasks, change, spec
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/skills/openspec-archive-change
|
dir: .opencode/skills/openspec-archive-change
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides a reusable automation skill for archiving completed experimental changes via the openspec CLI
|
Defines an automation skill for archiving completed changes in an experimental workflow using the openspec CLI.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/skills/.pi-map.index.md
|
index: .opencode/skills/.pi-map.index.md
|
||||||
map: .opencode/skills/.pi-map.md
|
map: .opencode/skills/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: .opencode/skills/openspec-archive-change
|
|||||||
index: .opencode/skills/openspec-archive-change/.pi-map.index.md
|
index: .opencode/skills/openspec-archive-change/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides a reusable automation skill for archiving completed experimental changes via the openspec CLI
|
Defines an automation skill for archiving completed changes in an experimental workflow using the openspec CLI.
|
||||||
## files
|
## files
|
||||||
- SKILL.md | Defines a skill for archiving completed changes in an experimental workflow using the openspec CLI. | dep: openspec CLI, AskUserQuestion tool, Task tool, file system (mkdir, mv, read), JSON parsing
|
- SKILL.md | Defines a skill for archiving completed changes in an experimental workflow using the openspec CLI. | dep: openspec CLI, AskUserQuestion tool, Task tool, Skill tool, openspec-sync-specs skill
|
||||||
## arch
|
## arch
|
||||||
Skill-based modular automation pattern using markdown-defined CLI operations with structured metadata and command templates
|
Skill-based plugin architecture following a declarative markdown skill definition pattern for CLI workflow automation.
|
||||||
## tags
|
## tags
|
||||||
skill, defines, archiving, completed, changes, experimental, workflow, openspec
|
skill, openspec, defines, archiving, completed, changes, experimental, workflow
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/skills/openspec-explore
|
dir: .opencode/skills/openspec-explore
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines a conversational AI skill/persona for "explore mode" that serves as a thinking partner for exploring ideas, investigating problems, and clarifying requirements without implementing code.
|
Provides a conversational exploration skill for OpenSpec CLI that enables non-implementation ideation, problem investigation, and requirements clarification.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/skills/.pi-map.index.md
|
index: .opencode/skills/.pi-map.index.md
|
||||||
map: .opencode/skills/.pi-map.md
|
map: .opencode/skills/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: .opencode/skills/openspec-explore
|
|||||||
index: .opencode/skills/openspec-explore/.pi-map.index.md
|
index: .opencode/skills/openspec-explore/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines a conversational AI skill/persona for "explore mode" that serves as a thinking partner for exploring ideas, investigating problems, and clarifying requirements without implementing code.
|
Provides a conversational exploration skill for OpenSpec CLI that enables non-implementation ideation, problem investigation, and requirements clarification.
|
||||||
## files
|
## files
|
||||||
- SKILL.md | Defines a conversational AI skill/persona for "explore mode" - a thinking partner for exploring ideas, investigating problems, and clarifying requirements without implementing code. | dep: openspec CLI
|
- SKILL.md | Defines a conversational "explore mode" skill for OpenSpec CLI that acts as a thinking partner for exploring ideas, investigating problems, and clarifying requirements without implementing code. | dep: openspec CLI
|
||||||
## arch
|
## arch
|
||||||
Single-file skill definition using markdown-based persona specification with structured sections for description, usage guidelines, and behavioral constraints.
|
Skill-based plugin architecture using markdown-defined behavioral specifications with conversational AI patterns, separating exploration/thinking workflows from implementation tasks.
|
||||||
## tags
|
## tags
|
||||||
skill, defines, conversational, persona, explore, mode, thinking, partner
|
skill, defines, conversational, explore, mode, openspec, cli, acts
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .opencode/skills/openspec-propose
|
dir: .opencode/skills/openspec-propose
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides a structured workflow skill for proposing new changes using the openspec CLI with artifact generation in dependency order.
|
Automates the creation of structured software change proposals through a scaffolded directory workflow using the openspec CLI.
|
||||||
## parent
|
## parent
|
||||||
index: .opencode/skills/.pi-map.index.md
|
index: .opencode/skills/.pi-map.index.md
|
||||||
map: .opencode/skills/.pi-map.md
|
map: .opencode/skills/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: .opencode/skills/openspec-propose
|
|||||||
index: .opencode/skills/openspec-propose/.pi-map.index.md
|
index: .opencode/skills/openspec-propose/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides a structured workflow skill for proposing new changes using the openspec CLI with artifact generation in dependency order.
|
Automates the creation of structured software change proposals through a scaffolded directory workflow using the openspec CLI.
|
||||||
## files
|
## files
|
||||||
- SKILL.md | Defines a structured workflow for proposing new changes using the openspec CLI, generating proposal, design, and task artifacts in dependency order. | dep: openspec CLI, AskUserQuestion tool, TodoWrite tool
|
- SKILL.md | Defines an AI skill that automates proposing new software changes by scaffolding a directory structure and generating dependent artifacts (proposal, design, tasks) using the openspec CLI workflow. | dep: openspec CLI, AskUserQuestion tool, TodoWrite tool
|
||||||
## arch
|
## arch
|
||||||
Template-based skill definition using markdown documentation with sequential artifact generation (proposal → design → tasks) following dependency ordering.
|
Template-driven skill architecture following a sequential artifact generation pattern (proposal → design → tasks) with CLI-based workflow automation.
|
||||||
## tags
|
## tags
|
||||||
skill, defines, structured, workflow, proposing, new, changes, openspec
|
skill, defines, automates, proposing, new, software, changes, scaffolding
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
+4
-7
@@ -16,7 +16,7 @@ dir: .
|
|||||||
Trust boundary: index routes, map orients, source decides.
|
Trust boundary: index routes, map orients, source decides.
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing containerized orchestration, environment templates, and development tooling.
|
A self-hosted web platform for managing projects, git repositories, and development tools with OAuth2 authentication, built as a Dockerized multi-service application.
|
||||||
## parent
|
## parent
|
||||||
-
|
-
|
||||||
## children
|
## children
|
||||||
@@ -47,9 +47,6 @@ Infrastructure and deployment configuration package for a self-hosted project ma
|
|||||||
- e2e
|
- e2e
|
||||||
index: e2e/.pi-map.index.md
|
index: e2e/.pi-map.index.md
|
||||||
map: e2e/.pi-map.md
|
map: e2e/.pi-map.md
|
||||||
- minerv3
|
|
||||||
index: minerv3/.pi-map.index.md
|
|
||||||
map: minerv3/.pi-map.md
|
|
||||||
- openspec
|
- openspec
|
||||||
index: openspec/.pi-map.index.md
|
index: openspec/.pi-map.index.md
|
||||||
map: openspec/.pi-map.md
|
map: openspec/.pi-map.md
|
||||||
@@ -59,9 +56,6 @@ Infrastructure and deployment configuration package for a self-hosted project ma
|
|||||||
- tool-images
|
- tool-images
|
||||||
index: tool-images/.pi-map.index.md
|
index: tool-images/.pi-map.index.md
|
||||||
map: tool-images/.pi-map.md
|
map: tool-images/.pi-map.md
|
||||||
- uploads
|
|
||||||
index: uploads/.pi-map.index.md
|
|
||||||
map: uploads/.pi-map.md
|
|
||||||
## files
|
## files
|
||||||
- .env.example
|
- .env.example
|
||||||
- .gitignore
|
- .gitignore
|
||||||
@@ -73,6 +67,9 @@ Infrastructure and deployment configuration package for a self-hosted project ma
|
|||||||
- docker-compose.yml
|
- docker-compose.yml
|
||||||
- progress.md
|
- progress.md
|
||||||
- swap-pane
|
- swap-pane
|
||||||
|
- ui-audit-spacing-typography.md
|
||||||
|
- ui-rework-foundations-apply.md
|
||||||
|
- ui-rework-pass2-apply.md
|
||||||
## links
|
## links
|
||||||
index: ./.pi-map.index.md
|
index: ./.pi-map.index.md
|
||||||
map: ./.pi-map.md
|
map: ./.pi-map.md
|
||||||
|
|||||||
+16
-13
@@ -18,22 +18,25 @@ index: ./.pi-map.index.md
|
|||||||
Trust boundary: index routes, map orients, source decides.
|
Trust boundary: index routes, map orients, source decides.
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing containerized orchestration, environment templates, and development tooling.
|
A self-hosted web platform for managing projects, git repositories, and development tools with OAuth2 authentication, built as a Dockerized multi-service application.
|
||||||
## files
|
## files
|
||||||
- .env.example | Provides a template of environment variables for configuring a Headquarter application with PostgreSQL, Redis, Authentik SSO, and Docker/Traefik deployment
|
- .env.example | Template environment configuration file defining all required and optional environment variables for a multi-service application stack
|
||||||
- .gitignore | Specifies files and directories for Git to ignore across a multi-language project with Python, Node, and custom tooling | dep: Git
|
- .gitignore | Specifies patterns for files and directories that Git should ignore in this project. | dep: git
|
||||||
- AGENTS.md | Defines operational rules, workflows, and constraints for AI agents working within an OpenSpec-driven software development project. | dep: OpenSpec, superpowers, git, docker compose, conventional commits
|
- AGENTS.md | Defines agent behavior rules, workflow procedures, and project conventions for AI agents working on an OpenSpec-driven codebase. | dep: OpenSpec, git, superpowers workflow system, conventional commits
|
||||||
- CHANGELOG.md | Documents version history and notable changes for a Git-based project management web application
|
- CHANGELOG.md | Documents version history and notable changes to a project management and Git repository application
|
||||||
- Makefile | Provides standard development commands for containerized web application lifecycle management via Docker Compose | dep: docker compose, alembic, pytest, ruff, mypy, playwright, npm, postgres, redis
|
- Makefile | Provides standard development commands for managing a Docker Compose-based multi-service application (API, web, Postgres, Redis) with testing, migration, linting, and build automation. | dep: docker compose, alembic, pytest, ruff, mypy, playwright, npm/node
|
||||||
- README.md | A self-hosted platform for managing projects, git repositories, and development tools with OAuth2 authentication. | dep: FastAPI, SQLAlchemy, Pydantic, Alembic, python-jose, React, TypeScript, Vite, React Router, Docker, PostgreSQL, Traefik, Authentik, Git
|
- README.md | A self-hosted platform for managing projects, git repositories, and development tools with OAuth2 authentication. | dep: FastAPI, SQLAlchemy, Pydantic, Alembic, python-jose, React, TypeScript, Vite, React Router, Docker, PostgreSQL, Traefik, Authentik
|
||||||
- docker-compose.traefik.yml | Deploys a multi-service web application (frontend, API, PostgreSQL, Redis) behind an existing Traefik reverse proxy with TLS termination and environment-configurable domains. | dep: docker, traefik, postgres, redis, authentik, docker-compose
|
- docker-compose.traefik.yml | Deploys a multi-service web application stack (frontend, API, PostgreSQL, Redis) behind an existing Traefik reverse proxy with automatic HTTPS | dep: Docker, Docker Compose, Traefik, PostgreSQL, Redis, Authentik
|
||||||
- docker-compose.yml | Defines a multi-service Docker Compose stack with PostgreSQL, Redis, API backend, and web frontend services for a "headquarter" application | dep: Docker, PostgreSQL, Redis, Vite, asyncpg, nginx
|
- docker-compose.yml | Defines a multi-container Docker application with PostgreSQL, Redis, API backend, and web frontend services for a "headquarter" application. | dep: Docker Compose, PostgreSQL 15, Redis 7, Python/FastAPI (implied by asyncpg), Vite/Node.js (implied by web build), Alpine Linux
|
||||||
- progress.md | Tracks completed and remaining tasks for a backend-frontend code refactoring project organized in 7 phases
|
- progress.md | Documents the completed phases and remaining work of a backend-frontend code refactoring project involving modularization, subpackage extraction, and file reorganization.
|
||||||
- swap-pane | Empty file with no functionality
|
- swap-pane | Swaps two tmux panes between windows, preserving active pane state and layout | dep: tmux
|
||||||
|
- ui-audit-spacing-typography.md | Documents a comprehensive UI audit of spacing, typography, and visual rhythm issues in a React web application, identifying missing CSS classes, unstyled mobile components, inconsistent design tokens, and layout bugs across component and stylesheet files. | dep: React/TSX components, CSS modules/stylesheets, CSS custom properties (tokens), mobile-specific components, design system tokens
|
||||||
|
- ui-rework-foundations-apply.md | Documents the implementation of Pass 1 (Foundations) of a web UI spacing/typography/visual-rhythm rework, including token expansion, primitive CSS classes, component updates, and validation results. | dep: CSS design tokens, React/TSX components, OpenSpec documentation system, git/SSH, npm build toolchain
|
||||||
|
- ui-rework-pass2-apply.md | Documents a completed web UI refactoring pass that converted inline styles to token-based utility classes, unified form patterns, and added component utilities across multiple React components. | dep: React, CSS custom properties, OpenSpec, Git, npm, TypeScript, ESLint
|
||||||
## arch
|
## arch
|
||||||
Docker Compose-based microservices architecture with frontend/backend separation, PostgreSQL/Redis data layer, Traefik reverse proxy integration, and environment-driven configuration management following twelve-factor app principles.
|
Full-stack monolithic architecture with React frontend, API backend, PostgreSQL and Redis services, containerized via Docker Compose, using Traefik for reverse proxy/HTTPS, and following a token-based design system for UI consistency.
|
||||||
## tags
|
## tags
|
||||||
docker, redis, git, application, postgresql, compose, traefik, project
|
docker, application, git, web, react, ui, documents, rework
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .stoneforge
|
dir: .stoneforge
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Internal configuration and state tracking directory for the Stoneforge application
|
Infrastructure configuration and metadata storage for the Stoneforge tool
|
||||||
## parent
|
## parent
|
||||||
index: ./.pi-map.index.md
|
index: ./.pi-map.index.md
|
||||||
map: ./.pi-map.md
|
map: ./.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: .stoneforge
|
|||||||
index: .stoneforge/.pi-map.index.md
|
index: .stoneforge/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Internal configuration and state tracking directory for the Stoneforge application
|
Infrastructure configuration and metadata storage for the Stoneforge tool
|
||||||
## files
|
## files
|
||||||
- .dashboard-opened | Stores timestamp and identifier data for tracking when a dashboard was opened
|
- .dashboard-opened | Stores timestamp metadata for tracking when a dashboard was opened
|
||||||
- .gitignore | Specifies files and patterns for Git to ignore in version control
|
- .gitignore | Specifies files and patterns for Git to ignore in the repository | dep: git
|
||||||
- config.yaml | Configuration file for the Stoneforge application defining database, sync, playbook, identity, merge, workflow, and agent settings.
|
- config.yaml | YAML configuration file defining settings for the Stoneforge tool, including database, sync, playbooks, identity, merge, workflow, and agent permissions.
|
||||||
## arch
|
## arch
|
||||||
Simple dot-directory pattern storing metadata (.dashboard-opened), version control exclusions (.gitignore), and hierarchical YAML configuration (config.yaml) with domain-separated settings
|
Dot-directory pattern for tool-specific state, using YAML for hierarchical configuration and dotfiles for ephemeral runtime metadata
|
||||||
## tags
|
## tags
|
||||||
config, stores, timestamp, identifier, data, tracking, dashboard, was
|
git, config, stores, timestamp, metadata, tracking, dashboard, was
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: .stoneforge/sync
|
dir: .stoneforge/sync
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Persists distributed task execution state by storing dependency graphs and ephemeral worker agent records for a collaborative workflow system.
|
Provides persistent storage for entity relationships and AI worker agent records in a synchronization system.
|
||||||
## parent
|
## parent
|
||||||
index: .stoneforge/.pi-map.index.md
|
index: .stoneforge/.pi-map.index.md
|
||||||
map: .stoneforge/.pi-map.md
|
map: .stoneforge/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: .stoneforge/sync
|
|||||||
index: .stoneforge/sync/.pi-map.index.md
|
index: .stoneforge/sync/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Persists distributed task execution state by storing dependency graphs and ephemeral worker agent records for a collaborative workflow system.
|
Provides persistent storage for entity relationships and AI worker agent records in a synchronization system.
|
||||||
## files
|
## files
|
||||||
- dependencies.jsonl | Stores a sequence of dependency relationships between entities in JSON Lines format, tracking parent-child, blocking, and reply relationships with timestamps and creators.
|
- dependencies.jsonl | Stores dependency relationships between entities in JSONL format, including parent-child, blocking, and reply-to relationships with timestamps and creators.
|
||||||
- elements.jsonl | Stores JSONL records of ephemeral worker agents with their session history, worktree assignments, and lifecycle metadata for a distributed task execution system.
|
- elements.jsonl | Stores JSONL-formatted entity records for AI worker agents with their session histories and metadata in a data persistence file.
|
||||||
## arch
|
## arch
|
||||||
Event-sourced JSONL append-only logs with entity-relationship modeling (parent-child, blocking, reply) and session-based worker lifecycle tracking.
|
Append-only JSONL document store with separate files for dependency graph edges (dependencies.jsonl) and entity nodes (elements.jsonl), using a log-structured data pattern for time-ordered, immutable record keeping.
|
||||||
## tags
|
## tags
|
||||||
stores, relationships, dependencies, elements, sequence, dependency, entities, json
|
stores, relationships, jsonl, dependencies, elements, dependency, entities, format
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps
|
dir: apps
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains the main deployable application modules or entry points for the project.
|
Contains the main application entry points and executable modules for the project.
|
||||||
## parent
|
## parent
|
||||||
index: ./.pi-map.index.md
|
index: ./.pi-map.index.md
|
||||||
map: ./.pi-map.md
|
map: ./.pi-map.md
|
||||||
|
|||||||
+2
-2
@@ -4,10 +4,10 @@ dir: apps
|
|||||||
index: apps/.pi-map.index.md
|
index: apps/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Contains the main deployable application modules or entry points for the project.
|
Contains the main application entry points and executable modules for the project.
|
||||||
## files
|
## files
|
||||||
## arch
|
## arch
|
||||||
Modular monolith or microservices architecture with separate application boundaries, each potentially having its own configuration, dependencies, and lifecycle.
|
Modular application structure with separate deployable units, likely following microservices or multi-app monorepo pattern with shared infrastructure.
|
||||||
## tags
|
## tags
|
||||||
-
|
-
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api
|
dir: apps/api
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Self-hosted FastAPI backend API that manages projects, git repositories, and development tools via Docker instances.
|
FastAPI-based backend API service for managing projects, git repositories, and development tools in a self-hosted development platform.
|
||||||
## parent
|
## parent
|
||||||
index: apps/.pi-map.index.md
|
index: apps/.pi-map.index.md
|
||||||
map: apps/.pi-map.md
|
map: apps/.pi-map.md
|
||||||
@@ -10,12 +10,6 @@ map: apps/.pi-map.md
|
|||||||
- apps/api/.pi-lens
|
- apps/api/.pi-lens
|
||||||
index: apps/api/.pi-lens/.pi-map.index.md
|
index: apps/api/.pi-lens/.pi-map.index.md
|
||||||
map: apps/api/.pi-lens/.pi-map.md
|
map: apps/api/.pi-lens/.pi-map.md
|
||||||
- apps/api/.pytest_cache
|
|
||||||
index: apps/api/.pytest_cache/.pi-map.index.md
|
|
||||||
map: apps/api/.pytest_cache/.pi-map.md
|
|
||||||
- apps/api/.venv-test
|
|
||||||
index: apps/api/.venv-test/.pi-map.index.md
|
|
||||||
map: apps/api/.venv-test/.pi-map.md
|
|
||||||
- apps/api/alembic
|
- apps/api/alembic
|
||||||
index: apps/api/alembic/.pi-map.index.md
|
index: apps/api/alembic/.pi-map.index.md
|
||||||
map: apps/api/alembic/.pi-map.md
|
map: apps/api/alembic/.pi-map.md
|
||||||
|
|||||||
+10
-10
@@ -4,19 +4,19 @@ dir: apps/api
|
|||||||
index: apps/api/.pi-map.index.md
|
index: apps/api/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Self-hosted FastAPI backend API that manages projects, git repositories, and development tools via Docker instances.
|
FastAPI-based backend API service for managing projects, git repositories, and development tools in a self-hosted development platform.
|
||||||
## files
|
## files
|
||||||
- .dockerignore | Specifies files and directories to exclude from Docker build context to reduce image size and avoid copying unnecessary files into containers. | dep: Docker
|
- .dockerignore | Specifies files and directories to exclude from Docker build context to reduce image size and improve build performance. | dep: Docker
|
||||||
- Dockerfile | Multi-stage Docker build for a Python application with Docker socket access, Cloudflare tunneling, and database dependency waiting | dep: python:3.11-slim, gcc, libpq-dev, docker-ce-cli, docker-compose-plugin, cloudflared, uvicorn, pyproject.toml dependencies
|
- Dockerfile | Multi-stage Docker image for a Python web application with Docker-in-Docker capabilities, database waiting, and Cloudflare tunnel support | dep: python:3.11-slim, gcc, libpq-dev, docker-ce-cli, docker-compose-plugin, cloudflared, uvicorn, pyproject.toml dependencies
|
||||||
- README.md | Documentation for a self-hosted FastAPI backend API that manages projects, git repositories, and development tools via Docker instances. | dep: FastAPI, SQLAlchemy, PostgreSQL, asyncpg, Alembic, Docker, Docker Compose, Authentik, uvicorn, pytest, ruff, mypy
|
- README.md | README documentation for Headquarter API, a self-hosted FastAPI backend for managing projects, git repositories, and development tools. | dep: FastAPI, SQLAlchemy, PostgreSQL, asyncpg, Alembic, Docker, Docker Compose, Authentik, uvicorn, pytest, ruff, mypy
|
||||||
- alembic.ini | Configuration file for Alembic database migration tool connecting to a PostgreSQL database with async driver | dep: alembic, sqlalchemy, asyncpg, PostgreSQL
|
- alembic.ini | Configuration file for Alembic database migration tool specifying script location, database connection URL, and logging settings | dep: alembic, sqlalchemy, asyncpg, postgresql
|
||||||
- pyproject.toml | Defines Python project metadata, dependencies, and tool configurations for a FastAPI-based backend API called "headquarter-api" | dep: fastapi, uvicorn, sqlalchemy, asyncpg, alembic, pydantic, pydantic-settings, python-multipart, httpx, structlog, cryptography, pytest, pytest-asyncio, mypy, ruff, aiosqlite
|
- pyproject.toml | Defines Python project configuration, dependencies, and tool settings for a FastAPI-based backend API service | dep: fastapi, uvicorn, sqlalchemy, asyncpg, alembic, pydantic, pydantic-settings, python-multipart, httpx, structlog, cryptography, pytest, pytest-asyncio, mypy, ruff, aiosqlite
|
||||||
- uv.lock | Lock file for the uv Python package manager that pins exact dependency versions and their artifact hashes for reproducible installations | dep: uv, Python 3.11+, aiosqlite, alembic, annotated-doc, annotated-types, anyio, ast-serialize, asyncpg, and many other PyPI packages
|
- uv.lock | Lock file generated by uv package manager that records exact dependency versions, hashes, and download URLs for reproducible Python environment installation | dep: uv, PyPI, python
|
||||||
- wait-for-db.sh | Wait for a PostgreSQL database to become available before executing a command, with configurable retry logic. | dep: nc (netcat), sh (POSIX shell), sleep
|
- wait-for-db.sh | Waits for a PostgreSQL database to become available before executing the provided command | dep: nc (netcat), sh, sleep
|
||||||
## arch
|
## arch
|
||||||
Async Python/FastAPI with PostgreSQL (Alembic migrations), multi-stage Docker deployment with Cloudflare tunneling, uv package management, and containerized service orchestration.
|
Modern Python backend with FastAPI, SQLAlchemy/ORM with Alembic migrations, uv for dependency management, multi-stage Docker containerization with Docker-in-Docker support, and PostgreSQL database connectivity.
|
||||||
## tags
|
## tags
|
||||||
docker, alembic, python, database, fastapi, postgresql, asyncpg, uvicorn
|
docker, alembic, python, database, fastapi, uvicorn, pyproject, readme
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/alembic
|
dir: apps/api/alembic
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Database migration infrastructure for the API application, providing version-controlled schema evolution with async SQLAlchemy support.
|
Database migration infrastructure for the API application, enabling version-controlled schema changes with async database support.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/.pi-map.index.md
|
index: apps/api/.pi-map.index.md
|
||||||
map: apps/api/.pi-map.md
|
map: apps/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/alembic
|
|||||||
index: apps/api/alembic/.pi-map.index.md
|
index: apps/api/alembic/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Database migration infrastructure for the API application, providing version-controlled schema evolution with async SQLAlchemy support.
|
Database migration infrastructure for the API application, enabling version-controlled schema changes with async database support.
|
||||||
## files
|
## files
|
||||||
- env.py | Configures Alembic database migration environment with async SQLAlchemy support for a project. | exp: func:run_migrations_offline() → None, call:context.configure, call:context.begin_transaction, call:context.run_migrations, func:do_run_migrations(connection: Connection) → None, call:context.configure, call:context.begin_transaction, call:context.run_migrations, func:run_async_migrations() → None, call:async_engine_from_config, call:config.get_section, call:connectable.connect, call:connection.run_sync, call:connectable.dispose, func:run_migrations_online() → None, call:asyncio.run, call:run_async_migrations | dep: logging.config, alembic, sqlalchemy, sqlalchemy.engine, sqlalchemy.ext.asyncio, src.config, src.models, asyncio
|
- env.py | Configures Alembic database migration environment with async SQLAlchemy support | exp: func:run_migrations_offline() → None, call:context.configure, call:context.begin_transaction, call:context.run_migrations, func:do_run_migrations(connection: Connection) → None, call:context.configure, call:context.begin_transaction, call:context.run_migrations, func:run_async_migrations() → None, call:async_engine_from_config, call:config.get_section, call:connectable.connect, call:connection.run_sync, call:connectable.dispose, func:run_migrations_online() → None, call:asyncio.run, call:run_async_migrations | dep: logging.config, alembic, sqlalchemy, sqlalchemy.engine, sqlalchemy.ext.asyncio, src.config, src.models, asyncio
|
||||||
- script.py.mako | Alembic database migration script template that generates upgrade/downgrade functions for SQLAlchemy schema migrations | dep: alembic, sqlalchemy
|
- script.py.mako | Alembic database migration script template that generates upgrade/downgrade functions for SQL schema revisions | dep: alembic, sqlalchemy
|
||||||
## arch
|
## arch
|
||||||
Alembic migration framework with Mako templating for generating revision scripts, async SQLAlchemy engine configuration, and autogenerate capabilities for schema change tracking.
|
Template-based migration generation using Alembic with async SQLAlchemy engine configuration and environment setup.
|
||||||
## tags
|
## tags
|
||||||
migrations, run, sqlalchemy, async, alembic, call:context.configure, call:context.begin, transaction
|
migrations, run, async, sqlalchemy, alembic, call:context.configure, call:context.begin, transaction
|
||||||
## symbols
|
## symbols
|
||||||
- run_migrations_offline
|
- run_migrations_offline
|
||||||
- do_run_migrations
|
- do_run_migrations
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/alembic/versions
|
dir: apps/api/alembic/versions
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Manages incremental database schema evolution for the API application using Alembic migrations, tracking all table creations, column additions, relationship changes, and data transformations over the project's lifecycle.
|
Manages database schema evolution and version control for the API application using Alembic migration scripts.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/alembic/.pi-map.index.md
|
index: apps/api/alembic/.pi-map.index.md
|
||||||
map: apps/api/alembic/.pi-map.md
|
map: apps/api/alembic/.pi-map.md
|
||||||
@@ -48,6 +48,9 @@ map: apps/api/alembic/.pi-map.md
|
|||||||
- 2026_05_29_remove_ssh_keys_mount_from_manifest.py
|
- 2026_05_29_remove_ssh_keys_mount_from_manifest.py
|
||||||
- 2026_06_01_add_workspaces.py
|
- 2026_06_01_add_workspaces.py
|
||||||
- 2026_06_13_make_clone_mode_nullable.py
|
- 2026_06_13_make_clone_mode_nullable.py
|
||||||
|
- 2026_06_14_104415_add_tool_type_home_directory.py
|
||||||
|
- 2026_06_14_182955_fix_pi_agent_home_directory_mount.py
|
||||||
|
- 2026_06_15_090500_remove_pi_agent_explicit_repo_mount.py
|
||||||
- 398082499c30_add_tool_config_fields.py
|
- 398082499c30_add_tool_config_fields.py
|
||||||
- 6fc7bfcf199f_merge_remove_is_builtin_and_add_config_.py
|
- 6fc7bfcf199f_merge_remove_is_builtin_and_add_config_.py
|
||||||
- 86cec91fdb00_merge_profile_resolver_and_workspaces_.py
|
- 86cec91fdb00_merge_profile_resolver_and_workspaces_.py
|
||||||
@@ -55,6 +58,7 @@ map: apps/api/alembic/.pi-map.md
|
|||||||
- 8ed7dd80973d_create_config_folders_table.py
|
- 8ed7dd80973d_create_config_folders_table.py
|
||||||
- af8512103d67_add_tool_type_fields.py
|
- af8512103d67_add_tool_type_fields.py
|
||||||
- f3d2dc90ba3a_merge_single_interface_and_clone_mode.py
|
- f3d2dc90ba3a_merge_single_interface_and_clone_mode.py
|
||||||
|
- fc8f1a20cbf6_merge_home_directory_and_pi_agent_mount_.py
|
||||||
## links
|
## links
|
||||||
index: apps/api/alembic/versions/.pi-map.index.md
|
index: apps/api/alembic/versions/.pi-map.index.md
|
||||||
map: apps/api/alembic/versions/.pi-map.md
|
map: apps/api/alembic/versions/.pi-map.md
|
||||||
|
|||||||
@@ -4,58 +4,62 @@ dir: apps/api/alembic/versions
|
|||||||
index: apps/api/alembic/versions/.pi-map.index.md
|
index: apps/api/alembic/versions/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Manages incremental database schema evolution for the API application using Alembic migrations, tracking all table creations, column additions, relationship changes, and data transformations over the project's lifecycle.
|
Manages database schema evolution and version control for the API application using Alembic migration scripts.
|
||||||
## files
|
## files
|
||||||
- 0001_initial_schema.py | Defines the initial database schema migration creating five tables (users, ssh_keys, projects, git_repositories, user_configs) with relationships, indexes, and constraints using Alembic. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.String, call:postgresql.UUID, call:sa.DateTime, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:op.create_index, call:op.f, call:sa.Text, call:sa.ForeignKeyConstraint, call:sa.Boolean, call:postgresql.JSONB, func:downgrade() → None, call:op.drop_table, call:op.drop_index, call:op.f | dep: alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
- 0001_initial_schema.py | Creates the initial database schema with five tables (users, ssh_keys, projects, git_repositories, user_configs) using Alembic migrations | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.String, call:postgresql.UUID, call:sa.DateTime, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:op.create_index, call:op.f, call:sa.Text, call:sa.ForeignKeyConstraint, call:sa.Boolean, call:postgresql.JSONB, func:downgrade() → None, call:op.drop_table, call:op.drop_index, call:op.f | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 0002_refresh_tokens.py | Alembic database migration that creates a refresh_tokens table with indexes for user authentication token management | exp: func:upgrade() → None, call:op.get_bind, call:sa.inspect, call:inspector.has_table, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.String, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:inspector.get_indexes, call:op.f, call:op.create_index, func:downgrade() → None, call:op.get_bind, call:sa.inspect, call:inspector.has_table, call:inspector.get_indexes, call:op.f, call:op.drop_index, call:op.drop_table | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 0002_refresh_tokens.py | Alembic database migration that creates a refresh_tokens table with indexes for user authentication/session management | exp: func:upgrade() → None, call:op.get_bind, call:sa.inspect, call:inspector.has_table, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.String, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:inspector.get_indexes, call:op.f, call:op.create_index, func:downgrade() → None, call:op.get_bind, call:sa.inspect, call:inspector.has_table, call:inspector.get_indexes, call:op.f, call:op.drop_index, call:op.drop_table | dep: alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
||||||
- 0003_user_configs.py | Alembic database migration that creates a user_configs table with JSON configuration storage linked to users | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.JSON, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, func:downgrade() → None, call:op.drop_table | dep: typing, alembic, sqlalchemy
|
- 0003_user_configs.py | Alembic database migration that creates a user_configs table with JSON configuration storage linked to users via foreign key | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.JSON, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, func:downgrade() → None, call:op.drop_table | dep: typing, alembic, sqlalchemy
|
||||||
- 0004_tool_types.py | Alembic database migration that creates a tool_types table with metadata, templates, and versioning columns for a tool management system. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.ForeignKey, call:sa.DateTime, call:sa.text, func:downgrade() → None, call:op.drop_table | dep: typing, alembic, sqlalchemy
|
- 0004_tool_types.py | Alembic database migration that creates a tool_types table with metadata, templates, and user relationship columns | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.ForeignKey, call:sa.DateTime, call:sa.text, func:downgrade() → None, call:op.drop_table | dep: typing, alembic, sqlalchemy
|
||||||
- 0005_ssh_keys_timestamps.py | Alembic database migration that adds created_at and updated_at timestamp columns to the ssh_keys table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.DateTime, call:sa.text, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 0005_ssh_keys_timestamps.py | Alembic database migration that adds created_at and updated_at timestamp columns to the ssh_keys table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.DateTime, call:sa.text, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 0006_tool_instances.py | Alembic database migration that creates a tool_instances table with columns for tracking deployed tool instances, their status, container info, and foreign key relationships to tool_types, git_repositories, projects, and users. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.String, call:sa.Integer, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 0006_tool_instances.py | Alembic database migration that creates a tool_instances table with UUID primary key, foreign key relationships, timestamps, and indexes for tracking deployed tool instances | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.String, call:sa.Integer, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
||||||
- 0007_instance_container_name.py | Alembic database migration that adds a nullable container_name column to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 0007_instance_container_name.py | Alembic database migration that adds a nullable container_name column to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 0008_tool_type_category.py | Alembic database migration that adds `category` and `interfaces` columns to the `tool_types` table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 0008_tool_type_category.py | Alembic database migration that adds 'category' and 'interfaces' columns to the 'tool_types' table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 0009_tool_configs.py | Alembic database migration that creates a tool_configs table with UUID keys, foreign key relationships, and indexes for storing user/project tool configuration settings. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.String, call:sa.Text, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
- 0009_tool_configs.py | Alembic database migration that creates a tool_configs table for storing user tool configuration key-value pairs with optional project scoping | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.String, call:sa.Text, call:sa.DateTime, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 0010_tool_type_default_port.py | Alembic database migration that adds a nullable default_port column to the tool_types table. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Integer, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 0010_tool_type_default_port.py | Alembic database migration that adds a nullable default_port column to the tool_types table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Integer, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 0011_tool_instance_tunnel_fields.py | Alembic database migration that adds tunnel-related fields (public_url and tunnel_id) to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 0011_tool_instance_tunnel_fields.py | Alembic database migration that adds public_url and tunnel_id columns to the tool_instances table for tunnel functionality. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 0012_default_port_req.py | Alembic database migration that populates null default_port values for existing tool types and then makes the column non-nullable | exp: func:upgrade() → None, call:op.execute, call:op.alter_column, call:sa.Integer, func:downgrade() → None, call:op.alter_column, call:sa.Integer | dep: typing, alembic, sqlalchemy
|
- 0012_default_port_req.py | Alembic database migration that backfills default_port values for existing tool types and makes the column non-nullable | exp: func:upgrade() → None, call:op.execute, call:op.alter_column, call:sa.Integer, func:downgrade() → None, call:op.alter_column, call:sa.Integer | dep: typing, alembic, sqlalchemy
|
||||||
- 0013_add_config_profiles.py | Alembic database migration that adds config profiles, includes, mounts tables and links tool instances to profiles with defensive idempotent checks | exp: func:_table_exists(table_name: str) → bool, call:sa.inspect(op.get_bind()).has_table, call:op.get_bind, func:_column_exists(table_name: str, column_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_columns, call:op.get_bind, func:_index_exists(table_name: str, index_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_indexes, call:op.get_bind, func:_foreign_key_exists(table_name: str, constrained_columns: list[str], referred_table: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, func:upgrade() → None, call:_table_exists, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.String, call:sa.Text, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:_index_exists, call:op.create_index, call:sa.Integer, call:_column_exists, call:op.add_column, call:_foreign_key_exists, call:op.create_foreign_key, func:downgrade() → None, call:op.drop_index, call:op.drop_constraint, call:op.drop_column, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 0013_add_config_profiles.py | Database migration that adds config profiles, profile includes, profile mounts, and tool instance profile selection tables with defensive idempotent checks | exp: func:_table_exists(table_name: str) → bool, call:sa.inspect(op.get_bind()).has_table, call:op.get_bind, func:_column_exists(table_name: str, column_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_columns, call:op.get_bind, func:_index_exists(table_name: str, index_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_indexes, call:op.get_bind, func:_foreign_key_exists(table_name: str, constrained_columns: list[str], referred_table: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, func:upgrade() → None, call:_table_exists, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.String, call:sa.Text, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:_index_exists, call:op.create_index, call:sa.Integer, call:_column_exists, call:op.add_column, call:_foreign_key_exists, call:op.create_foreign_key, func:downgrade() → None, call:op.drop_index, call:op.drop_constraint, call:op.drop_column, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 0013_add_probe_result.py | Alembic database migration that adds a JSON probe_result column to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 0013_add_probe_result.py | Alembic database migration that adds a JSON probe_result column to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 0014_add_profile_resolver_fields.py | Alembic database migration that adds profile resolver fields (project_id, tool_type_id, environment_variables, etc.) to config_profiles table and restructures config_mounts table (renaming mount_path to target_path, adding mode/files, removing content/source_profile_id). | exp: func:_table_exists(table_name: str) → bool, call:sa.inspect(op.get_bind()).has_table, call:op.get_bind, func:_column_exists(table_name: str, column_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_columns, call:op.get_bind, func:_index_exists(table_name: str, index_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_indexes, call:op.get_bind, func:_foreign_key_exists(table_name: str, constrained_columns: list[str], referred_table: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, func:_foreign_key_names_for_column(table_name: str, column_name: str) → list[str], call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, call:names.append, func:upgrade() → None, call:_column_exists, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:sa.JSON, call:sa.Text, call:sa.Integer, call:sa.Boolean, call:_foreign_key_exists, call:op.create_foreign_key, call:_index_exists, call:op.create_index, call:op.alter_column, call:sa.String, call:_foreign_key_names_for_column, call:op.drop_constraint, call:op.drop_column, func:downgrade() → None, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:sa.Text, call:op.drop_column, call:op.alter_column, call:op.drop_index, call:op.drop_constraint | dep: collections.abc, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 0014_add_profile_resolver_fields.py | Alembic database migration that adds profile resolver fields (project_id, tool_type_id, environment_variables, start_command, working_directory, port, is_default) to config_profiles table, renames mount_path to target_path and adds mode/files columns to config_mounts table while removing source_profile_id and content columns | exp: func:_table_exists(table_name: str) → bool, call:sa.inspect(op.get_bind()).has_table, call:op.get_bind, func:_column_exists(table_name: str, column_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_columns, call:op.get_bind, func:_index_exists(table_name: str, index_name: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_indexes, call:op.get_bind, func:_foreign_key_exists(table_name: str, constrained_columns: list[str], referred_table: str) → bool, call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, func:_foreign_key_names_for_column(table_name: str, column_name: str) → list[str], call:_table_exists, call:sa.inspect(op.get_bind()).get_foreign_keys, call:op.get_bind, call:foreign_key.get, call:names.append, func:upgrade() → None, call:_column_exists, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:sa.JSON, call:sa.Text, call:sa.Integer, call:sa.Boolean, call:_foreign_key_exists, call:op.create_foreign_key, call:_index_exists, call:op.create_index, call:op.alter_column, call:sa.String, call:_foreign_key_names_for_column, call:op.drop_constraint, call:op.drop_column, func:downgrade() → None, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:sa.Text, call:op.drop_column, call:op.alter_column, call:op.drop_index, call:op.drop_constraint | dep: collections.abc, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 0014_merge_heads.py | Alembic merge migration that reconciles two divergent migration branches into a single history line | exp: func:upgrade() → None, func:downgrade() → None | dep: typing, alembic
|
- 0014_merge_heads.py | Alembic merge migration that combines two divergent migration branches into a single history line | exp: func:upgrade() → None, func:downgrade() → None | dep: typing, alembic
|
||||||
- 0015_single_interface.py | Alembic database migration that replaces a JSON array `interfaces` column with `interface_type` string and `requires_port` boolean columns in the `tool_types` table, with dialect-specific data migration for PostgreSQL and SQLite. | exp: func:_get_dialect() → str, call:op.get_bind, func:upgrade() → None, call:_get_dialect, call:op.add_column, call:sa.Column, call:sa.String, call:sa.Boolean, call:op.execute, call:op.alter_column, call:op.drop_column, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:_get_dialect, call:op.drop_constraint, call:op.add_column, call:sa.Column, call:postgresql.JSONB, call:sa.Text, call:op.execute, call:sa.JSON, call:op.drop_column | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, postgresql (dialect)
|
- 0015_single_interface.py | Alembic database migration that replaces a plural JSON interfaces column with singular interface_type and requires_port columns on tool_types table | exp: func:_get_dialect() → str, call:op.get_bind, func:upgrade() → None, call:_get_dialect, call:op.add_column, call:sa.Column, call:sa.String, call:sa.Boolean, call:op.execute, call:op.alter_column, call:op.drop_column, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:_get_dialect, call:op.drop_constraint, call:op.add_column, call:sa.Column, call:postgresql.JSONB, call:sa.Text, call:op.execute, call:sa.JSON, call:op.drop_column | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 069d3da4dc9b_add_ssh_key_id_to_config_profiles.py | Alembic database migration that adds a nullable UUID foreign key column `ssh_key_id` to the `config_profiles` table referencing `ssh_keys.id` with SET NULL on delete | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Uuid, call:sa.ForeignKey, func:downgrade() → None, call:op.drop_column | dep: alembic, sqlalchemy
|
- 069d3da4dc9b_add_ssh_key_id_to_config_profiles.py | Alembic database migration that adds an ssh_key_id foreign key column to the config_profiles table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Uuid, call:sa.ForeignKey, func:downgrade() → None, call:op.drop_column | dep: alembic, sqlalchemy
|
||||||
- 20260527160017_add_pi_agent_tool_type.py | Alembic database migration that adds a "pi-agent" terminal-based coding tool type to a tool_types table with Docker configuration templates | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text("SELECT id FROM tool_types WHERE name = 'pi-agent'") ).fetchone, call:sa.text, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text | dep: json, typing, alembic, uuid, sqlalchemy
|
- 20260527160017_add_pi_agent_tool_type.py | Alembic database migration that adds a new "pi-agent" tool type with terminal-based Docker development environment configuration | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text("SELECT id FROM tool_types WHERE name = 'pi-agent'") ).fetchone, call:sa.text, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text | dep: json, typing, alembic, uuid, sqlalchemy
|
||||||
- 2026_05_22_add_clone_mode.py | Alembic database migration that adds ssh_key_id foreign key to git_repositories table and clone_mode/branch columns to tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:op.create_foreign_key, call:sa.String, func:downgrade() → None, call:op.drop_column, call:op.drop_constraint | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 2026_05_22_add_clone_mode.py | Alembic database migration that adds ssh_key_id foreign key to git_repositories and clone_mode/branch columns to tool_instances | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:postgresql.UUID, call:op.create_foreign_key, call:sa.String, func:downgrade() → None, call:op.drop_column, call:op.drop_constraint | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 2026_05_23_remove_is_builtin.py | Alembic database migration to remove the `is_builtin` column from the `tool_types` table | exp: func:upgrade() → None, call:op.execute, func:downgrade() → None, call:op.add_column, call:sa.Column, call:sa.Boolean | dep: alembic, sqlalchemy
|
- 2026_05_23_remove_is_builtin.py | Alembic database migration that removes the `is_builtin` column from the `tool_types` table with downgrade support to restore it. | exp: func:upgrade() → None, call:op.execute, func:downgrade() → None, call:op.add_column, call:sa.Column, call:sa.Boolean | dep: alembic, sqlalchemy
|
||||||
- 2026_05_24_220141_add_startup_command.py | Alembic database migration that adds a nullable `startup_command` text column to the `tool_types` table. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Text, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 2026_05_24_220141_add_startup_command.py | Alembic database migration that adds a nullable `startup_command` text column to the `tool_types` table. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Text, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_24_add_config_profiles.py | Alembic database migration that creates config_profiles and config_profile_includes tables with indexes, and adds a foreign key column to tool_instances for managing user configuration profiles. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.ForeignKey, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:sa.Boolean, call:sa.DateTime, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:op.create_index, call:sa.Integer, call:op.add_column, func:downgrade() → None, call:op.drop_index, call:op.drop_column, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
- 2026_05_24_add_config_profiles.py | Alembic database migration that creates config_profiles and config_profile_includes tables with indexes, and adds a selected_config_profile_id foreign key to tool_instances | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.ForeignKey, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:sa.Boolean, call:sa.DateTime, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:op.create_index, call:sa.Integer, call:op.add_column, func:downgrade() → None, call:op.drop_index, call:op.drop_column, call:op.drop_table | dep: typing, alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- 2026_05_26_add_git_mounts.py | Alembic database migration that adds a git_mounts JSON column to the config_profiles table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
- 2026_05_26_add_git_mounts.py | Alembic database migration that adds a git_mounts JSON column to the config_profiles table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_27_external_repos.py | Alembic database migration that makes project_id nullable in git_repositories table to support external repositories and expands alembic_version version_num column to 64 characters. | exp: func:upgrade() → None, call:op.execute, call:op.alter_column, call:sa.UUID, func:downgrade() → None, call:op.alter_column, call:sa.UUID, call:op.execute | dep: typing, alembic, sqlalchemy
|
- 2026_05_27_external_repos.py | Alembic database migration that makes project_id nullable in git_repositories to support external repositories and expands alembic_version version_num column to prevent truncation. | exp: func:upgrade() → None, call:op.execute, call:op.alter_column, call:sa.UUID, func:downgrade() → None, call:op.alter_column, call:sa.UUID, call:op.execute | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_28_add_monitoring_tables.py | Alembic database migration that creates monitoring tables (instance_events and health_checks) with indexes for tracking tool instance events and health checks | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.DateTime, call:sa.func.now, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:sa.Boolean, call:sa.Integer, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
- 2026_05_28_add_monitoring_tables.py | Alembic database migration that creates monitoring tables (instance_events and health_checks) with indexes for tracking tool instance events and health check status. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.DateTime, call:sa.func.now, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:sa.Boolean, call:sa.Integer, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
||||||
- 2026_05_28_add_terminal_sessions_table.py | Alembic database migration that creates a terminal_sessions table with tracking columns and foreign key to tool_instances | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:op.f, func:downgrade() → None, call:op.drop_index, call:op.f, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
- 2026_05_28_add_terminal_sessions_table.py | Alembic database migration that creates a terminal_sessions table with foreign key to tool_instances for tracking terminal session lifecycle | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.DateTime, call:sa.text, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:op.f, func:downgrade() → None, call:op.drop_index, call:op.f, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
||||||
- 2026_05_28_add_tool_definition_manifests.py | Alembic database migration that creates a tool_definition_manifests table, adds manifest-related columns to tool_types and tool_instances, and migrates the pi-agent tool from Dockerfile-based to manifest-based definitions with seed data. | exp: func:upgrade() → None, call:op.get_bind, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.TIMESTAMP, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:sa.ForeignKeyConstraint, call:sa.CheckConstraint, call:conn.execute, call:sa.text, call:result.fetchone, call:op.add_column, call:op.create_foreign_key, call:op.drop_constraint, call:op.execute, call:json.dumps, call:str, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:op.drop_column, call:op.drop_constraint, call:op.drop_table | dep: json, uuid, typing, alembic, sqlalchemy
|
- 2026_05_28_add_tool_definition_manifests.py | Alembic database migration that creates a tool_definition_manifests table, adds manifest support to tool_types and tool_instances, and migrates the pi-agent tool from Dockerfile/compose templates to a JSON-based manifest system with a base Ubuntu image definition. | exp: func:upgrade() → None, call:op.get_bind, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.TIMESTAMP, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.UniqueConstraint, call:sa.ForeignKeyConstraint, call:sa.CheckConstraint, call:conn.execute, call:sa.text, call:result.fetchone, call:op.add_column, call:op.create_foreign_key, call:op.drop_constraint, call:op.execute, call:json.dumps, call:str, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:op.drop_column, call:op.drop_constraint, call:op.drop_table | dep: json, uuid, typing, alembic, sqlalchemy
|
||||||
- 2026_05_28_drop_tool_configs_and_config_folders.py | Alembic database migration that drops `tool_configs` and `config_folders` tables with conditional existence checks and full downgrade recreation | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:op.drop_table, func:downgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.TIMESTAMP, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.Integer | dep: typing, alembic, sqlalchemy
|
- 2026_05_28_drop_tool_configs_and_config_folders.py | Database migration that drops the `tool_configs` and `config_folders` tables with conditional existence checks, and provides downgrade to recreate them. | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:op.drop_table, func:downgrade() → None, call:op.create_table, call:sa.Column, call:sa.UUID, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.Boolean, call:sa.TIMESTAMP, call:sa.func.now, call:sa.PrimaryKeyConstraint, call:sa.Integer | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_29_add_notifications_table.py | Alembic database migration that creates a notifications table with user-linked, categorized, severity-graded messages supporting read/dismissed tracking and optimized querying indexes. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.DateTime, call:sa.func.now, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:sa.text, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
- 2026_05_29_add_notifications_table.py | Alembic database migration that creates a notifications table with user-linked, categorized, and severity-based notification records including read/dismissed tracking and optimized indexes. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.Text, call:sa.JSON, call:sa.DateTime, call:sa.func.now, call:sa.ForeignKeyConstraint, call:sa.PrimaryKeyConstraint, call:op.create_index, call:sa.text, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
||||||
- 2026_05_29_add_ssh_key_ids_to_tool_instances.py | Alembic database migration that adds a JSON column named ssh_key_ids to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: alembic, sqlalchemy
|
- 2026_05_29_add_ssh_key_ids_to_tool_instances.py | Alembic database migration that adds a JSON ssh_key_ids column to the tool_instances table | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.JSON, func:downgrade() → None, call:op.drop_column | dep: alembic, sqlalchemy
|
||||||
- 2026_05_29_drop_ssh_key_id_from_config_profiles.py | Alembic database migration that removes the ssh_key_id column from the config_profiles table | exp: func:upgrade() → None, call:op.drop_column, func:downgrade() → None, call:op.add_column, call:sa.Column, call:sa.Uuid, call:sa.ForeignKey | dep: alembic, sqlalchemy
|
- 2026_05_29_drop_ssh_key_id_from_config_profiles.py | Alembic database migration that removes the ssh_key_id column from the config_profiles table | exp: func:upgrade() → None, call:op.drop_column, func:downgrade() → None, call:op.add_column, call:sa.Column, call:sa.Uuid, call:sa.ForeignKey | dep: alembic, sqlalchemy
|
||||||
- 2026_05_29_fix_code_server_bind_addr.py | Alembic database migration that fixes code-server tool type compose templates by replacing deprecated `--bind-addr` flag with `--host` flag | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text(""" SELECT id, compose_template FROM tool_types WHERE name = 'code-server' AND compose_template LIKE '%--bind-addr%' """) ).fetchall, call:sa.text, call:compose_template.replace( "--bind-addr 0.0.0.0:8443", "--host 0.0.0.0" ).replace, call:print, func:downgrade() → None | dep: typing, alembic, sqlalchemy
|
- 2026_05_29_fix_code_server_bind_addr.py | Alembic database migration that fixes code-server tool type compose templates by replacing deprecated --bind-addr flag with --host flag | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text(""" SELECT id, compose_template FROM tool_types WHERE name = 'code-server' AND compose_template LIKE '%--bind-addr%' """) ).fetchall, call:sa.text, call:compose_template.replace( "--bind-addr 0.0.0.0:8443", "--host 0.0.0.0" ).replace, call:print, func:downgrade() → None | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_29_fix_code_server_bind_addr_port.py | Alembic database migration that fixes code-server Docker compose templates and instance files by replacing broken `--host` flags with correct `--bind-addr 0.0.0.0:port` configurations | exp: func:_fix_tool_type_templates(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, default_port FROM tool_types WHERE name = 'code-server' AND compose_template LIKE '%--host%' """) ).fetchall, call:sa.text, call:compose_template.split, call:len, call:line.lstrip, call:new_lines.append, call:"\n".join, call:print, func:_fix_instance_compose_files(conn) → None, call:conn.execute( sa.text(""" SELECT column_name FROM information_schema.columns WHERE table_name = 'tool_instances' AND column_name = 'compose_path' """) ).fetchone, call:sa.text, call:print, call:conn.execute( sa.text(""" SELECT id, compose_path, tool_type_id FROM tool_instances WHERE compose_path IS NOT NULL """) ).fetchall, call:Path, call:path.exists, call:path.read_text, call:conn.execute( sa.text(""" SELECT default_port FROM tool_types WHERE id = :id """), {"id": tool_type_id}, ).fetchone, call:yaml.safe_load, call:data["services"].values, call:path.write_text, call:yaml.dump, func:upgrade() → None, call:op.get_bind, call:_fix_tool_type_templates, call:_fix_instance_compose_files, func:downgrade() → None | dep: typing, alembic, yaml, pathlib, sqlalchemy
|
- 2026_05_29_fix_code_server_bind_addr_port.py | Alembic database migration that fixes code-server Docker compose templates by replacing broken `--host` flags with correct `--bind-addr 0.0.0.0:{port}` configurations in both database tool_type templates and on-disk instance compose files. | exp: func:_fix_tool_type_templates(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, default_port FROM tool_types WHERE name = 'code-server' AND compose_template LIKE '%--host%' """) ).fetchall, call:sa.text, call:compose_template.split, call:len, call:line.lstrip, call:new_lines.append, call:"\n".join, call:print, func:_fix_instance_compose_files(conn) → None, call:conn.execute( sa.text(""" SELECT column_name FROM information_schema.columns WHERE table_name = 'tool_instances' AND column_name = 'compose_path' """) ).fetchone, call:sa.text, call:print, call:conn.execute( sa.text(""" SELECT id, compose_path, tool_type_id FROM tool_instances WHERE compose_path IS NOT NULL """) ).fetchall, call:Path, call:path.exists, call:path.read_text, call:conn.execute( sa.text(""" SELECT default_port FROM tool_types WHERE id = :id """), {"id": tool_type_id}, ).fetchone, call:yaml.safe_load, call:data["services"].values, call:path.write_text, call:yaml.dump, func:upgrade() → None, call:op.get_bind, call:_fix_tool_type_templates, call:_fix_instance_compose_files, func:downgrade() → None | dep: typing, alembic, yaml, pathlib, sqlalchemy
|
||||||
- 2026_05_29_fix_web_tool_bind_address.py | Alembic database migration that updates code-server and jupyter-notebook tool type compose templates to bind to 0.0.0.0 | exp: func:_fix_code_server_compose(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, definition_type FROM tool_types WHERE name = 'code-server' """) ).fetchone, call:sa.text, call:compose_template.split, call:enumerate, call:len, call:line.lstrip, call:new_lines.append, call:image_line.lstrip, call:new_lines.index, call:new_lines.insert, call:"\n".join, call:print, func:_fix_jupyter_compose(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, definition_type FROM tool_types WHERE name = 'jupyter-notebook' """) ).fetchone, call:sa.text, call:compose_template.split, call:enumerate, call:new_lines.append, call:len, call:line.lstrip, call:"\n".join, call:print, func:upgrade() → None, call:op.get_bind, call:_fix_code_server_compose, call:_fix_jupyter_compose, func:downgrade() → None | dep: typing, alembic, sqlalchemy
|
- 2026_05_29_fix_web_tool_bind_address.py | Alembic database migration that fixes code-server and jupyter-notebook tool compose templates to bind to 0.0.0.0 | exp: func:_fix_code_server_compose(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, definition_type FROM tool_types WHERE name = 'code-server' """) ).fetchone, call:sa.text, call:compose_template.split, call:enumerate, call:len, call:line.lstrip, call:new_lines.append, call:image_line.lstrip, call:new_lines.index, call:new_lines.insert, call:"\n".join, call:print, func:_fix_jupyter_compose(conn) → None, call:conn.execute( sa.text(""" SELECT id, compose_template, definition_type FROM tool_types WHERE name = 'jupyter-notebook' """) ).fetchone, call:sa.text, call:compose_template.split, call:enumerate, call:new_lines.append, call:len, call:line.lstrip, call:"\n".join, call:print, func:upgrade() → None, call:op.get_bind, call:_fix_code_server_compose, call:_fix_jupyter_compose, func:downgrade() → None | dep: typing, alembic, sqlalchemy
|
||||||
- 2026_05_29_remove_lsio_command_override.py | Alembic database migration that removes broken command overrides containing --bind-addr or --host flags from LinuxServer.io code-server Docker Compose templates in both database tool_types records and on-disk instance compose files. | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text(""" SELECT id, compose_template FROM tool_types WHERE name = 'code-server' """) ).fetchall, call:sa.text, call:yaml.safe_load, call:data["services"].values, call:svc.get, call:yaml.dump, call:print, call:conn.execute( sa.text(""" SELECT column_name FROM information_schema.columns WHERE table_name = 'tool_instances' AND column_name = 'compose_path' """) ).fetchone, call:conn.execute( sa.text(""" SELECT id, compose_path FROM tool_instances WHERE compose_path IS NOT NULL """) ).fetchall, call:Path, call:path.exists, call:path.read_text, call:path.write_text, func:downgrade() → None | dep: collections.abc, alembic, yaml, pathlib, sqlalchemy, pathlib.Path, information_schema
|
- 2026_05_29_remove_lsio_command_override.py | Alembic database migration that removes broken command overrides containing --bind-addr or --host flags from LinuxServer.io code-server Docker Compose templates in both database records and on-disk compose files. | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute( sa.text(""" SELECT id, compose_template FROM tool_types WHERE name = 'code-server' """) ).fetchall, call:sa.text, call:yaml.safe_load, call:data["services"].values, call:svc.get, call:yaml.dump, call:print, call:conn.execute( sa.text(""" SELECT column_name FROM information_schema.columns WHERE table_name = 'tool_instances' AND column_name = 'compose_path' """) ).fetchone, call:conn.execute( sa.text(""" SELECT id, compose_path FROM tool_instances WHERE compose_path IS NOT NULL """) ).fetchall, call:Path, call:path.exists, call:path.read_text, call:path.write_text, func:downgrade() → None | dep: collections.abc, alembic, yaml, pathlib, sqlalchemy
|
||||||
- 2026_05_29_remove_ssh_keys_mount_from_manifest.py | Alembic database migration that removes (or restores) the ssh_keys mount from a JSON manifest stored in the tool_definition_manifests table for the pi-agent tool definition. | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:isinstance, call:json.loads, call:manifest.get, call:len, call:m.get, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:isinstance, call:json.loads, call:manifest.get, call:any, call:m.get, call:mounts.append, call:json.dumps | dep: json, typing, alembic, sqlalchemy
|
- 2026_05_29_remove_ssh_keys_mount_from_manifest.py | Alembic database migration that removes (and can restore) the ssh_keys mount from the pi-agent tool definition manifest stored as JSON | exp: func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:isinstance, call:json.loads, call:manifest.get, call:len, call:m.get, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:isinstance, call:json.loads, call:manifest.get, call:any, call:m.get, call:mounts.append, call:json.dumps | dep: json, typing, alembic, sqlalchemy
|
||||||
- 2026_06_01_add_workspaces.py | Alembic database migration that creates a workspaces table with foreign keys to git_repositories and users, adds indexes, and adds a workspace_id column to tool_instances | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.ForeignKey, call:sa.DateTime, call:sa.text, call:sa.UniqueConstraint, call:op.create_index, call:op.add_column, func:downgrade() → None, call:op.drop_index, call:op.drop_column, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
- 2026_06_01_add_workspaces.py | Alembic database migration that creates a workspaces table with indexes and adds a workspace_id foreign key to tool_instances | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:sa.Uuid, call:sa.String, call:sa.ForeignKey, call:sa.DateTime, call:sa.text, call:sa.UniqueConstraint, call:op.create_index, call:op.add_column, func:downgrade() → None, call:op.drop_index, call:op.drop_column, call:op.drop_table | dep: collections.abc, alembic, sqlalchemy
|
||||||
- 2026_06_13_make_clone_mode_nullable.py | Alembic database migration that makes the `clone_mode` column in `tool_instances` table nullable to allow NULL values for new rows | exp: func:upgrade() → None, call:op.alter_column, call:sa.String, func:downgrade() → None, call:op.alter_column, call:sa.String | dep: alembic, sqlalchemy
|
- 2026_06_13_make_clone_mode_nullable.py | Alembic database migration to make the `clone_mode` column nullable in the `tool_instances` table | exp: func:upgrade() → None, call:op.alter_column, call:sa.String, func:downgrade() → None, call:op.alter_column, call:sa.String | dep: alembic, sqlalchemy
|
||||||
- 398082499c30_add_tool_config_fields.py | Alembic database migration that adds five new columns (port_override, start_command, working_directory, environment_variables, volumes) to the tool_configs table with a port range check constraint. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Integer, call:sa.Text, call:postgresql.JSONB, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:op.drop_constraint, call:op.drop_column | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 2026_06_14_104415_add_tool_type_home_directory.py | Alembic database migration that adds a home_directory column to tool_types table and updates template strings from /workspace to a configurable path | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, call:op.execute, call:sa.update(tool_types) .where(tool_types.c.compose_template.is_not(None)) .values, call:tool_types.c.compose_template.is_not, call:sa.func.replace, call:sa.update(tool_types) .where(tool_types.c.dockerfile_template.is_not(None)) .values, call:tool_types.c.dockerfile_template.is_not, func:downgrade() → None, call:op.execute, call:sa.update(tool_types) .where(tool_types.c.compose_template.is_not(None)) .values, call:tool_types.c.compose_template.is_not, call:sa.func.replace, call:sa.update(tool_types) .where(tool_types.c.dockerfile_template.is_not(None)) .values, call:tool_types.c.dockerfile_template.is_not, call:op.drop_column | dep: typing, alembic, sqlalchemy.sql, sqlalchemy
|
||||||
- 6fc7bfcf199f_merge_remove_is_builtin_and_add_config_.py | Alembic database migration that merges two parallel revision branches (removing is_builtin and adding config_profiles) into a single history line | exp: func:upgrade() → None, func:downgrade() → None | dep: alembic
|
- 2026_06_14_182955_fix_pi_agent_home_directory_mount.py | Alembic database migration that updates the pi-agent tool definition manifest to mount repos under the home directory instead of /workspace | exp: func:_find_pi_agent_manifest(conn: sa.Connection) → tuple[Union[str, None], Union[dict, None]], call:conn.execute( sa.select(tool_definition_manifests.c.id, tool_definition_manifests.c.manifest) .where(tool_definition_manifests.c.name == "pi-agent") ).fetchone, call:sa.select(tool_definition_manifests.c.id, tool_definition_manifests.c.manifest) .where, call:dict, func:_update_manifest(conn: sa.Connection, manifest_id: str, manifest: dict) → None, call:conn.execute, call:sa.update(tool_definition_manifests) .where(tool_definition_manifests.c.id == manifest_id) .values, func:upgrade() → None, call:op.get_bind, call:_find_pi_agent_manifest, call:manifest.get, call:mount.get, call:manifest.setdefault, call:_update_manifest, func:downgrade() → None, call:op.get_bind, call:_find_pi_agent_manifest, call:manifest.get, call:mount.get, call:manifest.setdefault, call:_update_manifest | dep: typing, alembic, sqlalchemy.sql, sqlalchemy
|
||||||
|
- 2026_06_15_090500_remove_pi_agent_explicit_repo_mount.py | Alembic database migration that removes explicit repo mounts from pi-agent tool definition manifests since they are now synthesized by compile_compose | exp: func:_find_pi_agent_manifest(conn: sa.Connection) → tuple[Union[str, None], Union[dict, None]], call:conn.execute( sa.select( tool_definition_manifests.c.id, tool_definition_manifests.c.manifest ).where(tool_definition_manifests.c.name == "pi-agent") ).fetchone, call:sa.select( tool_definition_manifests.c.id, tool_definition_manifests.c.manifest ).where, call:dict, func:_update_manifest(conn: sa.Connection, manifest_id: str, manifest: dict) → None, call:conn.execute, call:sa.update(tool_definition_manifests) .where(tool_definition_manifests.c.id == manifest_id) .values, func:upgrade() → None, call:op.get_bind, call:_find_pi_agent_manifest, call:manifest.get, call:mount.get, call:_update_manifest, func:downgrade() → None, call:op.get_bind, call:_find_pi_agent_manifest, call:manifest.setdefault, call:any, call:mount.get, call:mounts.append, call:_update_manifest | dep: typing, alembic, sqlalchemy.sql, sqlalchemy
|
||||||
|
- 398082499c30_add_tool_config_fields.py | Alembic database migration that adds configuration fields (port_override, start_command, working_directory, environment_variables, volumes) to the tool_configs table with a port range check constraint. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.Integer, call:sa.Text, call:postgresql.JSONB, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:op.drop_constraint, call:op.drop_column | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
|
- 6fc7bfcf199f_merge_remove_is_builtin_and_add_config_.py | Alembic database migration that merges two branches (removing is_builtin and adding config_profiles) with no actual schema changes | exp: func:upgrade() → None, func:downgrade() → None | dep: alembic
|
||||||
- 86cec91fdb00_merge_profile_resolver_and_workspaces_.py | Alembic database migration that merges two divergent migration branches (profile resolver and workspaces) into a single head | exp: func:upgrade() → None, func:downgrade() → None | dep: alembic
|
- 86cec91fdb00_merge_profile_resolver_and_workspaces_.py | Alembic database migration that merges two divergent migration branches (profile resolver and workspaces) into a single head | exp: func:upgrade() → None, func:downgrade() → None | dep: alembic
|
||||||
- 8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py | Alembic database migration that removes pi_state and pi_config mounts from the pi-agent manifest in upgrade, and restores them in downgrade | exp: func:_load_manifest(manifest_json), call:isinstance, call:json.loads, func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:_load_manifest, call:manifest.get, call:len, call:m.get, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:_load_manifest, call:manifest.get, call:m.get, call:mounts.append, call:json.dumps | dep: json, alembic, sqlalchemy
|
- 8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py | Alembic database migration that removes pi_state and pi_config mounts from the pi-agent manifest in upgrade, and restores them in downgrade | exp: func:_load_manifest(manifest_json), call:isinstance, call:json.loads, func:upgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:_load_manifest, call:manifest.get, call:len, call:m.get, call:json.dumps, func:downgrade() → None, call:op.get_bind, call:conn.execute, call:sa.text, call:result.fetchone, call:_load_manifest, call:manifest.get, call:m.get, call:mounts.append, call:json.dumps | dep: json, alembic, sqlalchemy
|
||||||
- 8ed7dd80973d_create_config_folders_table.py | Alembic database migration that creates a config_folders table with user-owned configuration folders supporting JSONB file storage and project overrides | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.ForeignKey, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:sa.Boolean, call:sa.DateTime, call:sa.UniqueConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- 8ed7dd80973d_create_config_folders_table.py | Creates a database migration that adds a config_folders table for storing user configuration folders with JSONB metadata, foreign key relationships, and indexing. | exp: func:upgrade() → None, call:op.create_table, call:sa.Column, call:postgresql.UUID, call:sa.text, call:sa.ForeignKey, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:sa.Boolean, call:sa.DateTime, call:sa.UniqueConstraint, call:op.create_index, func:downgrade() → None, call:op.drop_index, call:op.drop_table | dep: alembic, sqlalchemy.dialects, sqlalchemy, postgresql dialect
|
||||||
- af8512103d67_add_tool_type_fields.py | Alembic database migration that adds new columns (definition_type, dockerfile_template, build_context, readiness_probe) to the tool_types table with a CHECK constraint on definition_type. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:op.drop_constraint, call:op.drop_column | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
- af8512103d67_add_tool_type_fields.py | Alembic database migration that adds new columns (definition_type, dockerfile_template, build_context, readiness_probe) to the tool_types table with a CHECK constraint on definition_type. | exp: func:upgrade() → None, call:op.add_column, call:sa.Column, call:sa.String, call:sa.Text, call:postgresql.JSONB, call:op.create_check_constraint, call:sa.text, func:downgrade() → None, call:op.drop_constraint, call:op.drop_column | dep: alembic, sqlalchemy.dialects, sqlalchemy, sqlalchemy.dialects.postgresql
|
||||||
- f3d2dc90ba3a_merge_single_interface_and_clone_mode.py | Alembic database migration that merges two prior revisions (single_interface and clone_mode) into a single migration path | exp: func:upgrade() → None, func:downgrade() → None | dep: typing, alembic
|
- f3d2dc90ba3a_merge_single_interface_and_clone_mode.py | Alembic database migration that merges two parent revisions (single_interface and clone_mode) into a single branch point with no actual schema changes | exp: func:upgrade() → None, func:downgrade() → None | dep: typing, alembic
|
||||||
|
- fc8f1a20cbf6_merge_home_directory_and_pi_agent_mount_.py | Alembic database migration that merges two branch heads (home directory and pi agent mount cleanup) into a single revision point | exp: func:upgrade() → None, func:downgrade() → None | dep: alembic
|
||||||
## arch
|
## arch
|
||||||
Linear and branched migration pattern using Alembic's revision system with merge migrations to reconcile divergent branches; each migration is an imperative upgrade/downgrade script containing raw SQL/DDL operations, with some migrations including data seeding and dialect-specific logic (PostgreSQL/SQLite), but lacks consistent naming convention (mixed timestamp and numeric prefixes) indicating organic evolution rather than planned schema design.
|
Linear migration history with branching/merge resolution pattern; each migration is an immutable, timestamped or sequenced script containing declarative SQLAlchemy operations (create_table, add_column, drop_column) with bidirectional upgrade/downgrade functions; includes data migrations, idempotent guards, and cross-references to on-disk file mutations.
|
||||||
## tags
|
## tags
|
||||||
column, table, call:op.drop, downgrade, alembic, upgrade, key, call:sa.text
|
column, table, call:op.drop, downgrade, upgrade, alembic, key, call:sa.text
|
||||||
## symbols
|
## symbols
|
||||||
- upgrade
|
- upgrade
|
||||||
- downgrade
|
- downgrade
|
||||||
|
|||||||
@@ -104,11 +104,11 @@ RUN git config --global init.defaultBranch main \\
|
|||||||
&& git config --global user.name "Developer"
|
&& git config --global user.name "Developer"
|
||||||
|
|
||||||
# Create default tmux config
|
# Create default tmux config
|
||||||
RUN echo 'set -g mouse on\\nset -g default-terminal "screen-256color"' > /home/user/.tmux.conf
|
RUN printf '%s\\n' 'set -g mouse on' 'set -g default-terminal "screen-256color"' > /home/user/.tmux.conf
|
||||||
|
|
||||||
# Create default ranger config
|
# Create default ranger config
|
||||||
RUN mkdir -p /home/user/.config/ranger \\
|
RUN mkdir -p /home/user/.config/ranger \\
|
||||||
&& echo 'set preview_files true\\nset use_preview_script true' > /home/user/.config/ranger/rc.conf
|
&& printf '%s\\n' 'set preview_files true' 'set use_preview_script true' > /home/user/.config/ranger/rc.conf
|
||||||
|
|
||||||
# Set up Pi config directory
|
# Set up Pi config directory
|
||||||
RUN mkdir -p /home/user/.pi/agent
|
RUN mkdir -p /home/user/.pi/agent
|
||||||
|
|||||||
@@ -308,10 +308,10 @@ RUN git config --global init.defaultBranch main \\
|
|||||||
&& git config --global user.email "dev@headquarter.local" \\
|
&& git config --global user.email "dev@headquarter.local" \\
|
||||||
&& git config --global user.name "Developer"
|
&& git config --global user.name "Developer"
|
||||||
|
|
||||||
RUN echo 'set -g mouse on\\nset -g default-terminal "screen-256color"' > /home/user/.tmux.conf
|
RUN printf '%s\\n' 'set -g mouse on' 'set -g default-terminal "screen-256color"' > /home/user/.tmux.conf
|
||||||
|
|
||||||
RUN mkdir -p /home/user/.config/ranger \\
|
RUN mkdir -p /home/user/.config/ranger \\
|
||||||
&& echo 'set preview_files true\\nset use_preview_script true' > /home/user/.config/ranger/rc.conf
|
&& printf '%s\\n' 'set preview_files true' 'set use_preview_script true' > /home/user/.config/ranger/rc.conf
|
||||||
|
|
||||||
RUN mkdir -p /home/user/.pi/agent
|
RUN mkdir -p /home/user/.pi/agent
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
"""add_tool_type_home_directory
|
||||||
|
|
||||||
|
Revision ID: 2026_06_14_104415
|
||||||
|
Revises: f3d2dc90ba3a
|
||||||
|
Create Date: 2026-06-14 10:44:15.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.sql import column, table
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "2026_06_14_104415"
|
||||||
|
down_revision: Union[str, Sequence[str], None] = "f3d2dc90ba3a"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
tool_types = table(
|
||||||
|
"tool_types",
|
||||||
|
column("id", sa.UUID),
|
||||||
|
column("home_directory", sa.String),
|
||||||
|
column("compose_template", sa.Text),
|
||||||
|
column("dockerfile_template", sa.Text),
|
||||||
|
)
|
||||||
|
|
||||||
|
OLD_WORKSPACE = "/workspace"
|
||||||
|
NEW_WORKSPACE = "/home/user/{{WORKSPACE_NAME}}"
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# Add the new column with a default that applies to existing rows.
|
||||||
|
op.add_column(
|
||||||
|
"tool_types",
|
||||||
|
sa.Column(
|
||||||
|
"home_directory",
|
||||||
|
sa.String(255),
|
||||||
|
nullable=False,
|
||||||
|
server_default="/home/user",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Rewrite legacy templates that mount the workspace at /workspace so they
|
||||||
|
# use the new configurable home directory and preserve the workspace name.
|
||||||
|
op.execute(
|
||||||
|
sa.update(tool_types)
|
||||||
|
.where(tool_types.c.compose_template.is_not(None))
|
||||||
|
.values(
|
||||||
|
compose_template=sa.func.replace(
|
||||||
|
tool_types.c.compose_template, OLD_WORKSPACE, NEW_WORKSPACE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
op.execute(
|
||||||
|
sa.update(tool_types)
|
||||||
|
.where(tool_types.c.dockerfile_template.is_not(None))
|
||||||
|
.values(
|
||||||
|
dockerfile_template=sa.func.replace(
|
||||||
|
tool_types.c.dockerfile_template, OLD_WORKSPACE, NEW_WORKSPACE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# Restore the original /workspace strings before dropping the column.
|
||||||
|
op.execute(
|
||||||
|
sa.update(tool_types)
|
||||||
|
.where(tool_types.c.compose_template.is_not(None))
|
||||||
|
.values(
|
||||||
|
compose_template=sa.func.replace(
|
||||||
|
tool_types.c.compose_template, NEW_WORKSPACE, OLD_WORKSPACE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
op.execute(
|
||||||
|
sa.update(tool_types)
|
||||||
|
.where(tool_types.c.dockerfile_template.is_not(None))
|
||||||
|
.values(
|
||||||
|
dockerfile_template=sa.func.replace(
|
||||||
|
tool_types.c.dockerfile_template, NEW_WORKSPACE, OLD_WORKSPACE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
op.drop_column("tool_types", "home_directory")
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
"""fix_pi_agent_home_directory_mount
|
||||||
|
|
||||||
|
Revision ID: 2026_06_14_182955
|
||||||
|
Revises: fc8f1a20cbf6
|
||||||
|
Create Date: 2026-06-14 18:29:55.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.sql import column, table
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "2026_06_14_182955"
|
||||||
|
down_revision: Union[str, Sequence[str], None] = "fc8f1a20cbf6"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
tool_definition_manifests = table(
|
||||||
|
"tool_definition_manifests",
|
||||||
|
column("id", sa.UUID),
|
||||||
|
column("name", sa.String),
|
||||||
|
column("manifest", sa.JSON),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_pi_agent_manifest(conn: sa.Connection) -> tuple[Union[str, None], Union[dict, None]]:
|
||||||
|
result = conn.execute(
|
||||||
|
sa.select(tool_definition_manifests.c.id, tool_definition_manifests.c.manifest)
|
||||||
|
.where(tool_definition_manifests.c.name == "pi-agent")
|
||||||
|
).fetchone()
|
||||||
|
if result is None:
|
||||||
|
return None, None
|
||||||
|
return result.id, dict(result.manifest)
|
||||||
|
|
||||||
|
|
||||||
|
def _update_manifest(conn: sa.Connection, manifest_id: str, manifest: dict) -> None:
|
||||||
|
conn.execute(
|
||||||
|
sa.update(tool_definition_manifests)
|
||||||
|
.where(tool_definition_manifests.c.id == manifest_id)
|
||||||
|
.values(manifest=manifest)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
conn = op.get_bind()
|
||||||
|
manifest_id, manifest = _find_pi_agent_manifest(conn)
|
||||||
|
if not manifest_id or not manifest:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Mount the repo under the configured home directory, preserving the repo
|
||||||
|
# directory name via the WORKSPACE_NAME runtime variable.
|
||||||
|
for mount in manifest.get("mounts", []):
|
||||||
|
if mount.get("source_type") == "repo":
|
||||||
|
mount["target"] = "~/{{WORKSPACE_NAME}}"
|
||||||
|
|
||||||
|
# Keep /workspace as a compatibility symlink to the real mount path.
|
||||||
|
runtime = manifest.setdefault("runtime", {})
|
||||||
|
runtime["working_dir"] = "/workspace"
|
||||||
|
|
||||||
|
# Update the startup script to chown the real mount path.
|
||||||
|
scripts = manifest.setdefault("scripts", {})
|
||||||
|
scripts["startup"] = [
|
||||||
|
'if [ -n "$WORKSPACE_NAME" ]; then sudo chown -R user:user "$HOME/$WORKSPACE_NAME" 2>/dev/null || true; fi',
|
||||||
|
]
|
||||||
|
|
||||||
|
_update_manifest(conn, manifest_id, manifest)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
conn = op.get_bind()
|
||||||
|
manifest_id, manifest = _find_pi_agent_manifest(conn)
|
||||||
|
if not manifest_id or not manifest:
|
||||||
|
return
|
||||||
|
|
||||||
|
for mount in manifest.get("mounts", []):
|
||||||
|
if mount.get("source_type") == "repo":
|
||||||
|
mount["target"] = "/workspace"
|
||||||
|
|
||||||
|
runtime = manifest.setdefault("runtime", {})
|
||||||
|
runtime["working_dir"] = "/workspace"
|
||||||
|
|
||||||
|
scripts = manifest.setdefault("scripts", {})
|
||||||
|
scripts["startup"] = [
|
||||||
|
"if [ -d /workspace ]; then sudo chown -R user:user /workspace 2>/dev/null || true; fi",
|
||||||
|
]
|
||||||
|
|
||||||
|
_update_manifest(conn, manifest_id, manifest)
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
"""remove pi agent explicit repo mount
|
||||||
|
|
||||||
|
Revision ID: 2026_06_15_090500
|
||||||
|
Revises: 2026_06_14_182955
|
||||||
|
Create Date: 2026-06-15 09:05:00.000000
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.sql import column, table
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "2026_06_15_090500"
|
||||||
|
down_revision: Union[str, Sequence[str], None] = "2026_06_14_182955"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
tool_definition_manifests = table(
|
||||||
|
"tool_definition_manifests",
|
||||||
|
column("id", sa.UUID),
|
||||||
|
column("name", sa.String),
|
||||||
|
column("manifest", sa.JSON),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_pi_agent_manifest(
|
||||||
|
conn: sa.Connection,
|
||||||
|
) -> tuple[Union[str, None], Union[dict, None]]:
|
||||||
|
result = conn.execute(
|
||||||
|
sa.select(
|
||||||
|
tool_definition_manifests.c.id, tool_definition_manifests.c.manifest
|
||||||
|
).where(tool_definition_manifests.c.name == "pi-agent")
|
||||||
|
).fetchone()
|
||||||
|
if result is None:
|
||||||
|
return None, None
|
||||||
|
return result.id, dict(result.manifest)
|
||||||
|
|
||||||
|
|
||||||
|
def _update_manifest(conn: sa.Connection, manifest_id: str, manifest: dict) -> None:
|
||||||
|
conn.execute(
|
||||||
|
sa.update(tool_definition_manifests)
|
||||||
|
.where(tool_definition_manifests.c.id == manifest_id)
|
||||||
|
.values(manifest=manifest)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
conn = op.get_bind()
|
||||||
|
manifest_id, manifest = _find_pi_agent_manifest(conn)
|
||||||
|
if not manifest_id or not manifest:
|
||||||
|
return
|
||||||
|
|
||||||
|
# The repo mount is now synthesized by compile_compose based on the
|
||||||
|
# instance's repository, so the manifest no longer needs an explicit
|
||||||
|
# repo mount with a {{WORKSPACE_NAME}} placeholder.
|
||||||
|
manifest["mounts"] = [
|
||||||
|
mount
|
||||||
|
for mount in manifest.get("mounts", [])
|
||||||
|
if mount.get("source_type") != "repo"
|
||||||
|
]
|
||||||
|
|
||||||
|
_update_manifest(conn, manifest_id, manifest)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
conn = op.get_bind()
|
||||||
|
manifest_id, manifest = _find_pi_agent_manifest(conn)
|
||||||
|
if not manifest_id or not manifest:
|
||||||
|
return
|
||||||
|
|
||||||
|
mounts = manifest.setdefault("mounts", [])
|
||||||
|
if not any(mount.get("source_type") == "repo" for mount in mounts):
|
||||||
|
mounts.append(
|
||||||
|
{
|
||||||
|
"name": "workspace",
|
||||||
|
"target": "~/{{WORKSPACE_NAME}}",
|
||||||
|
"source_type": "repo",
|
||||||
|
"writable": True,
|
||||||
|
"owner": "user",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
_update_manifest(conn, manifest_id, manifest)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
"""merge home directory and pi agent mount cleanup heads
|
||||||
|
|
||||||
|
Revision ID: fc8f1a20cbf6
|
||||||
|
Revises: 2026_06_14_104415, 8c6d1dbd4798
|
||||||
|
Create Date: 2026-06-14 11:08:41.273502
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'fc8f1a20cbf6'
|
||||||
|
down_revision = ('2026_06_14_104415', '8c6d1dbd4798')
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
pass
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src
|
dir: apps/api/src
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Core API application package that initializes and configures the Headquarter FastAPI backend with database, authentication, logging, and middleware infrastructure.
|
Core backend API package for the "Headquarter API" FastAPI application, handling configuration, database setup, logging, and application bootstrap.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/.pi-map.index.md
|
index: apps/api/.pi-map.index.md
|
||||||
map: apps/api/.pi-map.md
|
map: apps/api/.pi-map.md
|
||||||
@@ -13,9 +13,6 @@ map: apps/api/.pi-map.md
|
|||||||
- apps/api/src/auth
|
- apps/api/src/auth
|
||||||
index: apps/api/src/auth/.pi-map.index.md
|
index: apps/api/src/auth/.pi-map.index.md
|
||||||
map: apps/api/src/auth/.pi-map.md
|
map: apps/api/src/auth/.pi-map.md
|
||||||
- apps/api/src/headquarter_api.egg-info
|
|
||||||
index: apps/api/src/headquarter_api.egg-info/.pi-map.index.md
|
|
||||||
map: apps/api/src/headquarter_api.egg-info/.pi-map.md
|
|
||||||
- apps/api/src/models
|
- apps/api/src/models
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
@@ -49,6 +46,6 @@ map: apps/api/src/.pi-map.md
|
|||||||
- change src config
|
- change src config
|
||||||
read: config.py, logging_config.py
|
read: config.py, logging_config.py
|
||||||
- explore src subdirectories
|
- explore src subdirectories
|
||||||
index: apps/api/src/api/.pi-map.index.md, apps/api/src/auth/.pi-map.index.md, apps/api/src/headquarter_api.egg-info/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md, apps/api/src/auth/.pi-map.index.md, apps/api/src/models/.pi-map.index.md
|
||||||
## dirty
|
## dirty
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ dir: apps/api/src
|
|||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Core API application package that initializes and configures the Headquarter FastAPI backend with database, authentication, logging, and middleware infrastructure.
|
Core backend API package for the "Headquarter API" FastAPI application, handling configuration, database setup, logging, and application bootstrap.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Marks the directory as a Python package for the Headquarter API.
|
- __init__.py | Marks the directory as a Python package for the Headquarter API.
|
||||||
- config.py | Defines application configuration settings with environment-based overrides using Pydantic, including database URLs, service domains, OAuth/Authentik integration, JWT/session settings, and computed properties for environment-specific behavior. | exp: class:Settings, func:build_database_url(user: str, password: str, host: str, port: int, database: str) → str | dep: pydantic, pydantic_settings
|
- config.py | Defines application configuration settings with environment variable loading, database URL construction, and computed properties for service URLs and security settings. | exp: class:Settings, func:build_database_url(user: str, password: str, host: str, port: int, database: str) → str | dep: pydantic, pydantic_settings
|
||||||
- database.py | Sets up async SQLAlchemy database engine and session factory, with retry logic for database connectivity testing and Alembic migration execution via subprocess. | exp: func:init_database(max_retries, retry_delay) → bool, call:range, call:engine.connect, call:test_conn.execute, call:text, call:test_conn.close, call:logger.info, call:asyncio.get_event_loop().run_in_executor, call:subprocess.run, call:os.path.dirname, call:os.path.abspath, call:logger.debug, call:logger.error, call:asyncio.sleep, call:str(exc).lower, call:logger.warning | dep: asyncio, logging, os, subprocess, sqlalchemy.ext.asyncio, sqlalchemy.pool, src.config, sqlalchemy
|
- database.py | Sets up an async SQLAlchemy database engine with retry logic and runs Alembic migrations via subprocess to initialize the database. | exp: func:init_database(max_retries, retry_delay) → bool, call:range, call:engine.connect, call:test_conn.execute, call:text, call:test_conn.close, call:logger.info, call:asyncio.get_event_loop().run_in_executor, call:subprocess.run, call:os.path.dirname, call:os.path.abspath, call:logger.debug, call:logger.error, call:asyncio.sleep, call:str(exc).lower, call:logger.warning | dep: asyncio, logging, os, subprocess, sqlalchemy.ext.asyncio, sqlalchemy.pool, src.config, sqlalchemy
|
||||||
- logging_config.py | Configures structured JSON logging with correlation ID injection, custom formatters, and HTTP request/exception middleware for a FastAPI application. | exp: class:CorrelationIdFilter, method:filter(self, record: logging.LogRecord) → bool, call:get_correlation_id, class:JSONFormatter, method:format(self, record: logging.LogRecord) → str, call:self.formatTime, call:record.getMessage, call:getattr, call:self.formatException, call:json.dumps, method:formatTime(self, record: logging.LogRecord, datefmt) → str, call:time.strftime, call:time.gmtime, class:RequestLoggingMiddleware, method:dispatch(self, request: Request, call_next: Callable) → Response, call:time.time, call:logger.info, call:call_next, call:int, call:logger.error, call:type, call:traceback.format_exc, class:ExceptionLoggingMiddleware, method:dispatch(self, request: Request, call_next: Callable) → Response, call:call_next, call:logger.critical, call:traceback.format_exc, func:configure_logging(level) → None, call:JSONFormatter, call:logging.StreamHandler, call:console_handler.setFormatter, call:console_handler.addFilter, call:CorrelationIdFilter, call:root_logger.setLevel, call:logging.getLogger("uvicorn").setLevel, call:logging.getLogger("uvicorn.access").setLevel, call:logging.getLogger("sqlalchemy.engine").setLevel, call:logger.info, call:logging.getLevelName | dep: json, logging, sys, time, traceback, collections.abc, fastapi, starlette.middleware.base, src.services.shared.correlation
|
- logging_config.py | Configures structured JSON logging with correlation ID injection, request/response logging middleware, and exception handling for a FastAPI application. | exp: class:CorrelationIdFilter, method:filter(self, record: logging.LogRecord) → bool, call:get_correlation_id, class:JSONFormatter, method:format(self, record: logging.LogRecord) → str, call:self.formatTime, call:record.getMessage, call:getattr, call:self.formatException, call:json.dumps, method:formatTime(self, record: logging.LogRecord, datefmt) → str, call:time.strftime, call:time.gmtime, class:RequestLoggingMiddleware, method:dispatch(self, request: Request, call_next: Callable) → Response, call:time.time, call:logger.info, call:call_next, call:int, call:logger.error, call:type, call:traceback.format_exc, class:ExceptionLoggingMiddleware, method:dispatch(self, request: Request, call_next: Callable) → Response, call:call_next, call:logger.critical, call:traceback.format_exc, func:configure_logging(level) → None, call:JSONFormatter, call:logging.StreamHandler, call:console_handler.setFormatter, call:console_handler.addFilter, call:CorrelationIdFilter, call:root_logger.setLevel, call:logging.getLogger("uvicorn").setLevel, call:logging.getLogger("uvicorn.access").setLevel, call:logging.getLogger("sqlalchemy.engine").setLevel, call:logger.info, call:logging.getLevelName | dep: json, logging, sys, time, traceback, collections.abc, fastapi, starlette.middleware.base, src.services.shared.correlation, starlette
|
||||||
- main.py | Initializes and configures a FastAPI application for the "Headquarter API" with database setup, middleware, routing, and background services. | exp: func:_sanitize_validation_errors(errors), call:error.get, call:str, call:ctx.items, call:isinstance, call:type, call:sanitized.append, func:validation_exception_handler(request: Request, exc: RequestValidationError), call:exc.errors, call:logger.warning, call:_sanitize_validation_errors, call:JSONResponse, func:on_startup(), call:logger.info, call:init_database, call:logger.error, call:sys.exit, call:_health_monitor.start, call:seed_builtin_tool_types, func:on_shutdown(), call:logger.info, call:_health_monitor.stop | dep: logging, os, fastapi, fastapi.exceptions, fastapi.middleware.cors, fastapi.responses, fastapi.staticfiles, src.api.config, src.api.project, src.api.system, src.api.tool, src.api.user, src.api.workspace, src.config, src.models, src.database, src.logging_config, src.seeds.builtin_tool_types, src.services.instance, src.services.shared, sys, src.api.*
|
- main.py | Bootstraps a FastAPI application called "Headquarter API" with database initialization, health monitoring, CORS, logging middleware, and modular API routers. | exp: func:_sanitize_validation_errors(errors), call:error.get, call:str, call:ctx.items, call:isinstance, call:type, call:sanitized.append, func:validation_exception_handler(request: Request, exc: RequestValidationError), call:exc.errors, call:logger.warning, call:_sanitize_validation_errors, call:JSONResponse, func:on_startup(), call:logger.info, call:init_database, call:logger.error, call:sys.exit, call:_health_monitor.start, call:seed_builtin_tool_types, func:on_shutdown(), call:logger.info, call:_health_monitor.stop | dep: logging, os, fastapi, fastapi.exceptions, fastapi.middleware.cors, fastapi.responses, fastapi.staticfiles, src.api.config, src.api.project, src.api.system, src.api.tool, src.api.user, src.api.workspace, src.config, src.models, src.database, src.logging_config, src.seeds.builtin_tool_types, src.services.instance, src.services.shared, sys, src.api
|
||||||
## arch
|
## arch
|
||||||
Layered architecture using Pydantic for environment-based configuration, async SQLAlchemy with Alembic migrations, structured JSON logging with correlation IDs, and FastAPI middleware/routing pattern for a service-oriented backend.
|
Layered architecture with separation of concerns across config (settings/env), database (async SQLAlchemy with Alembic migrations), logging (structured JSON with middleware), and main (app composition with modular routers and health monitoring).
|
||||||
## tags
|
## tags
|
||||||
src, database, logging, call:logger.info, api, middleware, fastapi, filter
|
src, logging, database, api, call:logger.info, middleware, fastapi, filter
|
||||||
## symbols
|
## symbols
|
||||||
- Settings
|
- Settings
|
||||||
- CorrelationIdFilter
|
- CorrelationIdFilter
|
||||||
@@ -30,6 +30,6 @@ src, database, logging, call:logger.info, api, middleware, fastapi, filter
|
|||||||
- change src config
|
- change src config
|
||||||
read: config.py, logging_config.py
|
read: config.py, logging_config.py
|
||||||
- explore src subdirectories
|
- explore src subdirectories
|
||||||
index: apps/api/src/api/.pi-map.index.md, apps/api/src/auth/.pi-map.index.md, apps/api/src/headquarter_api.egg-info/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md, apps/api/src/auth/.pi-map.index.md, apps/api/src/models/.pi-map.index.md
|
||||||
## dirty
|
## dirty
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api
|
dir: apps/api/src/api
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines shared API infrastructure including reusable Pydantic validators for consistent input validation across API endpoints.
|
Provides shared Pydantic validators and package initialization for API schema validation across the API layer.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/api
|
|||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines shared API infrastructure including reusable Pydantic validators for consistent input validation across API endpoints.
|
Provides shared Pydantic validators and package initialization for API schema validation across the API layer.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Marks the directory as a Python package for API routers.
|
- __init__.py | Marks the directory as a Python package for API routers.
|
||||||
- shared_validators.py | Provides reusable Pydantic validator functions for API schema validation including mount paths, files, environment variables, and volume mounts. | exp: func:validate_mount_path(v: str | None) → str | None, call:v.startswith, raise:ValueError, func:validate_files(v: dict | None, max_size_bytes) → dict | None, call:v.items, call:path.startswith, call:len, call:content.encode, raise:ValueError, func:validate_env_vars(v: dict | None) → dict | None, call:isinstance, raise:ValueError, func:validate_volumes(v: list | None) → list | None, call:isinstance, call:enumerate, raise:ValueError
|
- shared_validators.py | Provides reusable Pydantic validators for API schema fields including mount paths, file dictionaries, environment variables, and volume mounts. | exp: func:validate_mount_path(v: str | None) → str | None, call:v.startswith, raise:ValueError, func:validate_files(v: dict | None, max_size_bytes) → dict | None, call:v.items, call:path.startswith, call:len, call:content.encode, raise:ValueError, func:validate_env_vars(v: dict | None) → dict | None, call:isinstance, raise:ValueError, func:validate_volumes(v: list | None) → list | None, call:isinstance, call:enumerate, raise:ValueError
|
||||||
## arch
|
## arch
|
||||||
Modular utility package with functional validation helpers using Pydantic for declarative schema enforcement.
|
Utility module pattern with reusable cross-cutting Pydantic validators for common API field types (mount paths, files, env vars, volumes).
|
||||||
## tags
|
## tags
|
||||||
validate, raise:value, error, call:isinstance, mount, api, init, path
|
validate, raise:value, error, call:isinstance, validators, mount, api, init
|
||||||
## symbols
|
## symbols
|
||||||
- validate_mount_path
|
- validate_mount_path
|
||||||
- validate_files
|
- validate_files
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/config
|
dir: apps/api/src/api/config
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI API endpoints for managing user configuration settings and configuration profiles.
|
Provides FastAPI API endpoints for managing user configuration settings and config profiles.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: apps/api/src/api/config
|
|||||||
index: apps/api/src/api/config/.pi-map.index.md
|
index: apps/api/src/api/config/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI API endpoints for managing user configuration settings and configuration profiles.
|
Provides FastAPI API endpoints for managing user configuration settings and config profiles.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Aggregates and exports configuration-related API routers for the config module. | dep: src.api.config.config_profiles, src.api.config.user_config
|
- __init__.py | Aggregates and exports config-related API routers for module-level access | dep: src.api.config.config_profiles, src.api.config.user_config
|
||||||
- config_profiles.py | FastAPI router providing CRUD endpoints for user config profiles with includes, resolution, defaults, and git URL validation | exp: func:list_config_profiles(project_id, tool_type_id, current_user_id, session), call:select(ConfigProfile) .where(ConfigProfile.user_id == user_uuid) .options, call:selectinload, call:uuid.UUID, call:conditions.append, call:ConfigProfile.project_id.is_, call:ConfigProfile.tool_type_id.is_, call:query.where, call:or_, call:session.execute, call:result.scalars().all, call:profile_to_response, func:create_config_profile(data: ConfigProfileCreate, current_user_id, session), call:create_profile, call:logger.debug, call:profile_to_response, func:get_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:profile_to_response, raise:HTTPException, func:update_config_profile(profile_id: str, data: ConfigProfileUpdate, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:update_profile, call:logger.debug, call:profile_to_response, raise:HTTPException, func:delete_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:session.delete, call:session.commit, call:logger.debug, raise:HTTPException, func:update_profile_includes_endpoint(profile_id: str, data: ConfigProfileIncludeUpdate, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:update_includes, call:session.execute, call:select(ConfigProfileInclude).where, call:inc_result.scalars().all, call:logger.debug, call:profile_to_response, call:list, raise:HTTPException, func:preview_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:resolve_profile, call:resolved_profile_to_dict, raise:HTTPException, func:resolve_default_profile_endpoint(project_id, tool_type_id, current_user_id, session), call:resolve_default_profile, call:uuid.UUID, func:get_default_profiles_endpoint(user_id, session) → dict, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, func:set_default_profiles_endpoint(data: DefaultProfilesUpdate, user_id, session) → dict, call:validate_default_profiles, call:get_or_create_user_config, call:session.commit, call:session.refresh, func:get_default_profile_for_tool_type_endpoint(tool_type_id: str, user_id, session) → dict, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:user_config.default_profiles.get, func:validate_git_url_endpoint(data: ValidateGitUrlRequest, current_user_id, session) → ValidateGitUrlResponse, call:validate_git_url | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.auth.dependencies, src.models, src.schemas.config, src.services.config.config_profile_resolver, src.services.config.crud_service, src.services.config.resolver_service
|
- config_profiles.py | FastAPI router providing CRUD endpoints for user-owned config profiles with include resolution, default profile management, and git URL validation. | exp: func:list_config_profiles(project_id, tool_type_id, current_user_id, session), call:select(ConfigProfile) .where(ConfigProfile.user_id == user_uuid) .options, call:selectinload, call:uuid.UUID, call:conditions.append, call:ConfigProfile.project_id.is_, call:ConfigProfile.tool_type_id.is_, call:query.where, call:or_, call:session.execute, call:result.scalars().all, call:profile_to_response, func:create_config_profile(data: ConfigProfileCreate, current_user_id, session), call:create_profile, call:logger.debug, call:profile_to_response, func:get_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:profile_to_response, raise:HTTPException, func:update_config_profile(profile_id: str, data: ConfigProfileUpdate, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:update_profile, call:logger.debug, call:profile_to_response, raise:HTTPException, func:delete_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:session.delete, call:session.commit, call:logger.debug, raise:HTTPException, func:update_profile_includes_endpoint(profile_id: str, data: ConfigProfileIncludeUpdate, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:update_includes, call:session.execute, call:select(ConfigProfileInclude).where, call:inc_result.scalars().all, call:logger.debug, call:profile_to_response, call:list, raise:HTTPException, func:preview_config_profile(profile_id: str, current_user_id, session), call:get_profile_with_includes, call:uuid.UUID, call:resolve_profile, call:resolved_profile_to_dict, raise:HTTPException, func:resolve_default_profile_endpoint(project_id, tool_type_id, current_user_id, session), call:resolve_default_profile, call:uuid.UUID, func:get_default_profiles_endpoint(user_id, session) → dict, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, func:set_default_profiles_endpoint(data: DefaultProfilesUpdate, user_id, session) → dict, call:validate_default_profiles, call:get_or_create_user_config, call:session.commit, call:session.refresh, func:get_default_profile_for_tool_type_endpoint(tool_type_id: str, user_id, session) → dict, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:user_config.default_profiles.get, func:validate_git_url_endpoint(data: ValidateGitUrlRequest, current_user_id, session) → ValidateGitUrlResponse, call:validate_git_url | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.auth.dependencies, src.models, src.schemas.config, src.services.config.config_profile_resolver, src.services.config.crud_service, src.services.config.resolver_service
|
||||||
- user_config.py | Provides FastAPI endpoints to get and update the current user's configuration settings, creating a default config if none exists. | exp: func:_get_or_create_config(session: AsyncSession, user_id: uuid.UUID) → UserConfig, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:UserConfig, call:session.add, call:session.commit, call:session.refresh, func:get_user_config(user_id, session) → UserConfigResponse, call:_get_user, call:_get_or_create_config, call:UserConfigResponse.model_validate, func:update_user_config(data: UserConfigUpdate, user_id, session) → UserConfigResponse, call:_get_user, call:_get_or_create_config, call:data.model_dump, call:logger.debug, call:session.commit, call:session.refresh, call:UserConfigResponse.model_validate | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.schemas.user
|
- user_config.py | Provides FastAPI endpoints for retrieving and updating user configuration settings with automatic record creation. | exp: func:_get_or_create_config(session: AsyncSession, user_id: uuid.UUID) → UserConfig, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:UserConfig, call:session.add, call:session.commit, call:session.refresh, func:get_user_config(user_id, session) → UserConfigResponse, call:_get_user, call:_get_or_create_config, call:UserConfigResponse.model_validate, func:update_user_config(data: UserConfigUpdate, user_id, session) → UserConfigResponse, call:_get_user, call:_get_or_create_config, call:data.model_dump, call:logger.debug, call:session.commit, call:session.refresh, call:UserConfigResponse.model_validate | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.schemas.user
|
||||||
## arch
|
## arch
|
||||||
Modular FastAPI router pattern with separate route modules for distinct resource domains (user config vs config profiles), each implementing standard CRUD operations with validation and default initialization logic.
|
Modular router-based architecture using FastAPI with separate route modules for distinct config domains (profiles vs. user settings), CRUD patterns, and include resolution for hierarchical config.
|
||||||
## tags
|
## tags
|
||||||
config, profile, get, user, includes, call:uuid.uuid, or, default
|
config, profile, get, user, call:uuid.uuid, includes, or, default
|
||||||
## symbols
|
## symbols
|
||||||
- list_config_profiles
|
- list_config_profiles
|
||||||
- create_config_profile
|
- create_config_profile
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/project
|
dir: apps/api/src/api/project
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI REST API endpoints for project and Git repository management, serving as the HTTP interface layer for the project's core domain operations.
|
Provides FastAPI REST API endpoints for project and Git repository management, exposing CRUD operations and version control functionality to API consumers.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/system
|
dir: apps/api/src/api/system
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides system-level API endpoints for monitoring, administration, and infrastructure interaction including dashboards, health checks, event streaming, notifications, and container terminal access.
|
Provides system-level API endpoints for monitoring, administration, and operational infrastructure including health checks, dashboards, real-time events, notifications, and container terminal access.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ dir: apps/api/src/api/system
|
|||||||
index: apps/api/src/api/system/.pi-map.index.md
|
index: apps/api/src/api/system/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides system-level API endpoints for monitoring, administration, and infrastructure interaction including dashboards, health checks, event streaming, notifications, and container terminal access.
|
Provides system-level API endpoints for monitoring, administration, and operational infrastructure including health checks, dashboards, real-time events, notifications, and container terminal access.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Aggregates and re-exports system API router modules from submodules for centralized access. | dep: src.api.system.dashboard, src.api.system.events, src.api.system.health, src.api.system.instance_proxy, src.api.system.notifications, src.api.system.terminal
|
- __init__.py | Aggregates and re-exports system API routers from submodules for centralized access. | dep: src.api.system.dashboard, src.api.system.events, src.api.system.health, src.api.system.instance_proxy, src.api.system.notifications, src.api.system.terminal
|
||||||
- dashboard.py | Provides a FastAPI endpoint that returns a dashboard summary with aggregated counts of projects, repositories, SSH keys, and recent activity for the authenticated user. | exp: func:get_dashboard_summary(user_id, session) → dict, call:session.execute, call:select(func.count()).select_from(Project).where, call:func.count, call:projects_result.scalar, call:select(func.count()).select_from(GitRepository).where, call:repos_result.scalar, call:select(func.count()).select_from(SSHKey).where, call:ssh_keys_result.scalar, call:select(Project) .where(Project.owner_id == user_id) .order_by(Project.created_at.desc()) .limit, call:Project.created_at.desc, call:recent_projects.scalars().all | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.models.project, src.models (GitRepository, Project, SSHKey)
|
- dashboard.py | Provides a FastAPI endpoint that returns a dashboard summary with counts of projects, repositories, SSH keys, and recent activity for the authenticated user. | exp: func:get_dashboard_summary(user_id, session) → dict, call:session.execute, call:select(func.count()).select_from(Project).where, call:func.count, call:projects_result.scalar, call:select(func.count()).select_from(GitRepository).where, call:repos_result.scalar, call:select(func.count()).select_from(SSHKey).where, call:ssh_keys_result.scalar, call:select(Project) .where(Project.owner_id == user_id) .order_by(Project.created_at.desc()) .limit, call:Project.created_at.desc, call:recent_projects.scalars().all | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.models.project
|
||||||
- events.py | Implements an SSE streaming endpoint that delivers instance events to authenticated users with per-user connection limits and keep-alive pings. | exp: func:events_stream(request: Request, user_id) → StreamingResponse, call:_connection_counts.get, call:InstanceEventBus, call:asyncio.Queue, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait, call:event_bus.subscribe, call:asyncio.wait_for, call:queue.get, call:json.dumps, call:unsubscribe, call:max, call:_connection_counts.pop, call:StreamingResponse, call:event_generator, raise:HTTPException, func:event_generator() → AsyncGenerator[str, None], call:InstanceEventBus, call:asyncio.Queue, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait, call:event_bus.subscribe, call:asyncio.wait_for, call:queue.get, call:json.dumps, call:unsubscribe, call:max, call:_connection_counts.get, call:_connection_counts.pop, func:on_event(payload: InstanceEventPayload) → None, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait | dep: asyncio, contextlib, json, uuid, collections.abc, fastapi, fastapi.responses, src.auth.dependencies, src.services.instance.event_bus
|
- events.py | Implements an SSE streaming endpoint that broadcasts instance events to authenticated users with per-user connection limits and backpressure handling. | exp: func:events_stream(request: Request, user_id) → StreamingResponse, call:_connection_counts.get, call:InstanceEventBus, call:asyncio.Queue, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait, call:event_bus.subscribe, call:asyncio.wait_for, call:queue.get, call:json.dumps, call:unsubscribe, call:max, call:_connection_counts.pop, call:StreamingResponse, call:event_generator, raise:HTTPException, func:event_generator() → AsyncGenerator[str, None], call:InstanceEventBus, call:asyncio.Queue, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait, call:event_bus.subscribe, call:asyncio.wait_for, call:queue.get, call:json.dumps, call:unsubscribe, call:max, call:_connection_counts.get, call:_connection_counts.pop, func:on_event(payload: InstanceEventPayload) → None, call:queue.put_nowait, call:contextlib.suppress, call:queue.get_nowait | dep: asyncio, contextlib, json, uuid, collections.abc, fastapi, fastapi.responses, src.auth.dependencies, src.services.instance.event_bus
|
||||||
- health.py | Implements FastAPI health check endpoints for monitoring system status including database connectivity and disk space. | exp: func:health_check() → dict[str, Any], call:HealthChecks, call:time_module.perf_counter, call:SessionLocal, call:session.execute, call:text, call:DatabaseHealth, call:round, call:shutil.disk_usage, call:DiskHealth, call:HealthResponse( status=overall_status, timestamp=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"), version="0.1.0", checks=checks, uptime_seconds=round(time.time() - _start_time, 2), ).model_dump, call:datetime.now(timezone.utc).isoformat().replace, call:time.time, func:health_check_db() → dict[str, Any], call:time_module.perf_counter, call:SessionLocal, call:session.execute, call:text, call:DatabaseHealthResponse( status="healthy", response_time_ms=round(db_time, 2), ).model_dump, call:round, call:DatabaseHealthResponse( status="unhealthy", response_time_ms=0.0, ).model_dump | dep: time, datetime, typing, fastapi, sqlalchemy, src.database, src.schemas.system, shutil
|
- health.py | Provides FastAPI health check endpoints that monitor database connectivity, disk space, and system uptime with performance timing. | exp: func:health_check() → dict[str, Any], call:HealthChecks, call:time_module.perf_counter, call:SessionLocal, call:session.execute, call:text, call:DatabaseHealth, call:round, call:shutil.disk_usage, call:DiskHealth, call:HealthResponse( status=overall_status, timestamp=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"), version="0.1.0", checks=checks, uptime_seconds=round(time.time() - _start_time, 2), ).model_dump, call:datetime.now(timezone.utc).isoformat().replace, call:time.time, func:health_check_db() → dict[str, Any], call:time_module.perf_counter, call:SessionLocal, call:session.execute, call:text, call:DatabaseHealthResponse( status="healthy", response_time_ms=round(db_time, 2), ).model_dump, call:round, call:DatabaseHealthResponse( status="unhealthy", response_time_ms=0.0, ).model_dump | dep: time, datetime, typing, fastapi, sqlalchemy, src.database, src.schemas.system, shutil
|
||||||
- instance_proxy.py | Proxies HTTP requests from FastAPI endpoints to running containerized tool instances after verifying ownership and status. | exp: func:_proxy_request(request: Request, instance_id: uuid.UUID, path: str, user_id: uuid.UUID, session: AsyncSession) → Response, call:session.get, call:str, call:request.headers.items, call:key.lower, call:httpx.AsyncClient, call:request.body, call:client.request, call:logger.error, call:dict, call:response_headers.pop, call:Response, raise:HTTPException, func:proxy_to_instance(request: Request, instance_id: uuid.UUID, path, user_id, session) → Response, call:_proxy_request | dep: logging, uuid, httpx, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models
|
- instance_proxy.py | HTTP proxy router that forwards incoming requests to running containerized tool instances after verifying ownership and instance status. | exp: func:_proxy_request(request: Request, instance_id: uuid.UUID, path: str, user_id: uuid.UUID, session: AsyncSession) → Response, call:session.get, call:str, call:request.headers.items, call:key.lower, call:httpx.AsyncClient, call:request.body, call:client.request, call:logger.error, call:dict, call:response_headers.pop, call:Response, raise:HTTPException, func:proxy_to_instance(request: Request, instance_id: uuid.UUID, path, user_id, session) → Response, call:_proxy_request | dep: logging, uuid, httpx, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models
|
||||||
- notifications.py | Defines FastAPI REST endpoints for managing user notifications (list, unread count, mark read, dismiss/clear) with support for muted categories from user config. | exp: class:NotificationItem, class:NotificationListResponse, class:UnreadCountResponse, class:MarkAllReadResponse, class:ClearAllResponse, func:_get_mute_categories(session: AsyncSession, user_id: uuid.UUID) → list[str], call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:config.config.get, call:isinstance, func:list_notifications(limit, offset, unread_only, user, session) → NotificationListResponse, call:_get_mute_categories, call:notification_service.list_notifications, call:NotificationListResponse, call:NotificationItem.model_validate, func:get_unread_count(user, session) → UnreadCountResponse, call:notification_service.get_unread_count, call:UnreadCountResponse, func:mark_notification_read(notification_id: uuid.UUID, user, session) → NotificationItem, call:notification_service.mark_read, call:NotificationItem.model_validate, raise:HTTPException, func:mark_all_read(user, session) → MarkAllReadResponse, call:notification_service.mark_all_read, call:MarkAllReadResponse, func:clear_all_notifications(user, session) → ClearAllResponse, call:notification_service.dismiss_all, call:ClearAllResponse, func:dismiss_notification(notification_id: uuid.UUID, user, session) → None, call:notification_service.dismiss, raise:HTTPException | dep: uuid, datetime, fastapi, pydantic, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models.user, src.models, src.services.shared.notification_service, sqlalchemy
|
- notifications.py | Provides FastAPI REST endpoints for managing user notifications including listing, marking read/unread, dismissing, and clearing all notifications with support for muted categories. | exp: class:NotificationItem, class:NotificationListResponse, class:UnreadCountResponse, class:MarkAllReadResponse, class:ClearAllResponse, func:_get_mute_categories(session: AsyncSession, user_id: uuid.UUID) → list[str], call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:config.config.get, call:isinstance, func:list_notifications(limit, offset, unread_only, user, session) → NotificationListResponse, call:_get_mute_categories, call:notification_service.list_notifications, call:NotificationListResponse, call:NotificationItem.model_validate, func:get_unread_count(user, session) → UnreadCountResponse, call:notification_service.get_unread_count, call:UnreadCountResponse, func:mark_notification_read(notification_id: uuid.UUID, user, session) → NotificationItem, call:notification_service.mark_read, call:NotificationItem.model_validate, raise:HTTPException, func:mark_all_read(user, session) → MarkAllReadResponse, call:notification_service.mark_all_read, call:MarkAllReadResponse, func:clear_all_notifications(user, session) → ClearAllResponse, call:notification_service.dismiss_all, call:ClearAllResponse, func:dismiss_notification(notification_id: uuid.UUID, user, session) → None, call:notification_service.dismiss, raise:HTTPException | dep: uuid, datetime, fastapi, pydantic, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models.user, src.models, src.services.shared.notification_service, sqlalchemy
|
||||||
- terminal.py | Provides WebSocket and HTTP endpoints for managing interactive terminal sessions attached to running Docker container tool instances, including session creation, attachment, input/output streaming, resize/reset control messages, and session listing. | exp: class:SessionRef, method:__init__(self, session, slot_session_id), func:terminal_websocket_default(websocket: WebSocket, instance_id: str, db_session) → None, call:_handle_terminal_websocket, func:terminal_websocket_specific(websocket: WebSocket, instance_id: str, session_id: str, db_session) → None, call:_handle_terminal_websocket, func:_handle_terminal_websocket(websocket: WebSocket, instance_id: str, target_session_id: str | None, db_session: AsyncSession) → None, call:logger.debug, call:websocket.accept, call:uuid.UUID, call:logger.error, call:websocket.close, call:_get_user_from_websocket, call:logger.warning, call:db_session.get, call:get_container_status, call:terminal_manager.get_or_create_session, call:terminal_manager.get_session, call:logger.info, call:terminal_manager.create_session, call:terminal_manager._find_key_by_internal_id, call:terminal_manager.attach_websocket, call:websocket.send_json, call:SessionRef, call:asyncio.create_task, call:_write_loop, call:_heartbeat_loop, call:asyncio.wait, call:len, call:task.cancel, call:str, call:suppress, call:terminal_manager.detach_websocket, func:_write_loop(session_ref: SessionRef, websocket, instance_id: str) → None, call:session.is_alive, call:asyncio.sleep, call:websocket.receive, call:session.write_input, call:text.startswith, call:json.loads, call:ctrl.get, call:logger.debug, call:session.resize, call:session.acknowledge_data, call:websocket.send_json, call:terminal_manager.reset_session, call:terminal_manager.attach_websocket, call:text.encode, func:_heartbeat_loop(websocket: WebSocket) → None, call:asyncio.sleep, call:websocket.send_json, func:_get_terminal_instance(instance_id: uuid.UUID, user_id: uuid.UUID, db_session: AsyncSession) → ToolInstance, call:db_session.get, raise:HTTPException, func:list_terminal_sessions(instance_id: uuid.UUID, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.execute, call:select(TerminalSessionModel) .where(TerminalSessionModel.instance_id == instance_id) .where(TerminalSessionModel.status != "closed") .order_by, call:TerminalSessionModel.created_at.asc, call:result.scalars().all, call:terminal_manager.get_session, call:str, call:sessions.append, call:live_session.has_websockets, call:row.created_at.isoformat, call:row.last_activity_at.isoformat, func:create_terminal_session(instance_id: uuid.UUID, data: dict, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.get, call:data.get, call:terminal_manager.create_session, raise:HTTPException, func:close_terminal_session(instance_id: uuid.UUID, session_id: str, user_id, db_session) → dict, call:_get_terminal_instance, call:terminal_manager._find_key_by_internal_id, call:str, call:terminal_manager.get_session, call:terminal_manager.close_session, raise:HTTPException, func:reset_specific_terminal_session(instance_id: uuid.UUID, session_id: str, user_id, db_session) → dict, call:_get_terminal_instance, call:terminal_manager._find_key_by_internal_id, call:str, call:terminal_manager.get_session, call:db_session.get, call:terminal_manager.reset_session, raise:HTTPException, func:rename_terminal_session(instance_id: uuid.UUID, session_id: str, data: dict, user_id, db_session) → dict, call:_get_terminal_instance, call:data.get, call:isinstance, call:terminal_manager.get_session, call:str, call:db_session.get, call:uuid.UUID, call:db_session.commit, raise:HTTPException, func:reset_terminal_session(instance_id: uuid.UUID, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.get, call:terminal_manager.reset_session, call:logger.info, call:str, call:logger.error, raise:HTTPException, func:_get_user_from_websocket(websocket: WebSocket, db_session: AsyncSession) → uuid.UUID | None, call:websocket.cookies.get, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str | dep: asyncio, json, logging, uuid, contextlib, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, starlette.websockets, src.auth.dependencies, src.models, src.services.terminal.terminal_manager, src.services.docker, src.auth.session, src.config, starlette
|
- terminal.py | Provides WebSocket and REST endpoints for browser-based terminal access to running Docker container tool instances, supporting multiple named sessions, authentication, and terminal reset/reconnect functionality. | exp: class:SessionRef, method:__init__(self, session, slot_session_id), func:terminal_websocket_default(websocket: WebSocket, instance_id: str, db_session) → None, call:_handle_terminal_websocket, func:terminal_websocket_specific(websocket: WebSocket, instance_id: str, session_id: str, db_session) → None, call:_handle_terminal_websocket, func:_handle_terminal_websocket(websocket: WebSocket, instance_id: str, target_session_id: str | None, db_session: AsyncSession) → None, call:logger.debug, call:websocket.accept, call:uuid.UUID, call:logger.error, call:websocket.close, call:_get_user_from_websocket, call:logger.warning, call:db_session.get, call:get_container_status, call:terminal_manager.get_or_create_session, call:terminal_manager.get_session, call:logger.info, call:terminal_manager.create_session, call:terminal_manager._find_key_by_internal_id, call:terminal_manager.attach_websocket, call:websocket.send_json, call:SessionRef, call:asyncio.create_task, call:_write_loop, call:_heartbeat_loop, call:asyncio.wait, call:len, call:task.cancel, call:str, call:suppress, call:terminal_manager.detach_websocket, func:_write_loop(session_ref: SessionRef, websocket, instance_id: str) → None, call:session.is_alive, call:asyncio.sleep, call:websocket.receive, call:session.write_input, call:text.startswith, call:json.loads, call:ctrl.get, call:logger.debug, call:session.resize, call:session.acknowledge_data, call:websocket.send_json, call:terminal_manager.reset_session, call:terminal_manager.attach_websocket, call:text.encode, func:_heartbeat_loop(websocket: WebSocket) → None, call:asyncio.sleep, call:websocket.send_json, func:_get_terminal_instance(instance_id: uuid.UUID, user_id: uuid.UUID, db_session: AsyncSession) → ToolInstance, call:db_session.get, raise:HTTPException, func:list_terminal_sessions(instance_id: uuid.UUID, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.execute, call:select(TerminalSessionModel) .where(TerminalSessionModel.instance_id == instance_id) .where(TerminalSessionModel.status != "closed") .order_by, call:TerminalSessionModel.created_at.asc, call:result.scalars().all, call:terminal_manager.get_session, call:str, call:sessions.append, call:live_session.has_websockets, call:row.created_at.isoformat, call:row.last_activity_at.isoformat, func:create_terminal_session(instance_id: uuid.UUID, data: dict, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.get, call:data.get, call:terminal_manager.create_session, raise:HTTPException, func:close_terminal_session(instance_id: uuid.UUID, session_id: str, user_id, db_session) → dict, call:_get_terminal_instance, call:terminal_manager._find_key_by_internal_id, call:str, call:terminal_manager.get_session, call:terminal_manager.close_session, raise:HTTPException, func:reset_specific_terminal_session(instance_id: uuid.UUID, session_id: str, user_id, db_session) → dict, call:_get_terminal_instance, call:terminal_manager._find_key_by_internal_id, call:str, call:terminal_manager.get_session, call:db_session.get, call:terminal_manager.reset_session, raise:HTTPException, func:rename_terminal_session(instance_id: uuid.UUID, session_id: str, data: dict, user_id, db_session) → dict, call:_get_terminal_instance, call:data.get, call:isinstance, call:terminal_manager.get_session, call:str, call:db_session.get, call:uuid.UUID, call:db_session.commit, raise:HTTPException, func:reset_terminal_session(instance_id: uuid.UUID, user_id, db_session) → dict, call:_get_terminal_instance, call:db_session.get, call:terminal_manager.reset_session, call:logger.info, call:str, call:logger.error, raise:HTTPException, func:_get_user_from_websocket(websocket: WebSocket, db_session: AsyncSession) → uuid.UUID | None, call:websocket.cookies.get, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str | dep: asyncio, json, logging, uuid, contextlib, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, starlette.websockets, src.auth.dependencies, src.models, src.services.terminal.terminal_manager, src.services.docker, src.auth.session, src.config, starlette
|
||||||
## arch
|
## arch
|
||||||
FastAPI router modules organized by domain concern with async/await patterns, SSE/WebSocket for real-time streaming, proxy pattern for container instance forwarding, and per-user authentication/authorization with connection limiting.
|
FastAPI router composition pattern with modular sub-routers aggregated via __init__.py, combining synchronous REST endpoints, SSE streaming, and WebSocket connections for real-time features, with authentication enforcement and resource ownership validation across operational and infrastructure concerns.
|
||||||
## tags
|
## tags
|
||||||
session, terminal, call:terminal, call:, src, get, response, websocket
|
terminal, session, call:terminal, call:, get, src, response, instance
|
||||||
## symbols
|
## symbols
|
||||||
- NotificationItem
|
- NotificationItem
|
||||||
- NotificationListResponse
|
- NotificationListResponse
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/tool
|
dir: apps/api/src/api/tool
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI REST API endpoints for managing Docker-based tools, including their definitions, types, instances, lifecycle operations, and active sessions.
|
Provides FastAPI REST API endpoints for managing containerized tools throughout their lifecycle, including type definitions, instance management, session tracking, and Docker operations.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ dir: apps/api/src/api/tool
|
|||||||
index: apps/api/src/api/tool/.pi-map.index.md
|
index: apps/api/src/api/tool/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI REST API endpoints for managing Docker-based tools, including their definitions, types, instances, lifecycle operations, and active sessions.
|
Provides FastAPI REST API endpoints for managing containerized tools throughout their lifecycle, including type definitions, instance management, session tracking, and Docker operations.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Aggregates and exports all tool-related API routers from submodules as a unified module interface. | dep: src.api.tool.sessions, src.api.tool.tool_definitions, src.api.tool.tool_instances, src.api.tool.tool_lifecycle, src.api.tool.tool_types
|
- __init__.py | Aggregates and exports router modules for the Tool API package. | dep: src.api.tool.sessions, src.api.tool.tool_definitions, src.api.tool.tool_instances, src.api.tool.tool_lifecycle, src.api.tool.tool_types
|
||||||
- sessions.py | Provides a FastAPI endpoint to retrieve all active tool instances (sessions) for the currently authenticated user with related metadata. | exp: func:get_user_sessions(user_id, session) → dict, call:_get_user, call:session.execute, call:select(ToolInstance) .where(ToolInstance.owner_id == user_id) .where( ToolInstance.status.in_( ["running", "building", "pending", "stopped", "error"] ) ) .order_by, call:ToolInstance.status.in_, call:ToolInstance.created_at.desc, call:result.scalars().all, call:session.get, call:sessions.append, call:str, call:instance.created_at.isoformat | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.models (GitRepository, Project, ToolInstance, ToolType, Workspace)
|
- sessions.py | Provides a FastAPI endpoint to retrieve all active tool sessions (running instances) for the currently authenticated user with related metadata. | exp: func:get_user_sessions(user_id, session) → dict, call:_get_user, call:session.execute, call:select(ToolInstance) .where(ToolInstance.owner_id == user_id) .where( ToolInstance.status.in_( ["running", "building", "pending", "stopped", "error"] ) ) .order_by, call:ToolInstance.status.in_, call:ToolInstance.created_at.desc, call:result.scalars().all, call:session.get, call:sessions.append, call:str, call:instance.created_at.isoformat | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models
|
||||||
- tool_definitions.py | FastAPI router providing CRUD endpoints and manifest compilation for tool definition manifests stored in a database. | exp: class:CreateToolDefinitionRequest, class:UpdateToolDefinitionRequest, func:create_tool_definition(data: CreateToolDefinitionRequest, user_id, session) → dict, call:uuid.UUID, call:session.get, call:session.execute, call:select(ToolDefinitionManifest).where, call:existing.scalar_one_or_none, call:ToolDefinitionManifest, call:session.add, call:session.commit, call:session.refresh, call:logger.info, call:str, call:definition.created_at.isoformat, raise:HTTPException, func:list_tool_definitions(user_id, session, include_bases) → dict, call:select, call:query.where, call:ToolDefinitionManifest.is_base.is_, call:session.execute, call:query.order_by, call:ToolDefinitionManifest.created_at.desc, call:result.scalars().all, call:str, call:d.created_at.isoformat, func:get_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:str, call:definition.created_at.isoformat, call:definition.updated_at.isoformat, raise:HTTPException, func:update_tool_definition(definition_id: uuid.UUID, data: UpdateToolDefinitionRequest, user_id, session) → dict, call:session.get, call:session.commit, call:session.refresh, call:logger.info, call:str, call:definition.updated_at.isoformat, raise:HTTPException, func:delete_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:session.execute, call:select(ToolType).where, call:result.scalars().all, call:", ".join, call:session.delete, call:session.commit, call:logger.info, call:str, raise:HTTPException, func:compile_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:dict, call:resolve_base, call:deep_merge, call:compile_dockerfile, call:compile_entrypoint, call:compute_image_tag, call:compile_compose, call:session.commit, call:str, raise:HTTPException | dep: logging, uuid, fastapi, pydantic, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.build.manifest_compiler
|
- tool_definitions.py | Provides FastAPI CRUD endpoints for managing tool definition manifests with compilation to Dockerfile and Docker Compose previews. | exp: class:CreateToolDefinitionRequest, class:UpdateToolDefinitionRequest, func:create_tool_definition(data: CreateToolDefinitionRequest, user_id, session) → dict, call:uuid.UUID, call:session.get, call:session.execute, call:select(ToolDefinitionManifest).where, call:existing.scalar_one_or_none, call:ToolDefinitionManifest, call:session.add, call:session.commit, call:session.refresh, call:logger.info, call:str, call:definition.created_at.isoformat, raise:HTTPException, func:list_tool_definitions(user_id, session, include_bases) → dict, call:select, call:query.where, call:ToolDefinitionManifest.is_base.is_, call:session.execute, call:query.order_by, call:ToolDefinitionManifest.created_at.desc, call:result.scalars().all, call:str, call:d.created_at.isoformat, func:get_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:str, call:definition.created_at.isoformat, call:definition.updated_at.isoformat, raise:HTTPException, func:update_tool_definition(definition_id: uuid.UUID, data: UpdateToolDefinitionRequest, user_id, session) → dict, call:session.get, call:session.commit, call:session.refresh, call:logger.info, call:str, call:definition.updated_at.isoformat, raise:HTTPException, func:delete_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:session.execute, call:select(ToolType).where, call:result.scalars().all, call:", ".join, call:session.delete, call:session.commit, call:logger.info, call:str, raise:HTTPException, func:compile_tool_definition(definition_id: uuid.UUID, user_id, session) → dict, call:session.get, call:dict, call:resolve_base, call:deep_merge, call:compile_dockerfile, call:compile_entrypoint, call:compute_image_tag, call:compile_compose, call:session.commit, call:str, raise:HTTPException | dep: logging, uuid, fastapi, pydantic, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.build.manifest_compiler
|
||||||
- tool_instances.py | Provides FastAPI REST endpoints for managing tool instances including CRUD operations, logs, health checks, tunnel recreation, event history, and HTTP proxying to running containers. | exp: func:create_instance(project_id: uuid.UUID, repo_id: uuid.UUID, data: CreateInstanceRequest, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:create_tool_instance, call:str, call:instance.created_at.isoformat, raise:HTTPException, func:list_instances(project_id: uuid.UUID, repo_id: uuid.UUID, user_id, session) → list[dict], call:_get_user, call:_get_owned_project, call:session.execute, call:select(ToolInstance) .where(ToolInstance.repository_id == repo_id) .where(ToolInstance.owner_id == user_id) .order_by, call:ToolInstance.created_at.desc, call:result.scalars().all, call:str, call:i.created_at.isoformat, func:get_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_status, call:str, call:instance.created_at.isoformat, call:instance.last_started_at.isoformat, raise:HTTPException, func:rename_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:data.get("display_name", "").strip, call:rename_tool_instance, call:str, raise:HTTPException, func:get_instance_logs(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, tail, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_logs, raise:HTTPException, func:recreate_tunnel_endpoint(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:recreate_instance_tunnel, raise:HTTPException, func:check_instance_tunnel_health(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_status, call:instance.probe_result.get, call:"\n".join, call:check_tunnel_health, call:tunnel_health.get, raise:HTTPException, func:get_instance_events(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, limit, user_id, session) → list[dict], call:_get_user, call:_get_owned_project, call:session.get, call:session.execute, call:select(InstanceEvent) .where(InstanceEvent.instance_id == instance_id) .order_by(InstanceEvent.created_at.desc()) .limit, call:InstanceEvent.created_at.desc, call:result.scalars().all, call:str, call:row.created_at.isoformat, raise:HTTPException, func:proxy_to_instance(request: Request, project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, path, user_id, session) → Response, call:session.get, call:str, call:dict, call:headers.pop, call:httpx.AsyncClient, call:request.body, call:client.request, call:logger.error, call:response_headers.pop, call:Response, raise:HTTPException | dep: logging, uuid, httpx, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.docker, src.services.shared.tunnel, src.schemas.tool, src.services.tool.instance_service
|
- tool_instances.py | FastAPI router providing REST endpoints for managing tool instances (CRUD, logs, health checks, tunnel management, proxying, and event history) within project repositories. | exp: func:create_instance(project_id: uuid.UUID, repo_id: uuid.UUID, data: CreateInstanceRequest, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:create_tool_instance, call:str, call:instance.created_at.isoformat, raise:HTTPException, func:list_instances(project_id: uuid.UUID, repo_id: uuid.UUID, user_id, session) → list[dict], call:_get_user, call:_get_owned_project, call:session.execute, call:select(ToolInstance) .where(ToolInstance.repository_id == repo_id) .where(ToolInstance.owner_id == user_id) .order_by, call:ToolInstance.created_at.desc, call:result.scalars().all, call:str, call:i.created_at.isoformat, func:get_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_status, call:str, call:instance.created_at.isoformat, call:instance.last_started_at.isoformat, raise:HTTPException, func:rename_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:data.get("display_name", "").strip, call:rename_tool_instance, call:str, raise:HTTPException, func:get_instance_logs(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, tail, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_logs, raise:HTTPException, func:recreate_tunnel_endpoint(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:recreate_instance_tunnel, raise:HTTPException, func:check_instance_tunnel_health(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:session.get, call:get_container_status, call:instance.probe_result.get, call:"\n".join, call:check_tunnel_health, call:tunnel_health.get, raise:HTTPException, func:get_instance_events(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, limit, user_id, session) → list[dict], call:_get_user, call:_get_owned_project, call:session.get, call:session.execute, call:select(InstanceEvent) .where(InstanceEvent.instance_id == instance_id) .order_by(InstanceEvent.created_at.desc()) .limit, call:InstanceEvent.created_at.desc, call:result.scalars().all, call:str, call:row.created_at.isoformat, raise:HTTPException, func:proxy_to_instance(request: Request, project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, path, user_id, session) → Response, call:session.get, call:str, call:dict, call:headers.pop, call:httpx.AsyncClient, call:request.body, call:client.request, call:logger.error, call:response_headers.pop, call:Response, raise:HTTPException | dep: logging, uuid, httpx, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.docker, src.services.shared.tunnel, src.schemas.tool, src.services.tool.instance_service
|
||||||
- tool_lifecycle.py | FastAPI router providing REST endpoints for managing Docker-based tool instance lifecycle operations (start, stop, restart, delete). | exp: func:start_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, data, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:start_tool_instance, raise:HTTPException, func:stop_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:stop_tool_instance, raise:HTTPException, func:restart_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:restart_tool_instance, raise:HTTPException, func:delete_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, force, user_id, session) → None, call:_get_user, call:_get_owned_project, call:delete_tool_instance, call:str, call:detail.lower, raise:HTTPException | dep: logging, uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.schemas.tool, src.services.tool.instance_service
|
- tool_lifecycle.py | FastAPI router providing REST endpoints for managing Docker-based tool instance lifecycle operations (start, stop, restart, delete). | exp: func:start_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, data, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:start_tool_instance, raise:HTTPException, func:stop_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:stop_tool_instance, raise:HTTPException, func:restart_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:_get_owned_project, call:restart_tool_instance, raise:HTTPException, func:delete_instance(project_id: uuid.UUID, repo_id: uuid.UUID, instance_id: uuid.UUID, force, user_id, session) → None, call:_get_user, call:_get_owned_project, call:delete_tool_instance, call:str, call:detail.lower, raise:HTTPException | dep: logging, uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.schemas.tool, src.services.tool.instance_service
|
||||||
- tool_types.py | Defines FastAPI routes for CRUD operations and validation of Docker tool types with compose/dockerfile/manifest definitions. | exp: func:_require_admin(user: User) → None, func:create_tool_type(data: ToolTypeCreate, user_id, session) → ToolType, call:_get_user, call:_require_admin, call:session.scalar, call:select(ToolType).where, call:ToolType, call:session.add, call:session.commit, call:session.refresh, raise:HTTPException, func:list_tool_types(user_id, session) → list[ToolType], call:_get_user, call:session.execute, call:select(ToolType).order_by, call:list, call:result.scalars().all, func:get_tool_type(tool_type_id: uuid.UUID, user_id, session) → ToolType, call:_get_user, call:session.get, raise:HTTPException, func:update_tool_type(tool_type_id: uuid.UUID, data: ToolTypeUpdate, user_id, session) → ToolType, call:_get_user, call:_require_admin, call:session.get, call:data.model_dump, call:update_data.get, call:validate_compose_yaml, call:check_port_exposed, call:validate_required_variables, call:update_data.items, call:setattr, call:session.commit, call:session.refresh, raise:HTTPException, func:validate_tool_type_template(data: ToolTypeValidateRequest, user_id, session) → dict, call:_get_user, call:errors.append, call:validate_compose_yaml, call:str, call:data.dockerfile_template.strip().startswith, call:len, func:validate_tool_type(tool_type_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:session.get, call:errors.append, call:validate_compose_yaml, call:str, call:tool_type.dockerfile_template.strip().startswith, call:len, raise:HTTPException, func:delete_tool_type(tool_type_id: uuid.UUID, user_id, session) → None, call:_get_user, call:_require_admin, call:session.get, call:session.delete, call:session.commit, raise:HTTPException | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.api.tool.tool_types_validation, src.auth.dependencies, src.models, src.models.user, src.schemas.tool
|
- tool_types.py | Defines FastAPI REST endpoints for CRUD operations on tool types with validation for Docker Compose, Dockerfile, and manifest definitions. | exp: func:_require_admin(user: User) → None, func:create_tool_type(data: ToolTypeCreate, user_id, session) → ToolType, call:_get_user, call:_require_admin, call:session.scalar, call:select(ToolType).where, call:ToolType, call:session.add, call:session.commit, call:session.refresh, raise:HTTPException, func:list_tool_types(user_id, session) → list[ToolType], call:_get_user, call:session.execute, call:select(ToolType).order_by, call:list, call:result.scalars().all, func:get_tool_type(tool_type_id: uuid.UUID, user_id, session) → ToolType, call:_get_user, call:session.get, raise:HTTPException, func:update_tool_type(tool_type_id: uuid.UUID, data: ToolTypeUpdate, user_id, session) → ToolType, call:_get_user, call:_require_admin, call:session.get, call:data.model_dump, call:update_data.get, call:validate_compose_yaml, call:check_port_exposed, call:validate_required_variables, call:update_data.items, call:setattr, call:session.commit, call:session.refresh, raise:HTTPException, func:validate_tool_type_template(data: ToolTypeValidateRequest, user_id, session) → dict, call:_get_user, call:errors.append, call:validate_compose_yaml, call:str, call:data.dockerfile_template.strip().startswith, call:len, func:validate_tool_type(tool_type_id: uuid.UUID, user_id, session) → dict, call:_get_user, call:session.get, call:errors.append, call:validate_compose_yaml, call:str, call:tool_type.dockerfile_template.strip().startswith, call:len, raise:HTTPException, func:delete_tool_type(tool_type_id: uuid.UUID, user_id, session) → None, call:_get_user, call:_require_admin, call:session.get, call:session.delete, call:session.commit, raise:HTTPException | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.api.tool.tool_types_validation, src.auth.dependencies, src.models, src.models.user, src.schemas.tool
|
||||||
- tool_types_validation.py | Validates Docker Compose YAML templates by sanitizing template variables, parsing YAML structure, checking port exposure, and verifying required variables exist. | exp: func:sanitize_template_vars(template: str) → str, call:re.sub, func:validate_compose_yaml(template: str) → dict, call:sanitize_template_vars, call:yaml.safe_load, call:isinstance, raise:ValueError, func:check_port_exposed(parsed: dict, port: int) → bool, call:str, call:isinstance, call:parsed["services"].values, call:port_mapping.split, call:mapping.split, func:validate_required_variables(template: str, variables: list[str]) → None, raise:HTTPException | dep: re, yaml, fastapi
|
- tool_types_validation.py | Provides validation utilities for Docker Compose templates including YAML parsing, port exposure checking, and required template variable verification. | exp: func:sanitize_template_vars(template: str) → str, call:re.sub, func:validate_compose_yaml(template: str) → dict, call:sanitize_template_vars, call:yaml.safe_load, call:isinstance, raise:ValueError, func:check_port_exposed(parsed: dict, port: int) → bool, call:str, call:isinstance, call:parsed["services"].values, call:port_mapping.split, call:mapping.split, func:validate_required_variables(template: str, variables: list[str]) → None, raise:HTTPException | dep: re, yaml, fastapi
|
||||||
## arch
|
## arch
|
||||||
Modular FastAPI router organization with clear separation of concerns across CRUD operations, Docker lifecycle management, YAML/Compose validation, and container proxying/tunneling.
|
Modular FastAPI router pattern with domain-driven separation of concerns (types, instances, sessions, lifecycle) and Docker-centric validation/compilation utilities for container orchestration.
|
||||||
## tags
|
## tags
|
||||||
get, call:, tool, raise:httpexception, user, instance, call:str, call:session.get
|
get, call:, tool, raise:httpexception, user, instance, call:str, call:session.get
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/user
|
dir: apps/api/src/api/user
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides authentication, user profile management, and SSH key operations for the API backend.
|
Provides user-facing API endpoints for authentication, profile management, and SSH key operations in the FastAPI backend.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/api/user
|
|||||||
index: apps/api/src/api/user/.pi-map.index.md
|
index: apps/api/src/api/user/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides authentication, user profile management, and SSH key operations for the API backend.
|
Provides user-facing API endpoints for authentication, profile management, and SSH key operations in the FastAPI backend.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Aggregates and exports user-related API routers from submodules for easy importing | dep: src.api.user.auth, src.api.user.ssh_keys, src.api.user.users
|
- __init__.py | Aggregates and exports user-related API routers from submodules for easy importing. | dep: src.api.user.auth, src.api.user.ssh_keys, src.api.user.users
|
||||||
- auth.py | Implements OAuth2/OIDC authentication endpoints for a FastAPI application using Authentik as the identity provider, including login initiation, callback handling, logout, and current user retrieval. | exp: func:get_db_session() → AsyncGenerator[AsyncSession, None], call:SessionLocal, func:login(next) → RedirectResponse, call:Settings, call:token_urlsafe, call:build_login_redirect_url, call:logger.debug, call:RedirectResponse, call:response.set_cookie, func:callback(code: str, state: str, auth_state, auth_next, session) → RedirectResponse, call:logger.debug, call:logger.warning, call:Settings, call:httpx.AsyncClient, call:exchange_code_for_tokens, call:logger.info, call:logger.error, call:fetch_user_info, call:str, call:user_info.get, call:session.scalar, call:select(User).where, call:User, call:session.add, call:session.commit, call:session.refresh, call:create_session_cookie, call:build_cookie_options, call:cast, call:bool, call:cookie_options.get, call:RedirectResponse, call:redirect_response.set_cookie, call:redirect_response.delete_cookie, raise:HTTPException, func:logout(response: Response) → dict[str, str], call:Settings, call:build_cookie_options, call:cast, call:bool, call:str, call:cookie_options.get, call:response.delete_cookie, func:me(session_cookie, session) → dict[str, Any], call:logger.debug, call:bool, call:logger.warning, call:Settings, call:decode_session_cookie, call:session.get, call:logger.info, call:str, raise:HTTPException | dep: logging, secrets, typing, httpx, fastapi, fastapi.responses, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.cookies, src.auth.oidc, src.auth.session, src.config, src.database, src.models.user
|
- auth.py | Implements OAuth2/OIDC authentication endpoints for a FastAPI application using Authentik as the identity provider, including login initiation, callback handling, session management, logout, and current user retrieval. | exp: func:get_db_session() → AsyncGenerator[AsyncSession, None], call:SessionLocal, func:login(next) → RedirectResponse, call:Settings, call:token_urlsafe, call:build_login_redirect_url, call:logger.debug, call:RedirectResponse, call:response.set_cookie, func:callback(code: str, state: str, auth_state, auth_next, session) → RedirectResponse, call:logger.debug, call:logger.warning, call:Settings, call:httpx.AsyncClient, call:exchange_code_for_tokens, call:logger.info, call:logger.error, call:fetch_user_info, call:str, call:user_info.get, call:session.scalar, call:select(User).where, call:User, call:session.add, call:session.commit, call:session.refresh, call:create_session_cookie, call:build_cookie_options, call:cast, call:bool, call:cookie_options.get, call:RedirectResponse, call:redirect_response.set_cookie, call:redirect_response.delete_cookie, raise:HTTPException, func:logout(response: Response) → dict[str, str], call:Settings, call:build_cookie_options, call:cast, call:bool, call:str, call:cookie_options.get, call:response.delete_cookie, func:me(session_cookie, session) → dict[str, Any], call:logger.debug, call:bool, call:logger.warning, call:Settings, call:decode_session_cookie, call:session.get, call:logger.info, call:str, raise:HTTPException | dep: logging, secrets, typing, httpx, fastapi, fastapi.responses, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.cookies, src.auth.oidc, src.auth.session, src.config, src.database, src.models.user
|
||||||
- ssh_keys.py | Implements a FastAPI router for managing Ed25519 SSH key pairs, including generation, storage with encrypted private keys, listing, deletion, and cryptographic signing/verification operations. | exp: func:_get_fernet() → Fernet, call:Settings, call:hashlib.sha256(settings.session_secret.encode()).digest, call:settings.session_secret.encode, call:base64.urlsafe_b64encode, call:Fernet, func:generate_ssh_key_pair() → tuple[str, str], call:Ed25519PrivateKey.generate, call:private_key.public_key, call:private_key.private_bytes, call:serialization.NoEncryption, call:public_key.public_bytes, call:private_bytes.decode, call:public_bytes.decode, func:create_ssh_key(data: SSHKeyCreate, user_id, session) → SSHKey, call:_get_user, call:generate_ssh_key_pair, call:_get_fernet, call:fernet.encrypt(private_key.encode()).decode, call:private_key.encode, call:SSHKey, call:session.add, call:session.commit, call:session.refresh, func:list_ssh_keys(user_id, session) → list[SSHKey], call:_get_user, call:session.execute, call:select(SSHKey).where, call:list, call:result.scalars().all, func:delete_ssh_key(key_id: uuid.UUID, user_id, session) → None, call:_get_user, call:session.get, call:session.delete, call:session.commit, raise:HTTPException, func:sign_payload(key_id: uuid.UUID, data: SignPayloadRequest, user_id, session) → SignatureResponse, call:_get_user, call:session.get, call:_get_fernet, call:fernet.decrypt(ssh_key.private_key_encrypted.encode()).decode, call:ssh_key.private_key_encrypted.encode, call:serialization.load_ssh_private_key, call:private_key_pem.encode, call:private_key.sign, call:data.payload.encode, call:SignatureResponse, call:base64.b64encode(signature).decode, raise:HTTPException, func:verify_signature(key_id: uuid.UUID, data: VerifySignatureRequest, user_id, session) → VerifySignatureResponse, call:_get_user, call:session.get, call:serialization.load_ssh_public_key, call:ssh_key.public_key.encode, call:base64.b64decode, call:public_key.verify, call:data.payload.encode, call:VerifySignatureResponse, raise:HTTPException | dep: base64, uuid, cryptography.fernet, cryptography.hazmat.primitives, cryptography.hazmat.primitives.asymmetric.ed25519, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.config, src.models, src.schemas.project, hashlib, cryptography
|
- ssh_keys.py | FastAPI router for managing Ed25519 SSH keys including generation, storage with encrypted private keys, signing payloads, and signature verification | exp: func:_get_fernet() → Fernet, call:Settings, call:hashlib.sha256(settings.session_secret.encode()).digest, call:settings.session_secret.encode, call:base64.urlsafe_b64encode, call:Fernet, func:generate_ssh_key_pair() → tuple[str, str], call:Ed25519PrivateKey.generate, call:private_key.public_key, call:private_key.private_bytes, call:serialization.NoEncryption, call:public_key.public_bytes, call:private_bytes.decode, call:public_bytes.decode, func:create_ssh_key(data: SSHKeyCreate, user_id, session) → SSHKey, call:_get_user, call:generate_ssh_key_pair, call:_get_fernet, call:fernet.encrypt(private_key.encode()).decode, call:private_key.encode, call:SSHKey, call:session.add, call:session.commit, call:session.refresh, func:list_ssh_keys(user_id, session) → list[SSHKey], call:_get_user, call:session.execute, call:select(SSHKey).where, call:list, call:result.scalars().all, func:delete_ssh_key(key_id: uuid.UUID, user_id, session) → None, call:_get_user, call:session.get, call:session.delete, call:session.commit, raise:HTTPException, func:sign_payload(key_id: uuid.UUID, data: SignPayloadRequest, user_id, session) → SignatureResponse, call:_get_user, call:session.get, call:_get_fernet, call:fernet.decrypt(ssh_key.private_key_encrypted.encode()).decode, call:ssh_key.private_key_encrypted.encode, call:serialization.load_ssh_private_key, call:private_key_pem.encode, call:private_key.sign, call:data.payload.encode, call:SignatureResponse, call:base64.b64encode(signature).decode, raise:HTTPException, func:verify_signature(key_id: uuid.UUID, data: VerifySignatureRequest, user_id, session) → VerifySignatureResponse, call:_get_user, call:session.get, call:serialization.load_ssh_public_key, call:ssh_key.public_key.encode, call:base64.b64decode, call:public_key.verify, call:data.payload.encode, call:VerifySignatureResponse, raise:HTTPException | dep: base64, uuid, cryptography.fernet, cryptography.hazmat.primitives, cryptography.hazmat.primitives.asymmetric.ed25519, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.config, src.models, src.schemas.project, hashlib, cryptography
|
||||||
- users.py | Implements FastAPI endpoints for authenticated user profile management including retrieval, updates, and avatar uploads. | exp: func:get_profile(user_id, session) → User, call:_get_user, func:update_profile(data: UserProfileUpdate, user_id, session) → User, call:_get_user, call:len, call:data.name.strip, call:data.email.strip, call:session.commit, call:session.refresh, raise:HTTPException, func:upload_avatar(file: UploadFile, user_id, session) → User, call:_get_user, call:file.read, call:len, call:Path, call:old_path.exists, call:old_path.unlink, call:filename_part.split(".")[-1].lower, call:uuid.uuid4, call:file_path.write_bytes, call:session.commit, call:session.refresh, raise:HTTPException | dep: uuid, pathlib, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models.user, src.schemas.user
|
- users.py | Implements FastAPI endpoints for user profile management including retrieval, updates, and avatar uploads with file validation. | exp: func:get_profile(user_id, session) → User, call:_get_user, func:update_profile(data: UserProfileUpdate, user_id, session) → User, call:_get_user, call:len, call:data.name.strip, call:data.email.strip, call:session.commit, call:session.refresh, raise:HTTPException, func:upload_avatar(file: UploadFile, user_id, session) → User, call:_get_user, call:file.read, call:len, call:Path, call:old_path.exists, call:old_path.unlink, call:filename_part.split(".")[-1].lower, call:uuid.uuid4, call:file_path.write_bytes, call:session.commit, call:session.refresh, raise:HTTPException | dep: uuid, pathlib, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models.user, src.schemas.user, sqlalchemy
|
||||||
## arch
|
## arch
|
||||||
Modular FastAPI router pattern with OAuth2/OIDC external identity provider integration, encrypted key storage, and file-based avatar handling.
|
Modular FastAPI router pattern with separate submodules for distinct concerns (auth, profile, SSH keys), using OAuth2/OIDC external identity provider (Authentik), encrypted key storage, and file upload handling.
|
||||||
## tags
|
## tags
|
||||||
user, get, call:, key, ssh, src, cookie, raise:httpexception
|
user, get, call:, key, ssh, src, cookie, raise:httpexception
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/api/workspace
|
dir: apps/api/src/api/workspace
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI REST endpoints for workspace management, file operations, git integration, and tool instance management within user workspaces.
|
Provides REST API endpoints for managing user workspaces, including file operations, Git version control, tool instances, and workspace lifecycle management.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/api/.pi-map.index.md
|
index: apps/api/src/api/.pi-map.index.md
|
||||||
map: apps/api/src/api/.pi-map.md
|
map: apps/api/src/api/.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: apps/api/src/api/workspace
|
|||||||
index: apps/api/src/api/workspace/.pi-map.index.md
|
index: apps/api/src/api/workspace/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides FastAPI REST endpoints for workspace management, file operations, git integration, and tool instance management within user workspaces.
|
Provides REST API endpoints for managing user workspaces, including file operations, Git version control, tool instances, and workspace lifecycle management.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Aggregates and re-exports workspace API router modules for centralized access | dep: src.api.workspace.workspace_files, src.api.workspace.workspace_git, src.api.workspace.workspace_instances, src.api.workspace.workspaces
|
- __init__.py | Aggregates and re-exports workspace-related API routers from submodules for centralized access. | dep: src.api.workspace.workspace_files, src.api.workspace.workspace_git, src.api.workspace.workspace_instances, src.api.workspace.workspaces
|
||||||
- workspace_files.py | Provides FastAPI endpoints for listing, reading, and writing files within user workspaces with optional git commit integration. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:list_files(workspace_id: uuid.UUID, path, user_id, session) → dict, call:_get_workspace, call:FileService, call:service.list_directory, raise:HTTPException, func:get_file_content(workspace_id: uuid.UUID, path: str, user_id, session) → dict, call:_get_workspace, call:FileService, call:service.read_file, raise:HTTPException, func:write_file(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:FileService, call:data.get("path", "").strip, call:data.get("message", "").strip, call:service.write_file, call:GitOperations, call:git.commit, raise:HTTPException | dep: uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.shared.file_service, sqlalchemy, src.services.git.git_operations
|
- workspace_files.py | Provides FastAPI endpoints for listing, reading, and writing files within user-owned workspaces with optional Git commit integration. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:list_files(workspace_id: uuid.UUID, path, user_id, session) → dict, call:_get_workspace, call:FileService, call:service.list_directory, raise:HTTPException, func:get_file_content(workspace_id: uuid.UUID, path: str, user_id, session) → dict, call:_get_workspace, call:FileService, call:service.read_file, raise:HTTPException, func:write_file(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:FileService, call:data.get("path", "").strip, call:data.get("message", "").strip, call:service.write_file, call:GitOperations, call:git.commit, raise:HTTPException | dep: uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.shared.file_service, sqlalchemy, src.services.git.git_operations
|
||||||
- workspace_git.py | Provides FastAPI REST endpoints for git operations (status, branches, commit, push, pull, fetch, checkout, history) scoped to user workspaces. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:git_status(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.status, raise:HTTPException, func:git_branches(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.branches, raise:HTTPException, func:git_commit(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:data.get("message", "").strip, call:GitOperations, call:git.commit, raise:HTTPException, func:git_push(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.push, raise:HTTPException, func:git_pull(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.pull, raise:HTTPException, func:git_fetch(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.fetch, raise:HTTPException, func:git_checkout(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:data.get("branch", "").strip, call:GitOperations, call:git.checkout, call:session.commit, raise:HTTPException, func:git_history(workspace_id: uuid.UUID, path, limit, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.history, raise:HTTPException | dep: uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.git.git_operations, sqlalchemy
|
- workspace_git.py | Provides FastAPI REST endpoints for executing git operations (status, branches, commit, push, pull, fetch, checkout, history) on user workspaces with authentication and database persistence. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:git_status(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.status, raise:HTTPException, func:git_branches(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.branches, raise:HTTPException, func:git_commit(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:data.get("message", "").strip, call:GitOperations, call:git.commit, raise:HTTPException, func:git_push(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.push, raise:HTTPException, func:git_pull(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.pull, raise:HTTPException, func:git_fetch(workspace_id: uuid.UUID, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.fetch, raise:HTTPException, func:git_checkout(workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_workspace, call:data.get("branch", "").strip, call:GitOperations, call:git.checkout, call:session.commit, raise:HTTPException, func:git_history(workspace_id: uuid.UUID, path, limit, user_id, session) → dict, call:_get_workspace, call:GitOperations, call:git.history, raise:HTTPException | dep: uuid, fastapi, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.services.git.git_operations, sqlalchemy
|
||||||
- workspace_instances.py | FastAPI router providing endpoints to create and list tool instances associated with a specific workspace. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:create_workspace_instance(workspace_id: uuid.UUID, data: CreateWorkspaceInstanceRequest, user_id, session) → dict, call:_get_workspace, call:session.get, call:CreateInstanceRequest, call:str, call:create_tool_instance, call:instance.created_at.isoformat, raise:HTTPException, func:list_workspace_instances(workspace_id: uuid.UUID, user_id, session) → list[dict], call:_get_workspace, call:session.execute, call:select(ToolInstance) .where(ToolInstance.workspace_id == workspace_id) .order_by, call:ToolInstance.created_at.desc, call:result.scalars().all, call:str, call:i.created_at.isoformat | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.schemas.tool, src.services.tool.instance_service
|
- workspace_instances.py | Defines FastAPI endpoints for creating and listing tool instances associated with a specific workspace. | exp: func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, user_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException, func:create_workspace_instance(workspace_id: uuid.UUID, data: CreateWorkspaceInstanceRequest, user_id, session) → dict, call:_get_workspace, call:session.get, call:CreateInstanceRequest, call:str, call:create_tool_instance, call:instance.created_at.isoformat, raise:HTTPException, func:list_workspace_instances(workspace_id: uuid.UUID, user_id, session) → list[dict], call:_get_workspace, call:session.execute, call:select(ToolInstance) .where(ToolInstance.workspace_id == workspace_id) .order_by, call:ToolInstance.created_at.desc, call:result.scalars().all, call:str, call:i.created_at.isoformat | dep: uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.auth.dependencies, src.models, src.schemas.tool, src.services.tool.instance_service
|
||||||
- workspaces.py | FastAPI router providing CRUD endpoints for workspace management with nested and top-level URL structures, including listing, creating, updating, deleting, and syncing workspaces tied to Git repositories. | exp: func:list_all_workspaces(user_id, session) → list[dict], call:select(func.count(ToolInstance.id)) .where(ToolInstance.workspace_id == Workspace.id) .correlate(Workspace) .scalar_subquery, call:func.count, call:session.execute, call:select( Workspace, GitRepository, instance_count.label("instance_count"), ) .join(GitRepository, Workspace.repo_id == GitRepository.id) .options(selectinload(GitRepository.project)) .where(Workspace.user_id == user_id) .order_by, call:instance_count.label, call:selectinload, call:Workspace.created_at.desc, call:result.all, call:str, call:ws.last_sync_at.isoformat, call:ws.created_at.isoformat, call:ws.updated_at.isoformat, func:delete_workspace_top_level(workspace_id: uuid.UUID, force, user_id, session) → dict, call:session.get, call:WorkspaceManager, call:manager.delete, call:session.commit, call:session.rollback, call:logger.error, raise:HTTPException, func:create_workspace_top_level(data: dict, user_id, session) → dict, call:data.get("repo_id", "").strip, call:uuid.UUID, call:session.get, call:data.get("name", "").strip, call:data.get("branch", "main").strip, call:WorkspaceManager, call:manager.create, call:session.add, call:session.commit, call:session.rollback, call:logger.error, call:session.refresh, call:str, call:workspace.created_at.isoformat, raise:HTTPException, func:list_workspaces(project_id: uuid.UUID, repo_id: uuid.UUID, user_id, session) → list[dict], call:_get_repo, call:select(func.count(ToolInstance.id)) .where(ToolInstance.workspace_id == Workspace.id) .correlate(Workspace) .scalar_subquery, call:func.count, call:session.execute, call:select( Workspace, instance_count.label("instance_count"), ) .where(Workspace.repo_id == repo_id) .order_by, call:instance_count.label, call:Workspace.created_at.desc, call:result.all, call:str, call:ws.last_sync_at.isoformat, call:ws.created_at.isoformat, call:ws.updated_at.isoformat, func:create_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_repo, call:data.get("name", "").strip, call:data.get("branch", "main").strip, call:WorkspaceManager, call:manager.create, call:session.add, call:session.commit, call:session.rollback, call:logger.error, call:session.refresh, call:str, call:workspace.created_at.isoformat, raise:HTTPException, func:get_workspace_detail(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:session.execute, call:select(func.count(ToolInstance.id)).where, call:func.count, call:result.scalar, call:str, call:workspace.last_sync_at.isoformat, call:workspace.created_at.isoformat, call:workspace.updated_at.isoformat, func:update_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:data.get("name", "").strip, call:data.get("branch", "").strip, call:session.commit, call:session.rollback, call:logger.error, call:str, raise:HTTPException, func:delete_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, force, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:WorkspaceManager, call:manager.delete, call:session.commit, call:session.rollback, call:logger.error, raise:HTTPException, func:sync_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:WorkspaceManager, call:manager.sync, call:session.commit, call:workspace.last_sync_at.isoformat, raise:HTTPException, func:_get_repo(session: AsyncSession, repo_id: uuid.UUID, project_id: uuid.UUID, user_id: uuid.UUID) → GitRepository, call:session.execute, call:select(GitRepository) .where( GitRepository.id == repo_id, GitRepository.project_id == project_id, ) .options, call:selectinload, call:result.scalar_one_or_none, raise:HTTPException, func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, repo_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.auth.dependencies, src.models, src.services.shared.workspace_manager
|
- workspaces.py | FastAPI router providing CRUD endpoints for managing Git workspaces with repository integration, instance tracking, and sync capabilities. | exp: func:list_all_workspaces(user_id, session) → list[dict], call:select(func.count(ToolInstance.id)) .where(ToolInstance.workspace_id == Workspace.id) .correlate(Workspace) .scalar_subquery, call:func.count, call:session.execute, call:select( Workspace, GitRepository, instance_count.label("instance_count"), ) .join(GitRepository, Workspace.repo_id == GitRepository.id) .options(selectinload(GitRepository.project)) .where(Workspace.user_id == user_id) .order_by, call:instance_count.label, call:selectinload, call:Workspace.created_at.desc, call:result.all, call:str, call:ws.last_sync_at.isoformat, call:ws.created_at.isoformat, call:ws.updated_at.isoformat, func:delete_workspace_top_level(workspace_id: uuid.UUID, force, user_id, session) → dict, call:session.get, call:WorkspaceManager, call:manager.delete, call:session.commit, call:session.rollback, call:logger.error, raise:HTTPException, func:create_workspace_top_level(data: dict, user_id, session) → dict, call:data.get("repo_id", "").strip, call:uuid.UUID, call:session.get, call:data.get("name", "").strip, call:data.get("branch", "main").strip, call:WorkspaceManager, call:manager.create, call:session.add, call:session.commit, call:session.rollback, call:logger.error, call:session.refresh, call:str, call:workspace.created_at.isoformat, raise:HTTPException, func:list_workspaces(project_id: uuid.UUID, repo_id: uuid.UUID, user_id, session) → list[dict], call:_get_repo, call:select(func.count(ToolInstance.id)) .where(ToolInstance.workspace_id == Workspace.id) .correlate(Workspace) .scalar_subquery, call:func.count, call:session.execute, call:select( Workspace, instance_count.label("instance_count"), ) .where(Workspace.repo_id == repo_id) .order_by, call:instance_count.label, call:Workspace.created_at.desc, call:result.all, call:str, call:ws.last_sync_at.isoformat, call:ws.created_at.isoformat, call:ws.updated_at.isoformat, func:create_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_repo, call:data.get("name", "").strip, call:data.get("branch", "main").strip, call:WorkspaceManager, call:manager.create, call:session.add, call:session.commit, call:session.rollback, call:logger.error, call:session.refresh, call:str, call:workspace.created_at.isoformat, raise:HTTPException, func:get_workspace_detail(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:session.execute, call:select(func.count(ToolInstance.id)).where, call:func.count, call:result.scalar, call:str, call:workspace.last_sync_at.isoformat, call:workspace.created_at.isoformat, call:workspace.updated_at.isoformat, func:update_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, data: dict, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:data.get("name", "").strip, call:data.get("branch", "").strip, call:session.commit, call:session.rollback, call:logger.error, call:str, raise:HTTPException, func:delete_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, force, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:WorkspaceManager, call:manager.delete, call:session.commit, call:session.rollback, call:logger.error, raise:HTTPException, func:sync_workspace(project_id: uuid.UUID, repo_id: uuid.UUID, workspace_id: uuid.UUID, user_id, session) → dict, call:_get_repo, call:_get_workspace, call:WorkspaceManager, call:manager.sync, call:session.commit, call:workspace.last_sync_at.isoformat, raise:HTTPException, func:_get_repo(session: AsyncSession, repo_id: uuid.UUID, project_id: uuid.UUID, user_id: uuid.UUID) → GitRepository, call:session.execute, call:select(GitRepository) .where( GitRepository.id == repo_id, GitRepository.project_id == project_id, ) .options, call:selectinload, call:result.scalar_one_or_none, raise:HTTPException, func:_get_workspace(session: AsyncSession, workspace_id: uuid.UUID, repo_id: uuid.UUID) → Workspace, call:session.execute, call:select(Workspace).where, call:result.scalar_one_or_none, raise:HTTPException | dep: logging, uuid, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.auth.dependencies, src.models, src.services.shared.workspace_manager
|
||||||
## arch
|
## arch
|
||||||
Modular FastAPI router pattern with domain-driven separation (files, git, instances, workspaces) using nested URL structures and git-backed workspace synchronization.
|
Modular FastAPI router decomposition with domain-driven vertical slicing (files/git/instances/workspaces as separate modules), aggregated through __init__.py barrel exports, combining database persistence with external Git repository integration.
|
||||||
## tags
|
## tags
|
||||||
workspace, get, raise:httpexception, call:, at.isoformat, git, call:select, call:data.get
|
workspace, get, raise:httpexception, call:, at.isoformat, git, call:select, call:data.get
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from sqlalchemy.orm import selectinload
|
|||||||
|
|
||||||
from src.auth.dependencies import get_current_user_id, get_db_session
|
from src.auth.dependencies import get_current_user_id, get_db_session
|
||||||
from src.models import GitRepository
|
from src.models import GitRepository
|
||||||
|
from src.models import Project
|
||||||
from src.models import ToolInstance
|
from src.models import ToolInstance
|
||||||
from src.models import Workspace
|
from src.models import Workspace
|
||||||
from src.services.shared.workspace_manager import WorkspaceHasInstancesError, WorkspaceManager
|
from src.services.shared.workspace_manager import WorkspaceHasInstancesError, WorkspaceManager
|
||||||
@@ -129,17 +130,26 @@ async def create_workspace_top_level(
|
|||||||
if not name:
|
if not name:
|
||||||
raise HTTPException(status_code=400, detail="Workspace name is required")
|
raise HTTPException(status_code=400, detail="Workspace name is required")
|
||||||
|
|
||||||
|
project = await session.get(Project, repo.project_id) if repo.project_id else None
|
||||||
manager = WorkspaceManager()
|
manager = WorkspaceManager()
|
||||||
try:
|
try:
|
||||||
workspace = await manager.create(repo, user_id, name, branch, session=session)
|
workspace = await manager.create(
|
||||||
|
repo, user_id, name, branch, session=session, project=project
|
||||||
|
)
|
||||||
session.add(workspace)
|
session.add(workspace)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except ValueError as exc:
|
||||||
|
await session.rollback()
|
||||||
|
logger.error("Failed to create workspace: %s", exc)
|
||||||
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
await session.rollback()
|
await session.rollback()
|
||||||
logger.error("Failed to create workspace: %s", exc)
|
logger.error("Failed to create workspace: %s", exc)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=409,
|
status_code=500,
|
||||||
detail="Workspace name already exists for this repository",
|
detail=f"Failed to create workspace: {exc}",
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
await session.refresh(workspace)
|
await session.refresh(workspace)
|
||||||
@@ -226,9 +236,12 @@ async def create_workspace(
|
|||||||
if not branch:
|
if not branch:
|
||||||
raise HTTPException(status_code=400, detail="Branch is required")
|
raise HTTPException(status_code=400, detail="Branch is required")
|
||||||
|
|
||||||
|
project = await session.get(Project, project_id)
|
||||||
manager = WorkspaceManager()
|
manager = WorkspaceManager()
|
||||||
try:
|
try:
|
||||||
workspace = await manager.create(repo, user_id, name, branch, session=session)
|
workspace = await manager.create(
|
||||||
|
repo, user_id, name, branch, session=session, project=project
|
||||||
|
)
|
||||||
session.add(workspace)
|
session.add(workspace)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
@@ -241,8 +254,8 @@ async def create_workspace(
|
|||||||
await session.rollback()
|
await session.rollback()
|
||||||
logger.error("Failed to create workspace: %s", exc)
|
logger.error("Failed to create workspace: %s", exc)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=409,
|
status_code=500,
|
||||||
detail="Workspace name already exists for this repository",
|
detail=f"Failed to create workspace: {exc}",
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
await session.refresh(workspace)
|
await session.refresh(workspace)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/auth
|
dir: apps/api/src/auth
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides authentication and authorization infrastructure for the API using OIDC/OAuth2 with Authentik, session cookies, and FastAPI dependencies.
|
Provides authentication and authorization infrastructure for the API, including OIDC login, session management, and dependency injection for protected routes.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: apps/api/src/auth
|
|||||||
index: apps/api/src/auth/.pi-map.index.md
|
index: apps/api/src/auth/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides authentication and authorization infrastructure for the API using OIDC/OAuth2 with Authentik, session cookies, and FastAPI dependencies.
|
Provides authentication and authorization infrastructure for the API, including OIDC login, session management, and dependency injection for protected routes.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports authentication utility functions from submodules to provide a unified public API for the auth package | dep: src.auth.cookies, src.auth.oidc, src.auth.session
|
- __init__.py | Exposes authentication utility functions as a public API through module-level imports | dep: src.auth.cookies, src.auth.oidc, src.auth.session
|
||||||
- cookies.py | Builds a dictionary of HTTP cookie options from application settings for secure cookie configuration. | exp: func:build_cookie_options(settings: Settings) → dict[str, str | bool | None] | dep: src.config, src.config.Settings
|
- cookies.py | Builds a dictionary of HTTP cookie options from application settings | exp: func:build_cookie_options(settings: Settings) → dict[str, str | bool | None] | dep: src.config, src.config.Settings
|
||||||
- dependencies.py | Provides FastAPI dependency functions for database sessions, user authentication, and project authorization. | exp: func:get_db_session(), call:SessionLocal, func:get_current_user_id(session_cookie) → uuid.UUID, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str, raise:HTTPException, func:get_current_user(session_cookie, db_session) → User, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str, call:db_session.get, raise:HTTPException, func:_get_user(session: AsyncSession, user_id: uuid.UUID) → User, call:session.get, raise:HTTPException, func:_get_owned_project(project_id: uuid.UUID, user_id: uuid.UUID, session: AsyncSession) → "Project", call:session.get, raise:HTTPException | dep: uuid, typing, fastapi, sqlalchemy.ext.asyncio, src.auth.session, src.config, src.database, src.models.project, src.models.user, sqlalchemy
|
- dependencies.py | Provides FastAPI dependency injection functions for database sessions, user authentication, and project ownership verification. | exp: func:get_db_session(), call:SessionLocal, func:get_current_user_id(session_cookie) → uuid.UUID, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str, raise:HTTPException, func:get_current_user(session_cookie, db_session) → User, call:Settings, call:decode_session_cookie, call:uuid.UUID, call:str, call:db_session.get, raise:HTTPException, func:_get_user(session: AsyncSession, user_id: uuid.UUID) → User, call:session.get, raise:HTTPException, func:_get_owned_project(project_id: uuid.UUID, user_id: uuid.UUID, session: AsyncSession) → "Project", call:session.get, raise:HTTPException | dep: uuid, typing, fastapi, sqlalchemy.ext.asyncio, src.auth.session, src.config, src.database, src.models.project, src.models.user, sqlalchemy
|
||||||
- oidc.py | Implements OIDC/OAuth2 authentication flow with Authentik, including login URL construction, authorization code exchange for tokens, and user info retrieval. | exp: func:build_login_redirect_url(settings: Settings, redirect_uri: str, state: str) → str, call:urlencode, func:exchange_code_for_tokens(settings: Settings, code: str, redirect_uri: str, client: httpx.AsyncClient) → dict[str, str], call:client.post, call:response.raise_for_status, call:response.json, call:payload.get, func:fetch_user_info(settings: Settings, access_token: str, client: httpx.AsyncClient) → dict[str, Any], call:client.get, call:response.raise_for_status, call:response.json | dep: typing, urllib.parse, httpx, src.config
|
- oidc.py | Implements OIDC authentication flow with Authentik for login redirect URL construction, authorization code exchange, and user info retrieval. | exp: func:build_login_redirect_url(settings: Settings, redirect_uri: str, state: str) → str, call:urlencode, func:exchange_code_for_tokens(settings: Settings, code: str, redirect_uri: str, client: httpx.AsyncClient) → dict[str, str], call:client.post, call:response.raise_for_status, call:response.json, call:payload.get, func:fetch_user_info(settings: Settings, access_token: str, client: httpx.AsyncClient) → dict[str, Any], call:client.get, call:response.raise_for_status, call:response.json | dep: typing, urllib.parse, httpx, src.config
|
||||||
- session.py | Implements creation and verification of signed session cookies using HMAC-SHA256 in a JWS-like format. | exp: func:_base64url_encode(data: bytes) → str, call:base64.urlsafe_b64encode(data).rstrip(b"=").decode, func:_base64url_decode(data: str) → bytes, call:len, call:base64.urlsafe_b64decode, func:create_session_cookie(settings: Settings, user_id: str) → str, call:int, call:(datetime.now(timezone.utc) + timedelta(hours=settings.session_ttl_hours)).timestamp, call:datetime.now, call:timedelta, call:_base64url_encode, call:json.dumps({"alg": "HS256", "typ": "session"}).encode, call:json.dumps(payload).encode, call:hmac.new( settings.session_secret.encode(), message.encode(), hashlib.sha256, ).digest, call:settings.session_secret.encode, call:message.encode, func:decode_session_cookie(settings: Settings, cookie_value: str) → dict[str, Any], call:cookie_value.split, call:len, call:hmac.new( settings.session_secret.encode(), message.encode(), hashlib.sha256, ).digest, call:settings.session_secret.encode, call:message.encode, call:_base64url_encode, call:hmac.compare_digest, call:_base64url_decode, call:json.loads, call:payload.get, call:int, call:datetime.now(timezone.utc).timestamp, raise:ValueError | dep: hmac, hashlib, json, base64, datetime, typing, src.config, src.config.Settings
|
- session.py | Creates and verifies signed JWT-like session cookies with HMAC-SHA256 signatures and expiration checks. | exp: func:_base64url_encode(data: bytes) → str, call:base64.urlsafe_b64encode(data).rstrip(b"=").decode, func:_base64url_decode(data: str) → bytes, call:len, call:base64.urlsafe_b64decode, func:create_session_cookie(settings: Settings, user_id: str) → str, call:int, call:(datetime.now(timezone.utc) + timedelta(hours=settings.session_ttl_hours)).timestamp, call:datetime.now, call:timedelta, call:_base64url_encode, call:json.dumps({"alg": "HS256", "typ": "session"}).encode, call:json.dumps(payload).encode, call:hmac.new( settings.session_secret.encode(), message.encode(), hashlib.sha256, ).digest, call:settings.session_secret.encode, call:message.encode, func:decode_session_cookie(settings: Settings, cookie_value: str) → dict[str, Any], call:cookie_value.split, call:len, call:hmac.new( settings.session_secret.encode(), message.encode(), hashlib.sha256, ).digest, call:settings.session_secret.encode, call:message.encode, call:_base64url_encode, call:hmac.compare_digest, call:_base64url_decode, call:json.loads, call:payload.get, call:int, call:datetime.now(timezone.utc).timestamp, raise:ValueError | dep: hmac, hashlib, json, base64, datetime, typing, src.config, src.config.Settings
|
||||||
## arch
|
## arch
|
||||||
Modular security layer with separation of concerns: protocol handling (OIDC), transport security (cookies/sessions), framework integration (dependencies), and clean public API (re-exports).
|
Modular security layer using FastAPI dependency injection pattern, with separation of concerns across cookie handling, OIDC flow, session state, and reusable auth dependencies.
|
||||||
## tags
|
## tags
|
||||||
session, src, cookie, user, get, base64url, raise:httpexception, call:
|
session, src, cookie, user, get, base64url, raise:httpexception, call:
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models
|
dir: apps/api/src/models
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Centralized database model definitions and shared infrastructure for the API's data layer.
|
Provides the foundational database model layer and unified public API for all SQLAlchemy ORM entities in the API application.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ dir: apps/api/src/models
|
|||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Centralized database model definitions and shared infrastructure for the API's data layer.
|
Provides the foundational database model layer and unified public API for all SQLAlchemy ORM entities in the API application.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports model classes from submodules to provide a centralized public API for the src.models package | dep: src.models.base, src.models.config.config_profile, src.models.project.git_repository, src.models.project.project, src.models.project.workspace, src.models.system.health_check, src.models.system.instance_event, src.models.system.notification, src.models.system.terminal_session, src.models.tool.tool_definition_manifest, src.models.tool.tool_instance, src.models.tool.tool_type, src.models.user.ssh_key, src.models.user.user, src.models.user.user_config
|
- __init__.py | Re-exports database models from submodules to provide a unified public API for the models package | dep: src.models.base, src.models.config.config_profile, src.models.project.git_repository, src.models.project.project, src.models.project.workspace, src.models.system.health_check, src.models.system.instance_event, src.models.system.notification, src.models.system.terminal_session, src.models.tool.tool_definition_manifest, src.models.tool.tool_instance, src.models.tool.tool_type, src.models.user.ssh_key, src.models.user.user, src.models.user.user_config
|
||||||
- base.py | Defines SQLAlchemy base model and reusable mixins for UUID primary keys and automatic timestamp tracking in database models. | exp: class:Base, class:UUIDPrimaryKeyMixin, class:TimestampMixin | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm
|
- base.py | Defines SQLAlchemy base model and reusable mixins for UUID primary keys and automatic timestamp tracking in database models. | exp: class:Base, class:UUIDPrimaryKeyMixin, class:TimestampMixin | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm
|
||||||
## arch
|
## arch
|
||||||
SQLAlchemy ORM with declarative base, mixin-based composition for cross-cutting concerns (UUIDs, timestamps), and explicit package-level re-exports for clean public API surface.
|
Implements a layered model architecture using SQLAlchemy declarative base with reusable mixins (UUID primary keys, timestamp tracking) and a facade pattern via `__init__.py` to centralize model imports.
|
||||||
## tags
|
## tags
|
||||||
models, src, base, project, system, user, mixin, tool
|
models, src, base, project, system, user, mixin, tool
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models/config
|
dir: apps/api/src/models/config
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides SQLAlchemy ORM models for configuration profiles that manage environment variables, mounts, files, and git mounts with support for profile inheritance and user/project/tool associations.
|
Provides SQLAlchemy ORM models for configuration profiles that store deployment settings like environment variables, mounts, and runtime hints.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/models/config
|
|||||||
index: apps/api/src/models/config/.pi-map.index.md
|
index: apps/api/src/models/config/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides SQLAlchemy ORM models for configuration profiles that manage environment variables, mounts, files, and git mounts with support for profile inheritance and user/project/tool associations.
|
Provides SQLAlchemy ORM models for configuration profiles that store deployment settings like environment variables, mounts, and runtime hints.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Exports config model classes from a subpackage for simplified importing | dep: src.models.config.config_profile
|
- __init__.py | Exports config model classes from a subpackage for simplified importing | dep: src.models.config.config_profile
|
||||||
- config_profile.py | Defines SQLAlchemy ORM models for configuration profiles and their includes, storing environment variables, runtime hints, mounts, files, and git mounts with user/project/tool associations and self-referential inclusion relationships. | exp: class:ConfigProfile, class:ConfigProfileInclude | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.user, src.models (ToolType)
|
- config_profile.py | Defines SQLAlchemy ORM models for configuration profiles and their include relationships, storing deployment settings like environment variables, mounts, and runtime hints. | exp: class:ConfigProfile, class:ConfigProfileInclude | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.user, src.models.ToolType
|
||||||
## arch
|
## arch
|
||||||
Uses SQLAlchemy ORM with declarative base pattern, implementing self-referential many-to-many relationships for profile inclusion, association tables for user/project/tool ownership, and polymorphic-like configuration through profile inheritance rather than class inheritance.
|
Package-level facade pattern with __init__.py exposing subpackage classes; domain model using SQLAlchemy ORM with relationship-based composition for profile includes.
|
||||||
## tags
|
## tags
|
||||||
config, src, models, profile, sqlalchemy, init, orm, mounts
|
config, models, src, profile, sqlalchemy, include, init, orm
|
||||||
## symbols
|
## symbols
|
||||||
- ConfigProfile
|
- ConfigProfile
|
||||||
- ConfigProfileInclude
|
- ConfigProfileInclude
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models/project
|
dir: apps/api/src/models/project
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines the core domain data models for project management, representing Git repositories, projects, and workspaces as SQLAlchemy ORM entities with their relationships.
|
Provides SQLAlchemy ORM models for core project-related domain entities (GitRepository, Project, Workspace) with their relationships.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ dir: apps/api/src/models/project
|
|||||||
index: apps/api/src/models/project/.pi-map.index.md
|
index: apps/api/src/models/project/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines the core domain data models for project management, representing Git repositories, projects, and workspaces as SQLAlchemy ORM entities with their relationships.
|
Provides SQLAlchemy ORM models for core project-related domain entities (GitRepository, Project, Workspace) with their relationships.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Exports the three main project model classes (GitRepository, Project, Workspace) as the public API for the models.project package. | dep: src.models.project.git_repository, src.models.project.project, src.models.project.workspace
|
- __init__.py | Exports the core project model classes (GitRepository, Project, Workspace) for the models package | dep: src.models.project.git_repository, src.models.project.project, src.models.project.workspace
|
||||||
- git_repository.py | Defines a SQLAlchemy ORM model for Git repositories with relationships to projects, users, and SSH keys. | exp: class:GitRepository | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.user, src.models.ssh_key
|
- git_repository.py | Defines a SQLAlchemy ORM model for Git repositories with relationships to projects, users, and SSH keys. | exp: class:GitRepository | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.user, src.models.SSHKey
|
||||||
- project.py | Defines a SQLAlchemy ORM model for a Project entity with relationships to users, Git repositories, and SSH keys. | exp: class:Project | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.user, src.models.GitRepository, src.models.SSHKey, src.models.user.User
|
- project.py | Defines a SQLAlchemy ORM model for projects with relationships to users, Git repositories, and SSH keys. | exp: class:Project | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.user, src.models.GitRepository, src.models.SSHKey, src.models.user.User
|
||||||
- workspace.py | Defines a SQLAlchemy ORM model for persistent writable Git repository clones associated with users. | exp: class:Workspace | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.user, src.models.GitRepository, src.models.user.User
|
- workspace.py | Defines a SQLAlchemy ORM model for persistent writable Git repository clones associated with users | exp: class:Workspace | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.user, src.models.GitRepository
|
||||||
## arch
|
## arch
|
||||||
Standard SQLAlchemy ORM model layer with declarative base pattern, using __init__.py as a public API facade to expose the three main entity classes while keeping implementation details in separate modules.
|
Data access layer using SQLAlchemy ORM with declarative models, explicit table relationships (many-to-many and foreign keys), and package-level facade pattern via __init__.py exports.
|
||||||
## tags
|
## tags
|
||||||
models, src, project, sqlalchemy, git, user, workspace, orm
|
models, src, project, sqlalchemy, git, workspace, orm, repository
|
||||||
## symbols
|
## symbols
|
||||||
- GitRepository
|
- GitRepository
|
||||||
- Project
|
- Project
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models/system
|
dir: apps/api/src/models/system
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides database persistence models for system-level operational concerns including health monitoring, audit logging, user notifications, and terminal session management.
|
Provides system-level SQLAlchemy ORM models for operational concerns including health monitoring, audit logging, notifications, and terminal session management.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ dir: apps/api/src/models/system
|
|||||||
index: apps/api/src/models/system/.pi-map.index.md
|
index: apps/api/src/models/system/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides database persistence models for system-level operational concerns including health monitoring, audit logging, user notifications, and terminal session management.
|
Provides system-level SQLAlchemy ORM models for operational concerns including health monitoring, audit logging, notifications, and terminal session management.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Exports system-related model classes from a package for convenient importing. | dep: src.models.system.health_check, src.models.system.instance_event, src.models.system.notification, src.models.system.terminal_session
|
- __init__.py | Package initialization file that exports system-related model classes for the models.system module | dep: src.models.system.health_check, src.models.system.instance_event, src.models.system.notification, src.models.system.terminal_session
|
||||||
- health_check.py | Defines a SQLAlchemy ORM model for storing health check snapshots of tool instances with various status and probe fields. | exp: class:HealthCheck | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm, src.models.base
|
- health_check.py | Defines a SQLAlchemy ORM model for storing health check snapshots of tool instances with various status and probe fields. | exp: class:HealthCheck | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm, src.models.base
|
||||||
- instance_event.py | Defines a SQLAlchemy ORM model for auditing instance lifecycle events with metadata, status tracking, and user attribution. | exp: class:InstanceEvent | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base
|
- instance_event.py | Defines a SQLAlchemy model for auditing instance lifecycle events with metadata, status tracking, and user attribution. | exp: class:InstanceEvent | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base
|
||||||
- notification.py | Defines a SQLAlchemy ORM model for storing user notifications with metadata, read/dismissed tracking, and polymorphic source references. | exp: class:Notification | dep: datetime, typing, uuid, sqlalchemy, sqlalchemy.orm, sqlalchemy.sql, src.models.base
|
- notification.py | Defines a SQLAlchemy ORM model for storing user notifications with support for categorization, severity levels, read/dismissed tracking, and polymorphic source references. | exp: class:Notification | dep: datetime, typing, uuid, sqlalchemy, sqlalchemy.orm, sqlalchemy.sql, src.models.base
|
||||||
- terminal_session.py | Defines a SQLAlchemy database model for storing terminal session metadata with lifecycle tracking. | exp: class:TerminalSessionModel | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm, src.models.base
|
- terminal_session.py | Defines a SQLAlchemy database model for storing terminal session metadata with lifecycle tracking. | exp: class:TerminalSessionModel | dep: uuid, datetime, sqlalchemy, sqlalchemy.orm, src.models.base
|
||||||
## arch
|
## arch
|
||||||
Uses SQLAlchemy ORM declarative models with consistent patterns including timestamp tracking, JSON metadata columns, enum-based status fields, and polymorphic relationships for extensible source attribution.
|
Standard SQLAlchemy declarative model pattern with polymorphic associations (notification sources), lifecycle state tracking, and timestamped audit fields across all models.
|
||||||
## tags
|
## tags
|
||||||
sqlalchemy, src, models, model, orm, system, notification, health
|
sqlalchemy, models, src, model, system, orm, notification, health
|
||||||
## symbols
|
## symbols
|
||||||
- HealthCheck
|
- HealthCheck
|
||||||
- InstanceEvent
|
- InstanceEvent
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models/tool
|
dir: apps/api/src/models/tool
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Database models for containerized tool lifecycle management, covering tool definitions, deployment instances, and categorization types.
|
Provides SQLAlchemy ORM models for managing containerized tool definitions, types, and deployed instances in the API.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ dir: apps/api/src/models/tool
|
|||||||
index: apps/api/src/models/tool/.pi-map.index.md
|
index: apps/api/src/models/tool/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Database models for containerized tool lifecycle management, covering tool definitions, deployment instances, and categorization types.
|
Provides SQLAlchemy ORM models for managing containerized tool definitions, types, and deployed instances in the API.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Exports the public API for the tool models module by re-exporting three key classes. | dep: src.models.tool.tool_definition_manifest, src.models.tool.tool_instance, src.models.tool.tool_type
|
- __init__.py | Package initialization file that exports the public API for the tool models module. | dep: src.models.tool.tool_definition_manifest, src.models.tool.tool_instance, src.models.tool.tool_type
|
||||||
- tool_definition_manifest.py | Defines a SQLAlchemy ORM model for storing tool definition manifests that compile to Dockerfiles and Compose files, supporting both base definitions and tool-specific definitions with inheritance. | exp: class:ToolDefinitionManifest | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.user
|
- tool_definition_manifest.py | Defines a SQLAlchemy model for tool definition manifests that can represent either base Docker images or tool definitions that inherit from bases, storing manifest JSON and cached Dockerfile/Compose outputs. | exp: class:ToolDefinitionManifest | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.user
|
||||||
- tool_instance.py | Defines a SQLAlchemy ORM model for tool instances that represent deployed tools with container metadata, status tracking, and relationships to users, projects, workspaces, and other entities. | exp: class:ToolInstance | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.project, src.models.user, src.models (ConfigProfile, GitRepository, Project, ToolType, User, Workspace)
|
- tool_instance.py | Defines a SQLAlchemy ORM model representing a deployed tool instance with container/runtime metadata and relationships to users, projects, and workspaces. | exp: class:ToolInstance | dep: uuid, datetime, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models, src.models.project, src.models.user, src.models (ConfigProfile, GitRepository, Project, ToolType, User, Workspace)
|
||||||
- tool_type.py | Defines a SQLAlchemy ORM model for tool types that represent configurable categories of tools with deployment templates, manifest references, and metadata. | exp: class:ToolType | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.tool.tool_definition_manifest, src.models.user
|
- tool_type.py | Defines a SQLAlchemy ORM model for tool types that specify metadata, configuration, and deployment templates for containerized tools. | exp: class:ToolType | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.tool.tool_definition_manifest, src.models.user
|
||||||
## arch
|
## arch
|
||||||
SQLAlchemy ORM with declarative models using inheritance hierarchies, relationship mappings, and polymorphic manifest compilation for Docker/Compose deployment.
|
Uses SQLAlchemy ORM with declarative models, inheritance patterns (base vs. derived tool definitions), and relational associations linking tools to users, projects, and workspaces.
|
||||||
## tags
|
## tags
|
||||||
tool, models, src, sqlalchemy, orm, definition, manifest, base
|
tool, models, src, sqlalchemy, definition, manifest, orm, instance
|
||||||
## symbols
|
## symbols
|
||||||
- ToolDefinitionManifest
|
- ToolDefinitionManifest
|
||||||
- ToolInstance
|
- ToolInstance
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ class ToolType(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|||||||
)
|
)
|
||||||
readiness_probe: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
readiness_probe: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||||
startup_command: Mapped[str | None] = mapped_column(Text, nullable=True)
|
startup_command: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
home_directory: Mapped[str] = mapped_column(
|
||||||
|
String(255), nullable=False, default="/home/user"
|
||||||
|
)
|
||||||
required_variables: Mapped[list[str]] = mapped_column(
|
required_variables: Mapped[list[str]] = mapped_column(
|
||||||
JSON, default=list, nullable=False
|
JSON, default=list, nullable=False
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/models/user
|
dir: apps/api/src/models/user
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides SQLAlchemy ORM data models for user authentication, SSH key storage, and per-user configuration management.
|
Database models package defining user-related entities including users, SSH keys, and user configuration with their relationships.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/models/.pi-map.index.md
|
index: apps/api/src/models/.pi-map.index.md
|
||||||
map: apps/api/src/models/.pi-map.md
|
map: apps/api/src/models/.pi-map.md
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ dir: apps/api/src/models/user
|
|||||||
index: apps/api/src/models/user/.pi-map.index.md
|
index: apps/api/src/models/user/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides SQLAlchemy ORM data models for user authentication, SSH key storage, and per-user configuration management.
|
Database models package defining user-related entities including users, SSH keys, and user configuration with their relationships.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Exports the user-related model classes (SSHKey, User, UserConfig) from a package for convenient importing. | dep: src.models.user.ssh_key, src.models.user.user, src.models.user.user_config
|
- __init__.py | Exports user-related model classes from a package for clean external imports. | dep: src.models.user.ssh_key, src.models.user.user, src.models.user.user_config
|
||||||
- ssh_key.py | Defines an SSHKey SQLAlchemy ORM model for storing encrypted SSH key pairs with user and optional project associations. | exp: class:SSHKey | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models.user
|
- ssh_key.py | Defines an SSHKey database model for storing encrypted SSH key pairs with associations to users and optional projects. | exp: class:SSHKey | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models.user
|
||||||
- user.py | Defines a SQLAlchemy ORM model for a User entity with authentication fields and relationships to projects, SSH keys, and user configuration. | exp: class:User | dep: typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.SSHKey, src.models.UserConfig
|
- user.py | Defines a SQLAlchemy ORM model for a User entity with authentication fields and relationships to projects, SSH keys, and user configuration. | exp: class:User | dep: typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.project, src.models, src.models.SSHKey, src.models.UserConfig
|
||||||
- user_config.py | Defines a SQLAlchemy model for storing per-user JSON configuration with typed property accessors for default profile IDs. | exp: class:UserConfig | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.user
|
- user_config.py | Defines a SQLAlchemy model for storing per-user JSON configuration data with typed property accessors for profile IDs. | exp: class:UserConfig | dep: uuid, typing, sqlalchemy, sqlalchemy.orm, src.models.base, src.models.user
|
||||||
## arch
|
## arch
|
||||||
Classic SQLAlchemy ORM model package pattern with declarative models, explicit table relationships, and a package-level __init__.py facade for clean imports.
|
SQLAlchemy ORM with declarative models, one-to-many relationships (User→SSHKey, User→Project, User→UserConfig), encrypted field storage for SSH keys, and JSON-typed configuration with property accessors for schema flexibility.
|
||||||
## tags
|
## tags
|
||||||
user, src, models, sqlalchemy, sshkey, orm, model, ssh
|
user, src, models, sqlalchemy, model, sshkey, ssh, orm
|
||||||
## symbols
|
## symbols
|
||||||
- SSHKey
|
- SSHKey
|
||||||
- User
|
- User
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas
|
dir: apps/api/src/schemas
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic schemas for data validation and serialization in the API layer.
|
Provides data validation schemas for the API application
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: apps/api/src/schemas
|
|||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic schemas for data validation and serialization in the API layer.
|
Provides data validation schemas for the API application
|
||||||
## files
|
## files
|
||||||
- __init__.py | Empty file with no functionality
|
- __init__.py | Swaps two tmux panes between windows, preserving active pane state and layout | dep: tmux
|
||||||
## arch
|
## arch
|
||||||
Standard Python package structure using __init__.py to mark the directory as an importable package, likely intended for request/response models following FastAPI/Pydantic patterns.
|
Package initialization with modular schema definitions using Pydantic or similar validation framework
|
||||||
## tags
|
## tags
|
||||||
init, empty, functionality
|
tmux, init, swaps, two, panes, windows, preserving, active
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas/config
|
dir: apps/api/src/schemas/config
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic validation schemas for configuration profile API request/response models with strict input validation.
|
Provides Pydantic schemas for configuration profile API operations with validated request/response models.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
map: apps/api/src/schemas/.pi-map.md
|
map: apps/api/src/schemas/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/schemas/config
|
|||||||
index: apps/api/src/schemas/config/.pi-map.index.md
|
index: apps/api/src/schemas/config/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic validation schemas for configuration profile API request/response models with strict input validation.
|
Provides Pydantic schemas for configuration profile API operations with validated request/response models.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports Pydantic schemas for configuration profile operations from a submodule to provide a clean public API. | dep: src.schemas.config.config_profile
|
- __init__.py | Re-exports config profile schema classes from a submodule to provide a unified public interface for the config schemas module. | dep: src.schemas.config.config_profile
|
||||||
- config_profile.py | Defines Pydantic request/response schemas for config profile API operations with validation for mounts, git URLs, UUIDs, and file paths. | exp: class:GitMountMapping, class:GitMountItem, class:MountItem, class:ConfigProfileCreate, class:ConfigProfileUpdate, class:ConfigProfileIncludeUpdate, class:ConfigProfileResponse, class:DefaultProfilesUpdate, class:ValidateGitUrlRequest, class:ValidateGitUrlResponse, func:_validate_uuid(v: str | None) → str | None, call:uuid.UUID, raise:ValueError | dep: uuid, pydantic, src.api.shared_validators
|
- config_profile.py | Defines Pydantic request/response schemas for configuration profile API operations with comprehensive input validation. | exp: class:GitMountMapping, class:GitMountItem, class:MountItem, class:ConfigProfileCreate, class:ConfigProfileUpdate, class:ConfigProfileIncludeUpdate, class:ConfigProfileResponse, class:DefaultProfilesUpdate, class:ValidateGitUrlRequest, class:ValidateGitUrlResponse, func:_validate_uuid(v: str | None) → str | None, call:uuid.UUID, raise:ValueError | dep: uuid, pydantic, src.api.shared_validators
|
||||||
## arch
|
## arch
|
||||||
Standard Python package pattern using `__init__.py` re-exports to expose a clean public API from internal modules, with Pydantic-based schema-per-resource organization.
|
Layered schema module using submodule organization with clean public interface via __init__.py re-exports, following Pydantic-based validation pattern for API contract definitions.
|
||||||
## tags
|
## tags
|
||||||
profile, config, git, mount, update, validate, response, item
|
config, profile, git, mount, update, validate, response, item
|
||||||
## symbols
|
## symbols
|
||||||
- GitMountMapping
|
- GitMountMapping
|
||||||
- GitMountItem
|
- GitMountItem
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas/project
|
dir: apps/api/src/schemas/project
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic data validation schemas for project-related API endpoints, serving as the contract layer between HTTP requests/responses and internal business logic.
|
Provides Pydantic data validation schemas for project-related API endpoints, serving as the contract layer between API requests/responses and internal business logic.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
map: apps/api/src/schemas/.pi-map.md
|
map: apps/api/src/schemas/.pi-map.md
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ dir: apps/api/src/schemas/project
|
|||||||
index: apps/api/src/schemas/project/.pi-map.index.md
|
index: apps/api/src/schemas/project/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic data validation schemas for project-related API endpoints, serving as the contract layer between HTTP requests/responses and internal business logic.
|
Provides Pydantic data validation schemas for project-related API endpoints, serving as the contract layer between API requests/responses and internal business logic.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports Pydantic schema classes from submodules to provide a unified public API for the project schemas module | dep: src.schemas.project.git_repository, src.schemas.project.project, src.schemas.project.ssh_key
|
- __init__.py | Re-exports Pydantic schema classes from submodules to provide a unified public API for project-related data models. | dep: src.schemas.project.git_repository, src.schemas.project.project, src.schemas.project.ssh_key
|
||||||
- git_repository.py | Defines Pydantic request/response schemas for Git repository operations in an API. | exp: class:GitRepositoryCreate, class:URLParseRequest, class:URLParseResponse, class:GitRepositoryResponse, class:UpdateSSHKeyRequest, class:FileListResponse, class:FileContentResponse, class:BranchesResponse, class:FileUpdateRequest, class:FileUpdateResponse, class:StatusResponse, class:BranchCreateRequest, class:CheckoutRequest, class:CommitRequest, class:CommitResponse, class:FetchResponse, class:PullResponse, class:PushResponse, class:MergeRequest, class:MergeResponse | dep: uuid, datetime, pydantic
|
- git_repository.py | Defines Pydantic request/response schemas for Git repository operations in an API. | exp: class:GitRepositoryCreate, class:URLParseRequest, class:URLParseResponse, class:GitRepositoryResponse, class:UpdateSSHKeyRequest, class:FileListResponse, class:FileContentResponse, class:BranchesResponse, class:FileUpdateRequest, class:FileUpdateResponse, class:StatusResponse, class:BranchCreateRequest, class:CheckoutRequest, class:CommitRequest, class:CommitResponse, class:FetchResponse, class:PullResponse, class:PushResponse, class:MergeRequest, class:MergeResponse | dep: uuid, datetime, pydantic
|
||||||
- project.py | Defines Pydantic request/response schemas for project-related API operations. | exp: class:ProjectCreate, class:ProjectUpdate, class:ProjectResponse, class:SetDefaultSSHKeyRequest | dep: uuid, pydantic
|
- project.py | Defines Pydantic request/response schemas for project-related API operations including creation, updates, responses, and default SSH key assignment. | exp: class:ProjectCreate, class:ProjectUpdate, class:ProjectResponse, class:SetDefaultSSHKeyRequest | dep: uuid, pydantic
|
||||||
- ssh_key.py | Defines Pydantic schemas for SSH key creation, response, signing, and signature verification in an API. | exp: class:SSHKeyCreate, class:SSHKeyResponse, class:SignPayloadRequest, class:SignatureResponse, class:VerifySignatureRequest, class:VerifySignatureResponse | dep: uuid, datetime, pydantic
|
- ssh_key.py | Defines Pydantic request/response schemas for SSH key management and signature operations in an API. | exp: class:SSHKeyCreate, class:SSHKeyResponse, class:SignPayloadRequest, class:SignatureResponse, class:VerifySignatureRequest, class:VerifySignatureResponse | dep: uuid, datetime, pydantic
|
||||||
## arch
|
## arch
|
||||||
Modular schema decomposition with submodule-per-domain pattern (project, git_repository, ssh_key) aggregated through __init__.py barrel exports, using Pydantic models for declarative validation and serialization.
|
Modular schema-per-domain pattern with clean separation of concerns (git repositories, projects, SSH keys) and centralized public API via `__init__.py` re-exports, following standard Pydantic model hierarchy with explicit request/response bifurcation.
|
||||||
## tags
|
## tags
|
||||||
response, request, project, create, update, sshkey, pydantic, schemas
|
response, request, project, create, update, sshkey, pydantic, git
|
||||||
## symbols
|
## symbols
|
||||||
- GitRepositoryCreate
|
- GitRepositoryCreate
|
||||||
- URLParseRequest
|
- URLParseRequest
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas/system
|
dir: apps/api/src/schemas/system
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Pydantic schema definitions for system health monitoring API responses.
|
Provides Pydantic data models for system health monitoring API responses, enabling standardized health check serialization across the API.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
map: apps/api/src/schemas/.pi-map.md
|
map: apps/api/src/schemas/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/schemas/system
|
|||||||
index: apps/api/src/schemas/system/.pi-map.index.md
|
index: apps/api/src/schemas/system/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Pydantic schema definitions for system health monitoring API responses.
|
Provides Pydantic data models for system health monitoring API responses, enabling standardized health check serialization across the API.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports health check schema classes from a submodule to provide a unified interface for the system schemas module. | dep: src.schemas.system.health
|
- __init__.py | Re-exports health-related schema classes from a submodule to provide a unified interface for the system schemas module. | dep: src.schemas.system.health
|
||||||
- health.py | Defines Pydantic data models for health check API responses including database, disk, and overall system health status. | exp: class:DatabaseHealth, class:DiskHealth, class:HealthChecks, class:HealthResponse, class:DatabaseHealthResponse | dep: pydantic
|
- health.py | Defines Pydantic data models for health check API responses including database, disk, and overall system health metrics. | exp: class:DatabaseHealth, class:DiskHealth, class:HealthChecks, class:HealthResponse, class:DatabaseHealthResponse | dep: pydantic
|
||||||
## arch
|
## arch
|
||||||
Simple modular schema layer with submodule organization and re-export pattern for clean API surface.
|
Simple submodule-based schema organization with explicit re-exports in __init__.py following a flat namespace pattern for cleaner imports.
|
||||||
## tags
|
## tags
|
||||||
health, database, response, system, disk, check, schemas, init
|
health, database, response, system, disk, schemas, init, pydantic
|
||||||
## symbols
|
## symbols
|
||||||
- DatabaseHealth
|
- DatabaseHealth
|
||||||
- DiskHealth
|
- DiskHealth
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas/tool
|
dir: apps/api/src/schemas/tool
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic data validation schemas for tool instance and tool type API operations in the API layer.
|
Provides Pydantic data validation schemas for tool-related API request/response models.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
map: apps/api/src/schemas/.pi-map.md
|
map: apps/api/src/schemas/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: apps/api/src/schemas/tool
|
|||||||
index: apps/api/src/schemas/tool/.pi-map.index.md
|
index: apps/api/src/schemas/tool/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Defines Pydantic data validation schemas for tool instance and tool type API operations in the API layer.
|
Provides Pydantic data validation schemas for tool-related API request/response models.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Package initialization file that exposes tool-related schema classes for import convenience. | dep: src.schemas.tool.tool_instance, src.schemas.tool.tool_type
|
- __init__.py | Re-exports tool-related Pydantic schemas from submodules to provide a unified public interface for the schemas.tool package. | dep: src.schemas.tool.tool_instance, src.schemas.tool.tool_type
|
||||||
- tool_instance.py | Defines Pydantic request/response schemas for tool instance lifecycle operations (create, create-on-workspace, start). | exp: class:CreateInstanceRequest, class:CreateWorkspaceInstanceRequest, class:StartInstanceRequest | dep: pydantic
|
- tool_instance.py | Defines Pydantic request/response schemas for tool instance lifecycle operations (create, create-on-workspace, start). | exp: class:CreateInstanceRequest, class:CreateWorkspaceInstanceRequest, class:StartInstanceRequest | dep: pydantic
|
||||||
- tool_type.py | Defines Pydantic request/response schemas for tool type CRUD operations with conditional validation logic based on definition type (compose/dockerfile/manifest). | exp: class:ToolTypeCreate, class:ToolTypeUpdate, class:ToolTypeResponse, class:ToolTypeValidateRequest | dep: uuid, datetime, pydantic, src.api.tool.tool_types_validation
|
- tool_type.py | Defines Pydantic request/response schemas for tool type CRUD operations with conditional validation logic based on definition type | exp: class:ToolTypeCreate, class:ToolTypeUpdate, class:ToolTypeResponse, class:ToolTypeValidateRequest | dep: uuid, datetime, pydantic, src.api.tool.tool_types_validation
|
||||||
## arch
|
## arch
|
||||||
Standard Pydantic schema package pattern with type-specific conditional validation using discriminated unions or field validators based on definition type.
|
Modular schema organization with submodule-per-entity pattern, re-exported through __init__.py for clean imports; uses conditional Pydantic validators for polymorphic definition type handling.
|
||||||
## tags
|
## tags
|
||||||
tool, type, request, instance, create, schemas, pydantic, response
|
tool, type, request, instance, create, schemas, pydantic, response
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/schemas/user
|
dir: apps/api/src/schemas/user
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Pydantic data validation schemas for user-related API requests and responses.
|
Defines Pydantic schemas for user-related request/response data serialization and validation in the API layer.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/schemas/.pi-map.index.md
|
index: apps/api/src/schemas/.pi-map.index.md
|
||||||
map: apps/api/src/schemas/.pi-map.md
|
map: apps/api/src/schemas/.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: apps/api/src/schemas/user
|
|||||||
index: apps/api/src/schemas/user/.pi-map.index.md
|
index: apps/api/src/schemas/user/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Pydantic data validation schemas for user-related API requests and responses.
|
Defines Pydantic schemas for user-related request/response data serialization and validation in the API layer.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports user-related Pydantic schemas from submodules to provide a unified public API for the user schemas package. | dep: src.schemas.user.user, src.schemas.user.user_config
|
- __init__.py | Exports user-related Pydantic schemas from submodules to provide a clean public API for the user schemas package. | dep: src.schemas.user.user, src.schemas.user.user_config
|
||||||
- user.py | Defines Pydantic response and update schemas for user profile data | exp: class:UserProfileResponse, class:UserProfileUpdate | dep: uuid, pydantic
|
- user.py | Defines Pydantic request/response schemas for user profile data in an API | exp: class:UserProfileResponse, class:UserProfileUpdate | dep: uuid, pydantic
|
||||||
- user_config.py | Defines Pydantic models for user configuration data transfer objects (response and update schemas). | exp: class:UserConfigResponse, class:UserConfigUpdate | dep: pydantic
|
- user_config.py | Defines Pydantic request/response schemas for user configuration data in an API. | exp: class:UserConfigResponse, class:UserConfigUpdate | dep: pydantic
|
||||||
## arch
|
## arch
|
||||||
Modular schema organization with submodule separation of concerns and unified package-level re-exports for clean imports.
|
Modular package pattern with clean public API via __init__.py exports, separating domain concerns (user profile vs. user configuration) into distinct schema modules.
|
||||||
## tags
|
## tags
|
||||||
user, schemas, response, update, config, pydantic, profile, src
|
user, schemas, response, config, pydantic, profile, update, api
|
||||||
## symbols
|
## symbols
|
||||||
- UserProfileResponse
|
- UserProfileResponse
|
||||||
- UserProfileUpdate
|
- UserProfileUpdate
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/scripts
|
dir: apps/api/src/scripts
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides utility scripts for administrative and setup tasks for the API application, specifically database seeding.
|
Provides utility scripts for database initialization and maintenance tasks for the API.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/scripts
|
|||||||
index: apps/api/src/scripts/.pi-map.index.md
|
index: apps/api/src/scripts/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides utility scripts for administrative and setup tasks for the API application, specifically database seeding.
|
Provides utility scripts for database initialization and maintenance tasks for the API.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Marks the directory as a Python package and provides a docstring describing it as utility scripts for the API package.
|
- __init__.py | Marks the directory as a Python package and provides a module docstring for API utility scripts.
|
||||||
- seed.py | Seeds a development user into the database using SQLAlchemy async operations, with idempotency check to avoid duplicates. | exp: func:build_seed_user() → Mapping[str, str | None], func:seed_database(session: AsyncSession) → User, call:build_seed_user, call:session.scalar, call:select(User).where, call:User, call:session.add, call:session.commit, call:session.refresh, func:run() → None, call:SessionLocal, call:seed_database, call:print, call:str, func:main() → None, call:asyncio.run, call:run | dep: collections.abc, sqlalchemy, sqlalchemy.ext.asyncio, src.database, src.models.user, asyncio
|
- seed.py | Seeds a development user into the database, creating it if it doesn't already exist based on email. | exp: func:build_seed_user() → Mapping[str, str | None], func:seed_database(session: AsyncSession) → User, call:build_seed_user, call:session.scalar, call:select(User).where, call:User, call:session.add, call:session.commit, call:session.refresh, func:run() → None, call:SessionLocal, call:seed_database, call:print, call:str, func:main() → None, call:asyncio.run, call:run | dep: collections.abc, sqlalchemy, sqlalchemy.ext.asyncio, src.database, src.models.user, asyncio
|
||||||
## arch
|
## arch
|
||||||
Simple procedural script architecture with async SQLAlchemy database operations and idempotent initialization patterns.
|
Simple procedural script pattern with direct database access via SQLAlchemy models, no service layer abstraction.
|
||||||
## tags
|
## tags
|
||||||
seed, user, database, sqlalchemy, package, init, call:build, call:session.scalar
|
seed, user, database, init, call:build, call:session.scalar, call:select, call:user
|
||||||
## symbols
|
## symbols
|
||||||
- build_seed_user
|
- build_seed_user
|
||||||
- seed_database
|
- seed_database
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/seeds
|
dir: apps/api/src/seeds
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides database seeding utilities for initializing built-in tool type configurations in the API application.
|
Provides database seeding utilities to populate initial built-in tool type configurations for the API application.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ dir: apps/api/src/seeds
|
|||||||
index: apps/api/src/seeds/.pi-map.index.md
|
index: apps/api/src/seeds/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides database seeding utilities for initializing built-in tool type configurations in the API application.
|
Provides database seeding utilities to populate initial built-in tool type configurations for the API application.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Marks the directory as a Python package for database seeding utilities.
|
- __init__.py | Marks directory as Python package for database seeding utilities
|
||||||
- builtin_tool_types.py | Seeds built-in tool types (code-server, jupyter-notebook, opencode) into a database with upsert logic, creating or updating Docker Compose-based development environment templates. | exp: func:_table_exists(session, table_name: str) → bool, call:session.execute, call:text, call:result.scalar, func:seed_builtin_tool_types(), call:SessionLocal, call:_table_exists, call:logger.warning, call:session.scalar, call:select(ToolType).where, call:ToolType, call:tool_data.get, call:session.add, call:logger.info, call:session.commit | dep: logging, sqlalchemy, src.database, src.models
|
- builtin_tool_types.py | Seeds built-in tool types (code-server, jupyter-notebook, opencode) into the database with Docker Compose templates, creating or updating records as needed. | exp: func:_table_exists(session, table_name: str) → bool, call:session.execute, call:text, call:result.scalar, func:seed_builtin_tool_types(), call:SessionLocal, call:_table_exists, call:logger.warning, call:session.scalar, call:select(ToolType).where, call:ToolType, call:tool_data.get, call:session.add, call:logger.info, call:session.commit | dep: logging, sqlalchemy, src.database, src.models
|
||||||
## arch
|
## arch
|
||||||
Simple procedural seeding script using SQLAlchemy upsert operations to populate reference data for containerized development environment templates.
|
Simple procedural seeding pattern with idempotent upsert operations, directly importing and executing database model creation logic with embedded Docker Compose template definitions.
|
||||||
## tags
|
## tags
|
||||||
tool, types, table, exists, builtin, call:tool, database, init
|
tool, types, table, exists, builtin, call:tool, database, init
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ services:
|
|||||||
- {{REPO_PATH}}:/config/workspace
|
- {{REPO_PATH}}:/config/workspace
|
||||||
ports:
|
ports:
|
||||||
- "8443:8443"
|
- "8443:8443"
|
||||||
restart: unless-stopped""",
|
restart: 'no'""",
|
||||||
"default_port": 8443,
|
"default_port": 8443,
|
||||||
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
||||||
},
|
},
|
||||||
@@ -87,7 +87,7 @@ services:
|
|||||||
- {{REPO_PATH}}:/home/jovyan/work
|
- {{REPO_PATH}}:/home/jovyan/work
|
||||||
ports:
|
ports:
|
||||||
- "8888:8888"
|
- "8888:8888"
|
||||||
restart: unless-stopped""",
|
restart: 'no'""",
|
||||||
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -102,9 +102,9 @@ services:
|
|||||||
opencode:
|
opencode:
|
||||||
image: node:20-slim
|
image: node:20-slim
|
||||||
container_name: {{TOOL_NAME}}
|
container_name: {{TOOL_NAME}}
|
||||||
working_dir: /workspace
|
working_dir: /home/user/{{WORKSPACE_NAME}}
|
||||||
volumes:
|
volumes:
|
||||||
- {{REPO_PATH}}:/workspace
|
- {{REPO_PATH}}:/home/user/{{WORKSPACE_NAME}}
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
command: >
|
command: >
|
||||||
@@ -116,13 +116,12 @@ services:
|
|||||||
npm bin -g &&
|
npm bin -g &&
|
||||||
ls -la $(npm bin -g) || echo 'ERROR: global bin dir not found' &&
|
ls -la $(npm bin -g) || echo 'ERROR: global bin dir not found' &&
|
||||||
echo 'export PATH=\"$(npm bin -g):\\$PATH\"' >> /root/.bashrc &&
|
echo 'export PATH=\"$(npm bin -g):\\$PATH\"' >> /root/.bashrc &&
|
||||||
echo 'cd /workspace' >> /root/.bashrc &&
|
echo 'cd /home/user/{{WORKSPACE_NAME}}' >> /root/.bashrc &&
|
||||||
echo 'OpenCode installation complete' &&
|
echo 'OpenCode installation complete' &&
|
||||||
cd /workspace &&
|
|
||||||
exec tail -f /dev/null"
|
exec tail -f /dev/null"
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: true
|
tty: true
|
||||||
restart: unless-stopped""",
|
restart: 'no'""",
|
||||||
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/services
|
dir: apps/api/src/services
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Marks the services directory as a Python package for business logic layer components.
|
Provides utility services for the API application, including tmux window management functionality.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/.pi-map.index.md
|
index: apps/api/src/.pi-map.index.md
|
||||||
map: apps/api/src/.pi-map.md
|
map: apps/api/src/.pi-map.md
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ dir: apps/api/src/services
|
|||||||
index: apps/api/src/services/.pi-map.index.md
|
index: apps/api/src/services/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides a Python package namespace for organizing service-layer modules in the API application.
|
Provides utility services for the API application, including tmux window management functionality.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Empty file with no functionality
|
- __init__.py | Swaps two tmux panes between windows, preserving active pane state and layout | dep: tmux
|
||||||
## arch
|
## arch
|
||||||
Standard Python package structure using __init__.py for directory-based module organization, following conventional layered architecture patterns.
|
Simple module-based architecture with service functions organized in a flat directory structure.
|
||||||
## tags
|
## tags
|
||||||
init, empty, functionality
|
tmux, init, swaps, two, panes, windows, preserving, active
|
||||||
## symbols
|
## symbols
|
||||||
-
|
-
|
||||||
## workflows
|
## workflows
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from typing import Any
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from src.services.config.config_profile_resolver import expand_container_path
|
||||||
from src.services.docker import sort_volumes_by_specificity
|
from src.services.docker import sort_volumes_by_specificity
|
||||||
|
|
||||||
|
|
||||||
@@ -142,13 +143,6 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
lines.append(" rm -rf /var/lib/apt/lists/*")
|
lines.append(" rm -rf /var/lib/apt/lists/*")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# NPM global packages
|
|
||||||
npm_packages = manifest.get("packages", {}).get("npm_global", [])
|
|
||||||
if npm_packages:
|
|
||||||
pkg_list = " ".join(shlex.quote(p) for p in npm_packages)
|
|
||||||
lines.append(f"RUN npm install -g {pkg_list}")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
# Pip packages
|
# Pip packages
|
||||||
pip_packages = manifest.get("packages", {}).get("pip", [])
|
pip_packages = manifest.get("packages", {}).get("pip", [])
|
||||||
if pip_packages:
|
if pip_packages:
|
||||||
@@ -158,6 +152,9 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
|
|
||||||
# User creation
|
# User creation
|
||||||
user = manifest.get("user")
|
user = manifest.get("user")
|
||||||
|
home_dir = get_manifest_home_dir(manifest)
|
||||||
|
workspace_name = manifest.get("workspace_name", "{{WORKSPACE_NAME}}")
|
||||||
|
npm_prefix = ""
|
||||||
if user:
|
if user:
|
||||||
name = user["name"]
|
name = user["name"]
|
||||||
uid = user["uid"]
|
uid = user["uid"]
|
||||||
@@ -168,22 +165,21 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
lines.append(f" useradd -u {uid} -g {gid} {create_home}-s {shell} {name}")
|
lines.append(f" useradd -u {uid} -g {gid} {create_home}-s {shell} {name}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
# Set HOME and USER for runtime compatibility
|
# Set HOME and USER for runtime compatibility
|
||||||
home = f"/home/{name}"
|
lines.append(f"ENV HOME={home_dir}")
|
||||||
lines.append(f"ENV HOME={home}")
|
|
||||||
lines.append(f"ENV USER={name}")
|
lines.append(f"ENV USER={name}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
# Ensure home directory exists and is writable by the user.
|
# Ensure home directory exists and is writable by the user.
|
||||||
# Recursively chown so any files copied from /etc/skel by useradd -m
|
# Recursively chown so any files copied from /etc/skel by useradd -m
|
||||||
# (e.g. .bashrc, .config) are owned by the container user.
|
# (e.g. .bashrc, .config) are owned by the container user.
|
||||||
lines.append(
|
lines.append(
|
||||||
f"RUN mkdir -p {home} && chown -R {name}:{name} {home} && chmod 755 {home}"
|
f"RUN mkdir -p {home_dir} && chown -R {name}:{name} {home_dir} && chmod 755 {home_dir}"
|
||||||
)
|
)
|
||||||
# Pre-create common config directories so apps like ranger can write
|
# Pre-create common config directories so apps like ranger can write
|
||||||
# their configs on first run without permission errors.
|
# their configs on first run without permission errors.
|
||||||
common_dirs = [".config", ".local/share", ".cache"]
|
common_dirs = [".config", ".local/share", ".cache"]
|
||||||
for d in common_dirs:
|
for d in common_dirs:
|
||||||
lines.append(
|
lines.append(
|
||||||
f"RUN mkdir -p {home}/{d} && chown -R {name}:{name} {home}/{d}"
|
f"RUN mkdir -p {home_dir}/{d} && chown -R {name}:{name} {home_dir}/{d}"
|
||||||
)
|
)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
@@ -193,6 +189,20 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
)
|
)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
# NPM global packages: install into a user-writable prefix so the
|
||||||
|
# container user can update global packages without touching
|
||||||
|
# /usr/lib/node_modules (which is owned by root).
|
||||||
|
npm_packages = manifest.get("packages", {}).get("npm_global", [])
|
||||||
|
if npm_packages:
|
||||||
|
pkg_list = " ".join(shlex.quote(p) for p in npm_packages)
|
||||||
|
npm_prefix = f"{home_dir}/.npm-global"
|
||||||
|
lines.append(
|
||||||
|
f"RUN mkdir -p {npm_prefix} && "
|
||||||
|
f"npm install -g --prefix {npm_prefix} {pkg_list}"
|
||||||
|
)
|
||||||
|
lines.append(f"ENV PATH={npm_prefix}/bin:$PATH")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
# Build scripts
|
# Build scripts
|
||||||
build_scripts = manifest.get("scripts", {}).get("build", [])
|
build_scripts = manifest.get("scripts", {}).get("build", [])
|
||||||
for script in build_scripts:
|
for script in build_scripts:
|
||||||
@@ -208,19 +218,36 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
|
|
||||||
# After build scripts, ensure everything in home is owned by the user
|
# After build scripts, ensure everything in home is owned by the user
|
||||||
if user and build_scripts:
|
if user and build_scripts:
|
||||||
lines.append(f"RUN chown -R {name}:{name} {home}")
|
lines.append(f"RUN chown -R {name}:{name} {home_dir}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Create mount target directories
|
# Create mount target directories that do NOT depend on runtime variables.
|
||||||
|
# Targets containing {{WORKSPACE_NAME}} will be created at container
|
||||||
|
# startup by the entrypoint, once the actual workspace/repo name is known.
|
||||||
mounts = manifest.get("mounts", [])
|
mounts = manifest.get("mounts", [])
|
||||||
if mounts:
|
static_dirs = [
|
||||||
dirs = [mount["target"] for mount in mounts]
|
mount["target"] for mount in mounts
|
||||||
dir_str = " ".join(dirs)
|
if "{{WORKSPACE_NAME}}" not in mount.get("target", "")
|
||||||
|
]
|
||||||
|
if static_dirs:
|
||||||
|
dir_str = " ".join(static_dirs)
|
||||||
lines.append(f"RUN mkdir -p {dir_str}")
|
lines.append(f"RUN mkdir -p {dir_str}")
|
||||||
if user:
|
if user:
|
||||||
lines.append(f"RUN chown -R {user['name']}:{user['name']} {dir_str}")
|
lines.append(f"RUN chown -R {user['name']}:{user['name']} {dir_str}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
# Ensure the project directory exists so the WORKDIR below succeeds. The
|
||||||
|
# compatibility /workspace symlink is no longer created for new images.
|
||||||
|
workspace_target = f"{home_dir}/{workspace_name}"
|
||||||
|
workspace_is_placeholder = "{{WORKSPACE_NAME}}" in workspace_name
|
||||||
|
if not workspace_is_placeholder:
|
||||||
|
lines.append(f"RUN mkdir -p {workspace_target}")
|
||||||
|
if user:
|
||||||
|
lines.append(
|
||||||
|
f"RUN chown -R {user['name']}:{user['name']} {home_dir}"
|
||||||
|
)
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
# Entrypoint for startup scripts
|
# Entrypoint for startup scripts
|
||||||
startup_scripts = manifest.get("scripts", {}).get("startup", [])
|
startup_scripts = manifest.get("scripts", {}).get("startup", [])
|
||||||
if startup_scripts:
|
if startup_scripts:
|
||||||
@@ -230,14 +257,25 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
lines.append("RUN chmod +x /usr/local/bin/headquarter-entrypoint")
|
lines.append("RUN chmod +x /usr/local/bin/headquarter-entrypoint")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Switch to runtime user
|
# Do not switch to the runtime user in the Dockerfile. The entrypoint
|
||||||
if user:
|
# starts as root so it can fix mount ownership, then it drops privileges
|
||||||
lines.append(f"USER {user['name']}")
|
# to the container user before exec-ing the real command.
|
||||||
lines.append(f"WORKDIR /home/{user['name']}")
|
|
||||||
lines.append("")
|
# Set WORKDIR to the project directory unless runtime.working_dir
|
||||||
|
# explicitly overrides it. When the workspace name is a runtime
|
||||||
|
# placeholder, the Dockerfile cannot know the literal directory, so fall
|
||||||
|
# back to the home directory; compose supplies the exact working_dir.
|
||||||
|
runtime = manifest.get("runtime", {})
|
||||||
|
working_dir = runtime.get("working_dir")
|
||||||
|
if working_dir:
|
||||||
|
lines.append(f"WORKDIR {expand_container_path(working_dir, home_dir)}")
|
||||||
|
elif workspace_is_placeholder:
|
||||||
|
lines.append(f"WORKDIR {home_dir}")
|
||||||
|
else:
|
||||||
|
lines.append(f"WORKDIR {workspace_target}")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
# Entrypoint and CMD
|
# Entrypoint and CMD
|
||||||
runtime = manifest.get("runtime", {})
|
|
||||||
if startup_scripts:
|
if startup_scripts:
|
||||||
lines.append('ENTRYPOINT ["/usr/local/bin/headquarter-entrypoint"]')
|
lines.append('ENTRYPOINT ["/usr/local/bin/headquarter-entrypoint"]')
|
||||||
|
|
||||||
@@ -251,6 +289,11 @@ def compile_dockerfile(manifest: dict) -> str:
|
|||||||
def compile_entrypoint(manifest: dict) -> str:
|
def compile_entrypoint(manifest: dict) -> str:
|
||||||
"""Generate the startup entrypoint script from startup scripts.
|
"""Generate the startup entrypoint script from startup scripts.
|
||||||
|
|
||||||
|
Injects a permission-fixer preamble that runs as root (or via sudo) before
|
||||||
|
any user-defined startup script. It chowns the home directory and a safe
|
||||||
|
subset of mount parents to the container user, ensures the project
|
||||||
|
directory exists, and avoids recursive chown of large repo subtrees.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
manifest: Fully resolved manifest JSON.
|
manifest: Fully resolved manifest JSON.
|
||||||
|
|
||||||
@@ -259,12 +302,98 @@ def compile_entrypoint(manifest: dict) -> str:
|
|||||||
"""
|
"""
|
||||||
lines = ["#!/bin/bash", "set -e", ""]
|
lines = ["#!/bin/bash", "set -e", ""]
|
||||||
|
|
||||||
|
user = manifest.get("user")
|
||||||
|
home_dir = get_manifest_home_dir(manifest)
|
||||||
|
|
||||||
|
# Permission fixer preamble: run as root when possible, else fall back to
|
||||||
|
# passwordless sudo configured in the Dockerfile.
|
||||||
|
lines.append("# Permission fixer preamble")
|
||||||
|
lines.append("CONTAINER_USER=''")
|
||||||
|
lines.append('if [ "$(id -u)" = '"'"'0'"'"' ]; then')
|
||||||
|
if user:
|
||||||
|
lines.append(f" CONTAINER_USER='{user['name']}'")
|
||||||
|
lines.append("else")
|
||||||
|
lines.append(" # Try passwordless sudo; ignore failure so the container still starts")
|
||||||
|
lines.append(" if sudo -n true 2>/dev/null; then")
|
||||||
|
lines.append(" SUDO='sudo'")
|
||||||
|
lines.append(" else")
|
||||||
|
lines.append(" SUDO=''")
|
||||||
|
lines.append(" fi")
|
||||||
|
lines.append("fi")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
if user:
|
||||||
|
name = user["name"]
|
||||||
|
uid = user["uid"]
|
||||||
|
gid = user["gid"]
|
||||||
|
lines.append(f"USER_NAME='{name}'")
|
||||||
|
lines.append(f"USER_UID='{uid}'")
|
||||||
|
lines.append(f"USER_GID='{gid}'")
|
||||||
|
lines.append(f"HOME_DIR='{home_dir}'")
|
||||||
|
lines.append('WORKSPACE_NAME="${WORKSPACE_NAME:-workspace}"')
|
||||||
|
lines.append('WORKSPACE_TARGET="${HOME_DIR}/${WORKSPACE_NAME}"')
|
||||||
|
lines.append("")
|
||||||
|
lines.append("fix_owner() {")
|
||||||
|
lines.append(" local path=\"$1\"")
|
||||||
|
lines.append(' [ -e "$path" ] || return 0')
|
||||||
|
lines.append(' if [ -n "$SUDO" ]; then')
|
||||||
|
lines.append(' sudo chown "$USER_UID:$USER_GID" "$path" 2>/dev/null || true')
|
||||||
|
lines.append(' elif [ "$(id -u)" = "0" ]; then')
|
||||||
|
lines.append(' chown "$USER_UID:$USER_GID" "$path" 2>/dev/null || true')
|
||||||
|
lines.append(' fi')
|
||||||
|
lines.append("}")
|
||||||
|
lines.append("")
|
||||||
|
lines.append("# Ensure home directory exists and is owned by the container user")
|
||||||
|
lines.append('mkdir -p "$HOME_DIR"')
|
||||||
|
lines.append('fix_owner "$HOME_DIR"')
|
||||||
|
lines.append("")
|
||||||
|
lines.append("# Ensure project directory exists and is owned by the container user")
|
||||||
|
lines.append('mkdir -p "$WORKSPACE_TARGET"')
|
||||||
|
lines.append('fix_owner "$WORKSPACE_TARGET"')
|
||||||
|
lines.append("")
|
||||||
|
lines.append("# Remove stale placeholder directory baked into older images")
|
||||||
|
lines.append('if [ -d "${HOME_DIR}/{{WORKSPACE_NAME}}" ]; then')
|
||||||
|
lines.append(' rm -rf "${HOME_DIR}/{{WORKSPACE_NAME}}"')
|
||||||
|
lines.append('fi')
|
||||||
|
lines.append("")
|
||||||
|
lines.append("# Fix ownership of declared mount targets (top-level only)")
|
||||||
|
for mount in manifest.get("mounts", []):
|
||||||
|
target = mount.get("target")
|
||||||
|
if not target:
|
||||||
|
continue
|
||||||
|
# Expand any ~/$HOME placeholders and the runtime workspace name
|
||||||
|
# in the mount target so ownership is fixed at container startup.
|
||||||
|
expanded = (
|
||||||
|
target.replace("~", home_dir)
|
||||||
|
.replace("$HOME", home_dir)
|
||||||
|
.replace("{{WORKSPACE_NAME}}", "${WORKSPACE_NAME}")
|
||||||
|
)
|
||||||
|
if expanded.startswith(home_dir) and not mount.get("readonly", False):
|
||||||
|
lines.append(f'fix_owner "{expanded}"')
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
startup_scripts = manifest.get("scripts", {}).get("startup", [])
|
startup_scripts = manifest.get("scripts", {}).get("startup", [])
|
||||||
for script in startup_scripts:
|
for script in startup_scripts:
|
||||||
lines.append(script)
|
lines.append(script)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
lines.append('exec "$@"')
|
# Drop from root to the container user before running the real command.
|
||||||
|
# The Dockerfile no longer sets USER, so the entrypoint has root for the
|
||||||
|
# setup above. `runuser` (root-only, no PAM) preserves the environment,
|
||||||
|
# stdin, and TTY so interactive tools like bash keep running.
|
||||||
|
if user:
|
||||||
|
name = user["name"]
|
||||||
|
lines.append("# Drop privileges to the container user")
|
||||||
|
# When the container command is a shell, force an interactive login
|
||||||
|
# shell. Detached containers may not have stdin connected, and a plain
|
||||||
|
# /bin/bash invocation exits immediately with code 0. -il keeps it
|
||||||
|
# alive so the container stays running for docker exec/web terminals.
|
||||||
|
lines.append('if [ "$1" = "/bin/bash" ] || [ "$1" = "bash" ]; then')
|
||||||
|
lines.append(f' exec runuser -u {name} -- /bin/bash -il')
|
||||||
|
lines.append('fi')
|
||||||
|
lines.append(f'exec runuser -u {name} -- "$@"')
|
||||||
|
else:
|
||||||
|
lines.append('exec "$@"')
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
@@ -281,11 +410,18 @@ def compile_compose(manifest: dict, variables: dict[str, Any]) -> str:
|
|||||||
runtime = manifest.get("runtime", {})
|
runtime = manifest.get("runtime", {})
|
||||||
user = manifest.get("user")
|
user = manifest.get("user")
|
||||||
interface_type = manifest["interface_type"]
|
interface_type = manifest["interface_type"]
|
||||||
|
home_dir = get_manifest_home_dir(manifest)
|
||||||
|
|
||||||
|
# Determine the workspace/repo name from variables when available.
|
||||||
|
workspace_name = variables.get(
|
||||||
|
"WORKSPACE_NAME",
|
||||||
|
variables.get("REPO_NAME", "workspace"),
|
||||||
|
)
|
||||||
|
|
||||||
service: dict[str, Any] = {
|
service: dict[str, Any] = {
|
||||||
"image": variables["IMAGE_TAG"],
|
"image": variables["IMAGE_TAG"],
|
||||||
"container_name": variables["INSTANCE_NAME"],
|
"container_name": variables["INSTANCE_NAME"],
|
||||||
"restart": "unless-stopped",
|
"restart": "no",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Terminal-specific fields
|
# Terminal-specific fields
|
||||||
@@ -294,11 +430,18 @@ def compile_compose(manifest: dict, variables: dict[str, Any]) -> str:
|
|||||||
if runtime.get("tty", False):
|
if runtime.get("tty", False):
|
||||||
service["tty"] = True
|
service["tty"] = True
|
||||||
if runtime.get("working_dir"):
|
if runtime.get("working_dir"):
|
||||||
service["working_dir"] = runtime["working_dir"]
|
service["working_dir"] = expand_container_path(
|
||||||
|
runtime["working_dir"], home_dir
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
service["working_dir"] = f"{home_dir}/{workspace_name}"
|
||||||
|
|
||||||
# User override
|
# The entrypoint starts as root (Dockerfile does not set USER) so it can
|
||||||
|
# fix mount ownership. It drops privileges to the container user internally
|
||||||
|
# before exec-ing the real command, so do not set compose-level user
|
||||||
|
# override here.
|
||||||
if user:
|
if user:
|
||||||
service["user"] = f"{user['uid']}:{user['gid']}"
|
service["user"] = "0:0"
|
||||||
|
|
||||||
# Ports for web tools
|
# Ports for web tools
|
||||||
default_port = manifest.get("default_port")
|
default_port = manifest.get("default_port")
|
||||||
@@ -310,6 +453,12 @@ def compile_compose(manifest: dict, variables: dict[str, Any]) -> str:
|
|||||||
if env:
|
if env:
|
||||||
service["environment"] = dict(env)
|
service["environment"] = dict(env)
|
||||||
|
|
||||||
|
# Expose the project name so the entrypoint can create the project
|
||||||
|
# directory at container startup.
|
||||||
|
if "environment" not in service:
|
||||||
|
service["environment"] = {}
|
||||||
|
service["environment"]["WORKSPACE_NAME"] = workspace_name
|
||||||
|
|
||||||
# Merge extra env from config
|
# Merge extra env from config
|
||||||
extra_env = variables.get("EXTRA_ENV", {})
|
extra_env = variables.get("EXTRA_ENV", {})
|
||||||
if extra_env:
|
if extra_env:
|
||||||
@@ -319,14 +468,25 @@ def compile_compose(manifest: dict, variables: dict[str, Any]) -> str:
|
|||||||
|
|
||||||
# Volumes from mount schema
|
# Volumes from mount schema
|
||||||
volumes = []
|
volumes = []
|
||||||
|
has_explicit_repo_mount = False
|
||||||
for mount in manifest.get("mounts", []):
|
for mount in manifest.get("mounts", []):
|
||||||
source = resolve_mount_source(mount, variables)
|
source = resolve_mount_source(mount, variables)
|
||||||
if not source:
|
if not source:
|
||||||
continue
|
continue
|
||||||
target = mount["target"]
|
if mount.get("source_type") == "repo":
|
||||||
|
has_explicit_repo_mount = True
|
||||||
|
target = expand_container_path(mount["target"], home_dir)
|
||||||
|
target = target.replace("{{WORKSPACE_NAME}}", workspace_name)
|
||||||
readonly = ":ro" if mount.get("readonly", False) else ""
|
readonly = ":ro" if mount.get("readonly", False) else ""
|
||||||
volumes.append(f"{source}:{target}{readonly}")
|
volumes.append(f"{source}:{target}{readonly}")
|
||||||
|
|
||||||
|
# Synthesize a default repo/workspace mount when the manifest does not
|
||||||
|
# declare an explicit repo mount. This preserves the repo root directory
|
||||||
|
# name under the configured home directory.
|
||||||
|
if not has_explicit_repo_mount and variables.get("REPO_PATH"):
|
||||||
|
target = f"{home_dir}/{workspace_name}"
|
||||||
|
volumes.append(f"{variables['REPO_PATH']}:{target}")
|
||||||
|
|
||||||
# Append extra volumes from tool config / config profile
|
# Append extra volumes from tool config / config profile
|
||||||
for vol in variables.get("EXTRA_VOLUMES", []):
|
for vol in variables.get("EXTRA_VOLUMES", []):
|
||||||
vol_str = f"{vol['source']}:{vol['target']}"
|
vol_str = f"{vol['source']}:{vol['target']}"
|
||||||
@@ -385,7 +545,12 @@ def resolve_mount_source(mount: dict, variables: dict[str, Any]) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def get_manifest_home_dir(manifest: dict) -> str:
|
def get_manifest_home_dir(manifest: dict) -> str:
|
||||||
"""Get the home directory for a container based on manifest user config.
|
"""Get the home directory for a container based on manifest config.
|
||||||
|
|
||||||
|
Precedence:
|
||||||
|
1. manifest["home_directory"] if present and non-empty.
|
||||||
|
2. /home/{user.name} if manifest.user.name is present.
|
||||||
|
3. /root otherwise.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
manifest: Fully resolved manifest JSON.
|
manifest: Fully resolved manifest JSON.
|
||||||
@@ -393,6 +558,10 @@ def get_manifest_home_dir(manifest: dict) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
Home directory path (e.g., /home/user or /root).
|
Home directory path (e.g., /home/user or /root).
|
||||||
"""
|
"""
|
||||||
|
home_directory = manifest.get("home_directory")
|
||||||
|
if home_directory and isinstance(home_directory, str) and home_directory.strip():
|
||||||
|
return home_directory.strip()
|
||||||
|
|
||||||
user = manifest.get("user")
|
user = manifest.get("user")
|
||||||
if user and user.get("name"):
|
if user and user.get("name"):
|
||||||
return f"/home/{user['name']}"
|
return f"/home/{user['name']}"
|
||||||
@@ -402,6 +571,10 @@ def get_manifest_home_dir(manifest: dict) -> str:
|
|||||||
def compute_image_tag(tool_name: str, manifest: dict) -> str:
|
def compute_image_tag(tool_name: str, manifest: dict) -> str:
|
||||||
"""Compute a deterministic image tag from manifest content.
|
"""Compute a deterministic image tag from manifest content.
|
||||||
|
|
||||||
|
The hash includes the manifest JSON plus a compiler version token so
|
||||||
|
that changes to the Dockerfile/entrypoint generation logic invalidate
|
||||||
|
previously built images.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tool_name: Human-readable tool name.
|
tool_name: Human-readable tool name.
|
||||||
manifest: Fully resolved manifest JSON.
|
manifest: Fully resolved manifest JSON.
|
||||||
@@ -409,9 +582,11 @@ def compute_image_tag(tool_name: str, manifest: dict) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
Docker image tag string.
|
Docker image tag string.
|
||||||
"""
|
"""
|
||||||
# Canonicalize: sort keys, stable JSON
|
compiler_version = "v4" # bump when compile_dockerfile/entrypoint/compose change
|
||||||
canonical = json.dumps(manifest, sort_keys=True, separators=(",", ":"))
|
canonical = json.dumps(manifest, sort_keys=True, separators=(",", ":"))
|
||||||
hash_suffix = hashlib.sha256(canonical.encode()).hexdigest()[:8]
|
hash_suffix = hashlib.sha256(
|
||||||
|
f"{compiler_version}:{canonical}".encode()
|
||||||
|
).hexdigest()[:8]
|
||||||
safe_name = tool_name.lower().replace(" ", "-").replace("_", "-")
|
safe_name = tool_name.lower().replace(" ", "-").replace("_", "-")
|
||||||
return f"headquarter/{safe_name}-{hash_suffix}:latest"
|
return f"headquarter/{safe_name}-{hash_suffix}:latest"
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/services/config
|
dir: apps/api/src/services/config
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides configuration profile management with recursive resolution, validation, and access control for container environment setup.
|
Provides configuration profile resolution, validation, and CRUD operations with recursive includes and cycle detection for the API layer.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/services/.pi-map.index.md
|
index: apps/api/src/services/.pi-map.index.md
|
||||||
map: apps/api/src/services/.pi-map.md
|
map: apps/api/src/services/.pi-map.md
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ dir: apps/api/src/services/config
|
|||||||
index: apps/api/src/services/config/.pi-map.index.md
|
index: apps/api/src/services/config/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides configuration profile management with recursive resolution, validation, and access control for container environment setup.
|
Provides configuration profile resolution, validation, and CRUD operations with recursive includes and cycle detection for the API layer.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Re-exports configuration profile resolution components from a subpackage to provide a unified public API. | dep: src.services.config.config_profile_resolver
|
- __init__.py | Re-exports configuration profile resolution components to make them accessible as a unified module interface. | dep: src.services.config.config_profile_resolver
|
||||||
- config_profile_resolver.py | Resolves configuration profiles recursively with ordered includes, deterministic merge rules, and cycle protection for container environment setup. | exp: class:ConfigProfileCycleError, class:ConfigProfileNotFoundError, class:ResolvedMount, class:ResolvedProfile, func:_detect_cycle(profile_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → bool, func:_merge_env_vars(base: dict[str, str], overlay: dict[str, str], overrides: dict[str, str], source_name: str) → dict[str, str], call:dict, call:overlay.items, func:_merge_runtime_hints(base: dict[str, Any], overlay: dict[str, Any], overrides: dict[str, str], source_name: str) → dict[str, Any], call:dict, call:overlay.items, func:_merge_files(base: dict[str, str], overlay: dict[str, str], overrides: dict[str, str], source_name: str) → dict[str, str], call:dict, call:overlay.items, func:_merge_mounts(base: dict[str, ResolvedMount], overlay: list[dict[str, Any]], overrides: dict[str, str], source_name: str) → dict[str, ResolvedMount], call:dict, call:mount_data.get, call:files.items, call:ResolvedMount, func:_merge_git_mounts(base: list[dict[str, Any]], overlay: list[dict[str, Any]], source_name: str) → list[dict[str, Any]], call:list, call:enumerate, call:_normalize_git_mount_entry, call:dict, call:m.get, call:mount.get, call:existing.get, call:existing["mappings"].append, call:existing_sources.add, call:len, call:result.append, func:_normalize_git_mount_entry(entry: dict[str, Any]) → dict[str, Any], call:dict, call:entry.get, call:entry.pop, func:_resolve_profile_recursive(session: AsyncSession, profile_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → ResolvedProfile, call:_detect_cycle, call:" -> ".join, call:str, call:session.get, call:ResolvedProfile, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == profile_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_resolve_profile_recursive, call:result.included_profiles.append, call:_merge_env_vars, call:_merge_runtime_hints, call:_merge_files, call:_merge_mounts, call:included.mounts.values, call:_merge_git_mounts, raise:ConfigProfileCycleError, raise:ConfigProfileNotFoundError, func:resolve_profile(session: AsyncSession, profile_id: uuid.UUID) → ResolvedProfile, call:_resolve_profile_recursive, call:set, func:check_include_cycle(session: AsyncSession, profile_id: uuid.UUID, new_include_id) → list[uuid.UUID] | None, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == current_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_check_from, call:set, call:len, func:_check_from(current_id: uuid.UUID, target_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → list[uuid.UUID] | None, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == current_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_check_from, func:apply_resolved_profile(instance_dir: str, resolved: ResolvedProfile, home_dir) → tuple[dict[str, str], dict[str, str], list[dict], dict[str, Any]], call:Path, call:dict, call:files.items, call:full_path.resolve().relative_to, call:instance_path.resolve, call:logger.warning, call:full_path.parent.mkdir, call:full_path.write_text, call:resolved.mounts.values, call:os.path.normpath, call:expand_container_path, call:expanded_target.lstrip("/").replace, call:mount_dir.mkdir, call:mount.files.items, call:mount_dir.resolve, call:volume_mounts.append, call:str, func:expand_container_path(path: str, home_dir: str) → str, call:path.startswith, call:os.path.join, func:resolved_profile_to_dict(resolved: ResolvedProfile) → dict[str, Any], call:str, call:resolved.mounts.values | dep: logging, os, uuid, dataclasses, typing, sqlalchemy, sqlalchemy.ext.asyncio, src.models, pathlib
|
- config_profile_resolver.py | Resolves configuration profiles recursively with ordered includes, deterministic merge rules, and cycle detection. | exp: class:ConfigProfileCycleError, class:ConfigProfileNotFoundError, class:ResolvedMount, class:ResolvedProfile, func:_detect_cycle(profile_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → bool, func:_merge_env_vars(base: dict[str, str], overlay: dict[str, str], overrides: dict[str, str], source_name: str) → dict[str, str], call:dict, call:overlay.items, func:_merge_runtime_hints(base: dict[str, Any], overlay: dict[str, Any], overrides: dict[str, str], source_name: str) → dict[str, Any], call:dict, call:overlay.items, func:_merge_files(base: dict[str, str], overlay: dict[str, str], overrides: dict[str, str], source_name: str) → dict[str, str], call:dict, call:overlay.items, func:_merge_mounts(base: dict[str, ResolvedMount], overlay: list[dict[str, Any]], overrides: dict[str, str], source_name: str) → dict[str, ResolvedMount], call:dict, call:mount_data.get, call:files.items, call:ResolvedMount, func:_find_mount_conflicts(profile: ConfigProfile, resolved: ResolvedProfile) → list[dict[str, Any]], call:m.get("files", {}).keys, call:resolved.mounts.values, call:conflicts.append, func:_merge_git_mounts(base: list[dict[str, Any]], overlay: list[dict[str, Any]], source_name: str) → list[dict[str, Any]], call:list, call:enumerate, call:_normalize_git_mount_entry, call:dict, call:m.get, call:mount.get, call:existing.get, call:existing["mappings"].append, call:existing_sources.add, call:len, call:result.append, func:_normalize_git_mount_entry(entry: dict[str, Any]) → dict[str, Any], call:dict, call:entry.get, call:entry.pop, func:_resolve_profile_recursive(session: AsyncSession, profile_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → ResolvedProfile, call:_detect_cycle, call:" -> ".join, call:str, call:session.get, call:ResolvedProfile, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == profile_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_resolve_profile_recursive, call:result.included_profiles.append, call:_merge_env_vars, call:_merge_runtime_hints, call:_merge_files, call:_merge_mounts, call:included.mounts.values, call:_merge_git_mounts, raise:ConfigProfileCycleError, raise:ConfigProfileNotFoundError, func:resolve_profile(session: AsyncSession, profile_id: uuid.UUID) → ResolvedProfile, call:_resolve_profile_recursive, call:set, func:check_include_cycle(session: AsyncSession, profile_id: uuid.UUID, new_include_id) → list[uuid.UUID] | None, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == current_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_check_from, call:set, call:len, func:_check_from(current_id: uuid.UUID, target_id: uuid.UUID, visited: set[uuid.UUID], path: list[uuid.UUID]) → list[uuid.UUID] | None, call:select(ConfigProfileInclude) .where(ConfigProfileInclude.profile_id == current_id) .order_by, call:session.execute, call:include_result.scalars().all, call:_check_from, func:apply_resolved_profile(instance_dir: str, resolved: ResolvedProfile, home_dir) → tuple[dict[str, str], dict[str, str], list[dict], dict[str, Any]], call:Path, call:dict, call:files.items, call:full_path.resolve().relative_to, call:instance_path.resolve, call:logger.warning, call:full_path.parent.mkdir, call:full_path.write_text, call:resolved.mounts.values, call:os.path.normpath, call:expand_container_path, call:expanded_target.lstrip("/").replace, call:mount_dir.mkdir, call:mount.files.items, call:mount_dir.resolve, call:volume_mounts.append, call:str, func:expand_container_path(path: str, home_dir: str) → str, call:path.startswith, call:os.path.join, func:resolved_profile_to_dict(resolved: ResolvedProfile) → dict[str, Any], call:str, call:resolved.mounts.values | dep: logging, os, uuid, dataclasses, typing, sqlalchemy, sqlalchemy.ext.asyncio, src.models, pathlib
|
||||||
- crud_service.py | Provides CRUD operations for configuration profiles including validation, access control, size limits, and include cycle detection. | exp: func:calculate_profile_size(data: dict) → int, call:data.get("env_vars", {}).items, call:len, call:key.encode, call:str(value).encode, call:data.get("runtime_hints", {}).items, call:str(mount.get("target", "")).encode, call:str(mount.get("mode", "")).encode, call:mount.get("files", {}).items, call:path.encode, call:content.encode, call:data.get("files", {}).items, func:get_profile_with_includes(session: AsyncSession, profile_id: uuid.UUID) → ConfigProfile | None, call:session.execute, call:select(ConfigProfile) .where(ConfigProfile.id == profile_id) .options, call:selectinload, call:result.scalar_one_or_none, func:check_access(session: AsyncSession, user_id: uuid.UUID, project_id, tool_type_id) → None, call:session.get, raise:HTTPException, func:validate_git_mounts(session: AsyncSession, user_id: uuid.UUID, git_mounts: list[Any], project_id) → None, call:mount.get, call:remote_url.startswith, raise:HTTPException, func:profile_to_response(profile: ConfigProfile, includes) → dict, call:str, call:profile.created_at.isoformat, call:profile.updated_at.isoformat, func:get_or_create_user_config(session: AsyncSession, user_id: uuid.UUID) → UserConfig, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:UserConfig, call:session.add, func:validate_default_profiles(session: AsyncSession, user_id: uuid.UUID, default_profiles: dict[str, str]) → None, call:default_profiles.items, call:uuid.UUID, call:session.get, raise:HTTPException, func:create_profile(session: AsyncSession, user_id: uuid.UUID, data: Any) → ConfigProfile, call:session.execute, call:select(ConfigProfile) .where( ConfigProfile.user_id == user_id, ConfigProfile.name == data.name, ) .options, call:selectinload, call:existing.scalar_one_or_none, call:uuid.UUID, call:check_access, call:m.model_dump, call:hasattr, call:validate_git_mounts, call:calculate_profile_size, call:data.model_dump, call:ConfigProfile, call:session.add, call:session.commit, call:select(ConfigProfile) .where(ConfigProfile.id == profile.id) .options, call:result.scalar_one, raise:HTTPException, func:update_profile(session: AsyncSession, profile: ConfigProfile, data: Any) → ConfigProfile, call:data.model_dump, call:session.execute, call:select(ConfigProfile).where, call:existing.scalar_one_or_none, call:uuid.UUID, call:check_access, call:m.model_dump, call:hasattr, call:validate_git_mounts, call:profile_to_response, call:calculate_profile_size, call:update_data.items, call:isinstance, call:setattr, call:session.commit, call:select(ConfigProfile) .where(ConfigProfile.id == profile.id) .options, call:selectinload, call:result.scalar_one, raise:HTTPException, func:update_includes(session: AsyncSession, profile: ConfigProfile, included_ids: list[uuid.UUID], user_id: uuid.UUID) → ConfigProfile, call:session.get, call:check_include_cycle, call:" -> ".join, call:str, call:session.execute, call:select(ConfigProfileInclude).where, call:result.scalars().all, call:session.delete, call:session.flush, call:enumerate, call:ConfigProfileInclude, call:session.add, call:session.commit, call:select(ConfigProfile).where, call:result.scalar_one, raise:HTTPException | dep: uuid, typing, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.models, src.models.project, src.services.config.config_profile_resolver
|
- crud_service.py | Provides CRUD operations and validation logic for configuration profiles, including size limits, access control, and include cycle detection. | exp: func:calculate_profile_size(data: dict) → int, call:data.get("env_vars", {}).items, call:len, call:key.encode, call:str(value).encode, call:data.get("runtime_hints", {}).items, call:str(mount.get("target", "")).encode, call:str(mount.get("mode", "")).encode, call:mount.get("files", {}).items, call:path.encode, call:content.encode, call:data.get("files", {}).items, func:get_profile_with_includes(session: AsyncSession, profile_id: uuid.UUID) → ConfigProfile | None, call:session.execute, call:select(ConfigProfile) .where(ConfigProfile.id == profile_id) .options, call:selectinload, call:result.scalar_one_or_none, func:check_access(session: AsyncSession, user_id: uuid.UUID, project_id, tool_type_id) → None, call:session.get, raise:HTTPException, func:validate_git_mounts(session: AsyncSession, user_id: uuid.UUID, git_mounts: list[Any], project_id) → None, call:mount.get, call:remote_url.startswith, raise:HTTPException, func:profile_to_response(profile: ConfigProfile, includes) → dict, call:str, call:profile.created_at.isoformat, call:profile.updated_at.isoformat, func:get_or_create_user_config(session: AsyncSession, user_id: uuid.UUID) → UserConfig, call:session.execute, call:select(UserConfig).where, call:result.scalar_one_or_none, call:UserConfig, call:session.add, func:validate_default_profiles(session: AsyncSession, user_id: uuid.UUID, default_profiles: dict[str, str]) → None, call:default_profiles.items, call:uuid.UUID, call:session.get, raise:HTTPException, func:create_profile(session: AsyncSession, user_id: uuid.UUID, data: Any) → ConfigProfile, call:session.execute, call:select(ConfigProfile) .where( ConfigProfile.user_id == user_id, ConfigProfile.name == data.name, ) .options, call:selectinload, call:existing.scalar_one_or_none, call:uuid.UUID, call:check_access, call:m.model_dump, call:hasattr, call:validate_git_mounts, call:calculate_profile_size, call:data.model_dump, call:ConfigProfile, call:session.add, call:session.commit, call:select(ConfigProfile) .where(ConfigProfile.id == profile.id) .options, call:result.scalar_one, raise:HTTPException, func:update_profile(session: AsyncSession, profile: ConfigProfile, data: Any) → ConfigProfile, call:data.model_dump, call:session.execute, call:select(ConfigProfile).where, call:existing.scalar_one_or_none, call:uuid.UUID, call:check_access, call:m.model_dump, call:hasattr, call:validate_git_mounts, call:profile_to_response, call:calculate_profile_size, call:update_data.items, call:isinstance, call:setattr, call:session.commit, call:select(ConfigProfile) .where(ConfigProfile.id == profile.id) .options, call:selectinload, call:result.scalar_one, raise:HTTPException, func:update_includes(session: AsyncSession, profile: ConfigProfile, included_ids: list[uuid.UUID], user_id: uuid.UUID) → ConfigProfile, call:session.get, call:check_include_cycle, call:" -> ".join, call:str, call:session.execute, call:select(ConfigProfileInclude).where, call:result.scalars().all, call:session.delete, call:session.flush, call:enumerate, call:ConfigProfileInclude, call:session.add, call:session.commit, call:select(ConfigProfile).where, call:result.scalar_one, raise:HTTPException | dep: uuid, typing, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, sqlalchemy.orm, src.models, src.models.project, src.services.config.config_profile_resolver
|
||||||
- resolver_service.py | Resolves default configuration profiles for users/projects/tools and validates Git URLs with SSH key support. | exp: func:resolve_default_profile(session: AsyncSession, user_id: uuid.UUID, project_id: uuid.UUID, tool_type_id: uuid.UUID) → dict, call:select(ConfigProfile) .where(ConfigProfile.user_id == user_id) .where( (ConfigProfile.project_id.is_(None) & ConfigProfile.tool_type_id.is_(None)) | (ConfigProfile.project_id == project_id) | (ConfigProfile.tool_type_id == tool_type_id) | ( (ConfigProfile.project_id == project_id) & (ConfigProfile.tool_type_id == tool_type_id) ) ) .order_by, call:ConfigProfile.project_id.is_, call:ConfigProfile.tool_type_id.is_, call:session.execute, call:result.scalars().all, call:str, func:validate_git_url(session: AsyncSession, current_user_id: uuid.UUID, url: str, ssh_key_id: str | None) → ValidateGitUrlResponse, call:parse_git_url, call:url.strip, call:parse_result.get, call:ValidateGitUrlResponse, call:uuid.UUID, call:session.get, call:_get_fernet, call:fernet.decrypt(ssh_key.private_key_encrypted.encode()).decode, call:ssh_key.private_key_encrypted.encode, call:tempfile.mkstemp, call:os.write, call:private_key.encode, call:os.close, call:os.chmod, call:subprocess.run, call:os.path.exists, call:os.unlink, call:result.stderr.strip, call:stderr.lower, call:result.stdout.strip().split, call:line.strip, call:line.split, call:len, call:ref.startswith, call:branches.append | dep: logging, os, subprocess, uuid, typing, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.models, src.services.shared.ssh_keys, src.utils.git_url_parser, src.schemas.config, tempfile
|
- resolver_service.py | Resolves default configuration profiles for users/projects/tools and validates Git URLs by checking remote repository accessibility and listing branches, optionally using SSH key authentication. | exp: func:resolve_default_profile(session: AsyncSession, user_id: uuid.UUID, project_id: uuid.UUID, tool_type_id: uuid.UUID) → dict, call:select(ConfigProfile) .where(ConfigProfile.user_id == user_id) .where( (ConfigProfile.project_id.is_(None) & ConfigProfile.tool_type_id.is_(None)) | (ConfigProfile.project_id == project_id) | (ConfigProfile.tool_type_id == tool_type_id) | ( (ConfigProfile.project_id == project_id) & (ConfigProfile.tool_type_id == tool_type_id) ) ) .order_by, call:ConfigProfile.project_id.is_, call:ConfigProfile.tool_type_id.is_, call:session.execute, call:result.scalars().all, call:str, func:validate_git_url(session: AsyncSession, current_user_id: uuid.UUID, url: str, ssh_key_id: str | None) → ValidateGitUrlResponse, call:parse_git_url, call:url.strip, call:parse_result.get, call:ValidateGitUrlResponse, call:uuid.UUID, call:session.get, call:_get_fernet, call:fernet.decrypt(ssh_key.private_key_encrypted.encode()).decode, call:ssh_key.private_key_encrypted.encode, call:tempfile.mkstemp, call:os.write, call:private_key.encode, call:os.close, call:os.chmod, call:subprocess.run, call:os.path.exists, call:os.unlink, call:result.stderr.strip, call:stderr.lower, call:result.stdout.strip().split, call:line.strip, call:line.split, call:len, call:ref.startswith, call:branches.append | dep: logging, os, subprocess, uuid, typing, fastapi, sqlalchemy, sqlalchemy.ext.asyncio, src.models, src.services.shared.ssh_keys, src.utils.git_url_parser, src.schemas.config, tempfile
|
||||||
## arch
|
## arch
|
||||||
Layered service architecture with separation between resolution logic (recursive merge with cycle detection), CRUD operations (validation, access control, size limits), and default resolution (Git/SSH integration), exposed through a unified facade pattern via __init__.py.
|
Service-layer pattern with separation between resolution logic (recursive merge with cycle detection), CRUD operations (validation, access control, size limits), and external integration (Git URL validation with SSH support), exposed through a unified module facade.
|
||||||
## tags
|
## tags
|
||||||
profile, call:, call:select, merge, git, call:str, call:session.execute, cycle
|
profile, call:, call:select, merge, git, call:str, call:session.execute, cycle
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -172,6 +172,47 @@ def _merge_mounts(
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _find_mount_conflicts(
|
||||||
|
profile: ConfigProfile,
|
||||||
|
resolved: ResolvedProfile,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""Find mounts on the profile that override mounts from included profiles.
|
||||||
|
|
||||||
|
Returns a list of conflict descriptors with the target path, the included
|
||||||
|
profile that originally provided the mount, and the current profile name.
|
||||||
|
"""
|
||||||
|
conflicts = []
|
||||||
|
own_targets = {m["target"] for m in (profile.mounts or [])}
|
||||||
|
own_files = {f for m in (profile.mounts or []) for f in m.get("files", {}).keys()}
|
||||||
|
|
||||||
|
for mount in resolved.mounts.values():
|
||||||
|
if mount.target in own_targets:
|
||||||
|
# The profile itself has a mount at the same target as an included one.
|
||||||
|
conflicts.append(
|
||||||
|
{
|
||||||
|
"type": "mount_target",
|
||||||
|
"target": mount.target,
|
||||||
|
"overridden_by": profile.name,
|
||||||
|
"source": resolved.profile_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
for rel_path in mount.files:
|
||||||
|
if rel_path in own_files:
|
||||||
|
conflicts.append(
|
||||||
|
{
|
||||||
|
"type": "mount_file",
|
||||||
|
"target": mount.target,
|
||||||
|
"file": rel_path,
|
||||||
|
"overridden_by": profile.name,
|
||||||
|
"source": resolved.profile_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return conflicts
|
||||||
|
|
||||||
|
|
||||||
def _merge_git_mounts(
|
def _merge_git_mounts(
|
||||||
base: list[dict[str, Any]],
|
base: list[dict[str, Any]],
|
||||||
overlay: list[dict[str, Any]],
|
overlay: list[dict[str, Any]],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/services/docker
|
dir: apps/api/src/services/docker
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Docker infrastructure services for container lifecycle management, compose orchestration, configuration deployment, and secure tunneling to expose internal services.
|
Provides Docker infrastructure automation for container lifecycle management, service composition, configuration deployment, and secure public tunneling.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/services/.pi-map.index.md
|
index: apps/api/src/services/.pi-map.index.md
|
||||||
map: apps/api/src/services/.pi-map.md
|
map: apps/api/src/services/.pi-map.md
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ dir: apps/api/src/services/docker
|
|||||||
index: apps/api/src/services/docker/.pi-map.index.md
|
index: apps/api/src/services/docker/.pi-map.index.md
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Provides Docker infrastructure services for container lifecycle management, compose orchestration, configuration deployment, and secure tunneling to expose internal services.
|
Provides Docker infrastructure automation for container lifecycle management, service composition, configuration deployment, and secure public tunneling.
|
||||||
## files
|
## files
|
||||||
- __init__.py | Package initialization file that exposes Docker-related service functions for container operations, compose management, configuration staging, and tunnel management. | dep: src.services.docker.compose, src.services.docker.config_staging, src.services.docker.container, src.services.docker.tunnel
|
- __init__.py | Exports Docker service functions for container, compose, config staging, and tunnel operations as a unified package interface. | dep: src.services.docker.compose, src.services.docker.config_staging, src.services.docker.container, src.services.docker.tunnel
|
||||||
- compose.py | Generates, renders, and executes Docker Compose commands for container orchestration with volume sorting and template substitution. | exp: func:sort_volumes_by_specificity(volumes: list[str]) → list[str], call:vol.split, call:len, call:parts[1].rstrip, call:target.count, call:targets.append, call:Counter(targets).items, call:logger.warning, call:sorted, func:_target_depth(vol: str) → int, call:vol.split, call:len, call:parts[1].rstrip, call:target.count, func:render_compose_template(template: str, variables: dict[str, Any]) → str, call:variables.items, call:result.replace, call:str, func:write_compose_file(instance_dir: str, content: str) → str, call:Path, call:compose_path.write_text, call:str, func:execute_compose_command(compose_path: str, action: str, timeout, env_file) → tuple[int, str, str], call:Path, call:cmd.extend, call:cmd.append, call:subprocess.run, call:str, raise:ValueError | dep: logging, subprocess, collections, pathlib, typing, collections.Counter, pathlib.Path, typing.Any
|
- compose.py | Generates, renders, and executes Docker Compose files with volume sorting and template variable substitution. | exp: func:sort_volumes_by_specificity(volumes: list[str]) → list[str], call:vol.split, call:len, call:parts[1].rstrip, call:target.count, call:targets.append, call:Counter(targets).items, call:logger.warning, call:sorted, func:_target_depth(vol: str) → int, call:vol.split, call:len, call:parts[1].rstrip, call:target.count, func:render_compose_template(template: str, variables: dict[str, Any]) → str, call:variables.items, call:result.replace, call:str, call:aliases.items, call:variables.get, func:write_compose_file(instance_dir: str, content: str) → str, call:Path, call:compose_path.write_text, call:str, func:execute_compose_command(compose_path: str, action: str, timeout, env_file) → tuple[int, str, str], call:Path, call:cmd.extend, call:cmd.append, call:subprocess.run, call:str, raise:ValueError | dep: logging, subprocess, collections, pathlib, typing, collections.Counter, pathlib.Path, typing.Any
|
||||||
- config_staging.py | Stages configuration files into instance directories with security checks for path traversal. | exp: func:ensure_instance_directory(instance_id: str, base_path) → str, call:Settings, call:Path, call:instance_dir.mkdir, call:str, call:instance_dir.absolute, func:write_env_file(instance_dir: str, env_vars: dict[str, str]) → str, call:Path, call:env_vars.items, call:env_path.write_text, call:"\n".join, call:str, func:write_config_files(instance_dir: str, files: dict[str, str]) → None, call:Path, call:files.items, call:full_path.resolve().relative_to, call:instance_path.resolve, call:full_path.parent.mkdir, call:full_path.write_text, raise:ValueError | dep: logging, pathlib, src.config, src.config.Settings
|
- config_staging.py | Stages configuration files into instance directories with path security validation and environment file generation. | exp: func:ensure_instance_directory(instance_id: str, base_path) → str, call:Settings, call:Path, call:instance_dir.mkdir, call:str, call:instance_dir.absolute, func:write_env_file(instance_dir: str, env_vars: dict[str, str]) → str, call:Path, call:env_vars.items, call:env_path.write_text, call:"\n".join, call:str, func:write_config_files(instance_dir: str, files: dict[str, str]) → None, call:Path, call:files.items, call:full_path.resolve().relative_to, call:instance_path.resolve, call:full_path.parent.mkdir, call:full_path.write_text, raise:ValueError | dep: logging, pathlib, src.config, src.config.Settings
|
||||||
- container.py | Provides Docker container runtime queries and network management utilities via subprocess calls to the Docker CLI. | exp: func:get_container_id(instance_name: str) → str | None, call:instance_name.lower, call:subprocess.run, call:result.stdout.strip, call:ps_result.stdout.strip().splitlines, call:line.split, call:len, call:name.lower, func:get_container_name(instance_name: str) → str | None, call:subprocess.run, call:instance_name.lower, call:result.stdout.strip().lstrip, func:get_backend_network_name() → str, call:subprocess.run, call:result.stdout.strip().split, call:net.lower, func:connect_container_to_network(container_name: str, network_name) → bool, call:get_backend_network_name, call:subprocess.run, func:get_container_ip_on_network(container_id: str, network_name) → str | None, call:get_backend_network_name, call:subprocess.run, call:result.stdout.strip, func:is_container_on_network(container_id: str, network_name) → bool, call:get_backend_network_name, call:subprocess.run, func:get_container_status(container_id: str) → dict[str, Any], call:subprocess.run, call:result.stdout.strip().split, call:int, call:len, call:parts[1].isdigit, func:wait_for_container_running(container_id: str, timeout, interval) → dict[str, Any], call:time.time, call:get_container_status, call:time.sleep, func:get_container_logs(container_id: str, tail) → str, call:subprocess.run, call:str, func:find_free_port(start, end) → int, call:range, call:socket.socket, call:s.connect_ex, raise:RuntimeError | dep: logging, subprocess, time, typing, socket
|
- container.py | Provides utility functions for querying Docker container runtime state, managing network connections, and finding free ports via subprocess calls to the Docker CLI. | exp: func:get_container_id(instance_name: str) → str | None, call:instance_name.lower, call:subprocess.run, call:result.stdout.strip, call:ps_result.stdout.strip().splitlines, call:line.split, call:len, call:name.lower, func:get_container_name(instance_name: str) → str | None, call:subprocess.run, call:instance_name.lower, call:result.stdout.strip().lstrip, func:get_backend_network_name() → str, call:subprocess.run, call:result.stdout.strip().split, call:net.lower, func:connect_container_to_network(container_name: str, network_name) → bool, call:get_backend_network_name, call:subprocess.run, func:get_container_ip_on_network(container_id: str, network_name) → str | None, call:get_backend_network_name, call:subprocess.run, call:result.stdout.strip, func:is_container_on_network(container_id: str, network_name) → bool, call:get_backend_network_name, call:subprocess.run, func:get_container_status(container_id: str) → dict[str, Any], call:subprocess.run, call:result.stdout.strip().split, call:int, call:len, call:parts[1].isdigit, func:wait_for_container_running(container_id: str, timeout, interval) → dict[str, Any], call:time.time, call:get_container_status, call:time.sleep, func:get_container_logs(container_id: str, tail) → str, call:subprocess.run, call:str, func:find_free_port(start, end) → int, call:range, call:socket.socket, call:s.connect_ex, raise:RuntimeError | dep: logging, subprocess, time, typing, socket
|
||||||
- tunnel.py | Manages Cloudflare tunnels by orchestrating cloudflared Docker containers to expose internal services via temporary public URLs. | exp: func:_tunnel_container_name(instance_name: str) → str, call:instance_name.lower, func:_ensure_image() → None, call:subprocess.run, call:result.stdout.strip, call:logger.info, call:logger.warning, func:_cleanup_stale_tunnel(tunnel_name: str) → None, call:subprocess.run, func:_get_tunnel_logs(tunnel_name: str) → tuple[str, str], call:subprocess.run, func:_get_tunnel_exit_code(tunnel_name: str) → int | None, call:subprocess.run, call:int, call:result.stdout.strip, func:start_tunnel(instance_name: str, container_port: int, timeout, target_url) → dict[str, str], call:_ensure_image, call:_tunnel_container_name, call:_cleanup_stale_tunnel, call:instance_name.lower, call:get_backend_network_name, call:logger.debug, call:" ".join, call:subprocess.run, call:proc.stdout.strip, call:re.compile, call:__import__("time").time, call:_get_tunnel_logs, call:url_pattern.search, call:match.group, call:_get_tunnel_exit_code, call:__import__("time").sleep, call:logger.info, raise:RuntimeError, func:stop_tunnel(instance_name: str) → None, call:_tunnel_container_name, call:_cleanup_stale_tunnel, call:logger.debug, func:recreate_tunnel(instance_name: str, container_port: int, target_url) → dict[str, str], call:stop_tunnel, call:start_tunnel, func:check_tunnel_health(url: str, timeout) → dict[str, Any], call:subprocess.run, call:int, call:result.stdout.strip, call:str(exc).lower, call:any | dep: logging, re, subprocess, typing, src.services.docker.container
|
- tunnel.py | Manages Cloudflare tunnels by orchestrating cloudflared Docker containers to expose internal services via temporary public URLs. | exp: func:_tunnel_container_name(instance_name: str) → str, call:instance_name.lower, func:_ensure_image() → None, call:subprocess.run, call:result.stdout.strip, call:logger.info, call:logger.warning, func:_cleanup_stale_tunnel(tunnel_name: str) → None, call:subprocess.run, func:_get_tunnel_logs(tunnel_name: str) → tuple[str, str], call:subprocess.run, func:_get_tunnel_exit_code(tunnel_name: str) → int | None, call:subprocess.run, call:int, call:result.stdout.strip, func:start_tunnel(instance_name: str, container_port: int, timeout, target_url) → dict[str, str], call:_ensure_image, call:_tunnel_container_name, call:_cleanup_stale_tunnel, call:instance_name.lower, call:get_backend_network_name, call:logger.debug, call:" ".join, call:subprocess.run, call:proc.stdout.strip, call:re.compile, call:__import__("time").time, call:_get_tunnel_logs, call:url_pattern.search, call:match.group, call:_get_tunnel_exit_code, call:__import__("time").sleep, call:logger.info, raise:RuntimeError, func:stop_tunnel(instance_name: str) → None, call:_tunnel_container_name, call:_cleanup_stale_tunnel, call:logger.debug, func:recreate_tunnel(instance_name: str, container_port: int, target_url) → dict[str, str], call:stop_tunnel, call:start_tunnel, func:check_tunnel_health(url: str, timeout) → dict[str, Any], call:subprocess.run, call:int, call:result.stdout.strip, call:str(exc).lower, call:any | dep: logging, re, subprocess, typing, src.services.docker.container, time
|
||||||
## arch
|
## arch
|
||||||
Subprocess-based CLI wrapper architecture around Docker/cloudflared tools with template rendering, path-traversal-safe file staging, and functional decomposition into single-responsibility modules.
|
Modular service-oriented architecture with CLI-wrapper pattern for Docker operations, template-based file generation, and subprocess-based external tool orchestration.
|
||||||
## tags
|
## tags
|
||||||
tunnel, container, call:subprocess.run, get, name, call:, network, call:result.stdout.strip
|
tunnel, container, call:subprocess.run, get, name, call:, network, call:result.stdout.strip
|
||||||
## symbols
|
## symbols
|
||||||
|
|||||||
@@ -61,6 +61,19 @@ def render_compose_template(template: str, variables: dict[str, Any]) -> str:
|
|||||||
for key, value in variables.items():
|
for key, value in variables.items():
|
||||||
placeholder = f"{{{{{key}}}}}"
|
placeholder = f"{{{{{key}}}}}"
|
||||||
result = result.replace(placeholder, str(value))
|
result = result.replace(placeholder, str(value))
|
||||||
|
|
||||||
|
# Convenience aliases so legacy and migrated templates can use lowercase
|
||||||
|
# placeholders without changing every stored template.
|
||||||
|
aliases = {
|
||||||
|
"{{workspace_name}}": "WORKSPACE_NAME",
|
||||||
|
"{{home_directory}}": "HOME_DIRECTORY",
|
||||||
|
}
|
||||||
|
for alias_placeholder, key in aliases.items():
|
||||||
|
if alias_placeholder in result:
|
||||||
|
result = result.replace(
|
||||||
|
alias_placeholder, str(variables.get(key, "workspace"))
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ def get_container_logs(container_id: str, tail: int = 100) -> str:
|
|||||||
tail: Number of lines to return
|
tail: Number of lines to return
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Container logs
|
Container logs (stdout + stderr)
|
||||||
"""
|
"""
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["docker", "logs", "--tail", str(tail), container_id],
|
["docker", "logs", "--tail", str(tail), container_id],
|
||||||
@@ -291,9 +291,15 @@ def get_container_logs(container_id: str, tail: int = 100) -> str:
|
|||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.returncode == 0:
|
if result.returncode != 0:
|
||||||
return result.stdout
|
return f"Failed to get logs: {result.stderr}"
|
||||||
return f"Failed to get logs: {result.stderr}"
|
|
||||||
|
logs = result.stdout
|
||||||
|
if result.stderr:
|
||||||
|
if logs:
|
||||||
|
logs += "\n"
|
||||||
|
logs += f"STDERR:\n{result.stderr}"
|
||||||
|
return logs
|
||||||
|
|
||||||
|
|
||||||
def find_free_port(start: int = 10000, end: int = 20000) -> int:
|
def find_free_port(start: int = 10000, end: int = 20000) -> int:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
dir: apps/api/src/services/git
|
dir: apps/api/src/services/git
|
||||||
|
|
||||||
## role
|
## role
|
||||||
Encapsulates all Git version control operations for workspace management, providing both synchronous and asynchronous interfaces for repository cloning, commit history, branch management, and remote operations with SSH authentication support.
|
Provides Git repository operations for the API, including cloning, fetching, pulling, and branch management with SSH authentication support for workspace management.
|
||||||
## parent
|
## parent
|
||||||
index: apps/api/src/services/.pi-map.index.md
|
index: apps/api/src/services/.pi-map.index.md
|
||||||
map: apps/api/src/services/.pi-map.md
|
map: apps/api/src/services/.pi-map.md
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user