@rubytech/create-realagent-code 0.1.254 → 0.1.255
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/package.json +1 -1
- package/payload/platform/.docs/search-surface-contract.md +58 -0
- package/payload/platform/lib/embed-client/dist/index.d.ts +4 -0
- package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/embed-client/dist/index.js +53 -0
- package/payload/platform/lib/embed-client/dist/index.js.map +1 -0
- package/payload/platform/lib/embed-client/src/index.ts +53 -0
- package/payload/platform/lib/embed-client/tsconfig.json +8 -0
- package/payload/platform/lib/graph-search/dist/index.d.ts +27 -6
- package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-search/dist/index.js +19 -1
- package/payload/platform/lib/graph-search/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-search/src/index.ts +28 -6
- package/payload/platform/lib/graph-write/dist/index.d.ts +25 -0
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +78 -2
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +96 -1
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +3 -3
- package/payload/platform/plugins/admin/hooks/__tests__/{session-end-retrospective.test.sh → insight.test.sh} +152 -153
- package/payload/platform/plugins/admin/hooks/insight.sh +219 -0
- package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +5 -5
- package/payload/platform/plugins/admin/mcp/dist/index.js +33 -19
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +23 -23
- package/payload/platform/plugins/docs/references/graph.md +2 -0
- package/payload/platform/plugins/docs/references/internals.md +12 -1
- package/payload/platform/plugins/docs/references/neo4j.md +2 -2
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/session-retrospective.md +5 -18
- package/payload/platform/plugins/email/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +8 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +19 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +64 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +4 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +6 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +7 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +4 -0
- package/payload/platform/plugins/memory/PLUGIN.md +1 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js +5 -43
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js +41 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js +90 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js +27 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts +10 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js +47 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +1 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +5 -28
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js +20 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js +67 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +34 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js +61 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +23 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js +87 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +3 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js +34 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +19 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +33 -6
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +280 -10
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +76 -37
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +11 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +3 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +10 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +6 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -0
- package/payload/platform/plugins/memory/references/schema-base.md +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +15 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +4 -0
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
- package/payload/platform/scripts/identity-forbidden-token-check.mjs +0 -1
- package/payload/platform/scripts/setup-account.sh +2 -8
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +23 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +29 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +13 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +26 -2
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +12 -3
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +3 -2
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -2
- package/payload/platform/templates/specialists/agents/database-operator.md +2 -6
- package/payload/server/{chunk-M6A6EZD4.js → chunk-76HRO7NX.js} +16 -2
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +473 -28
- package/payload/platform/plugins/admin/hooks/session-end-retrospective.sh +0 -214
|
@@ -1,45 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Task
|
|
2
|
+
# Task 634 — on-demand `/insight` UserPromptSubmit hook test suite.
|
|
3
3
|
#
|
|
4
4
|
# Listener-mock pattern: a local Python HTTP server stands in for
|
|
5
5
|
# /api/admin/log-ingest and records every POST so the assertions can read
|
|
6
6
|
# every log line the hook emitted.
|
|
7
7
|
#
|
|
8
|
-
# Contract under test:
|
|
9
|
-
# -
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# -
|
|
14
|
-
#
|
|
8
|
+
# Contract under test (run-and-continue, no Stop gate):
|
|
9
|
+
# - Event is UserPromptSubmit. Trigger detection reads the `prompt` field
|
|
10
|
+
# of the stdin envelope, NOT the transcript. The token `/insight` is
|
|
11
|
+
# matched case-insensitively, as the whole message (after strip) OR as a
|
|
12
|
+
# standalone line — never embedded in prose.
|
|
13
|
+
# - On match: the four-pass instruction is printed to STDOUT (UserPromptSubmit
|
|
14
|
+
# stdout is injected as turn context), `trigger sessionId=<id> token=/insight`
|
|
15
|
+
# is emitted via log-ingest, exit 0. No stderr instruction, no exit 2.
|
|
16
|
+
# - Every gated-off / non-match path emits one `trigger-skipped reason=<r>`
|
|
17
|
+
# line and exits 0:
|
|
15
18
|
# role-not-admin | is-specialist | empty-stdin | missing-transcript |
|
|
16
|
-
# no-
|
|
17
|
-
# -
|
|
18
|
-
# `
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# `gate-blocked sessionId=<id> reason=sentinel-absent` emitted.
|
|
26
|
-
# - When the intent matches and the sentinel `tool_use` is present:
|
|
27
|
-
# exit 0, `gate-released sessionId=<id>` emitted.
|
|
28
|
-
# - Re-entry: a second Stop fired after the sentinel call still releases
|
|
29
|
-
# (the sentinel-grep is the re-entry guard).
|
|
30
|
-
# - Per-session scoping: a sentinel in a DIFFERENT session's JSONL does
|
|
31
|
-
# NOT release the active gate.
|
|
19
|
+
# no-insight-token
|
|
20
|
+
# - Standing reconciliation: on every invocation the hook scans the
|
|
21
|
+
# transcript (`transcript_path`) for the latest real-user turn whose text
|
|
22
|
+
# matches `/insight`; if no `session-retrospective-mark-complete` tool_use
|
|
23
|
+
# appears after that turn, it emits
|
|
24
|
+
# `prior-incomplete sessionId=<id> triggered-turn=<idx>`. A sentinel after
|
|
25
|
+
# the latest `/insight` turn suppresses the emit.
|
|
26
|
+
# - All log emissions go through POST /api/admin/log-ingest. The only stdout
|
|
27
|
+
# writer is the instruction block on the trigger path.
|
|
32
28
|
|
|
33
29
|
set -u
|
|
34
30
|
|
|
35
|
-
HOOK="$(cd "$(dirname "$0")/.." && pwd)/
|
|
31
|
+
HOOK="$(cd "$(dirname "$0")/.." && pwd)/insight.sh"
|
|
36
32
|
if [[ ! -x "$HOOK" ]]; then
|
|
37
33
|
echo "FAIL: $HOOK not executable" >&2
|
|
38
34
|
exit 1
|
|
39
35
|
fi
|
|
40
36
|
|
|
41
37
|
OP_ID='aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb'
|
|
42
|
-
OTHER_ID='99999999-7777-6666-5555-444444444444'
|
|
43
38
|
|
|
44
39
|
TMPFILES=()
|
|
45
40
|
LISTENER_PIDS=()
|
|
@@ -120,14 +115,11 @@ for raw in sys.stdin:
|
|
|
120
115
|
' || true
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
# Build a JSONL transcript from positional
|
|
124
|
-
#
|
|
125
|
-
# ""
|
|
126
|
-
# "tool_use:<NAME>"
|
|
127
|
-
#
|
|
128
|
-
# "tool_result" → user record carrying only a
|
|
129
|
-
# tool_result block (not a real
|
|
130
|
-
# user turn)
|
|
118
|
+
# Build a JSONL transcript from positional triples. Each triple is
|
|
119
|
+
# role|text|extra where extra is one of:
|
|
120
|
+
# "" → plain user/assistant text record
|
|
121
|
+
# "tool_use:<NAME>" → assistant record carrying a tool_use block
|
|
122
|
+
# "tool_result" → user record carrying only a tool_result block
|
|
131
123
|
write_transcript() {
|
|
132
124
|
local out="$1"; shift
|
|
133
125
|
: > "$out"
|
|
@@ -138,7 +130,7 @@ spec = sys.argv[2:]
|
|
|
138
130
|
with open(out, "w", encoding="utf-8") as f:
|
|
139
131
|
for entry in spec:
|
|
140
132
|
role, text, extra = entry.split("|", 2)
|
|
141
|
-
rec = {"type": role, "timestamp": "2026-
|
|
133
|
+
rec = {"type": role, "timestamp": "2026-06-05T10:00:00.000Z"}
|
|
142
134
|
if role == "user":
|
|
143
135
|
if extra == "tool_result":
|
|
144
136
|
rec["message"] = {
|
|
@@ -172,24 +164,33 @@ with open(out, "w", encoding="utf-8") as f:
|
|
|
172
164
|
PY
|
|
173
165
|
}
|
|
174
166
|
|
|
167
|
+
# UserPromptSubmit envelope: session_id, transcript_path, prompt, hook_event_name.
|
|
175
168
|
envelope_for() {
|
|
176
169
|
python3 -c '
|
|
177
170
|
import json, sys
|
|
178
|
-
print(json.dumps({
|
|
179
|
-
|
|
171
|
+
print(json.dumps({
|
|
172
|
+
"session_id": sys.argv[1],
|
|
173
|
+
"transcript_path": sys.argv[2],
|
|
174
|
+
"prompt": sys.argv[3],
|
|
175
|
+
"hook_event_name": "UserPromptSubmit",
|
|
176
|
+
}))
|
|
177
|
+
' "$1" "$2" "$3"
|
|
180
178
|
}
|
|
181
179
|
|
|
180
|
+
# A transcript with no prior /insight turn — used whenever the test is about
|
|
181
|
+
# trigger detection and reconciliation must stay silent.
|
|
182
|
+
NEUTRAL_TRANSCRIPT=$(mktemp); TMPFILES+=("$NEUTRAL_TRANSCRIPT")
|
|
183
|
+
|
|
182
184
|
# ---------------------------------------------------------------------------
|
|
183
185
|
# Case 1: role != admin → trigger-skipped reason=role-not-admin
|
|
184
186
|
# ---------------------------------------------------------------------------
|
|
185
187
|
start_listener
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
ENV_PUBLIC=$(envelope_for "$OP_ID" "$TRANSCRIPT_PUBLIC")
|
|
188
|
+
write_transcript "$NEUTRAL_TRANSCRIPT" "user|hello|" "assistant|hi|"
|
|
189
|
+
ENV_INSIGHT=$(envelope_for "$OP_ID" "$NEUTRAL_TRANSCRIPT" "/insight")
|
|
189
190
|
: > "$REQ_LOG"
|
|
190
|
-
run_hook "public" "" "$
|
|
191
|
+
run_hook "public" "" "$ENV_INSIGHT"
|
|
191
192
|
[[ "$HOOK_RC" -eq 0 ]] || fail "case-1 rc=$HOOK_RC"
|
|
192
|
-
[[ -z "$
|
|
193
|
+
[[ -z "$HOOK_STDOUT" ]] || fail "case-1 stdout must be empty, got: $HOOK_STDOUT"
|
|
193
194
|
if ingest_lines | grep -qE '^trigger-skipped sessionId=.* reason=role-not-admin$'; then
|
|
194
195
|
pass "case-1 role=public → trigger-skipped reason=role-not-admin"
|
|
195
196
|
else
|
|
@@ -200,9 +201,9 @@ fi
|
|
|
200
201
|
# Case 2: MAXY_SPECIALIST set → trigger-skipped is-specialist
|
|
201
202
|
# ---------------------------------------------------------------------------
|
|
202
203
|
: > "$REQ_LOG"
|
|
203
|
-
run_hook "admin" "database-operator" "$
|
|
204
|
+
run_hook "admin" "database-operator" "$ENV_INSIGHT"
|
|
204
205
|
[[ "$HOOK_RC" -eq 0 ]] || fail "case-2 rc=$HOOK_RC"
|
|
205
|
-
[[ -z "$
|
|
206
|
+
[[ -z "$HOOK_STDOUT" ]] || fail "case-2 stdout must be empty, got: $HOOK_STDOUT"
|
|
206
207
|
if ingest_lines | grep -qE '^trigger-skipped sessionId=.* reason=is-specialist specialist=database-operator$'; then
|
|
207
208
|
pass "case-2 specialist=database-operator → trigger-skipped is-specialist"
|
|
208
209
|
else
|
|
@@ -225,7 +226,7 @@ fi
|
|
|
225
226
|
# Case 4: missing transcript_path → trigger-skipped missing-transcript
|
|
226
227
|
# ---------------------------------------------------------------------------
|
|
227
228
|
: > "$REQ_LOG"
|
|
228
|
-
BAD_ENV=$(python3 -c 'import json,sys; print(json.dumps({"session_id": sys.argv[1]}))' "$OP_ID")
|
|
229
|
+
BAD_ENV=$(python3 -c 'import json,sys; print(json.dumps({"session_id": sys.argv[1], "prompt": "/insight"}))' "$OP_ID")
|
|
229
230
|
run_hook "admin" "" "$BAD_ENV"
|
|
230
231
|
[[ "$HOOK_RC" -eq 0 ]] || fail "case-4 rc=$HOOK_RC"
|
|
231
232
|
if ingest_lines | grep -qE "^trigger-skipped sessionId=${OP_ID} reason=missing-transcript$"; then
|
|
@@ -235,162 +236,160 @@ else
|
|
|
235
236
|
fi
|
|
236
237
|
|
|
237
238
|
# ---------------------------------------------------------------------------
|
|
238
|
-
# Case 5: no
|
|
239
|
+
# Case 5: prompt has no /insight token → trigger-skipped reason=no-insight-token
|
|
239
240
|
# ---------------------------------------------------------------------------
|
|
240
|
-
|
|
241
|
-
write_transcript "$TRANSCRIPT_BORING" \
|
|
242
|
-
"user|hello|" \
|
|
243
|
-
"assistant|hi|" \
|
|
244
|
-
"user|what's the weather|"
|
|
245
|
-
ENV_BORING=$(envelope_for "$OP_ID" "$TRANSCRIPT_BORING")
|
|
241
|
+
ENV_BORING=$(envelope_for "$OP_ID" "$NEUTRAL_TRANSCRIPT" "what's the weather today")
|
|
246
242
|
: > "$REQ_LOG"
|
|
247
243
|
run_hook "admin" "" "$ENV_BORING"
|
|
248
244
|
[[ "$HOOK_RC" -eq 0 ]] || fail "case-5 rc=$HOOK_RC"
|
|
249
|
-
[[ -z "$
|
|
250
|
-
if ingest_lines | grep -qE "^trigger-skipped sessionId=${OP_ID} reason=no-
|
|
251
|
-
pass "case-5 no
|
|
245
|
+
[[ -z "$HOOK_STDOUT" ]] || fail "case-5 stdout must be empty"
|
|
246
|
+
if ingest_lines | grep -qE "^trigger-skipped sessionId=${OP_ID} reason=no-insight-token$"; then
|
|
247
|
+
pass "case-5 no token → trigger-skipped reason=no-insight-token"
|
|
252
248
|
else
|
|
253
|
-
fail "case-5 expected no-
|
|
249
|
+
fail "case-5 expected no-insight-token, got: $(ingest_lines)"
|
|
254
250
|
fi
|
|
255
251
|
|
|
256
252
|
# ---------------------------------------------------------------------------
|
|
257
|
-
# Case 6:
|
|
253
|
+
# Case 6: prompt is exactly /insight → instruction on stdout, trigger logged
|
|
258
254
|
# ---------------------------------------------------------------------------
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if ! printf '%s' "$HOOK_STDERR" | grep -q "session-retrospective-mark-complete"; then
|
|
278
|
-
fail "case-6:${TOKEN} instruction block missing sentinel tool name on stderr"
|
|
279
|
-
continue
|
|
280
|
-
fi
|
|
281
|
-
if ! printf '%s' "$HOOK_STDERR" | grep -q "database-operator"; then
|
|
282
|
-
fail "case-6:${TOKEN} instruction block missing database-operator reference"
|
|
283
|
-
continue
|
|
284
|
-
fi
|
|
285
|
-
pass "case-6:${TOKEN} triggers gate-blocked exit 2 + instruction stderr"
|
|
286
|
-
done
|
|
255
|
+
: > "$REQ_LOG"
|
|
256
|
+
run_hook "admin" "" "$ENV_INSIGHT"
|
|
257
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-6 expected rc=0, got $HOOK_RC"
|
|
258
|
+
[[ -z "$HOOK_STDERR" ]] || fail "case-6 stderr must be empty (no exit-2 instruction path), got: $HOOK_STDERR"
|
|
259
|
+
if ! printf '%s' "$HOOK_STDOUT" | grep -q "session-retrospective-mark-complete"; then
|
|
260
|
+
fail "case-6 instruction (stdout) missing sentinel tool name"
|
|
261
|
+
fi
|
|
262
|
+
if ! printf '%s' "$HOOK_STDOUT" | grep -q "database-operator"; then
|
|
263
|
+
fail "case-6 instruction (stdout) missing database-operator reference"
|
|
264
|
+
fi
|
|
265
|
+
if ! printf '%s' "$HOOK_STDOUT" | grep -qi "keep going\|continue"; then
|
|
266
|
+
fail "case-6 instruction (stdout) missing run-and-continue wording"
|
|
267
|
+
fi
|
|
268
|
+
if ingest_lines | grep -qE "^trigger sessionId=${OP_ID} token=/insight$"; then
|
|
269
|
+
pass "case-6 /insight whole-message → instruction on stdout + trigger logged"
|
|
270
|
+
else
|
|
271
|
+
fail "case-6 expected trigger line, got: $(ingest_lines)"
|
|
272
|
+
fi
|
|
287
273
|
|
|
288
274
|
# ---------------------------------------------------------------------------
|
|
289
|
-
# Case 7:
|
|
275
|
+
# Case 7: /insight as a standalone line among other lines → triggers
|
|
290
276
|
# ---------------------------------------------------------------------------
|
|
291
|
-
|
|
292
|
-
write_transcript "$T_RELEASE" \
|
|
293
|
-
"user|hi|" \
|
|
294
|
-
"assistant|hello|" \
|
|
295
|
-
"user|/end|" \
|
|
296
|
-
"assistant|running retrospective|" \
|
|
297
|
-
"assistant||tool_use:mcp__admin__session-retrospective-mark-complete"
|
|
298
|
-
ENV_REL=$(envelope_for "$OP_ID" "$T_RELEASE")
|
|
277
|
+
ENV_LINE=$(envelope_for "$OP_ID" "$NEUTRAL_TRANSCRIPT" $'here is some context\n/insight\nthanks')
|
|
299
278
|
: > "$REQ_LOG"
|
|
300
|
-
run_hook "admin" "" "$
|
|
301
|
-
[[ "$HOOK_RC" -eq 0 ]] || fail "case-7
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
pass "case-7 sentinel present → gate-released exit 0"
|
|
279
|
+
run_hook "admin" "" "$ENV_LINE"
|
|
280
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-7 rc=$HOOK_RC"
|
|
281
|
+
if ingest_lines | grep -qE "^trigger sessionId=${OP_ID} token=/insight$"; then
|
|
282
|
+
pass "case-7 /insight standalone line → triggers"
|
|
305
283
|
else
|
|
306
|
-
fail "case-7 expected
|
|
284
|
+
fail "case-7 expected trigger, got: $(ingest_lines)"
|
|
307
285
|
fi
|
|
308
286
|
|
|
309
287
|
# ---------------------------------------------------------------------------
|
|
310
|
-
# Case 8:
|
|
288
|
+
# Case 8: case-insensitive — /INSIGHT triggers, logged as /insight
|
|
311
289
|
# ---------------------------------------------------------------------------
|
|
290
|
+
ENV_CASE=$(envelope_for "$OP_ID" "$NEUTRAL_TRANSCRIPT" "/INSIGHT")
|
|
312
291
|
: > "$REQ_LOG"
|
|
313
|
-
run_hook "admin" "" "$
|
|
314
|
-
[[ "$HOOK_RC" -eq 0 ]] || fail "case-8
|
|
315
|
-
if ingest_lines | grep -qE "^
|
|
316
|
-
pass "case-8
|
|
292
|
+
run_hook "admin" "" "$ENV_CASE"
|
|
293
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-8 rc=$HOOK_RC"
|
|
294
|
+
if ingest_lines | grep -qE "^trigger sessionId=${OP_ID} token=/insight$"; then
|
|
295
|
+
pass "case-8 case-insensitive: /INSIGHT normalises to /insight"
|
|
317
296
|
else
|
|
318
|
-
fail "case-8
|
|
297
|
+
fail "case-8 expected token=/insight, got: $(ingest_lines)"
|
|
319
298
|
fi
|
|
320
299
|
|
|
321
300
|
# ---------------------------------------------------------------------------
|
|
322
|
-
# Case 9:
|
|
323
|
-
# JSONL; active gate must NOT release
|
|
301
|
+
# Case 9: embedded prose does NOT trigger
|
|
324
302
|
# ---------------------------------------------------------------------------
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
303
|
+
ENV_PROSE=$(envelope_for "$OP_ID" "$NEUTRAL_TRANSCRIPT" "can you give me some /insight into the numbers")
|
|
304
|
+
: > "$REQ_LOG"
|
|
305
|
+
run_hook "admin" "" "$ENV_PROSE"
|
|
306
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-9 rc=$HOOK_RC"
|
|
307
|
+
[[ -z "$HOOK_STDOUT" ]] || fail "case-9 stdout must be empty (prose must not trigger)"
|
|
308
|
+
if ingest_lines | grep -qE "^trigger-skipped sessionId=${OP_ID} reason=no-insight-token$"; then
|
|
309
|
+
pass "case-9 embedded '/insight' prose does not trigger"
|
|
310
|
+
else
|
|
311
|
+
fail "case-9 expected no-insight-token, got: $(ingest_lines)"
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
# ---------------------------------------------------------------------------
|
|
315
|
+
# Case 10: reconciliation — prior /insight turn with NO sentinel after it →
|
|
316
|
+
# prior-incomplete emitted (and current non-token prompt skips)
|
|
317
|
+
# ---------------------------------------------------------------------------
|
|
318
|
+
T_INCOMPLETE=$(mktemp); TMPFILES+=("$T_INCOMPLETE")
|
|
319
|
+
write_transcript "$T_INCOMPLETE" \
|
|
320
|
+
"user|hi|" \
|
|
321
|
+
"assistant|hello|" \
|
|
322
|
+
"user|/insight|" \
|
|
323
|
+
"assistant|here is a prose summary|"
|
|
324
|
+
ENV_RECON=$(envelope_for "$OP_ID" "$T_INCOMPLETE" "what's next")
|
|
333
325
|
: > "$REQ_LOG"
|
|
334
|
-
run_hook "admin" "" "$
|
|
335
|
-
[[ "$HOOK_RC" -eq
|
|
336
|
-
if ingest_lines | grep -qE "^
|
|
337
|
-
|
|
326
|
+
run_hook "admin" "" "$ENV_RECON"
|
|
327
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-10 rc=$HOOK_RC"
|
|
328
|
+
if ! ingest_lines | grep -qE "^prior-incomplete sessionId=${OP_ID} triggered-turn=[0-9]+$"; then
|
|
329
|
+
fail "case-10 expected prior-incomplete, got: $(ingest_lines)"
|
|
330
|
+
elif ! ingest_lines | grep -qE "^trigger-skipped sessionId=${OP_ID} reason=no-insight-token$"; then
|
|
331
|
+
fail "case-10 expected current prompt skip, got: $(ingest_lines)"
|
|
338
332
|
else
|
|
339
|
-
|
|
333
|
+
pass "case-10 prior /insight without sentinel → prior-incomplete"
|
|
340
334
|
fi
|
|
341
335
|
|
|
342
336
|
# ---------------------------------------------------------------------------
|
|
343
|
-
# Case
|
|
344
|
-
#
|
|
337
|
+
# Case 11: reconciliation negative — prior /insight turn WITH a sentinel
|
|
338
|
+
# tool_use after it → no prior-incomplete
|
|
345
339
|
# ---------------------------------------------------------------------------
|
|
346
|
-
|
|
347
|
-
write_transcript "$
|
|
348
|
-
"user
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
|
|
340
|
+
T_COMPLETE=$(mktemp); TMPFILES+=("$T_COMPLETE")
|
|
341
|
+
write_transcript "$T_COMPLETE" \
|
|
342
|
+
"user|hi|" \
|
|
343
|
+
"user|/insight|" \
|
|
344
|
+
"assistant|running passes|" \
|
|
345
|
+
"assistant||tool_use:mcp__admin__session-retrospective-mark-complete"
|
|
346
|
+
ENV_DONE=$(envelope_for "$OP_ID" "$T_COMPLETE" "what's next")
|
|
352
347
|
: > "$REQ_LOG"
|
|
353
|
-
run_hook "admin" "" "$
|
|
354
|
-
[[ "$HOOK_RC" -eq
|
|
355
|
-
if ingest_lines | grep -qE "^
|
|
356
|
-
|
|
348
|
+
run_hook "admin" "" "$ENV_DONE"
|
|
349
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-11 rc=$HOOK_RC"
|
|
350
|
+
if ingest_lines | grep -qE "^prior-incomplete"; then
|
|
351
|
+
fail "case-11 sentinel present must suppress prior-incomplete, got: $(ingest_lines)"
|
|
357
352
|
else
|
|
358
|
-
|
|
353
|
+
pass "case-11 prior /insight with sentinel → no prior-incomplete"
|
|
359
354
|
fi
|
|
360
355
|
|
|
361
356
|
# ---------------------------------------------------------------------------
|
|
362
|
-
# Case
|
|
357
|
+
# Case 13: the just-submitted /insight turn is already in the transcript with
|
|
358
|
+
# no assistant response yet → must NOT self-report prior-incomplete.
|
|
359
|
+
# (Guards against the false positive if Claude Code writes the
|
|
360
|
+
# current prompt to the transcript before UserPromptSubmit fires.)
|
|
363
361
|
# ---------------------------------------------------------------------------
|
|
364
|
-
|
|
365
|
-
write_transcript "$
|
|
366
|
-
|
|
362
|
+
T_CURRENT=$(mktemp); TMPFILES+=("$T_CURRENT")
|
|
363
|
+
write_transcript "$T_CURRENT" \
|
|
364
|
+
"user|hi|" \
|
|
365
|
+
"assistant|hello|" \
|
|
366
|
+
"user|/insight|"
|
|
367
|
+
ENV_CURRENT=$(envelope_for "$OP_ID" "$T_CURRENT" "/insight")
|
|
367
368
|
: > "$REQ_LOG"
|
|
368
|
-
run_hook "admin" "" "$
|
|
369
|
-
[[ "$HOOK_RC" -eq 0 ]] || fail "case-
|
|
370
|
-
if ingest_lines | grep -qE "^
|
|
371
|
-
|
|
369
|
+
run_hook "admin" "" "$ENV_CURRENT"
|
|
370
|
+
[[ "$HOOK_RC" -eq 0 ]] || fail "case-13 rc=$HOOK_RC"
|
|
371
|
+
if ingest_lines | grep -qE "^prior-incomplete"; then
|
|
372
|
+
fail "case-13 current /insight turn must not self-report prior-incomplete, got: $(ingest_lines)"
|
|
373
|
+
elif ingest_lines | grep -qE "^trigger sessionId=${OP_ID} token=/insight$"; then
|
|
374
|
+
pass "case-13 current /insight (in transcript, no response yet) → trigger only, no prior-incomplete"
|
|
372
375
|
else
|
|
373
|
-
fail "case-
|
|
376
|
+
fail "case-13 expected trigger without prior-incomplete, got: $(ingest_lines)"
|
|
374
377
|
fi
|
|
375
378
|
|
|
376
379
|
# ---------------------------------------------------------------------------
|
|
377
|
-
# Case 12:
|
|
380
|
+
# Case 12: no path returns exit 2 — /insight must not block the turn
|
|
378
381
|
# ---------------------------------------------------------------------------
|
|
379
|
-
T_CASE=$(mktemp); TMPFILES+=("$T_CASE")
|
|
380
|
-
write_transcript "$T_CASE" "user|/END|"
|
|
381
|
-
ENV_CASE=$(envelope_for "$OP_ID" "$T_CASE")
|
|
382
382
|
: > "$REQ_LOG"
|
|
383
|
-
run_hook "admin" "" "$
|
|
384
|
-
[[ "$HOOK_RC" -eq 2 ]]
|
|
385
|
-
|
|
386
|
-
pass "case-12 case-insensitive: /END normalises to /end"
|
|
383
|
+
run_hook "admin" "" "$ENV_INSIGHT"
|
|
384
|
+
if [[ "$HOOK_RC" -eq 2 ]]; then
|
|
385
|
+
fail "case-12 hook must never exit 2 (run-and-continue), got rc=$HOOK_RC"
|
|
387
386
|
else
|
|
388
|
-
|
|
387
|
+
pass "case-12 trigger path exits 0, never 2"
|
|
389
388
|
fi
|
|
390
389
|
|
|
391
390
|
# ---------------------------------------------------------------------------
|
|
392
391
|
# Summary
|
|
393
392
|
# ---------------------------------------------------------------------------
|
|
394
393
|
echo
|
|
395
|
-
echo "
|
|
394
|
+
echo "insight tests: $PASS passed, $FAIL failed"
|
|
396
395
|
[[ "$FAIL" -eq 0 ]]
|