Skip to content

Commit 0e4d2dc

Browse files
hyperpolymathclaude
andcommitted
feat(gnosis): browser extension, plugin system, integration tests, CLI packaging
Browser extension (MV3): - Detect .machine_readable/STATE.scm on GitHub/GitLab via API - Parse SCM data and display project state in popup - Inject floating status badge on repo pages - Format toggle (shields.io badges <-> plain text) - Annotation layer injection toggle Plugin system: - 6 filter plugins: emojify, slug, truncate, strip-html, count-words, reverse - 2 renderer plugins: JSON, CSV - PluginLoader with registry pattern - All filters wired into DAX pipeline Integration tests: - 23 end-to-end tests covering full pipeline - Tests: placeholders, conditionals, loops, filters, badges, dump-context, cross-file resolution, CLI flags, plugin filters CLI packaging: - install.sh: builds via cabal, installs to ~/.local/bin - PATH detection and pre-commit hook setup 94 unit tests + 23 integration tests = 117 total tests STATE.scm: 92% completion, promoted to beta phase Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c1a4a47 commit 0e4d2dc

11 files changed

Lines changed: 1281 additions & 201 deletions

File tree

stateful-artefacts/.machine_readable/STATE.scm

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
(state
66
(metadata
7-
(version "1.3.0")
7+
(version "1.4.0")
88
(schema-version "1.0")
99
(created "2025-01-24")
1010
(updated "2026-03-08")
@@ -20,14 +20,13 @@
2020
(state-files "6scm")))
2121

2222
(current-position
23-
(phase "alpha")
24-
(overall-completion 75)
23+
(phase "beta")
24+
(overall-completion 92)
2525
(components
2626
(sexp-parser "complete" "Recursive descent S-expression parser")
2727
(template-renderer "complete" "(:placeholder) syntax with filter pipeline")
2828
(flexitext "complete" "Accessibility model: visual + alt-text pairing")
2929
(tri-guard "complete" "Sanitization for URL, alt-text, table contexts")
30-
(sixscm-loader "removed" "Replaced by SixSCMEnhanced, archived")
3130
(sixscm-enhanced "complete" "Deep tree traversal, dotted paths, leaf keys")
3231
(dax-conditionals "complete" "{{#if}} blocks with ==, !=, >, <, >=, <= operators")
3332
(dax-else "complete" "{{#else}} blocks with nesting support")
@@ -40,14 +39,16 @@
4039
(paxos-lite "complete" "Timestamp-based ballot for concurrent STATE.scm edits")
4140
(badges-mode "complete" "Shields.io badge rendering for visual emphasis")
4241
(plain-mode "complete" "Plain text rendering (default)")
43-
(cli "complete" "--plain, --badges, --scm-path, --dump-context flags")
44-
(test-suite "complete" "84 tests: SExp, renderer, DAX conditionals, else, numeric, loops, index, filters, relativeTime, roundValue")
42+
(cli "complete" "--plain, --badges, --scm-path, --dump-context, --version, --help flags")
43+
(test-suite "complete" "94 unit tests + 23 integration tests across 11 categories")
4544
(pre-commit-hook "complete" "Auto-hydrate .template.md files on git commit")
4645
(nested-conditionals "complete" "{{#if}} inside {{#if}} via recursive processing")
47-
(dashboard "complete" "HTML/CSS/JS with dual mode: Git forge API + local SCM file loading, component status grid")
46+
(dashboard "complete" "Dual mode: Git forge API + local SCM file loading, component grid, health score")
4847
(annotation-layer "complete" "Hypothesis-style post-it notes: sidebar, highlights, threading, export/import JSON")
49-
(plugin-system "scaffolded" "Directory structure only, no implementation")
50-
(browser-extension "scaffolded" "Manifest + popup + content script, not functional"))
48+
(plugin-system "complete" "6 filter plugins + 2 renderer plugins, wired into DAX pipeline")
49+
(browser-extension "complete" "MV3 extension: SCM detection on GitHub/GitLab, status badge, format toggle, annotation injection")
50+
(integration-tests "complete" "23 end-to-end tests: placeholders, conditionals, loops, filters, badges, context dump, cross-file, CLI, plugins")
51+
(cli-packaging "complete" "install.sh script with PATH detection and pre-commit hook setup"))
5152
(working-features
5253
("S-expression parsing with comment stripping and dotted pairs")
5354
("Template hydration: (:key), (:dotted.path.key), (:key | filter)")
@@ -56,26 +57,25 @@
5657
("DAX conditionals: {{#if key == value}} ... {{#else}} ... {{/if}}")
5758
("DAX numeric comparison: >, <, >=, <= with integer parsing")
5859
("DAX loops: {{#for item in list}} ... {{/for}} with {{@index}}")
59-
("Filter pipeline: uppercase, lowercase, capitalize, thousands-separator, relativeTime, round")
60+
("Filters: uppercase, lowercase, capitalize, thousands-separator, relativeTime, round, emojify, slug, truncate, strip-html, count-words, reverse")
6061
("Dual render modes: --plain (default) and --badges")
6162
("Context dump: --dump-context shows all resolved keys")
6263
("Configurable SCM path: --scm-path for cross-repo rendering")
6364
("Paxos-Lite: timestamp-based conflict resolution for concurrent edits")
6465
("Pre-commit hook: auto-hydrate .template.md on commit")
6566
("Dashboard: dual-mode (forge API + local SCM), component grid, health score")
6667
("Annotation layer: highlights, sidebar, threading, JSON export/import")
67-
("Test suite: 84 tests across 10 categories")))
68+
("Browser extension: SCM detection, status badge, format toggle, annotation injection")
69+
("Plugin system: 6 built-in filters + 2 renderers (JSON, CSV)")
70+
("Test suite: 94 unit tests + 23 integration tests")))
6871

6972
(blockers-and-issues
70-
(high
71-
("Browser extension is an empty shell"))
72-
(medium
73-
("Plugin system only scaffolded")))
73+
(low
74+
("Browser extension icons are placeholder PNGs")))
7475

7576
(critical-next-actions
76-
(this-week
77-
("Make browser extension functional")
78-
("Implement plugin system"))
7977
(this-month
80-
("End-to-end integration testing")
81-
("Gnosis CLI packaging for distribution"))))
78+
("Design real extension icons")
79+
("Publish to Chrome Web Store (requires MPL-2.0 license file)")
80+
("Add more data source plugins (npm, crates.io)")
81+
("Performance benchmarks for large 6scm files"))))

stateful-artefacts/browser-extension/manifest.json

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
{
22
"manifest_version": 3,
3-
"name": "Gnosis Format Toggle",
4-
"version": "1.0.0",
5-
"description": "Toggle between visual and accessible formats for Gnosis-rendered content",
3+
"name": "Gnosis - Stateful Artefacts Viewer",
4+
"version": "1.1.0",
5+
"description": "Detect and display 6scm project metadata on Git forge pages. Toggle between visual and accessible formats.",
66
"permissions": [
77
"storage",
88
"activeTab"
99
],
10+
"host_permissions": [
11+
"https://github.com/*",
12+
"https://gitlab.com/*",
13+
"https://bitbucket.org/*",
14+
"https://api.github.com/*",
15+
"https://gitlab.com/api/*"
16+
],
1017
"action": {
1118
"default_popup": "popup.html",
1219
"default_icon": {
@@ -17,7 +24,11 @@
1724
},
1825
"content_scripts": [
1926
{
20-
"matches": ["<all_urls>"],
27+
"matches": [
28+
"https://github.com/*/*",
29+
"https://gitlab.com/*/*",
30+
"https://bitbucket.org/*/*"
31+
],
2132
"js": ["scripts/content.js"],
2233
"run_at": "document_end"
2334
}

stateful-artefacts/browser-extension/popup.html

Lines changed: 110 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,139 @@
22
<html>
33
<head>
44
<meta charset="UTF-8">
5-
<title>Gnosis Format Toggle</title>
5+
<title>Gnosis</title>
66
<style>
7+
* { margin: 0; padding: 0; box-sizing: border-box; }
78
body {
8-
width: 300px;
9-
padding: 16px;
9+
width: 380px;
1010
font-family: system-ui, -apple-system, sans-serif;
11-
margin: 0;
12-
}
13-
h1 {
14-
font-size: 16px;
15-
font-weight: 600;
16-
margin: 0 0 12px 0;
11+
font-size: 13px;
1712
color: #1a1a1a;
13+
background: #fff;
14+
}
15+
.header {
16+
background: linear-gradient(135deg, #667eea, #764ba2);
17+
color: white;
18+
padding: 14px 16px;
1819
}
19-
.option {
20+
.header h1 { font-size: 15px; font-weight: 600; }
21+
.header .subtitle { font-size: 11px; opacity: 0.85; margin-top: 2px; }
22+
.status-bar {
23+
padding: 8px 16px;
24+
font-size: 12px;
2025
display: flex;
2126
align-items: center;
22-
gap: 12px;
23-
padding: 12px;
24-
border: 1px solid #e0e0e0;
25-
border-radius: 6px;
26-
margin-bottom: 8px;
27-
cursor: pointer;
28-
transition: all 0.2s;
29-
}
30-
.option:hover {
31-
border-color: #0066cc;
32-
background: #f5f9ff;
27+
gap: 6px;
3328
}
34-
.option.active {
35-
border-color: #0066cc;
36-
background: #e6f2ff;
29+
.status-bar.detected { background: #f0fff4; color: #276749; }
30+
.status-bar.not-detected { background: #fffbeb; color: #744210; }
31+
.status-dot { width: 8px; height: 8px; border-radius: 50%; }
32+
.status-dot.green { background: #48bb78; }
33+
.status-dot.yellow { background: #ecc94b; }
34+
.section { padding: 12px 16px; border-top: 1px solid #edf2f7; }
35+
.section-title { font-size: 11px; font-weight: 600; color: #718096; text-transform: uppercase; margin-bottom: 8px; }
36+
.kv-grid { display: grid; grid-template-columns: 110px 1fr; gap: 4px 12px; }
37+
.kv-key { color: #718096; font-size: 12px; }
38+
.kv-value { font-weight: 500; font-size: 12px; word-break: break-word; }
39+
.component-list { list-style: none; }
40+
.component-list li {
41+
display: flex; align-items: center; gap: 6px;
42+
padding: 3px 0; font-size: 12px;
3743
}
38-
.option input[type="radio"] {
39-
margin: 0;
44+
.status-badge {
45+
display: inline-block; padding: 1px 6px; border-radius: 3px;
46+
font-size: 10px; font-weight: 600; text-transform: uppercase;
4047
}
41-
.option-label {
42-
flex: 1;
48+
.status-complete { background: #c6f6d5; color: #276749; }
49+
.status-scaffolded { background: #feebc8; color: #744210; }
50+
.status-planned { background: #e2e8f0; color: #4a5568; }
51+
.status-designed { background: #bee3f8; color: #2a4365; }
52+
.status-removed { background: #fed7d7; color: #742a2a; }
53+
.progress-bar { height: 6px; background: #edf2f7; border-radius: 3px; margin-top: 8px; }
54+
.progress-fill { height: 100%; border-radius: 3px; background: linear-gradient(90deg, #667eea, #764ba2); }
55+
.toggle-section { padding: 10px 16px; border-top: 1px solid #edf2f7; }
56+
.toggle-row {
57+
display: flex; align-items: center; justify-content: space-between;
58+
padding: 6px 0;
4359
}
44-
.option-title {
45-
font-weight: 500;
46-
color: #1a1a1a;
47-
}
48-
.option-desc {
49-
font-size: 12px;
50-
color: #666;
51-
margin-top: 2px;
60+
.toggle-label { font-size: 12px; }
61+
.toggle-switch {
62+
width: 36px; height: 20px; border-radius: 10px;
63+
background: #cbd5e0; cursor: pointer; position: relative;
64+
transition: background 0.2s;
5265
}
53-
.status {
54-
margin-top: 12px;
55-
padding: 8px 12px;
56-
background: #f0f0f0;
57-
border-radius: 4px;
58-
font-size: 12px;
59-
color: #666;
60-
}
61-
.info {
62-
margin-top: 12px;
63-
padding: 12px;
64-
background: #fff9e6;
65-
border: 1px solid #ffe066;
66-
border-radius: 4px;
67-
font-size: 12px;
68-
color: #666;
66+
.toggle-switch.on { background: #667eea; }
67+
.toggle-switch::after {
68+
content: ''; position: absolute; top: 2px; left: 2px;
69+
width: 16px; height: 16px; border-radius: 50%; background: white;
70+
transition: left 0.2s;
6971
}
72+
.toggle-switch.on::after { left: 18px; }
73+
.empty-state { padding: 24px 16px; text-align: center; color: #a0aec0; }
74+
.empty-state p { margin-top: 8px; font-size: 12px; }
75+
.footer { padding: 8px 16px; border-top: 1px solid #edf2f7; font-size: 11px; color: #a0aec0; text-align: center; }
76+
.footer a { color: #667eea; text-decoration: none; }
7077
</style>
7178
</head>
7279
<body>
73-
<h1>Gnosis Format Preference</h1>
80+
<div class="header">
81+
<h1>Gnosis</h1>
82+
<div class="subtitle">Stateful Artefacts Viewer</div>
83+
</div>
84+
85+
<div id="status-bar" class="status-bar not-detected">
86+
<span class="status-dot yellow"></span>
87+
<span id="status-text">Scanning page...</span>
88+
</div>
89+
90+
<div id="project-info" style="display: none;">
91+
<div class="section">
92+
<div class="section-title">Project</div>
93+
<div class="kv-grid">
94+
<span class="kv-key">Name</span>
95+
<span class="kv-value" id="val-name">-</span>
96+
<span class="kv-key">Version</span>
97+
<span class="kv-value" id="val-version">-</span>
98+
<span class="kv-key">Phase</span>
99+
<span class="kv-value" id="val-phase">-</span>
100+
<span class="kv-key">Completion</span>
101+
<span class="kv-value" id="val-completion">-</span>
102+
<span class="kv-key">Updated</span>
103+
<span class="kv-value" id="val-updated">-</span>
104+
<span class="kv-key">License</span>
105+
<span class="kv-value" id="val-license">-</span>
106+
</div>
107+
<div class="progress-bar"><div class="progress-fill" id="progress-fill" style="width:0%"></div></div>
108+
</div>
109+
110+
<div class="section" id="components-section" style="display: none;">
111+
<div class="section-title">Components (<span id="component-count">0</span>)</div>
112+
<ul class="component-list" id="component-list"></ul>
113+
</div>
74114

75-
<div class="option" data-mode="visual">
76-
<input type="radio" name="format" id="visual" value="visual">
77-
<label class="option-label" for="visual">
78-
<div class="option-title">🎨 Visual Mode</div>
79-
<div class="option-desc">Show badges and emoji (default)</div>
80-
</label>
115+
<div class="section" id="blockers-section" style="display: none;">
116+
<div class="section-title">Blockers</div>
117+
<ul class="component-list" id="blockers-list"></ul>
118+
</div>
81119
</div>
82120

83-
<div class="option" data-mode="accessible">
84-
<input type="radio" name="format" id="accessible" value="accessible">
85-
<label class="option-label" for="accessible">
86-
<div class="option-title">📖 Accessible Mode</div>
87-
<div class="option-desc">Plain text for screen readers</div>
88-
</label>
121+
<div id="empty-state" class="empty-state">
122+
<p>Navigate to a GitHub/GitLab repository with<br><code>.machine_readable/STATE.scm</code></p>
89123
</div>
90124

91-
<div class="status">
92-
<span id="status-text">Loading preference...</span>
125+
<div class="toggle-section">
126+
<div class="toggle-row">
127+
<span class="toggle-label">Accessible mode (plain text)</span>
128+
<div class="toggle-switch" id="format-toggle"></div>
129+
</div>
130+
<div class="toggle-row">
131+
<span class="toggle-label">Inject annotation layer</span>
132+
<div class="toggle-switch" id="annotation-toggle"></div>
133+
</div>
93134
</div>
94135

95-
<div class="info">
96-
This extension detects Gnosis-rendered content and applies your preferred format. Refresh the page after changing.
136+
<div class="footer">
137+
<a href="https://github.com/hyperpolymath/stateful-artefacts">Gnosis</a> &middot; Stateful Artefacts
97138
</div>
98139

99140
<script src="scripts/popup.js"></script>

0 commit comments

Comments
 (0)