overlord-cli 0.2605131058.0 → 0.2605131312.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.
@@ -1570,6 +1570,34 @@ async function protocolPrompt(args) {
1570
1570
  }
1571
1571
  }
1572
1572
 
1573
+ // ---------------------------------------------------------------------------
1574
+ // discuss-objective (mark a draft objective as submitted)
1575
+ // ---------------------------------------------------------------------------
1576
+
1577
+ async function protocolDiscussObjective(args) {
1578
+ const flags = parseFlags(args);
1579
+ const ticketId = requireFlag(flags, 'ticket-id', process.env.TICKET_ID);
1580
+ const { platformUrl, bearerToken, localSecret, organizationId } =
1581
+ await resolveProtocolAuthForFlags(flags, ticketId);
1582
+ const timeoutMs = resolveTimeout(flags);
1583
+
1584
+ const body = {
1585
+ ticketId,
1586
+ ...(flags['objective-id'] ? { objectiveId: String(flags['objective-id']) } : {})
1587
+ };
1588
+
1589
+ const data = await apiPost(
1590
+ platformUrl,
1591
+ bearerToken,
1592
+ localSecret,
1593
+ organizationId,
1594
+ '/api/protocol/discuss-objective',
1595
+ body,
1596
+ timeoutMs
1597
+ );
1598
+ console.log(JSON.stringify(data, null, 2));
1599
+ }
1600
+
1573
1601
  // ---------------------------------------------------------------------------
1574
1602
  // create (create follow-up ticket draft only)
1575
1603
  // ---------------------------------------------------------------------------
@@ -1761,6 +1789,7 @@ Subcommands:
1761
1789
  connect Start a lightweight session without full context
1762
1790
  load-context Read ticket context without creating a session
1763
1791
  search-tickets Find tickets by keyword, status, project, creator, or update date
1792
+ discuss-objective Mark a draft objective as submitted (ready for review/execution)
1764
1793
  create Create a draft ticket without attaching (follow-up or standalone)
1765
1794
  prompt Create a ticket and attach to it immediately
1766
1795
  update Post progress, activity events, and optional change rationales
@@ -1998,6 +2027,16 @@ prompt:
1998
2027
  Returns:
1999
2028
  New ticket/session JSON plus SESSION_KEY and TICKET_ID on stderr when available
2000
2029
 
2030
+ discuss-objective:
2031
+ Purpose:
2032
+ Mark the latest draft objective on a ticket as "submitted", indicating the objective
2033
+ has been discussed and is ready for review or execution. Does NOT start execution —
2034
+ use \`attach\` to begin execution.
2035
+ Required:
2036
+ --ticket-id <ticket_id>
2037
+ Optional:
2038
+ --objective-id <id> Target a specific draft objective by UUID
2039
+
2001
2040
  create:
2002
2041
  Purpose:
2003
2042
  Create a draft ticket without attaching to it.
@@ -2089,6 +2128,8 @@ Examples:
2089
2128
  ovld protocol connect --ticket-id 1:899
2090
2129
  ovld protocol load-context --ticket-id 1:899
2091
2130
  ovld protocol search-tickets --query "auth refactor" --status next-up,execute --limit 10
2131
+ ovld protocol discuss-objective --ticket-id 1:899
2132
+ ovld protocol discuss-objective --ticket-id 1:899 --objective-id <objective-uuid>
2092
2133
  ovld protocol create --agent codex --objective "Capture follow-up work from this repo"
2093
2134
  ovld protocol create --agent codex --session-key <key> --ticket-id <ticket_id> --objective "Capture follow-up work"
2094
2135
  ovld protocol prompt --agent codex --objective "Implement user auth" --priority high
@@ -2138,6 +2179,10 @@ Examples:
2138
2179
  await protocolSearchTickets(args);
2139
2180
  return;
2140
2181
  }
2182
+ if (subcommand === 'discuss-objective') {
2183
+ await protocolDiscussObjective(args);
2184
+ return;
2185
+ }
2141
2186
  if (subcommand === 'create' || subcommand === 'create-ticket') {
2142
2187
  await protocolCreateTicket(args);
2143
2188
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2605131058.0",
3
+ "version": "0.2605131312.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "homepage": "https://www.ovld.ai/docs/",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Overlord ticket protocol workflow for Claude Code — attach/update/ask/deliver, slash commands, and hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -9,6 +9,23 @@ BODY=$(cat -)
9
9
  OVERLORD_BASE_URL="${CLAUDE_PLUGIN_OPTION_OVERLORD_URL:-$OVERLORD_URL}"
10
10
  OVERLORD_TOKEN="${CLAUDE_PLUGIN_OPTION_AGENT_TOKEN:-${CLAUDE_PLUGIN_OPTION_OVERLORD_ACCESS_TOKEN:-$OVERLORD_ACCESS_TOKEN}}"
11
11
  OVERLORD_LOCAL_SECRET="${OVERLORD_LOCAL_SECRET:-}"
12
+ HOOK_NAME="claude"
13
+ LOG_DIR="${HOME:-}/.ovld/logs"
14
+ LOG_FILE="${LOG_DIR}/user-prompt-submit-hook.log"
15
+
16
+ log_hook() {
17
+ mkdir -p "$LOG_DIR" 2>/dev/null || return 0
18
+ printf '%s [%s] %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$HOOK_NAME" "$1" >>"$LOG_FILE" 2>/dev/null || true
19
+ }
20
+
21
+ PROMPT_LEN=$(printf '%s' "$BODY" | python3 -c "import json,sys; print(len((json.load(sys.stdin).get('prompt') or '').strip()))" 2>/dev/null || echo "0")
22
+ SESSION_ID=$(printf '%s' "$BODY" | python3 -c "import json,sys; print(json.load(sys.stdin).get('session_id') or 'unknown')" 2>/dev/null || echo "unknown")
23
+ log_hook "received submit session_id=$SESSION_ID prompt_len=$PROMPT_LEN ticket_present=$([ -n "${TICKET_ID:-}" ] && echo yes || echo no)"
24
+
25
+ if [ -z "$OVERLORD_BASE_URL" ] || [ -z "$OVERLORD_TOKEN" ] || [ -z "${TICKET_ID:-}" ]; then
26
+ log_hook "missing required env base_url=$([ -n "$OVERLORD_BASE_URL" ] && echo yes || echo no) token=$([ -n "$OVERLORD_TOKEN" ] && echo yes || echo no) ticket=$([ -n "${TICKET_ID:-}" ] && echo yes || echo no)"
27
+ exit 0
28
+ fi
12
29
 
13
30
  if [ -n "$OVERLORD_BASE_URL" ] && [ -n "$OVERLORD_TOKEN" ] && [ -n "$TICKET_ID" ]; then
14
31
  PAYLOAD=$(
@@ -48,16 +65,31 @@ tid = os.environ.get('TICKET_ID', '')
48
65
  print(json.dumps({'hookType': 'UserPromptSubmit', 'ticketId': tid, 'prompt': text, 'turnIndex': turn_index}))
49
66
  " 2>/dev/null
50
67
  )
51
- if [ -n "$PAYLOAD" ]; then
52
- curl -sf -m 5 \
68
+ if [ -z "$PAYLOAD" ]; then
69
+ log_hook "failed to build hook-event payload from submit body"
70
+ exit 0
71
+ fi
72
+
73
+ PAYLOAD_TURN=$(printf '%s' "$PAYLOAD" | python3 -c "import json,sys; print(json.load(sys.stdin).get('turnIndex', 'unknown'))" 2>/dev/null || echo "unknown")
74
+ log_hook "built payload turn=$PAYLOAD_TURN posting hook-event"
75
+ (
76
+ RESPONSE_FILE=$(mktemp "${TMPDIR:-/tmp}/overlord-hook-event.XXXXXX")
77
+ HTTP_CODE=$(curl -sS -m 5 -o "$RESPONSE_FILE" -w "%{http_code}" \
53
78
  -X POST "$OVERLORD_BASE_URL/api/protocol/hook-event" \
54
79
  -H "Authorization: Bearer $OVERLORD_TOKEN" \
55
80
  -H "X-Overlord-Local-Secret: $OVERLORD_LOCAL_SECRET" \
56
81
  -H "Content-Type: application/json" \
57
- -d "$PAYLOAD" \
58
- >/dev/null 2>&1 &
82
+ -d "$PAYLOAD")
83
+ CURL_EXIT=$?
84
+ RESPONSE_PREVIEW=$(python3 -c "from pathlib import Path; import sys; p=Path(sys.argv[1]); text=p.read_text(encoding='utf-8', errors='replace') if p.exists() else ''; text=' '.join(text.split()); print(text[:200])" "$RESPONSE_FILE" 2>/dev/null || echo '')
85
+ rm -f "$RESPONSE_FILE"
86
+ if [ "$CURL_EXIT" -eq 0 ]; then
87
+ log_hook "hook-event POST finished exit=0 http_status=$HTTP_CODE response_preview=$RESPONSE_PREVIEW"
88
+ else
89
+ log_hook "hook-event POST failed exit=$CURL_EXIT http_status=${HTTP_CODE:-none} response_preview=$RESPONSE_PREVIEW"
90
+ fi
91
+ ) >/dev/null 2>&1 &
59
92
  disown
60
- fi
61
93
  fi
62
94
 
63
95
  exit 0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Chat-driven access to Overlord ticket protocol workflows with hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -5,24 +5,55 @@ BODY=$(cat -)
5
5
  OVERLORD_BASE_URL="${OVERLORD_URL:-}"
6
6
  OVERLORD_TOKEN="${OVERLORD_ACCESS_TOKEN:-}"
7
7
  OVERLORD_LOCAL_SECRET="${OVERLORD_LOCAL_SECRET:-}"
8
+ HOOK_NAME="codex"
9
+ LOG_DIR="${HOME:-}/.ovld/logs"
10
+ LOG_FILE="${LOG_DIR}/user-prompt-submit-hook.log"
11
+
12
+ log_hook() {
13
+ mkdir -p "$LOG_DIR" 2>/dev/null || return 0
14
+ printf '%s [%s] %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$HOOK_NAME" "$1" >>"$LOG_FILE" 2>/dev/null || true
15
+ }
8
16
 
9
17
  TURN=$(printf '%s' "$BODY" | python3 -c "import json,sys; print(json.load(sys.stdin).get('turn_number', 0))" 2>/dev/null || echo "0")
18
+ PROMPT_LEN=$(printf '%s' "$BODY" | python3 -c "import json,sys; print(len((json.load(sys.stdin).get('prompt') or '').strip()))" 2>/dev/null || echo "0")
19
+ log_hook "received submit turn=$TURN prompt_len=$PROMPT_LEN ticket_present=$([ -n "${TICKET_ID:-}" ] && echo yes || echo no)"
10
20
  if [ "$TURN" = "0" ]; then
21
+ log_hook "skipping initial submit turn=0"
22
+ exit 0
23
+ fi
24
+
25
+ if [ -z "$OVERLORD_BASE_URL" ] || [ -z "$OVERLORD_TOKEN" ] || [ -z "${TICKET_ID:-}" ]; then
26
+ log_hook "missing required env base_url=$([ -n "$OVERLORD_BASE_URL" ] && echo yes || echo no) token=$([ -n "$OVERLORD_TOKEN" ] && echo yes || echo no) ticket=$([ -n "${TICKET_ID:-}" ] && echo yes || echo no)"
11
27
  exit 0
12
28
  fi
13
29
 
14
30
  if [ -n "$OVERLORD_BASE_URL" ] && [ -n "$OVERLORD_TOKEN" ] && [ -n "$TICKET_ID" ]; then
15
31
  PAYLOAD=$(printf '%s' "$BODY" | python3 -c "import json,sys; body=json.load(sys.stdin); print(json.dumps({'hookType': 'UserPromptSubmit', 'ticketId': __import__('os').environ['TICKET_ID'], 'prompt': body.get('prompt', ''), 'turnIndex': body.get('turn_number', 0)}))" 2>/dev/null || echo '')
16
- if [ -n "$PAYLOAD" ]; then
17
- curl -sf -m 5 \
32
+ if [ -z "$PAYLOAD" ]; then
33
+ log_hook "failed to build hook-event payload from submit body"
34
+ exit 0
35
+ fi
36
+
37
+ PAYLOAD_TURN=$(printf '%s' "$PAYLOAD" | python3 -c "import json,sys; print(json.load(sys.stdin).get('turnIndex', 'unknown'))" 2>/dev/null || echo "unknown")
38
+ log_hook "built payload turn=$PAYLOAD_TURN posting hook-event"
39
+ (
40
+ RESPONSE_FILE=$(mktemp "${TMPDIR:-/tmp}/overlord-hook-event.XXXXXX")
41
+ HTTP_CODE=$(curl -sS -m 5 -o "$RESPONSE_FILE" -w "%{http_code}" \
18
42
  -X POST "$OVERLORD_BASE_URL/api/protocol/hook-event" \
19
43
  -H "Authorization: Bearer $OVERLORD_TOKEN" \
20
44
  -H "X-Overlord-Local-Secret: $OVERLORD_LOCAL_SECRET" \
21
45
  -H "Content-Type: application/json" \
22
- -d "$PAYLOAD" \
23
- >/dev/null 2>&1 &
46
+ -d "$PAYLOAD")
47
+ CURL_EXIT=$?
48
+ RESPONSE_PREVIEW=$(python3 -c "from pathlib import Path; import sys; p=Path(sys.argv[1]); text=p.read_text(encoding='utf-8', errors='replace') if p.exists() else ''; text=' '.join(text.split()); print(text[:200])" "$RESPONSE_FILE" 2>/dev/null || echo '')
49
+ rm -f "$RESPONSE_FILE"
50
+ if [ "$CURL_EXIT" -eq 0 ]; then
51
+ log_hook "hook-event POST finished exit=0 http_status=$HTTP_CODE response_preview=$RESPONSE_PREVIEW"
52
+ else
53
+ log_hook "hook-event POST failed exit=$CURL_EXIT http_status=${HTTP_CODE:-none} response_preview=$RESPONSE_PREVIEW"
54
+ fi
55
+ ) >/dev/null 2>&1 &
24
56
  disown
25
- fi
26
57
  fi
27
58
 
28
59
  exit 0