Create a new vault intent. Allocates a JIRA-style ID (e.g., "PIMO-1") and creates an intent directory with an `intent.md` scaffold. The prefix is derived from the project directory name on first use (first 4 alphanumeric chars, uppercased). Intent paths are view-scoped and session-scoped: `intents/ / / /intent.md`
(
&self,
options: IntentCreateOptions,
)
| 103 | /// Intent paths are view-scoped and session-scoped: |
| 104 | /// `intents/<view>/<session>/<turn>/intent.md` |
| 105 | pub fn vault_intent_create( |
| 106 | &self, |
| 107 | options: IntentCreateOptions, |
| 108 | ) -> Result<IntentCreateResult, RepositoryError> { |
| 109 | if !self.has_vault()? { |
| 110 | return Err(RepositoryError::InvalidOperation { |
| 111 | message: "Vault not initialized. Run `atomic vault init` first.".to_string(), |
| 112 | }); |
| 113 | } |
| 114 | |
| 115 | let priority = options.priority.unwrap_or_else(|| "medium".to_string()); |
| 116 | let view_name = self.current_view().to_string(); |
| 117 | |
| 118 | // Compute the session-scoped directory and file paths |
| 119 | let intent_dir = self.intent_dir_for(options.session_id.as_deref(), options.turn_id); |
| 120 | let intent_file = self.intent_file_for(options.session_id.as_deref(), options.turn_id); |
| 121 | |
| 122 | // Allocate ID inside a write transaction |
| 123 | let intent_id; |
| 124 | { |
| 125 | let mut txn = self |
| 126 | .pristine |
| 127 | .write_txn() |
| 128 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 129 | let mut manifest = txn |
| 130 | .get_vault_manifest() |
| 131 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 132 | |
| 133 | // Set prefix on first use, derived from project directory name |
| 134 | if manifest.intent_prefix.is_empty() { |
| 135 | let project_name = self |
| 136 | .root |
| 137 | .file_name() |
| 138 | .and_then(|n| n.to_str()) |
| 139 | .unwrap_or("vault"); |
| 140 | manifest.intent_prefix = VaultManifest::derive_intent_prefix(project_name); |
| 141 | // Fallback if project name yields empty prefix |
| 142 | if manifest.intent_prefix.is_empty() { |
| 143 | manifest.intent_prefix = "VAULT".to_string(); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | intent_id = manifest.allocate_intent_id(); |
| 148 | |
| 149 | // Add to manifest intents index |
| 150 | manifest.intents.insert( |
| 151 | intent_id.clone(), |
| 152 | IntentSummary { |
| 153 | status: "backlog".to_string(), |
| 154 | priority: priority.clone(), |
| 155 | assignee: options.assignee.clone(), |
| 156 | goals: 0, |
| 157 | blocked_by: Vec::new(), |
| 158 | title: options.title.clone(), |
| 159 | vault_path: intent_file.clone(), |
| 160 | }, |
| 161 | ); |
| 162 |