open-research-protocol 0.4.24 → 0.4.25
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.
- package/CHANGELOG.md +426 -0
- package/README.md +17 -0
- package/cli/orp.py +901 -3
- package/docs/AGENT_RUNTIME_BORROWING_NOTES.md +68 -0
- package/package.json +2 -1
- package/packages/orp-workspace-launcher/src/index.js +3 -0
- package/packages/orp-workspace-launcher/src/ledger.js +192 -33
- package/packages/orp-workspace-launcher/src/orp.js +61 -1
- package/packages/orp-workspace-launcher/src/tabs.js +147 -4
- package/packages/orp-workspace-launcher/test/ledger.test.js +226 -0
- package/packages/orp-workspace-launcher/test/tabs.test.js +60 -0
- package/cli/__pycache__/orp.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-agent-pilot.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-agent-replication.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-benchmark.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-canonical-continuation.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-continuation-pilot.cpython-311.pyc +0 -0
package/cli/orp.py
CHANGED
|
@@ -134,6 +134,9 @@ DEFAULT_HOSTED_BASE_URL = "https://orp.earth"
|
|
|
134
134
|
KERNEL_SCHEMA_VERSION = "1.0.0"
|
|
135
135
|
FRONTIER_SCHEMA_VERSION = "1.0.0"
|
|
136
136
|
FRONTIER_BANDS = ("exact", "structured", "horizon")
|
|
137
|
+
FRONTIER_ACTIVE_STATUSES = {"active", "in_progress", "running"}
|
|
138
|
+
FRONTIER_PENDING_STATUSES = {"", "pending", "planned", "ready"}
|
|
139
|
+
FRONTIER_TERMINAL_STATUSES = {"complete", "completed", "done", "skipped", "terminal"}
|
|
137
140
|
YOUTUBE_SOURCE_SCHEMA_VERSION = "1.0.0"
|
|
138
141
|
EXCHANGE_REPORT_SCHEMA_VERSION = "1.0.0"
|
|
139
142
|
MAINTENANCE_STATE_SCHEMA_VERSION = "1.0.0"
|
|
@@ -5869,10 +5872,12 @@ def _frontier_paths(repo_root: Path) -> dict[str, Path]:
|
|
|
5869
5872
|
"roadmap_json": root / "roadmap.json",
|
|
5870
5873
|
"checklist_json": root / "checklist.json",
|
|
5871
5874
|
"stack_json": root / "version-stack.json",
|
|
5875
|
+
"additional_json": root / "additional-items.json",
|
|
5872
5876
|
"state_md": root / "STATE.md",
|
|
5873
5877
|
"roadmap_md": root / "ROADMAP.md",
|
|
5874
5878
|
"checklist_md": root / "CHECKLIST.md",
|
|
5875
5879
|
"stack_md": root / "VERSION_STACK.md",
|
|
5880
|
+
"additional_md": root / "ADDITIONAL_ITEMS.md",
|
|
5876
5881
|
}
|
|
5877
5882
|
|
|
5878
5883
|
|
|
@@ -5923,6 +5928,18 @@ def _default_frontier_stack_payload(program_id: str, label: str) -> dict[str, An
|
|
|
5923
5928
|
}
|
|
5924
5929
|
|
|
5925
5930
|
|
|
5931
|
+
def _default_frontier_additional_payload(program_id: str = "", label: str = "") -> dict[str, Any]:
|
|
5932
|
+
return {
|
|
5933
|
+
"schema_version": FRONTIER_SCHEMA_VERSION,
|
|
5934
|
+
"kind": "orp_frontier_additional_items",
|
|
5935
|
+
"program_id": str(program_id).strip(),
|
|
5936
|
+
"label": str(label).strip(),
|
|
5937
|
+
"active_list_id": "",
|
|
5938
|
+
"active_item_id": "",
|
|
5939
|
+
"lists": [],
|
|
5940
|
+
}
|
|
5941
|
+
|
|
5942
|
+
|
|
5926
5943
|
def _frontier_load_stack(repo_root: Path) -> dict[str, Any]:
|
|
5927
5944
|
payload = _read_json_if_exists(_frontier_paths(repo_root)["stack_json"])
|
|
5928
5945
|
if not payload:
|
|
@@ -5976,6 +5993,485 @@ def _frontier_find_phase(
|
|
|
5976
5993
|
return None
|
|
5977
5994
|
|
|
5978
5995
|
|
|
5996
|
+
def _frontier_load_additional(repo_root: Path, stack: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
5997
|
+
payload = _read_json_if_exists(_frontier_paths(repo_root)["additional_json"])
|
|
5998
|
+
if not payload:
|
|
5999
|
+
stack_payload = stack if isinstance(stack, dict) else _read_json_if_exists(_frontier_paths(repo_root)["stack_json"])
|
|
6000
|
+
return _default_frontier_additional_payload(
|
|
6001
|
+
str((stack_payload or {}).get("program_id", "")).strip(),
|
|
6002
|
+
str((stack_payload or {}).get("label", "")).strip(),
|
|
6003
|
+
)
|
|
6004
|
+
if not isinstance(payload.get("lists"), list):
|
|
6005
|
+
payload["lists"] = []
|
|
6006
|
+
payload["active_list_id"] = str(payload.get("active_list_id", "")).strip()
|
|
6007
|
+
payload["active_item_id"] = str(payload.get("active_item_id", "")).strip()
|
|
6008
|
+
return payload
|
|
6009
|
+
|
|
6010
|
+
|
|
6011
|
+
def _frontier_find_additional_list(payload: dict[str, Any], list_id: str) -> dict[str, Any] | None:
|
|
6012
|
+
lists = payload.get("lists")
|
|
6013
|
+
if not isinstance(lists, list):
|
|
6014
|
+
return None
|
|
6015
|
+
for row in lists:
|
|
6016
|
+
if isinstance(row, dict) and str(row.get("id", "")).strip() == list_id:
|
|
6017
|
+
return row
|
|
6018
|
+
return None
|
|
6019
|
+
|
|
6020
|
+
|
|
6021
|
+
def _frontier_find_additional_item(item_list: dict[str, Any], item_id: str) -> dict[str, Any] | None:
|
|
6022
|
+
items = item_list.get("items")
|
|
6023
|
+
if not isinstance(items, list):
|
|
6024
|
+
return None
|
|
6025
|
+
for item in items:
|
|
6026
|
+
if isinstance(item, dict) and str(item.get("id", "")).strip() == item_id:
|
|
6027
|
+
return item
|
|
6028
|
+
return None
|
|
6029
|
+
|
|
6030
|
+
|
|
6031
|
+
def _frontier_active_additional_item(payload: dict[str, Any]) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
|
|
6032
|
+
list_id = str(payload.get("active_list_id", "")).strip()
|
|
6033
|
+
item_id = str(payload.get("active_item_id", "")).strip()
|
|
6034
|
+
if not list_id or not item_id:
|
|
6035
|
+
return (None, None)
|
|
6036
|
+
item_list = _frontier_find_additional_list(payload, list_id)
|
|
6037
|
+
if not isinstance(item_list, dict):
|
|
6038
|
+
return (None, None)
|
|
6039
|
+
item = _frontier_find_additional_item(item_list, item_id)
|
|
6040
|
+
if not isinstance(item, dict):
|
|
6041
|
+
return (None, None)
|
|
6042
|
+
return (item_list, item)
|
|
6043
|
+
|
|
6044
|
+
|
|
6045
|
+
def _frontier_normalize_additional_statuses(payload: dict[str, Any]) -> None:
|
|
6046
|
+
lists = payload.get("lists")
|
|
6047
|
+
if not isinstance(lists, list):
|
|
6048
|
+
payload["lists"] = []
|
|
6049
|
+
return
|
|
6050
|
+
for item_list in lists:
|
|
6051
|
+
if not isinstance(item_list, dict):
|
|
6052
|
+
continue
|
|
6053
|
+
items = item_list.get("items")
|
|
6054
|
+
if not isinstance(items, list):
|
|
6055
|
+
item_list["items"] = []
|
|
6056
|
+
items = item_list["items"]
|
|
6057
|
+
for item in items:
|
|
6058
|
+
if isinstance(item, dict):
|
|
6059
|
+
item["status"] = str(item.get("status", "")).strip() or "pending"
|
|
6060
|
+
if items and all(str(item.get("status", "")).strip() in {"complete", "skipped"} for item in items if isinstance(item, dict)):
|
|
6061
|
+
item_list["status"] = "complete"
|
|
6062
|
+
else:
|
|
6063
|
+
item_list["status"] = str(item_list.get("status", "")).strip() or "pending"
|
|
6064
|
+
|
|
6065
|
+
|
|
6066
|
+
def _frontier_next_pending_additional_item(payload: dict[str, Any]) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
|
|
6067
|
+
_frontier_normalize_additional_statuses(payload)
|
|
6068
|
+
lists = payload.get("lists")
|
|
6069
|
+
if not isinstance(lists, list):
|
|
6070
|
+
return (None, None)
|
|
6071
|
+
for item_list in lists:
|
|
6072
|
+
if not isinstance(item_list, dict) or str(item_list.get("status", "")).strip() in {"complete", "skipped"}:
|
|
6073
|
+
continue
|
|
6074
|
+
items = item_list.get("items")
|
|
6075
|
+
if not isinstance(items, list):
|
|
6076
|
+
continue
|
|
6077
|
+
for item in items:
|
|
6078
|
+
if isinstance(item, dict) and str(item.get("status", "")).strip() in {"", "pending"}:
|
|
6079
|
+
return (item_list, item)
|
|
6080
|
+
return (None, None)
|
|
6081
|
+
|
|
6082
|
+
|
|
6083
|
+
def _frontier_status(raw: Any, *, default: str = "pending") -> str:
|
|
6084
|
+
text = str(raw or "").strip().lower().replace(" ", "_").replace("-", "_")
|
|
6085
|
+
return text or default
|
|
6086
|
+
|
|
6087
|
+
|
|
6088
|
+
def _frontier_status_is_active(raw: Any) -> bool:
|
|
6089
|
+
return _frontier_status(raw, default="") in FRONTIER_ACTIVE_STATUSES
|
|
6090
|
+
|
|
6091
|
+
|
|
6092
|
+
def _frontier_status_is_pending(raw: Any) -> bool:
|
|
6093
|
+
return _frontier_status(raw, default="") in FRONTIER_PENDING_STATUSES
|
|
6094
|
+
|
|
6095
|
+
|
|
6096
|
+
def _frontier_status_is_terminal(raw: Any) -> bool:
|
|
6097
|
+
return _frontier_status(raw, default="") in FRONTIER_TERMINAL_STATUSES
|
|
6098
|
+
|
|
6099
|
+
|
|
6100
|
+
def _frontier_diagnostic_ok(issues: list[dict[str, Any]], *, strict: bool = False) -> bool:
|
|
6101
|
+
if any(str(issue.get("severity", "")).strip() == "error" for issue in issues):
|
|
6102
|
+
return False
|
|
6103
|
+
if strict and any(str(issue.get("severity", "")).strip() == "warning" for issue in issues):
|
|
6104
|
+
return False
|
|
6105
|
+
return True
|
|
6106
|
+
|
|
6107
|
+
|
|
6108
|
+
def _frontier_stack_summary(stack: dict[str, Any] | None) -> dict[str, int]:
|
|
6109
|
+
summary = {
|
|
6110
|
+
"versions": 0,
|
|
6111
|
+
"milestones": 0,
|
|
6112
|
+
"phases": 0,
|
|
6113
|
+
}
|
|
6114
|
+
if not isinstance(stack, dict):
|
|
6115
|
+
return summary
|
|
6116
|
+
versions = stack.get("versions")
|
|
6117
|
+
if not isinstance(versions, list):
|
|
6118
|
+
return summary
|
|
6119
|
+
for version in versions:
|
|
6120
|
+
if not isinstance(version, dict):
|
|
6121
|
+
continue
|
|
6122
|
+
summary["versions"] += 1
|
|
6123
|
+
milestones = version.get("milestones")
|
|
6124
|
+
if not isinstance(milestones, list):
|
|
6125
|
+
continue
|
|
6126
|
+
for milestone in milestones:
|
|
6127
|
+
if not isinstance(milestone, dict):
|
|
6128
|
+
continue
|
|
6129
|
+
summary["milestones"] += 1
|
|
6130
|
+
phases = milestone.get("phases")
|
|
6131
|
+
if isinstance(phases, list):
|
|
6132
|
+
summary["phases"] += len([phase for phase in phases if isinstance(phase, dict)])
|
|
6133
|
+
return summary
|
|
6134
|
+
|
|
6135
|
+
|
|
6136
|
+
def _frontier_compact_additional_item(item_list: dict[str, Any], item: dict[str, Any]) -> dict[str, str]:
|
|
6137
|
+
return {
|
|
6138
|
+
"list_id": str(item_list.get("id", "")).strip(),
|
|
6139
|
+
"list_label": str(item_list.get("label", "")).strip(),
|
|
6140
|
+
"item_id": str(item.get("id", "")).strip(),
|
|
6141
|
+
"item_label": str(item.get("label", "")).strip(),
|
|
6142
|
+
"status": _frontier_status(item.get("status")),
|
|
6143
|
+
}
|
|
6144
|
+
|
|
6145
|
+
|
|
6146
|
+
def _frontier_additional_summary(payload: dict[str, Any]) -> dict[str, Any]:
|
|
6147
|
+
active_list_id = str(payload.get("active_list_id", "")).strip()
|
|
6148
|
+
active_item_id = str(payload.get("active_item_id", "")).strip()
|
|
6149
|
+
summary: dict[str, Any] = {
|
|
6150
|
+
"lists": 0,
|
|
6151
|
+
"items": 0,
|
|
6152
|
+
"pending_items": 0,
|
|
6153
|
+
"active_items": 0,
|
|
6154
|
+
"complete_items": 0,
|
|
6155
|
+
"skipped_items": 0,
|
|
6156
|
+
"open_items": 0,
|
|
6157
|
+
"active_list_id": active_list_id,
|
|
6158
|
+
"active_item_id": active_item_id,
|
|
6159
|
+
"active_pointer_partial": bool(active_list_id) != bool(active_item_id),
|
|
6160
|
+
"active_pointer_valid": False,
|
|
6161
|
+
"active_item_status": "",
|
|
6162
|
+
"next_pending": None,
|
|
6163
|
+
}
|
|
6164
|
+
lists = payload.get("lists")
|
|
6165
|
+
if not isinstance(lists, list):
|
|
6166
|
+
return summary
|
|
6167
|
+
summary["lists"] = len([row for row in lists if isinstance(row, dict)])
|
|
6168
|
+
for item_list in lists:
|
|
6169
|
+
if not isinstance(item_list, dict):
|
|
6170
|
+
continue
|
|
6171
|
+
items = item_list.get("items")
|
|
6172
|
+
if not isinstance(items, list):
|
|
6173
|
+
continue
|
|
6174
|
+
for item in items:
|
|
6175
|
+
if not isinstance(item, dict):
|
|
6176
|
+
continue
|
|
6177
|
+
status = _frontier_status(item.get("status"))
|
|
6178
|
+
summary["items"] += 1
|
|
6179
|
+
if _frontier_status_is_active(status):
|
|
6180
|
+
summary["active_items"] += 1
|
|
6181
|
+
summary["open_items"] += 1
|
|
6182
|
+
elif status == "skipped":
|
|
6183
|
+
summary["skipped_items"] += 1
|
|
6184
|
+
elif _frontier_status_is_terminal(status):
|
|
6185
|
+
summary["complete_items"] += 1
|
|
6186
|
+
else:
|
|
6187
|
+
summary["pending_items"] += 1
|
|
6188
|
+
summary["open_items"] += 1
|
|
6189
|
+
if summary["next_pending"] is None:
|
|
6190
|
+
summary["next_pending"] = _frontier_compact_additional_item(item_list, item)
|
|
6191
|
+
|
|
6192
|
+
if (
|
|
6193
|
+
active_list_id
|
|
6194
|
+
and active_item_id
|
|
6195
|
+
and str(item_list.get("id", "")).strip() == active_list_id
|
|
6196
|
+
and str(item.get("id", "")).strip() == active_item_id
|
|
6197
|
+
):
|
|
6198
|
+
summary["active_pointer_valid"] = True
|
|
6199
|
+
summary["active_item_status"] = status
|
|
6200
|
+
|
|
6201
|
+
return summary
|
|
6202
|
+
|
|
6203
|
+
|
|
6204
|
+
def _frontier_terminal_declared(state: dict[str, Any] | None, stack: dict[str, Any] | None) -> bool:
|
|
6205
|
+
state_obj = state if isinstance(state, dict) else {}
|
|
6206
|
+
stack_obj = stack if isinstance(stack, dict) else {}
|
|
6207
|
+
if bool(state_obj.get("terminal")) or bool(stack_obj.get("terminal")):
|
|
6208
|
+
return True
|
|
6209
|
+
completion_status = _frontier_status(
|
|
6210
|
+
state_obj.get("completion_status", state_obj.get("completionStatus", stack_obj.get("completion_status", ""))),
|
|
6211
|
+
default="",
|
|
6212
|
+
)
|
|
6213
|
+
return completion_status in {"complete", "completed", "done", "terminal"}
|
|
6214
|
+
|
|
6215
|
+
|
|
6216
|
+
def _frontier_build_continuation_payload(
|
|
6217
|
+
repo_root: Path,
|
|
6218
|
+
stack: dict[str, Any] | None,
|
|
6219
|
+
state: dict[str, Any] | None,
|
|
6220
|
+
*,
|
|
6221
|
+
include_structural_issues: bool = True,
|
|
6222
|
+
strict: bool = False,
|
|
6223
|
+
) -> dict[str, Any]:
|
|
6224
|
+
issues: list[dict[str, Any]] = []
|
|
6225
|
+
paths = _frontier_paths(repo_root)
|
|
6226
|
+
stack_obj = stack if isinstance(stack, dict) else None
|
|
6227
|
+
state_obj = state if isinstance(state, dict) else None
|
|
6228
|
+
|
|
6229
|
+
if stack_obj is None and include_structural_issues:
|
|
6230
|
+
issues.append({"severity": "error", "code": "missing_stack", "message": "frontier version stack is missing."})
|
|
6231
|
+
if state_obj is None and include_structural_issues:
|
|
6232
|
+
issues.append({"severity": "error", "code": "missing_state", "message": "frontier state is missing."})
|
|
6233
|
+
|
|
6234
|
+
additional = _frontier_load_additional(repo_root, stack_obj)
|
|
6235
|
+
additional_summary = _frontier_additional_summary(additional)
|
|
6236
|
+
stack_summary = _frontier_stack_summary(stack_obj)
|
|
6237
|
+
blockers = _coerce_string_list(state_obj.get("blocked_by") if isinstance(state_obj, dict) else [])
|
|
6238
|
+
terminal_declared = _frontier_terminal_declared(state_obj, stack_obj)
|
|
6239
|
+
active_primary = False
|
|
6240
|
+
active_primary_status = ""
|
|
6241
|
+
active_primary_kind = ""
|
|
6242
|
+
active_primary_id = ""
|
|
6243
|
+
next_action = str(state_obj.get("next_action", "")).strip() if isinstance(state_obj, dict) else ""
|
|
6244
|
+
suggested_next_command = ""
|
|
6245
|
+
|
|
6246
|
+
if stack_obj is not None and state_obj is not None:
|
|
6247
|
+
active_version = str(state_obj.get("active_version", "")).strip()
|
|
6248
|
+
active_milestone = str(state_obj.get("active_milestone", "")).strip()
|
|
6249
|
+
active_phase = str(state_obj.get("active_phase", "")).strip()
|
|
6250
|
+
version = _frontier_find_version(stack_obj, active_version) if active_version else None
|
|
6251
|
+
_, milestone = _frontier_find_milestone(stack_obj, active_milestone) if active_milestone else (None, None)
|
|
6252
|
+
phase = _frontier_find_phase(milestone, active_phase) if active_phase and isinstance(milestone, dict) else None
|
|
6253
|
+
|
|
6254
|
+
if isinstance(version, dict):
|
|
6255
|
+
version_status = _frontier_status(version.get("status", ""))
|
|
6256
|
+
if _frontier_status_is_terminal(version_status):
|
|
6257
|
+
issues.append(
|
|
6258
|
+
{
|
|
6259
|
+
"severity": "error",
|
|
6260
|
+
"code": "stale_active_version_complete",
|
|
6261
|
+
"message": f"active version `{active_version}` is marked `{version_status}`; advance the frontier or declare terminal completion.",
|
|
6262
|
+
}
|
|
6263
|
+
)
|
|
6264
|
+
elif active_version:
|
|
6265
|
+
active_primary = True
|
|
6266
|
+
active_primary_kind = "version"
|
|
6267
|
+
active_primary_id = active_version
|
|
6268
|
+
active_primary_status = version_status
|
|
6269
|
+
|
|
6270
|
+
if isinstance(milestone, dict):
|
|
6271
|
+
milestone_status = _frontier_status(milestone.get("status", ""))
|
|
6272
|
+
if _frontier_status_is_terminal(milestone_status):
|
|
6273
|
+
issues.append(
|
|
6274
|
+
{
|
|
6275
|
+
"severity": "error",
|
|
6276
|
+
"code": "stale_active_milestone_complete",
|
|
6277
|
+
"message": f"active milestone `{active_milestone}` is marked `{milestone_status}`; advance the frontier or declare terminal completion.",
|
|
6278
|
+
}
|
|
6279
|
+
)
|
|
6280
|
+
if active_primary_kind == "version":
|
|
6281
|
+
active_primary = False
|
|
6282
|
+
elif active_milestone:
|
|
6283
|
+
active_primary = True
|
|
6284
|
+
active_primary_kind = "milestone"
|
|
6285
|
+
active_primary_id = active_milestone
|
|
6286
|
+
active_primary_status = milestone_status
|
|
6287
|
+
|
|
6288
|
+
if isinstance(phase, dict):
|
|
6289
|
+
phase_status = _frontier_status(phase.get("status", ""))
|
|
6290
|
+
if _frontier_status_is_terminal(phase_status):
|
|
6291
|
+
issues.append(
|
|
6292
|
+
{
|
|
6293
|
+
"severity": "error",
|
|
6294
|
+
"code": "stale_active_phase_complete",
|
|
6295
|
+
"message": f"active phase `{active_phase}` is marked `{phase_status}`; record the handoff and move the frontier to the next phase or queue item.",
|
|
6296
|
+
}
|
|
6297
|
+
)
|
|
6298
|
+
active_primary = False
|
|
6299
|
+
elif active_phase:
|
|
6300
|
+
active_primary = True
|
|
6301
|
+
active_primary_kind = "phase"
|
|
6302
|
+
active_primary_id = active_phase
|
|
6303
|
+
active_primary_status = phase_status
|
|
6304
|
+
|
|
6305
|
+
if additional_summary["active_pointer_partial"]:
|
|
6306
|
+
issues.append(
|
|
6307
|
+
{
|
|
6308
|
+
"severity": "error",
|
|
6309
|
+
"code": "partial_active_additional_pointer",
|
|
6310
|
+
"message": "frontier additional queue has only one of active_list_id or active_item_id set.",
|
|
6311
|
+
}
|
|
6312
|
+
)
|
|
6313
|
+
|
|
6314
|
+
active_list_id = str(additional_summary["active_list_id"]).strip()
|
|
6315
|
+
active_item_id = str(additional_summary["active_item_id"]).strip()
|
|
6316
|
+
if active_list_id or active_item_id:
|
|
6317
|
+
active_list, active_item = _frontier_active_additional_item(additional)
|
|
6318
|
+
if active_list is None:
|
|
6319
|
+
issues.append(
|
|
6320
|
+
{"severity": "error", "code": "missing_active_additional_list", "message": f"active additional list `{active_list_id}` does not exist."}
|
|
6321
|
+
)
|
|
6322
|
+
elif active_item is None:
|
|
6323
|
+
issues.append(
|
|
6324
|
+
{
|
|
6325
|
+
"severity": "error",
|
|
6326
|
+
"code": "missing_active_additional_item",
|
|
6327
|
+
"message": f"active additional item `{active_item_id}` does not exist in list `{active_list_id}`.",
|
|
6328
|
+
}
|
|
6329
|
+
)
|
|
6330
|
+
else:
|
|
6331
|
+
active_status = _frontier_status(active_item.get("status", ""))
|
|
6332
|
+
if _frontier_status_is_terminal(active_status):
|
|
6333
|
+
issues.append(
|
|
6334
|
+
{
|
|
6335
|
+
"severity": "error",
|
|
6336
|
+
"code": "stale_active_additional_item",
|
|
6337
|
+
"message": f"active additional item `{active_list_id}/{active_item_id}` is marked `{active_status}`; complete the handoff and activate the next pending item.",
|
|
6338
|
+
}
|
|
6339
|
+
)
|
|
6340
|
+
elif not _frontier_status_is_active(active_status):
|
|
6341
|
+
issues.append(
|
|
6342
|
+
{
|
|
6343
|
+
"severity": "warning",
|
|
6344
|
+
"code": "active_additional_item_not_marked_active",
|
|
6345
|
+
"message": f"active additional item `{active_list_id}/{active_item_id}` is marked `{active_status}` instead of active.",
|
|
6346
|
+
}
|
|
6347
|
+
)
|
|
6348
|
+
if not next_action:
|
|
6349
|
+
next_action = _frontier_additional_item_summary(active_list, active_item)
|
|
6350
|
+
|
|
6351
|
+
if not active_item_id and int(additional_summary["pending_items"]) > 0:
|
|
6352
|
+
issues.append(
|
|
6353
|
+
{
|
|
6354
|
+
"severity": "warning",
|
|
6355
|
+
"code": "pending_additional_without_active_pointer",
|
|
6356
|
+
"message": "frontier additional queue has pending work but no active item; run `orp frontier additional activate-next` before delegating queue work.",
|
|
6357
|
+
}
|
|
6358
|
+
)
|
|
6359
|
+
suggested_next_command = "orp frontier additional activate-next --json"
|
|
6360
|
+
next_pending = additional_summary.get("next_pending")
|
|
6361
|
+
if isinstance(next_pending, dict) and not next_action:
|
|
6362
|
+
next_action = (
|
|
6363
|
+
f"Activate additional item {next_pending.get('list_id', '')}/{next_pending.get('item_id', '')}: "
|
|
6364
|
+
f"{next_pending.get('item_label', '')}"
|
|
6365
|
+
)
|
|
6366
|
+
|
|
6367
|
+
defined_work = int(stack_summary["versions"]) + int(stack_summary["milestones"]) + int(stack_summary["phases"]) + int(additional_summary["items"])
|
|
6368
|
+
if (
|
|
6369
|
+
defined_work > 0
|
|
6370
|
+
and not blockers
|
|
6371
|
+
and not terminal_declared
|
|
6372
|
+
and not active_primary
|
|
6373
|
+
and int(additional_summary["active_items"]) == 0
|
|
6374
|
+
and int(additional_summary["pending_items"]) == 0
|
|
6375
|
+
):
|
|
6376
|
+
issues.append(
|
|
6377
|
+
{
|
|
6378
|
+
"severity": "warning",
|
|
6379
|
+
"code": "no_frontier_continuation_or_terminal_declaration",
|
|
6380
|
+
"message": "frontier has defined work but no active/open continuation and no terminal completion declaration.",
|
|
6381
|
+
}
|
|
6382
|
+
)
|
|
6383
|
+
|
|
6384
|
+
summary = {
|
|
6385
|
+
"defined_work": defined_work,
|
|
6386
|
+
"blocked": bool(blockers),
|
|
6387
|
+
"terminal_declared": terminal_declared,
|
|
6388
|
+
"active_primary": active_primary,
|
|
6389
|
+
"active_primary_kind": active_primary_kind,
|
|
6390
|
+
"active_primary_id": active_primary_id,
|
|
6391
|
+
"active_primary_status": active_primary_status,
|
|
6392
|
+
"additional": additional_summary,
|
|
6393
|
+
}
|
|
6394
|
+
return {
|
|
6395
|
+
"ok": _frontier_diagnostic_ok(issues, strict=strict),
|
|
6396
|
+
"strict": strict,
|
|
6397
|
+
"issues": issues,
|
|
6398
|
+
"summary": summary,
|
|
6399
|
+
"next_action": next_action,
|
|
6400
|
+
"suggested_next_command": suggested_next_command,
|
|
6401
|
+
"paths": {key: _path_for_state(value, repo_root) for key, value in paths.items()},
|
|
6402
|
+
}
|
|
6403
|
+
|
|
6404
|
+
|
|
6405
|
+
def _frontier_continuation_payload(repo_root: Path, *, strict: bool = False) -> dict[str, Any]:
|
|
6406
|
+
paths = _frontier_paths(repo_root)
|
|
6407
|
+
stack = _read_json_if_exists(paths["stack_json"])
|
|
6408
|
+
state = _read_json_if_exists(paths["state_json"])
|
|
6409
|
+
return _frontier_build_continuation_payload(repo_root, stack, state, include_structural_issues=True, strict=strict)
|
|
6410
|
+
|
|
6411
|
+
|
|
6412
|
+
def _frontier_additional_item_summary(item_list: dict[str, Any], item: dict[str, Any]) -> str:
|
|
6413
|
+
bits = [
|
|
6414
|
+
f"ORP additional item {str(item_list.get('id', '')).strip()}/{str(item.get('id', '')).strip()}: {str(item.get('label', '')).strip()}",
|
|
6415
|
+
]
|
|
6416
|
+
goal = str(item.get("goal", "")).strip()
|
|
6417
|
+
if goal:
|
|
6418
|
+
bits.append(f"Goal: {goal}")
|
|
6419
|
+
criteria = _coerce_string_list(item.get("success_criteria"))
|
|
6420
|
+
if criteria:
|
|
6421
|
+
bits.append("Success: " + "; ".join(criteria))
|
|
6422
|
+
return " ".join(bits)
|
|
6423
|
+
|
|
6424
|
+
|
|
6425
|
+
def _render_frontier_additional_md(payload: dict[str, Any]) -> str:
|
|
6426
|
+
lines = [
|
|
6427
|
+
f"# Additional Frontier Items: {payload.get('label', '') or payload.get('program_id', '')}",
|
|
6428
|
+
"",
|
|
6429
|
+
f"- active_list_id: `{payload.get('active_list_id', '') or '(none)'}`",
|
|
6430
|
+
f"- active_item_id: `{payload.get('active_item_id', '') or '(none)'}`",
|
|
6431
|
+
"",
|
|
6432
|
+
]
|
|
6433
|
+
lists = payload.get("lists")
|
|
6434
|
+
if isinstance(lists, list) and lists:
|
|
6435
|
+
for item_list in lists:
|
|
6436
|
+
if not isinstance(item_list, dict):
|
|
6437
|
+
continue
|
|
6438
|
+
lines.append(
|
|
6439
|
+
f"## `{item_list.get('id', '')}` {item_list.get('label', '')} (`{item_list.get('status', '') or 'pending'}`)"
|
|
6440
|
+
)
|
|
6441
|
+
lines.append("")
|
|
6442
|
+
items = item_list.get("items")
|
|
6443
|
+
if isinstance(items, list) and items:
|
|
6444
|
+
for item in items:
|
|
6445
|
+
if not isinstance(item, dict):
|
|
6446
|
+
continue
|
|
6447
|
+
marker = "x" if str(item.get("status", "")).strip() == "complete" else " "
|
|
6448
|
+
lines.append(
|
|
6449
|
+
f"- [{marker}] `{item.get('id', '')}` {item.get('label', '')} (`{item.get('status', '') or 'pending'}`)"
|
|
6450
|
+
)
|
|
6451
|
+
goal = str(item.get("goal", "")).strip()
|
|
6452
|
+
if goal:
|
|
6453
|
+
lines.append(f" - goal: {goal}")
|
|
6454
|
+
else:
|
|
6455
|
+
lines.append("- `(no items)`")
|
|
6456
|
+
lines.append("")
|
|
6457
|
+
else:
|
|
6458
|
+
lines.append("- `(no additional lists yet)`")
|
|
6459
|
+
lines.append("")
|
|
6460
|
+
return "\n".join(lines)
|
|
6461
|
+
|
|
6462
|
+
|
|
6463
|
+
def _frontier_write_additional_views(repo_root: Path, payload: dict[str, Any]) -> dict[str, str]:
|
|
6464
|
+
paths = _frontier_paths(repo_root)
|
|
6465
|
+
paths["root"].mkdir(parents=True, exist_ok=True)
|
|
6466
|
+
_frontier_normalize_additional_statuses(payload)
|
|
6467
|
+
_write_json(paths["additional_json"], payload)
|
|
6468
|
+
_write_text(paths["additional_md"], _render_frontier_additional_md(payload) + "\n")
|
|
6469
|
+
return {
|
|
6470
|
+
"additional_json": _path_for_state(paths["additional_json"], repo_root),
|
|
6471
|
+
"additional_md": _path_for_state(paths["additional_md"], repo_root),
|
|
6472
|
+
}
|
|
6473
|
+
|
|
6474
|
+
|
|
5979
6475
|
def _frontier_set_current_frontier(stack: dict[str, Any], state: dict[str, Any]) -> None:
|
|
5980
6476
|
stack["current_frontier"] = {
|
|
5981
6477
|
"active_version": str(state.get("active_version", "")).strip(),
|
|
@@ -6179,6 +6675,11 @@ def _frontier_write_materialized_views(repo_root: Path, stack: dict[str, Any], s
|
|
|
6179
6675
|
_frontier_set_current_frontier(stack, state)
|
|
6180
6676
|
roadmap = _frontier_build_roadmap_payload(stack, state)
|
|
6181
6677
|
checklist = _frontier_build_checklist_payload(stack, state)
|
|
6678
|
+
additional = _frontier_load_additional(repo_root, stack)
|
|
6679
|
+
if not str(additional.get("program_id", "")).strip():
|
|
6680
|
+
additional["program_id"] = str(stack.get("program_id", "")).strip()
|
|
6681
|
+
if not str(additional.get("label", "")).strip():
|
|
6682
|
+
additional["label"] = str(stack.get("label", "")).strip()
|
|
6182
6683
|
_write_json(paths["state_json"], state)
|
|
6183
6684
|
_write_json(paths["stack_json"], stack)
|
|
6184
6685
|
_write_json(paths["roadmap_json"], roadmap)
|
|
@@ -6187,6 +6688,7 @@ def _frontier_write_materialized_views(repo_root: Path, stack: dict[str, Any], s
|
|
|
6187
6688
|
_write_text(paths["roadmap_md"], _render_frontier_roadmap_md(roadmap) + "\n")
|
|
6188
6689
|
_write_text(paths["checklist_md"], _render_frontier_checklist_md(checklist) + "\n")
|
|
6189
6690
|
_write_text(paths["stack_md"], _render_frontier_stack_md(stack) + "\n")
|
|
6691
|
+
_frontier_write_additional_views(repo_root, additional)
|
|
6190
6692
|
return {key: _path_for_state(value, repo_root) for key, value in paths.items() if key != "root"}
|
|
6191
6693
|
|
|
6192
6694
|
|
|
@@ -6245,14 +6747,44 @@ def _frontier_doctor_payload(repo_root: Path) -> dict[str, Any]:
|
|
|
6245
6747
|
)
|
|
6246
6748
|
if band == "exact":
|
|
6247
6749
|
exact_milestones += 1
|
|
6750
|
+
milestone_id = str(milestone_row.get("id", "")).strip()
|
|
6751
|
+
if active_milestone and milestone_id and milestone_id != active_milestone:
|
|
6752
|
+
issues.append(
|
|
6753
|
+
{
|
|
6754
|
+
"severity": "warning",
|
|
6755
|
+
"code": "exact_milestone_not_live",
|
|
6756
|
+
"message": f"milestone `{milestone_id}` is marked exact but the live milestone is `{active_milestone}`.",
|
|
6757
|
+
}
|
|
6758
|
+
)
|
|
6248
6759
|
if exact_milestones > 1:
|
|
6249
6760
|
issues.append(
|
|
6250
6761
|
{"severity": "warning", "code": "multiple_exact_milestones", "message": f"{exact_milestones} milestones are marked exact; the planning rule expects only one live exact milestone."}
|
|
6251
6762
|
)
|
|
6252
6763
|
|
|
6764
|
+
continuation = _frontier_build_continuation_payload(
|
|
6765
|
+
repo_root,
|
|
6766
|
+
stack,
|
|
6767
|
+
state,
|
|
6768
|
+
include_structural_issues=False,
|
|
6769
|
+
)
|
|
6770
|
+
issues.extend(continuation["issues"])
|
|
6771
|
+
else:
|
|
6772
|
+
continuation = _frontier_build_continuation_payload(
|
|
6773
|
+
repo_root,
|
|
6774
|
+
stack if isinstance(stack, dict) else None,
|
|
6775
|
+
state if isinstance(state, dict) else None,
|
|
6776
|
+
include_structural_issues=False,
|
|
6777
|
+
)
|
|
6778
|
+
|
|
6253
6779
|
return {
|
|
6254
|
-
"ok":
|
|
6780
|
+
"ok": _frontier_diagnostic_ok(issues),
|
|
6255
6781
|
"issues": issues,
|
|
6782
|
+
"continuation": {
|
|
6783
|
+
"ok": continuation["ok"],
|
|
6784
|
+
"summary": continuation["summary"],
|
|
6785
|
+
"next_action": continuation["next_action"],
|
|
6786
|
+
"suggested_next_command": continuation["suggested_next_command"],
|
|
6787
|
+
},
|
|
6256
6788
|
"paths": {key: _path_for_state(value, repo_root) for key, value in paths.items()},
|
|
6257
6789
|
}
|
|
6258
6790
|
|
|
@@ -10769,12 +11301,16 @@ def _about_payload() -> dict[str, Any]:
|
|
|
10769
11301
|
},
|
|
10770
11302
|
{
|
|
10771
11303
|
"id": "frontier",
|
|
10772
|
-
"description": "Version-stack, milestone, phase, and
|
|
11304
|
+
"description": "Version-stack, milestone, phase, additional-queue, and continuation-preflight control for long-running agent-first research programs.",
|
|
10773
11305
|
"entrypoints": [
|
|
10774
11306
|
["frontier", "init"],
|
|
10775
11307
|
["frontier", "state"],
|
|
10776
11308
|
["frontier", "roadmap"],
|
|
10777
11309
|
["frontier", "checklist"],
|
|
11310
|
+
["frontier", "continuation-status"],
|
|
11311
|
+
["frontier", "preflight-delegate"],
|
|
11312
|
+
["frontier", "additional", "list"],
|
|
11313
|
+
["frontier", "additional", "activate-next"],
|
|
10778
11314
|
["frontier", "stack"],
|
|
10779
11315
|
["frontier", "add-version"],
|
|
10780
11316
|
["frontier", "add-milestone"],
|
|
@@ -10942,6 +11478,13 @@ def _about_payload() -> dict[str, Any]:
|
|
|
10942
11478
|
{"name": "frontier_state", "path": ["frontier", "state"], "json_output": True},
|
|
10943
11479
|
{"name": "frontier_roadmap", "path": ["frontier", "roadmap"], "json_output": True},
|
|
10944
11480
|
{"name": "frontier_checklist", "path": ["frontier", "checklist"], "json_output": True},
|
|
11481
|
+
{"name": "frontier_continuation_status", "path": ["frontier", "continuation-status"], "json_output": True},
|
|
11482
|
+
{"name": "frontier_preflight_delegate", "path": ["frontier", "preflight-delegate"], "json_output": True},
|
|
11483
|
+
{"name": "frontier_additional_list", "path": ["frontier", "additional", "list"], "json_output": True},
|
|
11484
|
+
{"name": "frontier_additional_add_list", "path": ["frontier", "additional", "add-list"], "json_output": True},
|
|
11485
|
+
{"name": "frontier_additional_add_item", "path": ["frontier", "additional", "add-item"], "json_output": True},
|
|
11486
|
+
{"name": "frontier_additional_activate_next", "path": ["frontier", "additional", "activate-next"], "json_output": True},
|
|
11487
|
+
{"name": "frontier_additional_complete_active", "path": ["frontier", "additional", "complete-active"], "json_output": True},
|
|
10945
11488
|
{"name": "frontier_stack", "path": ["frontier", "stack"], "json_output": True},
|
|
10946
11489
|
{"name": "frontier_add_version", "path": ["frontier", "add-version"], "json_output": True},
|
|
10947
11490
|
{"name": "frontier_add_milestone", "path": ["frontier", "add-milestone"], "json_output": True},
|
|
@@ -10973,7 +11516,7 @@ def _about_payload() -> dict[str, Any]:
|
|
|
10973
11516
|
"Discovery profiles in ORP are portable search-intent files managed directly by ORP.",
|
|
10974
11517
|
"Knowledge exchange is a built-in ORP ability exposed through `orp exchange repo synthesize`, producing structured exchange artifacts and transfer maps for local or remote source repositories.",
|
|
10975
11518
|
"Collaboration is a built-in ORP ability exposed through `orp collaborate ...`.",
|
|
10976
|
-
"Frontier control is a built-in ORP ability exposed through `orp frontier ...`, separating the exact live point, the exact active milestone, the near structured checklist, and
|
|
11519
|
+
"Frontier control is a built-in ORP ability exposed through `orp frontier ...`, separating the exact live point, the exact active milestone, the near structured checklist, the additional work queue, and strict continuation preflight before delegation.",
|
|
10977
11520
|
"Agent modes are lightweight optional overlays for taste, perspective shifts, fresh movement, and intentional comprehension breakdowns; `orp mode breakdown granular-breakdown --json` gives agents a broad-to-atomic ladder for complex work, while `orp mode nudge granular-breakdown --json` gives a short reminder card.",
|
|
10978
11521
|
"Project/session linking is a built-in ORP ability exposed through `orp link ...` and stored machine-locally under `.git/orp/link/`.",
|
|
10979
11522
|
"Secrets are easiest to understand as saved credentials and related login metadata: humans usually run `orp secrets add ...` and paste the value at the prompt, agents usually pipe the value with `--value-stdin`, optional usernames can be stored alongside the secret when a service needs them, and local macOS Keychain caching plus hosted sync are optional layers on top.",
|
|
@@ -13532,6 +14075,245 @@ def cmd_frontier_checklist(args: argparse.Namespace) -> int:
|
|
|
13532
14075
|
return 0
|
|
13533
14076
|
|
|
13534
14077
|
|
|
14078
|
+
def cmd_frontier_additional_list(args: argparse.Namespace) -> int:
|
|
14079
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14080
|
+
stack = _frontier_load_stack(repo_root)
|
|
14081
|
+
payload = _frontier_load_additional(repo_root, stack)
|
|
14082
|
+
lists = payload.get("lists")
|
|
14083
|
+
rows = lists if isinstance(lists, list) else []
|
|
14084
|
+
pending_items = 0
|
|
14085
|
+
active_items = 0
|
|
14086
|
+
complete_items = 0
|
|
14087
|
+
for item_list in rows:
|
|
14088
|
+
if not isinstance(item_list, dict):
|
|
14089
|
+
continue
|
|
14090
|
+
items = item_list.get("items")
|
|
14091
|
+
if not isinstance(items, list):
|
|
14092
|
+
continue
|
|
14093
|
+
for item in items:
|
|
14094
|
+
if not isinstance(item, dict):
|
|
14095
|
+
continue
|
|
14096
|
+
status = str(item.get("status", "")).strip() or "pending"
|
|
14097
|
+
if status == "active":
|
|
14098
|
+
active_items += 1
|
|
14099
|
+
elif status == "complete":
|
|
14100
|
+
complete_items += 1
|
|
14101
|
+
else:
|
|
14102
|
+
pending_items += 1
|
|
14103
|
+
result = {
|
|
14104
|
+
"ok": True,
|
|
14105
|
+
**payload,
|
|
14106
|
+
"summary": {
|
|
14107
|
+
"lists": len(rows),
|
|
14108
|
+
"pending_items": pending_items,
|
|
14109
|
+
"active_items": active_items,
|
|
14110
|
+
"complete_items": complete_items,
|
|
14111
|
+
},
|
|
14112
|
+
"paths": {
|
|
14113
|
+
"additional_json": _path_for_state(_frontier_paths(repo_root)["additional_json"], repo_root),
|
|
14114
|
+
"additional_md": _path_for_state(_frontier_paths(repo_root)["additional_md"], repo_root),
|
|
14115
|
+
},
|
|
14116
|
+
}
|
|
14117
|
+
if args.json_output:
|
|
14118
|
+
_print_json(result)
|
|
14119
|
+
else:
|
|
14120
|
+
print(f"lists={len(rows)}")
|
|
14121
|
+
print(f"active_list_id={payload.get('active_list_id', '') or '(none)'}")
|
|
14122
|
+
print(f"active_item_id={payload.get('active_item_id', '') or '(none)'}")
|
|
14123
|
+
print(f"pending_items={pending_items}")
|
|
14124
|
+
print(f"active_items={active_items}")
|
|
14125
|
+
print(f"complete_items={complete_items}")
|
|
14126
|
+
return 0
|
|
14127
|
+
|
|
14128
|
+
|
|
14129
|
+
def cmd_frontier_additional_add_list(args: argparse.Namespace) -> int:
|
|
14130
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14131
|
+
stack = _frontier_load_stack(repo_root)
|
|
14132
|
+
payload = _frontier_load_additional(repo_root, stack)
|
|
14133
|
+
list_id = str(args.id).strip()
|
|
14134
|
+
if _frontier_find_additional_list(payload, list_id) is not None:
|
|
14135
|
+
raise RuntimeError(f"frontier additional list `{list_id}` already exists.")
|
|
14136
|
+
item_list = {
|
|
14137
|
+
"id": list_id,
|
|
14138
|
+
"label": str(args.label).strip(),
|
|
14139
|
+
"status": str(args.status or "pending").strip() or "pending",
|
|
14140
|
+
"items": [],
|
|
14141
|
+
}
|
|
14142
|
+
lists = payload.get("lists")
|
|
14143
|
+
if not isinstance(lists, list):
|
|
14144
|
+
lists = []
|
|
14145
|
+
payload["lists"] = lists
|
|
14146
|
+
lists.append(item_list)
|
|
14147
|
+
written = _frontier_write_additional_views(repo_root, payload)
|
|
14148
|
+
result = {"ok": True, "list": item_list, "paths": written}
|
|
14149
|
+
if args.json_output:
|
|
14150
|
+
_print_json(result)
|
|
14151
|
+
else:
|
|
14152
|
+
print(f"list_id={list_id}")
|
|
14153
|
+
print(f"label={item_list['label']}")
|
|
14154
|
+
return 0
|
|
14155
|
+
|
|
14156
|
+
|
|
14157
|
+
def cmd_frontier_additional_add_item(args: argparse.Namespace) -> int:
|
|
14158
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14159
|
+
stack = _frontier_load_stack(repo_root)
|
|
14160
|
+
payload = _frontier_load_additional(repo_root, stack)
|
|
14161
|
+
list_id = str(args.list).strip()
|
|
14162
|
+
item_list = _frontier_find_additional_list(payload, list_id)
|
|
14163
|
+
if item_list is None:
|
|
14164
|
+
raise RuntimeError(f"frontier additional list `{list_id}` was not found.")
|
|
14165
|
+
item_id = str(args.id).strip()
|
|
14166
|
+
if _frontier_find_additional_item(item_list, item_id) is not None:
|
|
14167
|
+
raise RuntimeError(f"frontier additional item `{item_id}` already exists in list `{list_id}`.")
|
|
14168
|
+
item = {
|
|
14169
|
+
"id": item_id,
|
|
14170
|
+
"label": str(args.label).strip(),
|
|
14171
|
+
"status": str(args.status or "pending").strip() or "pending",
|
|
14172
|
+
"goal": str(args.goal or "").strip(),
|
|
14173
|
+
"depends_on": _coerce_string_list(getattr(args, "depends_on", [])),
|
|
14174
|
+
"requirements": _coerce_string_list(getattr(args, "requirement", [])),
|
|
14175
|
+
"success_criteria": _coerce_string_list(getattr(args, "success_criterion", [])),
|
|
14176
|
+
"plans": _coerce_string_list(getattr(args, "plan", [])),
|
|
14177
|
+
}
|
|
14178
|
+
items = item_list.get("items")
|
|
14179
|
+
if not isinstance(items, list):
|
|
14180
|
+
items = []
|
|
14181
|
+
item_list["items"] = items
|
|
14182
|
+
items.append(item)
|
|
14183
|
+
written = _frontier_write_additional_views(repo_root, payload)
|
|
14184
|
+
result = {"ok": True, "list_id": list_id, "item": item, "paths": written}
|
|
14185
|
+
if args.json_output:
|
|
14186
|
+
_print_json(result)
|
|
14187
|
+
else:
|
|
14188
|
+
print(f"list_id={list_id}")
|
|
14189
|
+
print(f"item_id={item_id}")
|
|
14190
|
+
print(f"label={item['label']}")
|
|
14191
|
+
return 0
|
|
14192
|
+
|
|
14193
|
+
|
|
14194
|
+
def cmd_frontier_additional_activate_next(args: argparse.Namespace) -> int:
|
|
14195
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14196
|
+
stack = _frontier_load_stack(repo_root)
|
|
14197
|
+
payload = _frontier_load_additional(repo_root, stack)
|
|
14198
|
+
active_list, active_item = _frontier_active_additional_item(payload)
|
|
14199
|
+
already_active = active_list is not None and active_item is not None and str(active_item.get("status", "")).strip() == "active"
|
|
14200
|
+
if not already_active:
|
|
14201
|
+
active_list, active_item = _frontier_next_pending_additional_item(payload)
|
|
14202
|
+
if active_list is not None and active_item is not None:
|
|
14203
|
+
active_list["status"] = "active"
|
|
14204
|
+
active_item["status"] = "active"
|
|
14205
|
+
payload["active_list_id"] = str(active_list.get("id", "")).strip()
|
|
14206
|
+
payload["active_item_id"] = str(active_item.get("id", "")).strip()
|
|
14207
|
+
else:
|
|
14208
|
+
payload["active_list_id"] = ""
|
|
14209
|
+
payload["active_item_id"] = ""
|
|
14210
|
+
written = _frontier_write_additional_views(repo_root, payload)
|
|
14211
|
+
activated = active_list is not None and active_item is not None
|
|
14212
|
+
result = {
|
|
14213
|
+
"ok": True,
|
|
14214
|
+
"activated": activated,
|
|
14215
|
+
"already_active": already_active,
|
|
14216
|
+
"active_list_id": payload.get("active_list_id", ""),
|
|
14217
|
+
"active_item_id": payload.get("active_item_id", ""),
|
|
14218
|
+
"list": active_list if activated else None,
|
|
14219
|
+
"item": active_item if activated else None,
|
|
14220
|
+
"next_action": _frontier_additional_item_summary(active_list, active_item) if activated else "",
|
|
14221
|
+
"paths": written,
|
|
14222
|
+
}
|
|
14223
|
+
if args.json_output:
|
|
14224
|
+
_print_json(result)
|
|
14225
|
+
else:
|
|
14226
|
+
print(f"activated={'true' if activated else 'false'}")
|
|
14227
|
+
if activated:
|
|
14228
|
+
print(f"active_list_id={result['active_list_id']}")
|
|
14229
|
+
print(f"active_item_id={result['active_item_id']}")
|
|
14230
|
+
print(f"next_action={result['next_action']}")
|
|
14231
|
+
return 0
|
|
14232
|
+
|
|
14233
|
+
|
|
14234
|
+
def cmd_frontier_additional_complete_active(args: argparse.Namespace) -> int:
|
|
14235
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14236
|
+
stack = _frontier_load_stack(repo_root)
|
|
14237
|
+
payload = _frontier_load_additional(repo_root, stack)
|
|
14238
|
+
active_list, active_item = _frontier_active_additional_item(payload)
|
|
14239
|
+
completed = active_list is not None and active_item is not None
|
|
14240
|
+
list_completed = False
|
|
14241
|
+
if completed:
|
|
14242
|
+
active_item["status"] = str(args.status or "complete").strip() or "complete"
|
|
14243
|
+
items = active_list.get("items")
|
|
14244
|
+
if isinstance(items, list) and all(
|
|
14245
|
+
str(item.get("status", "")).strip() in {"complete", "skipped"} for item in items if isinstance(item, dict)
|
|
14246
|
+
):
|
|
14247
|
+
active_list["status"] = "complete"
|
|
14248
|
+
list_completed = True
|
|
14249
|
+
payload["active_list_id"] = ""
|
|
14250
|
+
payload["active_item_id"] = ""
|
|
14251
|
+
written = _frontier_write_additional_views(repo_root, payload)
|
|
14252
|
+
result = {
|
|
14253
|
+
"ok": True,
|
|
14254
|
+
"completed": completed,
|
|
14255
|
+
"list_completed": list_completed,
|
|
14256
|
+
"list": active_list if completed else None,
|
|
14257
|
+
"item": active_item if completed else None,
|
|
14258
|
+
"paths": written,
|
|
14259
|
+
}
|
|
14260
|
+
if args.json_output:
|
|
14261
|
+
_print_json(result)
|
|
14262
|
+
else:
|
|
14263
|
+
print(f"completed={'true' if completed else 'false'}")
|
|
14264
|
+
print(f"list_completed={'true' if list_completed else 'false'}")
|
|
14265
|
+
return 0
|
|
14266
|
+
|
|
14267
|
+
|
|
14268
|
+
def _print_frontier_diagnostic_payload(payload: dict[str, Any]) -> None:
|
|
14269
|
+
print(f"ok={'true' if payload.get('ok') else 'false'}")
|
|
14270
|
+
print(f"next_action={payload.get('next_action', '') or '(none)'}")
|
|
14271
|
+
suggested = str(payload.get("suggested_next_command", "")).strip()
|
|
14272
|
+
if suggested:
|
|
14273
|
+
print(f"suggested_next_command={suggested}")
|
|
14274
|
+
summary = payload.get("summary")
|
|
14275
|
+
if isinstance(summary, dict):
|
|
14276
|
+
print(f"active_primary={summary.get('active_primary_kind', '') or '(none)'}:{summary.get('active_primary_id', '') or '(none)'}")
|
|
14277
|
+
additional = summary.get("additional")
|
|
14278
|
+
if isinstance(additional, dict):
|
|
14279
|
+
print(f"pending_additional_items={additional.get('pending_items', 0)}")
|
|
14280
|
+
print(f"active_additional={additional.get('active_list_id', '') or '(none)'}/{additional.get('active_item_id', '') or '(none)'}")
|
|
14281
|
+
for issue in payload.get("issues", []):
|
|
14282
|
+
if isinstance(issue, dict):
|
|
14283
|
+
print(f"issue={issue.get('severity','')}:{issue.get('code','')}:{issue.get('message','')}")
|
|
14284
|
+
|
|
14285
|
+
|
|
14286
|
+
def cmd_frontier_continuation_status(args: argparse.Namespace) -> int:
|
|
14287
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14288
|
+
strict = bool(getattr(args, "strict", False))
|
|
14289
|
+
payload = _frontier_continuation_payload(repo_root, strict=strict)
|
|
14290
|
+
if args.json_output:
|
|
14291
|
+
_print_json(payload)
|
|
14292
|
+
else:
|
|
14293
|
+
_print_frontier_diagnostic_payload(payload)
|
|
14294
|
+
return 0 if payload["ok"] else 1
|
|
14295
|
+
|
|
14296
|
+
|
|
14297
|
+
def cmd_frontier_preflight_delegate(args: argparse.Namespace) -> int:
|
|
14298
|
+
repo_root = Path(args.repo_root).resolve()
|
|
14299
|
+
payload = _frontier_doctor_payload(repo_root)
|
|
14300
|
+
payload["strict"] = True
|
|
14301
|
+
payload["ok"] = _frontier_diagnostic_ok(payload.get("issues", []), strict=True)
|
|
14302
|
+
continuation = payload.get("continuation") if isinstance(payload.get("continuation"), dict) else {}
|
|
14303
|
+
payload["next_action"] = continuation.get("next_action", "")
|
|
14304
|
+
payload["suggested_next_command"] = continuation.get("suggested_next_command", "")
|
|
14305
|
+
payload["summary"] = continuation.get("summary", {})
|
|
14306
|
+
payload["preflight"] = {
|
|
14307
|
+
"ready": bool(payload["ok"]),
|
|
14308
|
+
"purpose": "Block delegation when the frontier cannot prove a single safe continuation or terminal state.",
|
|
14309
|
+
}
|
|
14310
|
+
if args.json_output:
|
|
14311
|
+
_print_json(payload)
|
|
14312
|
+
else:
|
|
14313
|
+
_print_frontier_diagnostic_payload(payload)
|
|
14314
|
+
return 0 if payload["ok"] else 1
|
|
14315
|
+
|
|
14316
|
+
|
|
13535
14317
|
def cmd_frontier_add_version(args: argparse.Namespace) -> int:
|
|
13536
14318
|
repo_root = Path(args.repo_root).resolve()
|
|
13537
14319
|
stack = _frontier_load_stack(repo_root)
|
|
@@ -13739,6 +14521,9 @@ def cmd_frontier_render(args: argparse.Namespace) -> int:
|
|
|
13739
14521
|
def cmd_frontier_doctor(args: argparse.Namespace) -> int:
|
|
13740
14522
|
repo_root = Path(args.repo_root).resolve()
|
|
13741
14523
|
payload = _frontier_doctor_payload(repo_root)
|
|
14524
|
+
strict = bool(getattr(args, "strict", False))
|
|
14525
|
+
payload["strict"] = strict
|
|
14526
|
+
payload["ok"] = _frontier_diagnostic_ok(payload.get("issues", []), strict=strict)
|
|
13742
14527
|
fixes_applied: list[str] = []
|
|
13743
14528
|
if args.fix and payload["ok"]:
|
|
13744
14529
|
stack = _frontier_load_stack(repo_root)
|
|
@@ -24592,6 +25377,114 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
24592
25377
|
add_json_flag(s_frontier_checklist)
|
|
24593
25378
|
s_frontier_checklist.set_defaults(func=cmd_frontier_checklist, json_output=False)
|
|
24594
25379
|
|
|
25380
|
+
s_frontier_continuation_status = frontier_sub.add_parser(
|
|
25381
|
+
"continuation-status",
|
|
25382
|
+
help="Show whether the frontier has a safe next continuation, blocker, or terminal declaration",
|
|
25383
|
+
)
|
|
25384
|
+
s_frontier_continuation_status.add_argument(
|
|
25385
|
+
"--strict",
|
|
25386
|
+
action="store_true",
|
|
25387
|
+
help="Return non-zero when continuation warnings are present",
|
|
25388
|
+
)
|
|
25389
|
+
add_json_flag(s_frontier_continuation_status)
|
|
25390
|
+
s_frontier_continuation_status.set_defaults(func=cmd_frontier_continuation_status, json_output=False)
|
|
25391
|
+
|
|
25392
|
+
s_frontier_preflight_delegate = frontier_sub.add_parser(
|
|
25393
|
+
"preflight-delegate",
|
|
25394
|
+
help="Fail delegation when frontier continuation is stale, ambiguous, or not activated",
|
|
25395
|
+
)
|
|
25396
|
+
add_json_flag(s_frontier_preflight_delegate)
|
|
25397
|
+
s_frontier_preflight_delegate.set_defaults(func=cmd_frontier_preflight_delegate, json_output=False)
|
|
25398
|
+
|
|
25399
|
+
s_frontier_additional = frontier_sub.add_parser(
|
|
25400
|
+
"additional",
|
|
25401
|
+
help="Manage queued additional Frontier work that should run after the active delegate objective",
|
|
25402
|
+
)
|
|
25403
|
+
frontier_additional_sub = s_frontier_additional.add_subparsers(dest="frontier_additional_cmd", required=True)
|
|
25404
|
+
|
|
25405
|
+
s_frontier_additional_list = frontier_additional_sub.add_parser(
|
|
25406
|
+
"list",
|
|
25407
|
+
help="Show additional Frontier work lists and their item states",
|
|
25408
|
+
)
|
|
25409
|
+
add_json_flag(s_frontier_additional_list)
|
|
25410
|
+
s_frontier_additional_list.set_defaults(func=cmd_frontier_additional_list, json_output=False)
|
|
25411
|
+
|
|
25412
|
+
s_frontier_additional_add_list = frontier_additional_sub.add_parser(
|
|
25413
|
+
"add-list",
|
|
25414
|
+
help="Add an additional work list that delegates may drain after the active objective",
|
|
25415
|
+
)
|
|
25416
|
+
s_frontier_additional_add_list.add_argument("--id", required=True, help="Additional list id")
|
|
25417
|
+
s_frontier_additional_add_list.add_argument("--label", required=True, help="Additional list label")
|
|
25418
|
+
s_frontier_additional_add_list.add_argument(
|
|
25419
|
+
"--status",
|
|
25420
|
+
default="pending",
|
|
25421
|
+
choices=["pending", "active", "complete"],
|
|
25422
|
+
help="List status (default: pending)",
|
|
25423
|
+
)
|
|
25424
|
+
add_json_flag(s_frontier_additional_add_list)
|
|
25425
|
+
s_frontier_additional_add_list.set_defaults(func=cmd_frontier_additional_add_list, json_output=False)
|
|
25426
|
+
|
|
25427
|
+
s_frontier_additional_add_item = frontier_additional_sub.add_parser(
|
|
25428
|
+
"add-item",
|
|
25429
|
+
help="Add one item to an additional Frontier work list",
|
|
25430
|
+
)
|
|
25431
|
+
s_frontier_additional_add_item.add_argument("--list", required=True, help="Parent additional list id")
|
|
25432
|
+
s_frontier_additional_add_item.add_argument("--id", required=True, help="Additional item id")
|
|
25433
|
+
s_frontier_additional_add_item.add_argument("--label", required=True, help="Additional item label")
|
|
25434
|
+
s_frontier_additional_add_item.add_argument(
|
|
25435
|
+
"--status",
|
|
25436
|
+
default="pending",
|
|
25437
|
+
choices=["pending", "active", "complete", "skipped"],
|
|
25438
|
+
help="Item status (default: pending)",
|
|
25439
|
+
)
|
|
25440
|
+
s_frontier_additional_add_item.add_argument("--goal", default="", help="Optional item goal")
|
|
25441
|
+
s_frontier_additional_add_item.add_argument(
|
|
25442
|
+
"--depends-on",
|
|
25443
|
+
action="append",
|
|
25444
|
+
default=[],
|
|
25445
|
+
help="Dependency item, phase, or milestone id (repeatable)",
|
|
25446
|
+
)
|
|
25447
|
+
s_frontier_additional_add_item.add_argument(
|
|
25448
|
+
"--requirement",
|
|
25449
|
+
action="append",
|
|
25450
|
+
default=[],
|
|
25451
|
+
help="Requirement identifier or note (repeatable)",
|
|
25452
|
+
)
|
|
25453
|
+
s_frontier_additional_add_item.add_argument(
|
|
25454
|
+
"--success-criterion",
|
|
25455
|
+
action="append",
|
|
25456
|
+
default=[],
|
|
25457
|
+
help="Item success criterion (repeatable)",
|
|
25458
|
+
)
|
|
25459
|
+
s_frontier_additional_add_item.add_argument(
|
|
25460
|
+
"--plan",
|
|
25461
|
+
action="append",
|
|
25462
|
+
default=[],
|
|
25463
|
+
help="Plan id or plan note (repeatable)",
|
|
25464
|
+
)
|
|
25465
|
+
add_json_flag(s_frontier_additional_add_item)
|
|
25466
|
+
s_frontier_additional_add_item.set_defaults(func=cmd_frontier_additional_add_item, json_output=False)
|
|
25467
|
+
|
|
25468
|
+
s_frontier_additional_activate_next = frontier_additional_sub.add_parser(
|
|
25469
|
+
"activate-next",
|
|
25470
|
+
help="Activate and print the next pending additional Frontier item",
|
|
25471
|
+
)
|
|
25472
|
+
add_json_flag(s_frontier_additional_activate_next)
|
|
25473
|
+
s_frontier_additional_activate_next.set_defaults(func=cmd_frontier_additional_activate_next, json_output=False)
|
|
25474
|
+
|
|
25475
|
+
s_frontier_additional_complete_active = frontier_additional_sub.add_parser(
|
|
25476
|
+
"complete-active",
|
|
25477
|
+
help="Mark the active additional Frontier item complete",
|
|
25478
|
+
)
|
|
25479
|
+
s_frontier_additional_complete_active.add_argument(
|
|
25480
|
+
"--status",
|
|
25481
|
+
default="complete",
|
|
25482
|
+
choices=["complete", "skipped"],
|
|
25483
|
+
help="Completion status for the active item (default: complete)",
|
|
25484
|
+
)
|
|
25485
|
+
add_json_flag(s_frontier_additional_complete_active)
|
|
25486
|
+
s_frontier_additional_complete_active.set_defaults(func=cmd_frontier_additional_complete_active, json_output=False)
|
|
25487
|
+
|
|
24595
25488
|
s_frontier_stack = frontier_sub.add_parser(
|
|
24596
25489
|
"stack",
|
|
24597
25490
|
help="Show the larger major-version stack",
|
|
@@ -24745,6 +25638,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
24745
25638
|
action="store_true",
|
|
24746
25639
|
help="Re-render materialized frontier views when the frontier is otherwise consistent",
|
|
24747
25640
|
)
|
|
25641
|
+
s_frontier_doctor.add_argument(
|
|
25642
|
+
"--strict",
|
|
25643
|
+
action="store_true",
|
|
25644
|
+
help="Return non-zero when frontier warnings are present",
|
|
25645
|
+
)
|
|
24748
25646
|
add_json_flag(s_frontier_doctor)
|
|
24749
25647
|
s_frontier_doctor.set_defaults(func=cmd_frontier_doctor, json_output=False)
|
|
24750
25648
|
|