delimit-cli 3.13.2 → 3.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -147,8 +147,17 @@ def add_item(
147
147
  source: str = "session",
148
148
  project_path: str = ".",
149
149
  tags: Optional[List[str]] = None,
150
+ acceptance_criteria: Optional[List[str]] = None,
151
+ context: str = "",
152
+ tools_needed: Optional[List[str]] = None,
153
+ estimated_complexity: str = "",
150
154
  ) -> Dict[str, Any]:
151
- """Add a new item to the project's strategy or operational ledger."""
155
+ """Add a new item to the project's strategy or operational ledger.
156
+
157
+ LED-189: Items can have acceptance_criteria (testable "done when" conditions).
158
+ LED-190: Items can have context, tools_needed, and estimated_complexity
159
+ for agent-executable task format.
160
+ """
152
161
  _ensure(project_path)
153
162
  venture = _detect_venture(project_path)
154
163
  ledger_dir = _project_ledger_dir(project_path)
@@ -173,8 +182,26 @@ def add_item(
173
182
  "status": "open",
174
183
  "tags": tags or [],
175
184
  }
185
+ # LED-189: Optional acceptance criteria
186
+ if acceptance_criteria:
187
+ entry["acceptance_criteria"] = acceptance_criteria
188
+ # LED-190: Optional agent-executable fields
189
+ if context:
190
+ entry["context"] = context
191
+ if tools_needed:
192
+ entry["tools_needed"] = tools_needed
193
+ if estimated_complexity:
194
+ entry["estimated_complexity"] = estimated_complexity
176
195
 
177
196
  result = _append(path, entry)
197
+
198
+ # Sync to Supabase for dashboard visibility
199
+ try:
200
+ from ai.supabase_sync import sync_ledger_item
201
+ sync_ledger_item(result)
202
+ except Exception:
203
+ pass # Never let cloud sync break ledger operations
204
+
178
205
  return {
179
206
  "added": result,
180
207
  "ledger": ledger,
@@ -183,6 +210,17 @@ def add_item(
183
210
  }
184
211
 
185
212
 
213
+ def _find_item_in_ledger_dir(item_id: str, ledger_dir: Path) -> Optional[Dict[str, Any]]:
214
+ """Search a ledger directory for an item by ID. Returns (ledger_name, path) or None."""
215
+ for ledger_name, filename in [("ops", "operations.jsonl"), ("strategy", "strategy.jsonl")]:
216
+ path = ledger_dir / filename
217
+ items = _read_ledger(path)
218
+ for item in items:
219
+ if item.get("id") == item_id and item.get("type") != "update":
220
+ return {"ledger_name": ledger_name, "path": path}
221
+ return None
222
+
223
+
186
224
  def update_item(
187
225
  item_id: str,
188
226
  status: Optional[str] = None,
@@ -194,24 +232,55 @@ def update_item(
194
232
  _ensure(project_path)
195
233
  ledger_dir = _project_ledger_dir(project_path)
196
234
 
197
- for ledger_name, filename in [("ops", "operations.jsonl"), ("strategy", "strategy.jsonl")]:
198
- path = ledger_dir / filename
199
- items = _read_ledger(path)
200
- for item in items:
201
- if item.get("id") == item_id and item.get("type") != "update":
202
- update = {
203
- "id": item_id,
204
- "type": "update",
205
- "updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
206
- }
207
- if status:
208
- update["status"] = status
209
- if note:
210
- update["note"] = note
211
- if priority:
212
- update["priority"] = priority
213
- _append(path, update)
214
- return {"updated": item_id, "changes": update, "ledger": ledger_name}
235
+ # First, search the specified project's ledger
236
+ found = _find_item_in_ledger_dir(item_id, ledger_dir)
237
+
238
+ # If not found, search all registered ventures as a fallback
239
+ if not found:
240
+ try:
241
+ ventures = {}
242
+ if VENTURES_FILE.exists():
243
+ ventures = json.loads(VENTURES_FILE.read_text())
244
+ except Exception:
245
+ ventures = {}
246
+
247
+ searched = {str(ledger_dir)}
248
+ for _name, info in ventures.items():
249
+ vpath = info.get("path", "")
250
+ if not vpath:
251
+ continue
252
+ candidate_dir = Path(vpath) / ".delimit" / "ledger"
253
+ if str(candidate_dir) in searched:
254
+ continue
255
+ searched.add(str(candidate_dir))
256
+ found = _find_item_in_ledger_dir(item_id, candidate_dir)
257
+ if found:
258
+ break
259
+
260
+ if found:
261
+ ledger_name = found["ledger_name"]
262
+ path = found["path"]
263
+ update = {
264
+ "id": item_id,
265
+ "type": "update",
266
+ "updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
267
+ }
268
+ if status:
269
+ update["status"] = status
270
+ if note:
271
+ update["note"] = note
272
+ if priority:
273
+ update["priority"] = priority
274
+ _append(path, update)
275
+
276
+ # Sync to Supabase for dashboard visibility
277
+ try:
278
+ from ai.supabase_sync import sync_ledger_update
279
+ sync_ledger_update(item_id, status=status or "", note=note or "")
280
+ except Exception:
281
+ pass # Never let cloud sync break ledger operations
282
+
283
+ return {"updated": item_id, "changes": update, "ledger": ledger_name}
215
284
 
216
285
  return {"error": f"Item {item_id} not found in project ledger"}
217
286