pantheon-opencode 1.0.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/AGENTS.md +37 -0
- package/LICENSE +21 -0
- package/README.md +1013 -0
- package/bin/pantheon-init.mjs +183 -0
- package/commands/pantheon-audit.md +25 -0
- package/commands/pantheon-bg.md +10 -0
- package/commands/pantheon-consolidate.md +11 -0
- package/commands/pantheon-deepwork.md +128 -0
- package/commands/pantheon-doc.md +10 -0
- package/commands/pantheon-focus.md +9 -0
- package/commands/pantheon-forget.md +58 -0
- package/commands/pantheon-hash.md +11 -0
- package/commands/pantheon-optimize.md +79 -0
- package/commands/pantheon-remember.md +44 -0
- package/commands/pantheon-search.md +48 -0
- package/commands/pantheon-status.md +71 -0
- package/commands/pantheon-todo.md +11 -0
- package/commands/pantheon.md +49 -0
- package/docs/AGENT-MCP.md +194 -0
- package/docs/ARCHITECTURE.md +384 -0
- package/docs/BRANCH-PROTECTION.md +142 -0
- package/docs/INDEX.md +81 -0
- package/docs/INSTALLATION.md +217 -0
- package/docs/MCP.md +238 -0
- package/docs/MEMORY.md +471 -0
- package/docs/MIGRATION-MEMORY-BANK.md +139 -0
- package/docs/PLATFORMS.md +5 -0
- package/docs/QUICKSTART.md +49 -0
- package/docs/README.md +18 -0
- package/docs/RELEASING.md +256 -0
- package/docs/SETUP.md +5 -0
- package/docs/UPGRADING.md +41 -0
- package/docs/mcp-recommendations.md +439 -0
- package/docs/mcp-tools.md +156 -0
- package/docs/mcp-user-guide.md +204 -0
- package/docs/persistence-mcp.md +111 -0
- package/package.json +72 -0
- package/pantheon.schema.json +158 -0
- package/scripts/__init__.py +0 -0
- package/scripts/_pantheon_paths.py +68 -0
- package/scripts/check-version-consistency.sh +23 -0
- package/scripts/code_mode_server.py +202 -0
- package/scripts/doctor.mjs +763 -0
- package/scripts/generate-prompts.sh +222 -0
- package/scripts/generate-routing-docs.mjs +104 -0
- package/scripts/hash_verify.py +192 -0
- package/scripts/init-pantheon-mcp.sh +118 -0
- package/scripts/install/agents-md.mjs +214 -0
- package/scripts/install/health-check.mjs +196 -0
- package/scripts/install/migrate.mjs +209 -0
- package/scripts/install/opencode.mjs +645 -0
- package/scripts/install/shared.mjs +655 -0
- package/scripts/install/venv.mjs +116 -0
- package/scripts/install-mcp.mjs +885 -0
- package/scripts/install.mjs +26 -0
- package/scripts/manifest.mjs +622 -0
- package/scripts/mcp_persistence_server.py +459 -0
- package/scripts/mcp_resources_server.py +206 -0
- package/scripts/memory_cache.py +78 -0
- package/scripts/memory_mcp_server.py +605 -0
- package/scripts/paths.py +64 -0
- package/scripts/prune_context.py +72 -0
- package/scripts/release-bundle.mjs +109 -0
- package/scripts/scrub-secrets.py +282 -0
- package/scripts/scrub_secrets.py +281 -0
- package/scripts/test-context-compression.sh +166 -0
- package/scripts/themis_heuristic_scan.py +287 -0
- package/scripts/todo_enforcer.py +242 -0
- package/scripts/uninstall.mjs +1057 -0
- package/scripts/validate-routing.mjs +160 -0
- package/scripts/validate_agent_frontmatter.py +226 -0
- package/scripts/versioning.mjs +254 -0
- package/skills-lock.json +16 -0
- package/src/agents/aphrodite.md +162 -0
- package/src/agents/apollo.md +109 -0
- package/src/agents/athena.md +226 -0
- package/src/agents/demeter.md +146 -0
- package/src/agents/gaia.md +82 -0
- package/src/agents/hephaestus.md +105 -0
- package/src/agents/hermes.md +302 -0
- package/src/agents/iris.md +99 -0
- package/src/agents/mnemosyne.md +226 -0
- package/src/agents/nyx.md +87 -0
- package/src/agents/prometheus.md +199 -0
- package/src/agents/talos.md +93 -0
- package/src/agents/themis.md +187 -0
- package/src/agents/zeus.md +209 -0
- package/src/instructions/agent-return-format.instructions.md +26 -0
- package/src/instructions/backend-standards.instructions.md +45 -0
- package/src/instructions/documentation-standards.instructions.md +53 -0
- package/src/instructions/frontend-standards.instructions.md +46 -0
- package/src/instructions/memory-protocol.instructions.md +67 -0
- package/src/instructions/yagni.instructions.md +21 -0
- package/src/instructions/zeus-anti-stall.instructions.md +72 -0
- package/src/instructions/zeus-communication-rules.instructions.md +15 -0
- package/src/instructions/zeus-council-synthesis.instructions.md +105 -0
- package/src/instructions/zeus-timeout-retry.instructions.md +127 -0
- package/src/mcp/_pantheon_paths.py +67 -0
- package/src/mcp/code_mode_server.py +202 -0
- package/src/mcp/init-pantheon-mcp.sh +118 -0
- package/src/mcp/install-mcp.mjs +885 -0
- package/src/mcp/mcp_persistence_server.py +458 -0
- package/src/mcp/mcp_resources_server.py +205 -0
- package/src/mcp/memory_mcp_server.py +604 -0
- package/src/mcp/requirements-mcp-core.txt +5 -0
- package/src/mcp/requirements-mcp.txt +5 -0
- package/src/plugin.ts +19 -0
- package/src/plugins/tui/dist/tui.js +143 -0
- package/src/plugins/tui/dist/tui.tsx +144 -0
- package/src/plugins/tui/package.json +32 -0
- package/src/plugins/tui/src/index.tsx +144 -0
- package/src/plugins/tui/tsdown.config.ts +22 -0
- package/src/routing.yml +499 -0
- package/src/skills/README.md +230 -0
- package/src/skills/agent-coordination/SKILL.md +95 -0
- package/src/skills/artifact-management/SKILL.md +118 -0
- package/src/skills/auto-continue/SKILL.md +280 -0
- package/src/skills/code-review-checklist/SKILL.md +139 -0
- package/src/skills/context-compression/SKILL.md +861 -0
- package/src/skills/git-workflow-and-versioning/SKILL.md +32 -0
- package/src/skills/incremental-implementation/SKILL.md +27 -0
- package/src/skills/memory-bank/SKILL.md +165 -0
- package/src/skills/orchestration-workflow/SKILL.md +311 -0
- package/src/skills/security-hardening/SKILL.md +36 -0
- package/src/skills/session-goal/SKILL.md +138 -0
- package/src/skills/spec-driven-development/SKILL.md +23 -0
- package/src/skills/tdd-with-agents/SKILL.md +170 -0
- package/src/skills/visual-review-pipeline/SKILL.md +200 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
scrub-secrets.py — Credential scrubber for Memory Bank promotions.
|
|
4
|
+
|
|
5
|
+
Scrubs credentials, tokens, and secrets from text before promoting it
|
|
6
|
+
to permanent memory bank files. Uses Python 3.9+ stdlib only.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 scripts/scrub-secrets.py --file path/to/file
|
|
10
|
+
# scrub in-place (with .bak backup)
|
|
11
|
+
python3 scripts/scrub-secrets.py --stdin
|
|
12
|
+
# read stdin, write scrubbed to stdout
|
|
13
|
+
python3 scripts/scrub-secrets.py --audit path/to/file
|
|
14
|
+
# only report, don't modify
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import sys
|
|
23
|
+
from re import Match
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Pattern definitions — order matters (private keys first to catch multi-line)
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _make_redactor(pattern: str, replacement: str) -> tuple[re.Pattern, str]:
|
|
31
|
+
"""Compile a pattern with DOTALL for multi-line."""
|
|
32
|
+
return (re.compile(pattern, re.DOTALL), replacement)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
REDACTORS: list[tuple[re.Pattern, str]] = [
|
|
36
|
+
# SSH private keys (multi-line, before generic private key)
|
|
37
|
+
_make_redactor(
|
|
38
|
+
r"-----BEGIN\s+OPENSSH\s+PRIVATE\s+KEY-----"
|
|
39
|
+
r".*?-----END\s+OPENSSH\s+PRIVATE\s+KEY-----",
|
|
40
|
+
"[SSH PRIVATE KEY REDACTED]",
|
|
41
|
+
),
|
|
42
|
+
# Private keys (multi-line, must run before Bearer/JWT)
|
|
43
|
+
_make_redactor(
|
|
44
|
+
r"-----BEGIN\s+.*?PRIVATE\s+KEY-----"
|
|
45
|
+
r".*?-----END\s+.*?PRIVATE\s+KEY-----",
|
|
46
|
+
"[PRIVATE KEY REDACTED]",
|
|
47
|
+
),
|
|
48
|
+
# Certificates (multi-line)
|
|
49
|
+
_make_redactor(
|
|
50
|
+
r"-----BEGIN\s+CERTIFICATE-----"
|
|
51
|
+
r".*?-----END\s+CERTIFICATE-----",
|
|
52
|
+
"[CERTIFICATE REDACTED]",
|
|
53
|
+
),
|
|
54
|
+
# Bearer tokens
|
|
55
|
+
_make_redactor(
|
|
56
|
+
r"Bearer\s+[A-Za-z0-9\-._~+/]+=*",
|
|
57
|
+
"Bearer [REDACTED]",
|
|
58
|
+
),
|
|
59
|
+
# JWTs
|
|
60
|
+
_make_redactor(
|
|
61
|
+
r"eyJ[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+",
|
|
62
|
+
"[JWT REDACTED]",
|
|
63
|
+
),
|
|
64
|
+
# GitHub PATs
|
|
65
|
+
_make_redactor(
|
|
66
|
+
r"ghp_[A-Za-z0-9]{36}",
|
|
67
|
+
"[GITHUB TOKEN REDACTED]",
|
|
68
|
+
),
|
|
69
|
+
# OpenAI keys
|
|
70
|
+
_make_redactor(
|
|
71
|
+
r"sk-[A-Za-z0-9\-_]{10,}",
|
|
72
|
+
"[OPENAI KEY REDACTED]",
|
|
73
|
+
),
|
|
74
|
+
# API keys (api_key, api-key, apikey)
|
|
75
|
+
_make_redactor(
|
|
76
|
+
r"(api[_-]?key|apikey)\s*[=:]\s*['\"]?[A-Za-z0-9\-_]{8,}",
|
|
77
|
+
r"\1=[REDACTED]",
|
|
78
|
+
),
|
|
79
|
+
# Passwords / tokens / secrets
|
|
80
|
+
_make_redactor(
|
|
81
|
+
r"(token|secret|password)\s*[=:]\s*['\"]?[A-Za-z0-9\-_]{8,}",
|
|
82
|
+
r"\1=[REDACTED]",
|
|
83
|
+
),
|
|
84
|
+
# AWS Access Keys
|
|
85
|
+
_make_redactor(
|
|
86
|
+
r"AKIA[0-9A-Z]{16}",
|
|
87
|
+
"[AWS KEY REDACTED]",
|
|
88
|
+
),
|
|
89
|
+
# Google API Keys
|
|
90
|
+
_make_redactor(
|
|
91
|
+
r"AIza[0-9A-Za-z\-_]{35}",
|
|
92
|
+
"[GOOGLE API KEY REDACTED]",
|
|
93
|
+
),
|
|
94
|
+
# Slack tokens
|
|
95
|
+
_make_redactor(
|
|
96
|
+
r"xox[baprs]-[0-9a-zA-Z-]{20,}",
|
|
97
|
+
"[SLACK TOKEN REDACTED]",
|
|
98
|
+
),
|
|
99
|
+
# Heroku API Keys (UUID format)
|
|
100
|
+
_make_redactor(
|
|
101
|
+
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
|
102
|
+
"[HEROKU API KEY REDACTED]",
|
|
103
|
+
),
|
|
104
|
+
# Database connection strings (non-greedy to prevent over-matching)
|
|
105
|
+
_make_redactor(
|
|
106
|
+
r"postgresql\+?:\/\/.*?:.*?@",
|
|
107
|
+
"[POSTGRESQL CONNECTION REDACTED]",
|
|
108
|
+
),
|
|
109
|
+
_make_redactor(
|
|
110
|
+
r"mysql\+?:\/\/.*?:.*?@",
|
|
111
|
+
"[MYSQL CONNECTION REDACTED]",
|
|
112
|
+
),
|
|
113
|
+
_make_redactor(
|
|
114
|
+
r"redis\+?:\/\/.*?:.*?@",
|
|
115
|
+
"[REDIS CONNECTION REDACTED]",
|
|
116
|
+
),
|
|
117
|
+
# .env export statements
|
|
118
|
+
_make_redactor(
|
|
119
|
+
r"export\s+\w+=['\"]?\S+",
|
|
120
|
+
"[ENV EXPORT REDACTED]",
|
|
121
|
+
),
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
# Classification dispatch: prefix → label
|
|
125
|
+
_CLASSIFIERS: list[tuple[str, str]] = [
|
|
126
|
+
("-----BEGIN OPENSSH", "ssh_private_key"),
|
|
127
|
+
("-----BEGIN CERTIFICATE", "certificate"),
|
|
128
|
+
("-----BEGIN", "private_key"),
|
|
129
|
+
("Bearer ", "bearer_token"),
|
|
130
|
+
("eyJ", "jwt"),
|
|
131
|
+
("ghp_", "github_pat"),
|
|
132
|
+
("sk-", "openai_key"),
|
|
133
|
+
("xox", "slack_token"),
|
|
134
|
+
("AKIA", "aws_key"),
|
|
135
|
+
("AIza", "google_api_key"),
|
|
136
|
+
("postgresql://", "postgresql_conn"),
|
|
137
|
+
("mysql://", "mysql_conn"),
|
|
138
|
+
("redis://", "redis_conn"),
|
|
139
|
+
("export ", "env_export"),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _classify_match(matched: str) -> str:
|
|
144
|
+
"""Return a human-readable label for a matched secret."""
|
|
145
|
+
for prefix, label in _CLASSIFIERS:
|
|
146
|
+
if matched.startswith(prefix):
|
|
147
|
+
return label
|
|
148
|
+
if re.match(r"api[_-]?key|apikey", matched, re.IGNORECASE):
|
|
149
|
+
return "api_key"
|
|
150
|
+
if re.match(r"(token|secret|password)\s*=", matched, re.IGNORECASE):
|
|
151
|
+
return "credential"
|
|
152
|
+
if re.match(
|
|
153
|
+
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
|
154
|
+
matched,
|
|
155
|
+
):
|
|
156
|
+
return "heroku_uuid"
|
|
157
|
+
return "unknown_secret"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def scrub(content: str) -> tuple[str, list[dict]]:
|
|
161
|
+
"""Scrub secrets from *content*.
|
|
162
|
+
|
|
163
|
+
Returns (scrubbed_content, redactions) where each redaction dict has:
|
|
164
|
+
type — human-readable label for the matched secret
|
|
165
|
+
position — (start, end) tuple of character offsets in original
|
|
166
|
+
replacement — what the secret was replaced with
|
|
167
|
+
|
|
168
|
+
Each redactor runs independently so every match in the input is
|
|
169
|
+
captured exactly once. Overlapping matches across *different* patterns
|
|
170
|
+
are possible but extremely unlikely given the pattern design.
|
|
171
|
+
"""
|
|
172
|
+
redactions: list[dict] = []
|
|
173
|
+
scrubbed = content
|
|
174
|
+
|
|
175
|
+
for pattern, replacement in REDACTORS:
|
|
176
|
+
# Walk matches in reverse offset order so replacements don't shift
|
|
177
|
+
# positions of yet-unreplaced matches.
|
|
178
|
+
matches: list[Match] = list(pattern.finditer(scrubbed))
|
|
179
|
+
for m in reversed(matches):
|
|
180
|
+
start, end = m.start(), m.end()
|
|
181
|
+
matched_text = m.group(0)
|
|
182
|
+
resolved = m.expand(replacement) if "\\" in replacement else replacement
|
|
183
|
+
|
|
184
|
+
redactions.append(
|
|
185
|
+
{
|
|
186
|
+
"type": _classify_match(matched_text),
|
|
187
|
+
"position": (start, end),
|
|
188
|
+
"replacement": resolved,
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
scrubbed = scrubbed[:start] + resolved + scrubbed[end:]
|
|
192
|
+
|
|
193
|
+
# Restore original order (positional, ascending)
|
|
194
|
+
redactions.reverse()
|
|
195
|
+
return scrubbed, redactions
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
# CLI
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _audit(path: str) -> None:
|
|
204
|
+
"""Print what would be redacted without modifying the file."""
|
|
205
|
+
with open(path, encoding="utf-8") as fh:
|
|
206
|
+
content = fh.read()
|
|
207
|
+
_, redactions = scrub(content)
|
|
208
|
+
if not redactions:
|
|
209
|
+
print(f"[OK] {path}: no secrets found")
|
|
210
|
+
return
|
|
211
|
+
print(f"[SCAN] {path}: {len(redactions)} potential secret(s) found:")
|
|
212
|
+
for r in redactions:
|
|
213
|
+
print(f" [{r['type']}] at {r['position']} -> {r['replacement']}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _scrub_file(path: str) -> None:
|
|
217
|
+
"""Scrub file in-place, creating a .bak backup."""
|
|
218
|
+
with open(path, encoding="utf-8") as fh:
|
|
219
|
+
content = fh.read()
|
|
220
|
+
scrubbed, redactions = scrub(content)
|
|
221
|
+
if not redactions:
|
|
222
|
+
print(f"[OK] {path}: no secrets found, file unchanged")
|
|
223
|
+
return
|
|
224
|
+
# Write backup
|
|
225
|
+
bak = path + ".bak"
|
|
226
|
+
if not os.path.exists(bak):
|
|
227
|
+
os.rename(path, bak)
|
|
228
|
+
else:
|
|
229
|
+
print(f"[WARN] {bak} already exists, skipping backup")
|
|
230
|
+
with open(path, "w", encoding="utf-8") as fh:
|
|
231
|
+
fh.write(scrubbed)
|
|
232
|
+
print(
|
|
233
|
+
f"[SECURE] {path}: {len(redactions)} secret(s) redacted "
|
|
234
|
+
f"({' + '.join(r['type'] for r in redactions)})"
|
|
235
|
+
)
|
|
236
|
+
print(f" Backup: {bak}")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _scrub_stdin() -> None:
|
|
240
|
+
"""Read stdin, write scrubbed output to stdout."""
|
|
241
|
+
content = sys.stdin.read()
|
|
242
|
+
scrubbed, redactions = scrub(content)
|
|
243
|
+
for r in redactions:
|
|
244
|
+
print(f" [REDACTED {r['type']}]", file=sys.stderr)
|
|
245
|
+
sys.stdout.write(scrubbed)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def main() -> None:
|
|
249
|
+
parser = argparse.ArgumentParser(
|
|
250
|
+
description="Scrub secrets from text before promoting to "
|
|
251
|
+
"permanent memory bank files.",
|
|
252
|
+
)
|
|
253
|
+
group = parser.add_mutually_exclusive_group(required=True)
|
|
254
|
+
group.add_argument(
|
|
255
|
+
"--file",
|
|
256
|
+
type=str,
|
|
257
|
+
help="Scrub file in-place (with .bak backup)",
|
|
258
|
+
)
|
|
259
|
+
group.add_argument(
|
|
260
|
+
"--stdin",
|
|
261
|
+
action="store_true",
|
|
262
|
+
help="Read stdin, write scrubbed to stdout",
|
|
263
|
+
)
|
|
264
|
+
group.add_argument(
|
|
265
|
+
"--audit",
|
|
266
|
+
type=str,
|
|
267
|
+
help="Only report what would be redacted",
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
args = parser.parse_args()
|
|
271
|
+
|
|
272
|
+
if args.file:
|
|
273
|
+
_scrub_file(args.file)
|
|
274
|
+
elif args.stdin:
|
|
275
|
+
_scrub_stdin()
|
|
276
|
+
elif args.audit:
|
|
277
|
+
_audit(args.audit)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
if __name__ == "__main__":
|
|
281
|
+
main()
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Test: Context Compression Pipeline
|
|
3
|
+
# Simulates Themis APPROVED → triggers compress_context handoff
|
|
4
|
+
#
|
|
5
|
+
# Usage: bash scripts/test-context-compression.sh
|
|
6
|
+
#
|
|
7
|
+
# This script validates the prerequisites for the Level 2 context compression
|
|
8
|
+
# pipeline and creates mock artifacts for end-to-end testing.
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
echo "=== Context Compression Test ==="
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
# Step 1: Verify prerequisites
|
|
16
|
+
echo "[1/4] Checking prerequisites..."
|
|
17
|
+
errors=0
|
|
18
|
+
|
|
19
|
+
test -f skills/context-compression/SKILL.md || { echo " ❌ SKILL.md not found"; errors=$((errors + 1)); }
|
|
20
|
+
test -f agents/mnemosyne.agent.md || { echo " ❌ mnemosyne.agent.md not found"; errors=$((errors + 1)); }
|
|
21
|
+
test -f agents/zeus.agent.md || { echo " ❌ zeus.agent.md not found"; errors=$((errors + 1)); }
|
|
22
|
+
test -f routing.yml || { echo " ❌ routing.yml not found"; errors=$((errors + 1)); }
|
|
23
|
+
test -f skills/artifact-management/SKILL.md || { echo " ❌ artifact-protocol.instructions.md not found"; errors=$((errors + 1)); }
|
|
24
|
+
test -f .pantheon/memory-bank/01-active-context.md || { echo " ❌ active-context.md not found"; errors=$((errors + 1)); }
|
|
25
|
+
test -d .pantheon/memory-bank/.tmp || mkdir -p .pantheon/memory-bank/.tmp
|
|
26
|
+
|
|
27
|
+
if [ -f scripts/scrub-secrets.py ]; then
|
|
28
|
+
echo " ✅ scrub-secrets.py found (217 lines, $(grep -c 'def ' scripts/scrub-secrets.py || echo 0) functions)"
|
|
29
|
+
else
|
|
30
|
+
echo " ⚠️ scrub-secrets.py not found (will skip scrubbing)"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Verify compress_context handoff in routing.yml
|
|
34
|
+
if grep -q "compress_context" routing.yml; then
|
|
35
|
+
HANDOFF_LINE=$(grep -n "compress_context" routing.yml | head -1 | cut -d: -f1)
|
|
36
|
+
echo " ✅ compress_context handoff found in routing.yml at line $HANDOFF_LINE"
|
|
37
|
+
else
|
|
38
|
+
echo " ❌ compress_context handoff missing from routing.yml"
|
|
39
|
+
errors=$((errors + 1))
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Verify ZZ artifact mention in artifact-protocol
|
|
43
|
+
if grep -q "ZZ-phase" skills/artifact-management/SKILL.md; then
|
|
44
|
+
echo " ✅ ZZ artifact format documented in artifact-protocol.instructions.md"
|
|
45
|
+
else
|
|
46
|
+
echo " ❌ ZZ artifact format missing from artifact-protocol.instructions.md"
|
|
47
|
+
errors=$((errors + 1))
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Verify context-compression trigger was added to zeus.agent.md
|
|
51
|
+
if grep -q "Context Compression Trigger" agents/zeus.agent.md; then
|
|
52
|
+
echo " ✅ Context Compression Trigger section present in zeus.agent.md"
|
|
53
|
+
else
|
|
54
|
+
echo " ⚠️ Context Compression Trigger section not yet in zeus.agent.md"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [ "$errors" -gt 0 ]; then
|
|
58
|
+
echo " ❌ $errors prerequisite(s) missing — aborting"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
echo " ✅ All prerequisites met"
|
|
62
|
+
echo ""
|
|
63
|
+
|
|
64
|
+
# Step 2: Create a mock IMPL artifact for testing
|
|
65
|
+
echo "[2/4] Creating mock IMPL artifact..."
|
|
66
|
+
|
|
67
|
+
cat > .pantheon/memory-bank/.tmp/IMPL-test-phase-hermes.md << 'ARTIFACT'
|
|
68
|
+
# IMPL-test-phase-hermes
|
|
69
|
+
**Date:** 2026-06-26 **Status:** Awaiting Compression Test
|
|
70
|
+
|
|
71
|
+
## What Was Implemented
|
|
72
|
+
- test/file.py — mock implementation for compression test
|
|
73
|
+
- test/schema.py — mock schema migration for priority scoring test
|
|
74
|
+
|
|
75
|
+
## Tests
|
|
76
|
+
- ✅ 5 tests passing / Coverage: 87%
|
|
77
|
+
|
|
78
|
+
## Notes for Themis
|
|
79
|
+
This is a test artifact to validate the compression pipeline end-to-end.
|
|
80
|
+
ARTIFACT
|
|
81
|
+
|
|
82
|
+
cat > .pantheon/memory-bank/.tmp/IMPL-test-phase-demeter.md << 'ARTIFACT'
|
|
83
|
+
# IMPL-test-phase-demeter
|
|
84
|
+
**Date:** 2026-06-26 **Status:** Awaiting Compression Test
|
|
85
|
+
|
|
86
|
+
## What Was Implemented
|
|
87
|
+
- backend/migrations/0013_add_refresh_tokens.py — new refresh_tokens table
|
|
88
|
+
- backend/models/token.py — Token model with FK to users
|
|
89
|
+
|
|
90
|
+
## Tests
|
|
91
|
+
- ✅ Migration tested: upgrade + downgrade both verified
|
|
92
|
+
|
|
93
|
+
## Notes for Themis
|
|
94
|
+
New table: refresh_tokens with (user_id, token_hash, expires_at, revoked_at)
|
|
95
|
+
ARTIFACT
|
|
96
|
+
|
|
97
|
+
echo " ✅ 2 mock artifacts created (hermes + demeter)"
|
|
98
|
+
echo ""
|
|
99
|
+
|
|
100
|
+
# Step 3: Create mock subtask_summary for compression
|
|
101
|
+
echo "[3/4] Creating mock subtask summaries..."
|
|
102
|
+
|
|
103
|
+
cat > .pantheon/memory-bank/.tmp/subtask-hermes.json << 'JSON'
|
|
104
|
+
{
|
|
105
|
+
"files_changed": ["test/file.py", "test/schema.py"],
|
|
106
|
+
"summary": "Added JWT auth endpoint with refresh token rotation",
|
|
107
|
+
"tests": "✅ All passing",
|
|
108
|
+
"coverage": "87%",
|
|
109
|
+
"status": "complete",
|
|
110
|
+
"blockers": null
|
|
111
|
+
}
|
|
112
|
+
JSON
|
|
113
|
+
|
|
114
|
+
cat > .pantheon/memory-bank/.tmp/subtask-demeter.json << 'JSON'
|
|
115
|
+
{
|
|
116
|
+
"files_changed": ["backend/migrations/0013_add_refresh_tokens.py", "backend/models/token.py"],
|
|
117
|
+
"summary": "Created refresh_tokens table with FK to users, hashed token, expires_at, revoked_at",
|
|
118
|
+
"tests": "✅ Migration upgrade + downgrade verified",
|
|
119
|
+
"coverage": "100%",
|
|
120
|
+
"status": "complete",
|
|
121
|
+
"blockers": null
|
|
122
|
+
}
|
|
123
|
+
JSON
|
|
124
|
+
|
|
125
|
+
echo " ✅ 2 mock subtask summaries created"
|
|
126
|
+
echo ""
|
|
127
|
+
|
|
128
|
+
# Step 4: Verify .tmp structure is writable and correct
|
|
129
|
+
echo "[4/4] Verifying .tmp structure..."
|
|
130
|
+
ls -la .pantheon/memory-bank/.tmp/
|
|
131
|
+
echo ""
|
|
132
|
+
echo " ✅ .tmp structure looks correct"
|
|
133
|
+
echo ""
|
|
134
|
+
|
|
135
|
+
# Step 5: Validate scrub-secrets.py works
|
|
136
|
+
echo "[5/4] Testing scrub-secrets.py (bonus)..."
|
|
137
|
+
if [ -f scripts/scrub-secrets.py ]; then
|
|
138
|
+
# Test with a simple secret
|
|
139
|
+
SECRET_TEST=$(echo "Bearer my-test-token-12345" | python3 scripts/scrub-secrets.py --stdin 2>/dev/null)
|
|
140
|
+
if echo "$SECRET_TEST" | grep -q "REDACTED"; then
|
|
141
|
+
echo " ✅ scrub-secrets.py: secret detection working"
|
|
142
|
+
else
|
|
143
|
+
echo " ⚠️ scrub-secrets.py: did not detect test secret (may need different pattern)"
|
|
144
|
+
fi
|
|
145
|
+
fi
|
|
146
|
+
echo ""
|
|
147
|
+
|
|
148
|
+
echo "=== Test Complete ==="
|
|
149
|
+
echo ""
|
|
150
|
+
echo "Mock artifacts ready for compression pipeline test."
|
|
151
|
+
echo ""
|
|
152
|
+
echo "Next manual step: Trigger compress_context handoff:"
|
|
153
|
+
echo " @mnemosyne Run compression pipeline with test artifacts"
|
|
154
|
+
echo ""
|
|
155
|
+
echo "Expected output:"
|
|
156
|
+
echo " - .pantheon/memory-bank/.tmp/ZZ-test-context.md"
|
|
157
|
+
echo " - Updated 01-active-context.md with compressed entries"
|
|
158
|
+
echo " - Updated 02-progress-log.md with archived mock artifact"
|
|
159
|
+
echo ""
|
|
160
|
+
echo "Scoring verification (expected):"
|
|
161
|
+
echo " - subtask-hermes.json: JWT + endpoint + token keywords → HIGH (score ~0.71)"
|
|
162
|
+
echo " - subtask-demeter.json: migration + new table + FK keywords → CRITICAL (score ~0.83)"
|
|
163
|
+
echo ""
|
|
164
|
+
echo "To clean up test artifacts:"
|
|
165
|
+
echo " rm .pantheon/memory-bank/.tmp/IMPL-test-phase-*.md"
|
|
166
|
+
echo " rm .pantheon/memory-bank/.tmp/subtask-*.json"
|