overlord-cli 0.2605121205.0 → 0.2605131058.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.
package/README.md CHANGED
@@ -130,6 +130,8 @@ Agents can find docs here: https://www.ovld.ai/docs/for-agents
130
130
  - `attachment-download-url` - get a signed download URL for an existing objective attachment
131
131
  - `attachment-upload-file` - prepare, upload, and finalize a local objective attachment in one command
132
132
 
133
+ `ovld protocol deliver` accepts either discrete flags like `--summary` / `--artifacts-json`, an inline full payload with `--payload-json '{"summary":"...","artifacts":[...],"changeRationales":[...]}'`, or a file/stdin payload with `--payload-file <path|->`.
134
+
133
135
  ## License
134
136
 
135
137
  Permission is granted to use this software for any purpose, free of charge. You may not modify, distribute, sublicense, or sell copies of the software without explicit permission from the author.
@@ -1122,14 +1122,28 @@ async function protocolDeliver(args) {
1122
1122
  const { sessionKey, ticketId } = resolveSessionFlags(flags);
1123
1123
  if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
1124
1124
  if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
1125
+ if (flags['payload-file'] && flags['payload-json']) {
1126
+ throw new Error('Use either --payload-file or --payload-json, not both');
1127
+ }
1125
1128
  const deliverPayload = flags['payload-file']
1126
1129
  ? await readJsonFileOrStdin(String(flags['payload-file']), '--payload-file')
1127
- : null;
1128
- const summary =
1129
- deliverPayload?.summary ??
1130
- (flags['summary-file']
1130
+ : flags['payload-json']
1131
+ ? parseJsonFlag('--payload-json', flags['payload-json'])
1132
+ : null;
1133
+ if (deliverPayload && (flags.summary || flags['summary-file'])) {
1134
+ throw new Error('Use either payload input or --summary/--summary-file, not both');
1135
+ }
1136
+ const summary = deliverPayload
1137
+ ? (() => {
1138
+ const value = deliverPayload.summary;
1139
+ if (typeof value !== 'string' || !value.trim()) {
1140
+ throw new Error('payload input must include a non-empty summary');
1141
+ }
1142
+ return value;
1143
+ })()
1144
+ : flags['summary-file']
1131
1145
  ? await readTextFileOrStdin(String(flags['summary-file']), '--summary-file')
1132
- : requireFlag(flags, 'summary', undefined));
1146
+ : requireFlag(flags, 'summary', undefined);
1133
1147
 
1134
1148
  const { platformUrl, bearerToken, localSecret, organizationId } =
1135
1149
  await resolveProtocolAuthForFlags(flags, ticketId);
@@ -1137,10 +1151,10 @@ async function protocolDeliver(args) {
1137
1151
 
1138
1152
  let artifacts = deliverPayload?.artifacts ?? [];
1139
1153
  if (deliverPayload && flags['artifacts-file']) {
1140
- throw new Error('Use either --payload-file or --artifacts-file, not both');
1154
+ throw new Error('Use either payload input or --artifacts-file, not both');
1141
1155
  }
1142
1156
  if (deliverPayload && flags['artifacts-json']) {
1143
- throw new Error('Use either --payload-file or --artifacts-json, not both');
1157
+ throw new Error('Use either payload input or --artifacts-json, not both');
1144
1158
  }
1145
1159
  if (flags['artifacts-file']) {
1146
1160
  artifacts = await readJsonFileOrStdin(String(flags['artifacts-file']), '--artifacts-file');
@@ -1149,7 +1163,7 @@ async function protocolDeliver(args) {
1149
1163
  }
1150
1164
 
1151
1165
  if (deliverPayload && (flags['change-rationales-file'] || flags['change-rationales-json'])) {
1152
- throw new Error('Use either --payload-file or change-rationale flags, not both');
1166
+ throw new Error('Use either payload input or change-rationale flags, not both');
1153
1167
  }
1154
1168
 
1155
1169
  const changeRationales =
@@ -1943,6 +1957,7 @@ deliver:
1943
1957
  --session-key <key>
1944
1958
  --ticket-id <ticket_id>
1945
1959
  --summary <text> or --summary-file <path|->
1960
+ or: --payload-json <json>
1946
1961
  or: --payload-file <path|-> containing { summary, artifacts, changeRationales }
1947
1962
  Optional:
1948
1963
  --artifacts-json <json>
@@ -1951,9 +1966,10 @@ deliver:
1951
1966
  --change-rationales-file <path|->
1952
1967
  --skip-file-change-check Bypass local git vs changeRationales validation
1953
1968
  Notes:
1969
+ Use --payload-json when the full delivery JSON fits comfortably inline.
1954
1970
  Use --payload-file - to read the full delivery JSON from stdin without creating a scratch file.
1955
1971
  Use --summary-file - to pipe just the summary text via stdin (avoids shell special-char issues).
1956
- Do not combine --payload-file with --artifacts-json/--artifacts-file or change-rationale flags.
1972
+ Do not combine --payload-json/--payload-file with --summary/--summary-file, --artifacts-json/--artifacts-file, or change-rationale flags.
1957
1973
  In a git workspace, deliver validates that changed files are represented by changeRationales unless skipped.
1958
1974
 
1959
1975
  prompt:
@@ -2089,6 +2105,7 @@ Examples:
2089
2105
  ovld protocol attachment-download-url --session-key <key> --ticket-id <ticket_id> --attachment-id <attachment-id>
2090
2106
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done"
2091
2107
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done" --artifacts-file ./artifacts.json
2108
+ ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --payload-json '{"summary":"Done","artifacts":[{"type":"note","label":"Delivery","content":"..."}]}'
2092
2109
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --payload-file ./deliver.json
2093
2110
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --payload-file -
2094
2111
  ovld protocol deliver --session-key <key> --ticket-id <ticket_id> --summary "Done" --skip-file-change-check
@@ -88,7 +88,7 @@ If you receive a prompt with a specified ticket ID, adhere to the following. If
88
88
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
89
89
  \`\`\`
90
90
 
91
- For larger or quote-sensitive deliveries, prefer a single JSON payload on stdin:
91
+ Use \`--payload-json\` when the full delivery object fits comfortably inline. For larger or quote-sensitive deliveries, prefer a single JSON payload on stdin:
92
92
  \`\`\`bash
93
93
  ovld protocol deliver --session-key <sessionKey> --ticket-id $TICKET_ID --payload-file -
94
94
  \`\`\`
@@ -261,7 +261,7 @@ When done, deliver with artifacts and change rationales:
261
261
  \`\`\`bash
262
262
  ovld protocol deliver --session-key <sessionKey> --ticket-id $TICKET_ID --summary "Narrative: what you did, next steps." --artifacts-json '[{"type":"next_steps","label":"Next steps","content":"..."}]' --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
263
263
  \`\`\`
264
- For larger delivery JSON, prefer \`--payload-file -\` with stdin so no scratch file needs to be created or removed. If you use a JSON file for delivery transport, keep it ephemeral scratch data outside the repository and remove it after the protocol call.
264
+ Use \`--payload-json\` for compact inline delivery objects. For larger delivery JSON, prefer \`--payload-file -\` with stdin so no scratch file needs to be created or removed. If you use a JSON file for delivery transport, keep it ephemeral scratch data outside the repository and remove it after the protocol call.
265
265
 
266
266
  Rules:
267
267
  - Always attach first and deliver last.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2605121205.0",
3
+ "version": "0.2605131058.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,18 +1,53 @@
1
1
  #!/bin/bash
2
2
  # Overlord UserPromptSubmit hook — fires before Claude processes each user turn.
3
+ # Claude Code does not expose turn_number in the hook body; we persist the last
4
+ # posted turnIndex per session_id and send (last + 1). The first submit is
5
+ # turnIndex 0 (initial injected ticket/objective prompt), which
6
+ # POST /api/protocol/hook-event skips — same contract as the Cursor hook.
3
7
 
4
8
  BODY=$(cat -)
5
9
  OVERLORD_BASE_URL="${CLAUDE_PLUGIN_OPTION_OVERLORD_URL:-$OVERLORD_URL}"
6
10
  OVERLORD_TOKEN="${CLAUDE_PLUGIN_OPTION_AGENT_TOKEN:-${CLAUDE_PLUGIN_OPTION_OVERLORD_ACCESS_TOKEN:-$OVERLORD_ACCESS_TOKEN}}"
7
11
  OVERLORD_LOCAL_SECRET="${OVERLORD_LOCAL_SECRET:-}"
8
12
 
9
- TURN=$(printf '%s' "$BODY" | python3 -c "import json,sys; print(json.load(sys.stdin).get('turn_number', 0))" 2>/dev/null || echo "0")
10
- if [ "$TURN" = "0" ]; then
11
- exit 0
12
- fi
13
-
14
13
  if [ -n "$OVERLORD_BASE_URL" ] && [ -n "$OVERLORD_TOKEN" ] && [ -n "$TICKET_ID" ]; then
15
- 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 '')
14
+ PAYLOAD=$(
15
+ printf '%s' "$BODY" | python3 -c "
16
+ import hashlib
17
+ import json
18
+ import os
19
+ import sys
20
+
21
+ try:
22
+ body = json.load(sys.stdin)
23
+ except Exception:
24
+ sys.exit(0)
25
+
26
+ text = (body.get('prompt') or '').strip()
27
+ if not text:
28
+ sys.exit(0)
29
+
30
+ sid = body.get('session_id') or 'unknown'
31
+ state_dir = os.path.join(os.path.expanduser('~'), '.ovld', 'claude-user-prompt-hook')
32
+ os.makedirs(state_dir, exist_ok=True)
33
+ path = os.path.join(state_dir, hashlib.sha256(sid.encode()).hexdigest())
34
+ last_posted = -1
35
+ try:
36
+ with open(path, encoding='utf-8') as handle:
37
+ raw = (handle.read() or '').strip()
38
+ if raw != '':
39
+ last_posted = int(raw)
40
+ except Exception:
41
+ last_posted = -1
42
+
43
+ turn_index = last_posted + 1
44
+ with open(path, 'w', encoding='utf-8') as handle:
45
+ handle.write(str(turn_index))
46
+
47
+ tid = os.environ.get('TICKET_ID', '')
48
+ print(json.dumps({'hookType': 'UserPromptSubmit', 'ticketId': tid, 'prompt': text, 'turnIndex': turn_index}))
49
+ " 2>/dev/null
50
+ )
16
51
  if [ -n "$PAYLOAD" ]; then
17
52
  curl -sf -m 5 \
18
53
  -X POST "$OVERLORD_BASE_URL/api/protocol/hook-event" \
@@ -75,7 +75,7 @@ ovld protocol deliver --session-key <sessionKey> \
75
75
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
76
76
  ```
77
77
 
78
- `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed. If the summary contains special characters, use `--summary-file -` and pipe via a single-quoted heredoc (`<<'EOF'`) to prevent shell expansion. If you use `--payload-file`, `--artifacts-file`, or `--change-rationales-file` with a real path, treat that file as ephemeral scratch data outside the repository and remove it after delivery.
78
+ `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. Use `--payload-json` when the full delivery object fits comfortably inline. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed. If the summary contains special characters, use `--summary-file -` and pipe via a single-quoted heredoc (`<<'EOF'`) to prevent shell expansion. If you use `--payload-file`, `--artifacts-file`, or `--change-rationales-file` with a real path, treat that file as ephemeral scratch data outside the repository and remove it after delivery.
79
79
 
80
80
  ## Mode 2: Asked From Chat To Use Overlord
81
81
 
@@ -99,7 +99,7 @@ Always include `changeRationales` when delivering. Optionally include them on up
99
99
 
100
100
  Before delivering, make sure every meaningful git-tracked file change is represented in `changeRationales`; do not send `file_changes` as an artifact.
101
101
 
102
- These are structured protocol payloads that Overlord stores as first-class rows in the `file_changes` table. Prefer inline JSON or the dedicated command below. For larger full delivery payloads, prefer `--payload-file -` so summary, artifacts, and change rationales stay in one JSON document without creating a temporary file. Ordinary deliver artifacts should use `next_steps`, `test_results`, `migration`, `note`, `url`, or `decision`.
102
+ These are structured protocol payloads that Overlord stores as first-class rows in the `file_changes` table. Prefer inline JSON or the dedicated command below. Use `--payload-json` for compact full delivery payloads, or `--payload-file -` when the JSON is larger or quote-sensitive so summary, artifacts, and change rationales stay in one JSON document without creating a temporary file. Ordinary deliver artifacts should use `next_steps`, `test_results`, `migration`, `note`, `url`, or `decision`.
103
103
 
104
104
  ```bash
105
105
  ovld protocol record-change-rationales --session-key <sessionKey> --ticket-id $TICKET_ID \
@@ -182,4 +182,4 @@ The `attach` and `load-context` responses already include `attachments` and `obj
182
182
  - Do not add or commit changes unless the user explicitly asks you to commit.
183
183
  - Delivery is the concluding step. After delivering, stop unless the user follows up or the ticket is reopened.
184
184
 
185
- <!-- version: 0.4.8 -->
185
+ <!-- version: 0.4.9 -->
@@ -1,7 +1,8 @@
1
1
  #!/bin/bash
2
2
  # Overlord Cursor beforeSubmitPrompt hook — posts user composer prompts to the ticket activity feed.
3
- # Cursor does not expose Claude's turn_number; we send a monotonic turnIndex per conversation (always >= 1)
4
- # so POST /api/protocol/hook-event records the event (the API skips only turnIndex === 0).
3
+ # Cursor does not expose Claude's turn_number; we persist the last posted turnIndex per conversation_id
4
+ # and send (last + 1). The first submit is turnIndex 0 (initial injected ticket/objective prompt), which
5
+ # POST /api/protocol/hook-event skips — same contract as Claude's turn_number 0.
5
6
 
6
7
  BODY=$(cat -)
7
8
 
@@ -31,17 +32,21 @@ cid = body.get('conversation_id') or 'unknown'
31
32
  state_dir = os.path.join(os.path.expanduser('~'), '.ovld', 'cursor-user-prompt-hook')
32
33
  os.makedirs(state_dir, exist_ok=True)
33
34
  path = os.path.join(state_dir, hashlib.sha256(cid.encode()).hexdigest())
35
+ last_posted = -1
34
36
  try:
35
37
  with open(path, encoding='utf-8') as handle:
36
- n = int((handle.read() or '0').strip() or '0')
38
+ raw = (handle.read() or '').strip()
39
+ if raw != '':
40
+ last_posted = int(raw)
37
41
  except Exception:
38
- n = 0
39
- n += 1
42
+ last_posted = -1
43
+
44
+ turn_index = last_posted + 1
40
45
  with open(path, 'w', encoding='utf-8') as handle:
41
- handle.write(str(n))
46
+ handle.write(str(turn_index))
42
47
 
43
48
  tid = os.environ.get('TICKET_ID', '')
44
- print(json.dumps({'hookType': 'UserPromptSubmit', 'ticketId': tid, 'prompt': text, 'turnIndex': n}))
49
+ print(json.dumps({'hookType': 'UserPromptSubmit', 'ticketId': tid, 'prompt': text, 'turnIndex': turn_index}))
45
50
  " 2>/dev/null
46
51
  )
47
52
  if [ -n "$PAYLOAD" ]; then
@@ -61,7 +61,7 @@ ovld protocol deliver --session-key <sessionKey> \
61
61
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
62
62
  ```
63
63
 
64
- `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed.
64
+ `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. Use `--payload-json` when the full delivery object fits comfortably inline. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed.
65
65
 
66
66
  ## Mode 2: Asked From Chat To Use Overlord
67
67
 
@@ -152,4 +152,4 @@ Objective attachment uploads also expose two-step variants — `attachment-prepa
152
152
  - If you must run `ovld auth login`, always include `--organization-id <id>` — use the organization ID from the ticket prompt context to select the organization non-interactively and avoid a blocking TTY prompt.
153
153
  - Delivery is the concluding step. After delivering, stop unless the user follows up or the ticket is reopened.
154
154
 
155
- <!-- version: 0.4.8 -->
155
+ <!-- version: 0.4.9 -->
@@ -65,7 +65,7 @@ ovld protocol deliver --session-key <sessionKey> \
65
65
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
66
66
  ```
67
67
 
68
- `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed. If you use `--payload-file`, `--artifacts-file`, or `--change-rationales-file` with a real path, treat that file as ephemeral scratch data outside the repository and remove it after delivery.
68
+ `ovld protocol deliver` automatically creates a local checkpoint before the API request when the workspace is JJ- or Git-managed; use `--skip-checkpoint` only when intentionally bypassing local provenance. Use `--payload-json` when the full delivery object fits comfortably inline. For larger delivery payloads, prefer `--payload-file -` and stream the full JSON on stdin so no scratch file needs to be created or removed. If you use `--payload-file`, `--artifacts-file`, or `--change-rationales-file` with a real path, treat that file as ephemeral scratch data outside the repository and remove it after delivery.
69
69
 
70
70
  ## Mode 2: Asked From Chat To Use Overlord
71
71
 
@@ -111,7 +111,7 @@ Always include `changeRationales` when delivering. Optionally include them on up
111
111
 
112
112
  Before delivering, make sure every meaningful git-tracked file change is represented in `changeRationales`; do not send `file_changes` as an artifact.
113
113
 
114
- These are structured protocol payloads that Overlord stores as first-class rows in the `file_changes` table. Prefer inline JSON or the dedicated command below. For larger full delivery payloads, prefer `--payload-file -` so summary, artifacts, and change rationales stay in one JSON document without creating a temporary file. Ordinary deliver artifacts should use `next_steps`, `test_results`, `migration`, `note`, `url`, or `decision`.
114
+ These are structured protocol payloads that Overlord stores as first-class rows in the `file_changes` table. Prefer inline JSON or the dedicated command below. Use `--payload-json` for compact full delivery payloads, or `--payload-file -` when the JSON is larger or quote-sensitive so summary, artifacts, and change rationales stay in one JSON document without creating a temporary file. Ordinary deliver artifacts should use `next_steps`, `test_results`, `migration`, `note`, `url`, or `decision`.
115
115
 
116
116
  ```bash
117
117
  ovld protocol record-change-rationales --session-key <sessionKey> --ticket-id $TICKET_ID \
@@ -158,4 +158,4 @@ The `attach` and `load-context` responses already include `attachments` and `obj
158
158
  - If a protocol or MCP call fails with auth/session errors, run `ovld auth repair` yourself before asking the user to log in again or proceed without Overlord updates.
159
159
  - If you must run `ovld auth login`, always include `--organization-id <id>` — use the organization ID from the ticket prompt context to select the organization non-interactively and avoid a blocking TTY prompt.
160
160
 
161
- <!-- version: 0.4.8 -->
161
+ <!-- version: 0.4.9 -->