toga-ai 1.0.178 → 1.0.180

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.
@@ -141,3 +141,7 @@ parallel but separate `_Worker_Elite` handler — see related doc.
141
141
  - `2.0/apps/worker2/features/elite-freshservice-sync.md` — sister Freshservice client.
142
142
  - `2.0/apps/worker2/features/startech-webhook-handler.md` — the multi-client webhook pattern WJE predates.
143
143
  - `1.0/apps/library/features/toga2-api-client-and-bridge.md` — `App_Api_Toga2::syncWithTogadesk`.
144
+
145
+ ## Change history
146
+
147
+ - 2026-06-23 (jcardinal) — Added missing Change history section for schema compliance (no content change).
@@ -33,7 +33,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
33
33
  ## standalone framework
34
34
 
35
35
  - **togatech** (TOGA Technology Website) — 2 doc(s) → [standalone/apps/togatech/INDEX.md](standalone/apps/togatech/INDEX.md)
36
- - **forward** (Forwarder) — 3 doc(s) → [standalone/apps/forward/INDEX.md](standalone/apps/forward/INDEX.md)
36
+ - **forward** (Forwarder) — 4 doc(s) → [standalone/apps/forward/INDEX.md](standalone/apps/forward/INDEX.md)
37
37
 
38
38
  ## Clients
39
39
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
- | [Forwarder Architecture](architecture.md) | Forwarder is a tiny **standalone PHP application** that powers TOGA's short, branded redirect domains. | forward/forward.ini, forward/index.php, forward/.htaccess, forward/.platform/httpd/conf.d/rewritemap.conf, forward/.ebextensions/rewritemap.config, forward/composer.json |
5
+ | [Forwarder Architecture](architecture.md) | Forwarder is a tiny **standalone PHP application** that powers TOGA's short, branded redirect domains. | forward/forward.ini, forward/index.php, forward/.htaccess, forward/.platform/httpd/conf.d/rewritemap.conf, forward/.ebextensions/rewritemap.config, forward/design/index.php, forward/composer.json |
6
+ | [Design Demo Admin Tool](features/design-demo-admin.md) | A standalone, dependency-free PHP tool served at `https://demo.togatech.com/design` that lets the **design team** publish self-contained "Claude Design" HTML ex | forward/design/index.php, forward/design/.config.example.php, forward/.gitignore, forward/.htaccess, forward/.ebextensions/php-uploads.config |
6
7
  | [Encrypted-Link Handler](features/encrypted-link-handler.md) | A `index.php` feature in [Forwarder](../architecture.md) for redirect domains whose URL path carries an **encrypted token** that must be decoded before redirect | forward/index.php |
7
8
  | [Static Demo Hosting](features/static-demo-hosting.md) | A lightweight way to host self-contained static HTML pages (demos, exported designs, download landing pages) on the Forwarder app under a clean URL — e.g. | forward/.htaccess, forward/togadesk/index.html |
@@ -14,6 +14,7 @@ files:
14
14
  - forward/.htaccess
15
15
  - forward/.platform/httpd/conf.d/rewritemap.conf
16
16
  - forward/.ebextensions/rewritemap.config
17
+ - forward/design/index.php
17
18
  - forward/composer.json
18
19
  related: []
19
20
  ---
@@ -75,6 +76,7 @@ The `.htaccess` at the repo root drives a plain-text lookup table:
75
76
  (e.g. `sos.*` → `/sos/`), it redirects to `/<subdomain>/` and serves that dir's
76
77
  `index.html`. Used for the bundled `sos/` Splashtop SOS download page.
77
78
  - **404** — otherwise returns a styled `404` echoing the unmatched `host + uri`.
79
+ - **Design Demo Admin tool** — `/design` serves `design/index.php`, a self-serve UI for the design team to publish and version Claude Design HTML exports via the GitHub API. It runs as a normal directory request (not through the redirect map). See the [Design Demo Admin](features/design-demo-admin.md) feature doc.
78
80
 
79
81
  ## Deployment (Elastic Beanstalk / Apache)
80
82
 
@@ -90,6 +92,7 @@ The `.htaccess` at the repo root drives a plain-text lookup table:
90
92
  - `composer.json` declares a `Togatech\Forward\` PSR-4 autoload over `src/` but has **no
91
93
  dependencies** and no `src/` is shipped today — the app is effectively a single
92
94
  `index.php` plus the Apache config.
95
+ - **`DirectoryIndex index.html index.php`** in `.htaccess` makes `/design/` load `design/index.php` and lets nested static-demo version paths `/<project>/<vN>/` serve via Apache's normal directory index. The single-segment static-demo rewrite rule does not match two-segment paths, and the `index.php` map-miss fallback does not fire for real directories — so versioned demo URLs resolve as directory-index lookups.
93
96
 
94
97
  ## The `decrypt()` scheme
95
98
 
@@ -119,3 +122,4 @@ Treat this as obfuscation only. Anything genuinely sensitive must not rely on it
119
122
 
120
123
  - 2026-06-18 (jcardinal) — Initial architecture documentation; registered `forward`
121
124
  (Forwarder, standalone) in the knowledge base.
125
+ - 2026-06-23 (jcardinal) — Added the `/design` Design Demo Admin route and a `DirectoryIndex index.html index.php` directive in `.htaccess` (enables `/design/` and nested `/<project>/<vN>/` demo paths).
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: Design Demo Admin Tool
3
+ framework: "standalone"
4
+ repo: forward
5
+ project: Forwarder
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-06-23
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - forward/design/index.php
13
+ - forward/design/.config.example.php
14
+ - forward/.gitignore
15
+ - forward/.htaccess
16
+ - forward/.ebextensions/php-uploads.config
17
+ related:
18
+ - standalone/apps/forward/features/static-demo-hosting.md
19
+ - standalone/apps/forward/architecture.md
20
+ ---
21
+
22
+ ## Summary
23
+
24
+ A standalone, dependency-free PHP tool served at `https://demo.togatech.com/design` that
25
+ lets the **design team** publish self-contained "Claude Design" HTML exports to the
26
+ `forward` repo as **versioned demos** — no developer, no git, no local checkout required.
27
+ It sits on top of [Static Demo Hosting](static-demo-hosting.md): static hosting serves the
28
+ files; this tool is the self-serve UI that writes and versions them.
29
+
30
+ The tool does **all** repo access over the **GitHub REST API** — never the local
31
+ filesystem — because in production it runs on the Elastic Beanstalk host, not a git
32
+ checkout. Publishing pushes a commit to `_main`, which triggers the existing EB
33
+ auto-deploy ("live in a few minutes").
34
+
35
+ ## Key files / entry points
36
+
37
+ - `forward/design/index.php` — the entire tool: a single-file PHP backend + HTML/JS UI.
38
+ `declare(strict_types=1)`. Served at `/design` (was `/admin`; renamed this session).
39
+ - `forward/design/.config.example.php` — template for local dev config (the real
40
+ `.config.php` is git-ignored).
41
+ - `forward/.gitignore` — ignores `design/.config.php` so a local token is never tracked.
42
+ - `forward/.htaccess` — `DirectoryIndex index.html index.php` so `/design/` loads
43
+ `index.php`, and so nested `/<project>/<vN>/` paths serve via Apache's directory index.
44
+
45
+ ## How it works
46
+
47
+ ### GitHub API access (no filesystem)
48
+
49
+ - **Reads / listing:** GitHub **Contents API**.
50
+ - **Writes:** GitHub **Git Data API** — blob → tree → commit → update-ref — so a publish
51
+ is an **atomic multi-file commit** (the version's files + the regenerated stub +
52
+ `project.json` all land in one commit).
53
+ - **Auth:** token from `getenv('FORWARD_GITHUB_TOKEN')` (an Elastic Beanstalk environment
54
+ property in prod) or an uncommitted `design/.config.php` for local dev. See gotchas — the
55
+ token must **never** live in the tracked `index.php`.
56
+
57
+ ### Versioning model (decided this session)
58
+
59
+ - **Sequential `/v1`, `/v2`, `/v3` URL folders** — not semver, not date-based.
60
+ - Each project has a **`project.json` manifest** at its folder root:
61
+ ```json
62
+ {
63
+ "title": "...", "latest": "v3", "hidden": false,
64
+ "versions": [
65
+ { "id": "v3", "label": "...", "notes": "...", "author": "...",
66
+ "date": "YYYY-MM-DD", "hidden": false }
67
+ ]
68
+ }
69
+ ```
70
+ Human detail (label / author / notes) lives in the **manifest**, not the URL.
71
+ - **"latest" pointer:** the bare `/<project>` serves an auto-generated `index.html` **stub**
72
+ that meta-refresh / JS-redirects (relative `./vN/`) to the newest **visible** version.
73
+ The stub is regenerated on every publish/unlist.
74
+ - A directory is treated as a **managed demo iff it contains `project.json`** — this is how
75
+ the tool distinguishes demos from infrastructure directories.
76
+
77
+ ### Actions
78
+
79
+ - **Publish a version** — uploads a self-contained HTML export as the next `vN/index.html`,
80
+ appends a version entry to `project.json`, regenerates the stub, commits.
81
+ - **Adopt** — converts a legacy `index.html`-only demo folder (e.g. `togadesk`) into a
82
+ managed demo: moves the existing page to `v1/index.html`, writes `project.json`,
83
+ regenerates the stub.
84
+ - **Remove = unlist only** — sets a `hidden` flag in `project.json`; files are **never
85
+ deleted** (explicit owner decision).
86
+ - **Copy Claude Design prompt** — one-click copy of the standard self-contained-HTML export
87
+ prompt (the same prompt documented in [static-demo-hosting](static-demo-hosting.md)).
88
+
89
+ ### Naming & validation
90
+
91
+ - Folder names auto-normalized to **lowercase kebab-case**, validated against a kebab regex
92
+ plus a reserved/excluded list.
93
+ - **`EXCLUDED_FOLDERS`** constant (`design`, `sos`) + `RESERVED_NAMES` are never listed or
94
+ managed (owner-requested; expected to grow over time).
95
+
96
+ ### Hardening
97
+
98
+ Input length caps; version-id regex guard; HTML content sniff on upload; security headers;
99
+ no client-facing leakage of GitHub/curl error detail; `declare(strict_types=1)`.
100
+
101
+ ## Access control
102
+
103
+ **No authentication** — explicit owner product decision. The `/design` URL is unlisted;
104
+ anyone who reaches it can publish or unlist. Do not treat the tool as protected.
105
+
106
+ ## Data model
107
+
108
+ `project.json` per managed demo (see Versioning model above). No database.
109
+
110
+ ## Client variations
111
+
112
+ None — internal/shared design-team tool.
113
+
114
+ ## Gotchas / known issues
115
+
116
+ - **Contents API inlines only ≤1 MB.** The GitHub Contents API returns an **empty**
117
+ `content` field for files over ~1 MB. Design exports are routinely multi-MB (the
118
+ `togadesk` demo is ~4.2 MB), so reading them via the base64 Contents response silently
119
+ returned empty content — adopt committed a **0-byte `v1/index.html`** (blank page). Fix:
120
+ `ghReadFile()` uses the **raw media type** (`Accept: application/vnd.github.raw`), which
121
+ streams files up to 100 MB.
122
+ - **Never hardcode the GitHub token in the tracked `index.php`.** `design/index.php` is
123
+ git-**tracked**; only `design/.config.php` is git-ignored. Hardcoding a `ghp_` token in
124
+ `index.php` leaked a live token into pushed `_main` history of `agilantsolutions/forward`.
125
+ Use `getenv('FORWARD_GITHUB_TOKEN')` (EB env property) or the uncommitted `.config.php`. A
126
+ leaked token must be **revoked/rotated** — a later commit does not remove it from history.
127
+ Prefer a **fine-grained PAT** scoped to only the `forward` repo's Contents R/W.
128
+ - **Raise PHP upload limits for multi-MB designs (AL1 / PHP 7.3 specifics).** Default
129
+ `upload_max_filesize` (~2 MB) rejects real multi-MB design exports. The deploy platform
130
+ is **PHP 7.3 on 64-bit Amazon Linux 1**, where these values are **not** settable via the
131
+ `aws:elasticbeanstalk:container:php:phpini` option namespace. Instead a
132
+ `.ebextensions/php-uploads.config` drops a custom ini at
133
+ `/etc/php-7.3.d/99-design-uploads.ini` setting `upload_max_filesize=25M`,
134
+ `post_max_size=30M`, `memory_limit=256M`, `max_execution_time=60`.
135
+ - **Publishing pushes to `_main`** and triggers EB auto-deploy — changes go live in a few
136
+ minutes; there is no staging step.
137
+
138
+ ## Change history
139
+
140
+ - 2026-06-23 — Built the Design Demo Admin tool: GitHub-API-only publishing, sequential
141
+ `/vN` versioning with a `project.json` manifest + auto-generated latest-pointer stub,
142
+ adopt/unlist actions, `/design` route. Fixed the >1 MB Contents-API empty-content bug
143
+ (raw media type) and the tracked-token leak (env/`.config.php`). (jcardinal)
144
+
145
+ ## Related docs
146
+
147
+ - [Static Demo Hosting](static-demo-hosting.md)
148
+ - [Forwarder Architecture](../architecture.md)
@@ -6,13 +6,14 @@ project: Forwarder
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-18
9
+ updated: 2026-06-23
10
10
  owners: ["jcardinal"]
11
11
  files:
12
12
  - forward/.htaccess
13
13
  - forward/togadesk/index.html
14
14
  related:
15
15
  - standalone/apps/forward/architecture.md
16
+ - standalone/apps/forward/features/design-demo-admin.md
16
17
  ---
17
18
 
18
19
  ## Summary
@@ -55,6 +56,14 @@ RewriteRule ^([^/]+)/?$ /$1/index.html [L]
55
56
  deploy the EB app → `demo.togatech.com/<name>` works immediately. No code or `.htaccess`
56
57
  change is needed for each new demo.
57
58
 
59
+ **Self-serve + versioning.** The design team no longer has to commit by hand: the
60
+ [Design Demo Admin tool](design-demo-admin.md) at `/design` publishes exports via the
61
+ GitHub API and adds **sequential `/vN/` versioning** on top of this static layout (a
62
+ `project.json` manifest plus an auto-generated latest-pointer stub at the bare
63
+ `/<project>`). The nested `/<project>/<vN>/` URLs are served by Apache's normal directory
64
+ index (a `DirectoryIndex index.html index.php` line in `.htaccess`); the single-segment
65
+ static-demo rewrite rule above does not match two segments.
66
+
58
67
  This is distinct from the older subdomain-based **local directory handler** in `index.php`
59
68
  (`sos.*` → `/sos/`), which runs only on a map miss and issues a redirect. The static-demo
60
69
  rule is path-based, redirect-free, and runs in Apache before PHP. See the
@@ -106,6 +115,9 @@ None — uniform, shared/internal.
106
115
 
107
116
  ## Change history
108
117
 
118
+ - 2026-06-23 — Added self-serve publishing + sequential `/vN/` versioning on top of static
119
+ hosting via the new [Design Demo Admin tool](design-demo-admin.md); nested version paths
120
+ served by a `DirectoryIndex index.html index.php` line in `.htaccess` (jcardinal).
109
121
  - 2026-06-18 — Added static demo hosting: `.htaccess` rule + `togadesk/` demo; documented
110
122
  the Claude Design export prompt (jcardinal).
111
123
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.178",
3
+ "version": "1.0.180",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -375,6 +375,29 @@ Ready to proceed?
375
375
  or "you have full access" — proceed without further permission prompts, but still flag any
376
376
  write outside the expected scope.
377
377
 
378
+ ### Write discipline — stub-first to avoid the GateGuard double-emit tax
379
+
380
+ The ECC fact-forcing gate (`gateguard-fact-force.js`, a `PreToolUse` hook) **denies the
381
+ first Write/Edit to each new file path per session**, then allows the retry. The gate keys
382
+ **only on `file_path` — it never inspects content** (verified in the hook: it `markChecked`s
383
+ the path on the deny, so any subsequent write to that path is allowed regardless of content).
384
+
385
+ That means generating a large file's full content on the first attempt is wasted: the attempt
386
+ is denied and you must re-emit the entire content on the retry — paying ~2× output tokens for
387
+ every large new file.
388
+
389
+ **Rule — when creating a new file (or fully rewriting a large one):**
390
+
391
+ 1. First Write to that path is a **minimal stub** (one line, or empty).
392
+ 2. Present the gate's facts / do the real investigation (this is the gate's actual quality
393
+ purpose — keep it for code).
394
+ 3. Write the **full content** on the second call — it passes on the first real attempt.
395
+
396
+ Full content is emitted **once**. Scope note: the win is **large new-file Writes**. `Edit`s
397
+ also gate once per file, but `old_string`/`new_string` are small, so stub-first isn't worth
398
+ it there. Markdown doc trees are already gate-exempt via `GATEGUARD_EDIT_EXEMPT` — no stub
399
+ needed for those.
400
+
378
401
  ---
379
402
 
380
403
  ### Agent selection (how to build the plan internally)