toga-ai 1.0.577 → 1.0.579
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/.claude-plugin/marketplace.json +5 -0
- package/knowledge/1.0/apps/tools/INDEX.md +1 -0
- package/knowledge/1.0/apps/tools/architecture.md +31 -2
- package/knowledge/1.0/apps/tools/features/clickup-sprint-dashboard.md +68 -4
- package/knowledge/1.0/apps/tools/features/oneuptime-monitor-status-panel.md +232 -0
- package/knowledge/INDEX.md +2 -2
- package/package.json +1 -1
- package/skills/migrate-github-org/SKILL.md +84 -0
- package/skills/migrate-github-org/migrate-github-org.sh +77 -0
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
"name": "harness-audit",
|
|
44
44
|
"command": "/harness-audit",
|
|
45
45
|
"description": "Audit knowledge base and harness health, score 0-100."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "migrate-github-org",
|
|
49
|
+
"command": "/migrate-github-org",
|
|
50
|
+
"description": "Repoint local git remotes from the old GitHub org to the new org across every repo in the developer's workspace."
|
|
46
51
|
}
|
|
47
52
|
],
|
|
48
53
|
"agents": [
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
| [/errors Curation Console (Tools → shared Core Logs DB)](features/errors-curation-console.md) | Internal-only triage/curation screen for the 2.0 Issue/Event error-reporting pipeline, built as a 1.0 Tools MVC page reading the **shared Core Logs DB** through | tools/mvc/errors/get.php, tools/mvc/errors/post.php, tools/mvc/errors/issue/get.php, tools/assets/css/style.css, tools/_/app/nav.php, tools/config.production.ini |
|
|
11
11
|
| [Legacy Email Notifier (tools /email-migration/notify)](features/legacy-email-notifier.md) | An SSO-gated admin tool at **`/email-migration/notify`** (nav group **Email Migration** > **Legacy Notifier**, personas `['TOGa Technology','Development Team']` | tools/mvc/email-migration/notify/get.php, tools/mvc/email-migration/notify/post.php, tools/_/app/nav.php |
|
|
12
12
|
| [Tools MVC — Routing, CSRF & App_Database Access Patterns](features/mvc-data-access-patterns.md) | The load-bearing 1.0 (`App_`) framework conventions a developer needs when adding a page to the Tools app — URL routing, CSRF, and DB access through `App_Databa | tools/_/app/nav.php, tools/mvc/get.php, library/app/error.php, library/app/database.php |
|
|
13
|
+
| [OneUptime Monitor Status Panel & Outage Alerting (tools /clickup/react)](features/oneuptime-monitor-status-panel.md) | A live **operational monitor column** on the wall-display dashboard at `/clickup/react`. | tools/assets/clickup/sprint-dashboard.html, tools/mvc/clickup/react/get.php |
|
|
13
14
|
| [Tools Persona-Gated Navigation (App_Nav)](features/persona-gated-navigation.md) | `App_Nav` is the Tools app's two-level, **persona-gated** navigation. | tools/_/app/nav.php, tools/mvc/get.php |
|
|
14
15
|
| [Tools SAML SSO Consumer & Persona-Gated Auth (App_Auth)](features/saml-sso-auth.md) | `App_Auth` is the Tools app's authentication layer: it consumes the SAML gateway `?saml=` handoff (see the 2.0 SAML downstream integration contract), establishe | tools/_/app/auth.php, tools/mvc/sso/initiate/get.php, tools/mvc/sso/get.php, tools/mvc/login/get.php, tools/mvc/login/post.php, tools/mvc/logout/get.php, tools/mvc/get.php, tools/config.production.ini, tools/config.local.ini |
|
|
15
16
|
| [Talos Knowledge Base Admin UI (KB Documents + Vocabulary)](features/talos-kb-documents-admin.md) | > **PER-AI-MODEL, DATA-DRIVEN SCOPING (2026-07-29).** The KB-documents and Vocabulary admin > UIs were refactored from a single hard-coded **"development-team"* | tools/mvc/talos/kb-documents/get.php, tools/mvc/talos/kb-documents/post.php, tools/mvc/talos/knowledge-bases/get.php, tools/mvc/talos/knowledge-bases/post.php, tools/mvc/talos/vocabulary/get.php, tools/mvc/talos/vocabulary/post.php, tools/_/app/talos/s3.php, tools/_/app/talos/bedrock.php, tools/_/app/pg.php, tools/_/app/model/true/aimodels.php, tools/_/app/model/true/vectorindexes.php, tools/_/app/model/true/aimodels_vectorindexes.php, tools/_/app/worker.php, tools/_/app/nav.php, tools/config.production.ini, tools/config.alpha.ini, tools/.platform/httpd/conf.d/timeouts.conf, tools/.platform/hooks/prebuild/01-install-php-pgsql.sh, tools/.platform/hooks/postdeploy/01-restart-php.sh |
|
|
@@ -6,8 +6,8 @@ project: Tools
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
10
|
-
owners: [jcardinal]
|
|
9
|
+
updated: 2026-08-14
|
|
10
|
+
owners: [jcardinal, kyalamarthi]
|
|
11
11
|
files:
|
|
12
12
|
- tools/index.php
|
|
13
13
|
- tools/_/app/framework.php
|
|
@@ -30,6 +30,7 @@ related:
|
|
|
30
30
|
- ./features/saml-sso-auth.md
|
|
31
31
|
- ./features/persona-gated-navigation.md
|
|
32
32
|
- ./features/developer-tools.md
|
|
33
|
+
- ./features/oneuptime-monitor-status-panel.md
|
|
33
34
|
- ../library/architecture.md
|
|
34
35
|
- ../library/features/mvc-page-pattern-and-app-skeleton.md
|
|
35
36
|
---
|
|
@@ -97,6 +98,24 @@ routes to `/login` (one-step SSO sign-in — no intermediate welcome card). A pe
|
|
|
97
98
|
authenticated user gets the dashboard's explicit empty-state (see
|
|
98
99
|
`features/persona-gated-navigation.md`).
|
|
99
100
|
|
|
101
|
+
## Wall-display routes & third-party browser dependencies
|
|
102
|
+
|
|
103
|
+
Tools is no longer only a click-through internal-tool shell: `/clickup/react` is an
|
|
104
|
+
**unattended wall display** that holds a full-screen colour state **indefinitely** — an ambient,
|
|
105
|
+
always-on status surface rather than a page someone visits (see
|
|
106
|
+
`features/clickup-sprint-dashboard.md` and `features/oneuptime-monitor-status-panel.md`). Two
|
|
107
|
+
architectural consequences:
|
|
108
|
+
|
|
109
|
+
- **One cross-origin browser dependency.** Every other fetch in this app is same-origin and
|
|
110
|
+
authenticated by the SSO session cookie. The monitor column is the sole exception: the browser
|
|
111
|
+
POSTs directly to the OneUptime **public** status-page API on another host (CORS-open, no
|
|
112
|
+
credentials, raw JSON — not the api2 envelope). Nothing proxies it server-side today, so an
|
|
113
|
+
upstream CORS or availability change breaks that panel in the browser with no server-side signal.
|
|
114
|
+
- **Iframed pages carry their own permission policy.** `mvc/clickup/react/get.php` embeds its
|
|
115
|
+
asset in an iframe, and browser autoplay policy is scoped **per-iframe** — an iframed page that
|
|
116
|
+
must play audio needs `allow="… autoplay"` on the frame or it is blocked silently. Unattended
|
|
117
|
+
displays additionally never receive the user gesture browsers require before audio plays.
|
|
118
|
+
|
|
100
119
|
## Adding a tool
|
|
101
120
|
|
|
102
121
|
Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one entry to
|
|
@@ -115,6 +134,11 @@ Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one ent
|
|
|
115
134
|
**Action still owed:** rotate every secret in `config.production.ini` — the file was
|
|
116
135
|
reachable, so treat all of it as compromised. (Location only — no values recorded here.)
|
|
117
136
|
- **SSO initiation + replay defense are open items** — see `features/saml-sso-auth.md`.
|
|
137
|
+
- **Unproxied third-party polling from the browser (`/clickup/react`).** The monitor column pulls
|
|
138
|
+
~250 KB from OneUptime every 5s — ~3 MB/min **per open tab** — to render about six numbers, and
|
|
139
|
+
hardcodes the status-page ID in the HTML asset. Recommended fix: a small server-side endpoint
|
|
140
|
+
(e.g. `/v2/monitors/status/`) that fetches, reduces and caches ~5s, moving the ID into config and
|
|
141
|
+
removing the cross-origin dependency. Advisory, not scheduled.
|
|
118
142
|
- **Framework-level Sentry error reporting is an open gap.** Prod printed "Sentry is not
|
|
119
143
|
installed" because `sentry/sentry` was missing from `composer.json` (added `^4.10`; sibling
|
|
120
144
|
apps use `^4.10`/`^4.19`). But even with Sentry in `vendor/`, the 1.0 framework does **not**
|
|
@@ -123,6 +147,11 @@ Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one ent
|
|
|
123
147
|
composer package must `require_once` the autoloader itself.
|
|
124
148
|
|
|
125
149
|
## Change history
|
|
150
|
+
- 2026-08-14 — Recorded that `/clickup/react` is now an unattended wall display holding a
|
|
151
|
+
full-screen colour state indefinitely, carrying the app's only cross-origin browser dependency
|
|
152
|
+
(OneUptime public status-page API) plus per-iframe permission policy
|
|
153
|
+
(`allow="fullscreen; autoplay"`), and logged the unproxied ~3 MB/min poll + hardcoded
|
|
154
|
+
status-page ID as a known issue with a server-side-proxy fix. (kyalamarthi)
|
|
126
155
|
- 2026-08-04 — Added the app-wide light/dark/auto theme: `assets/css/theme.css` token layer
|
|
127
156
|
registered first in `App_FrameworkIndex_Tools`, pre-paint `data-theme` stamping via the
|
|
128
157
|
one-and-only `setHeaderCode()` hook, `localStorage` preference (no DB column), nav/public
|
|
@@ -6,7 +6,7 @@ project: Tools
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-14
|
|
10
10
|
owners: [kyalamarthi, jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- tools/_/app/clickup/sprint.php
|
|
@@ -21,6 +21,7 @@ files:
|
|
|
21
21
|
- tools/mvc/login/get.php
|
|
22
22
|
- tools/_/app/nav.php
|
|
23
23
|
related:
|
|
24
|
+
- ./oneuptime-monitor-status-panel.md
|
|
24
25
|
- ./persona-gated-navigation.md
|
|
25
26
|
- ./saml-sso-auth.md
|
|
26
27
|
- ./mvc-data-access-patterns.md
|
|
@@ -36,6 +37,12 @@ built for a wall-mounted **TV display** ("TOGa IQ" internal sprint metrics). It
|
|
|
36
37
|
standalone Node/Express prototype from a prior session, folding the dashboard into `tools`
|
|
37
38
|
so it runs on the existing App\_ framework + SSO with no separate service.
|
|
38
39
|
|
|
40
|
+
The page is now a **two-column split**: this sprint board at 80%, and an operational
|
|
41
|
+
**monitor status column** filling the rest — documented separately in
|
|
42
|
+
[OneUptime Monitor Status Panel](./oneuptime-monitor-status-panel.md). The sprint board itself
|
|
43
|
+
was left byte-for-byte unchanged when that landed (its component was renamed `SprintBoard` and
|
|
44
|
+
wrapped in a two-line `Dashboard`).
|
|
45
|
+
|
|
39
46
|
It reads the **same Team DB** and reproduces the **same Power BI-parity metric definitions**
|
|
40
47
|
already documented for worker2 — see
|
|
41
48
|
[team-sprint-management](../../../2.0/apps/worker2/features/team-sprint-management.md). This
|
|
@@ -80,11 +87,39 @@ Babel-standalone from CDN, JSX inside a `<script type="text/babel">`. **No build
|
|
|
80
87
|
npm, no bundler.** It fetches `/v2/sprints/*` **same-origin**, so the SSO session cookie
|
|
81
88
|
authenticates the calls automatically. Do not mistake this for a bundled React app.
|
|
82
89
|
|
|
90
|
+
### Retiring a work type or a departed developer — filter client-side, not in the mock
|
|
91
|
+
|
|
92
|
+
Two `ALL_CAPS` constants near the top of the HTML drop rows from the **live** API responses,
|
|
93
|
+
both matched case-insensitively and trimmed:
|
|
94
|
+
|
|
95
|
+
- **`RETIRED_WORK_TYPES`** — applied to the `worktype-breakdown` response. Currently `STRETCH`,
|
|
96
|
+
retired because the team no longer plans stretch work. The STRETCH **KPI tile** (which called
|
|
97
|
+
`/v2/sprints/tile/?category=stretch`), its colour mapping and its Work Type slice were removed
|
|
98
|
+
outright.
|
|
99
|
+
- **`FORMER_DEVS`** — applied to the `points-by-dev` response, to keep a departed developer off
|
|
100
|
+
"Sprint Points By Dev".
|
|
101
|
+
|
|
102
|
+
**Editing the `USE_MOCK` fixtures does nothing.** `USE_MOCK` is `false` and the live API drives
|
|
103
|
+
the page, so a name or category only disappears when it is filtered out of the **response**.
|
|
104
|
+
Verified against live sprint 84: the departed developer was still returned by
|
|
105
|
+
`/v2/sprints/points-by-dev/` with 33 points (In Review 29, Complete 4), while the API had
|
|
106
|
+
already stopped returning STRETCH — so that filter now matters only for historical sprints.
|
|
107
|
+
See [Gotchas](#gotchas) for the historical-sprint caveat these filters carry.
|
|
108
|
+
|
|
109
|
+
### Sprint Burndown series
|
|
110
|
+
|
|
111
|
+
Burndown is **Target** (grey dashed) + **Committed** (red) only. The blue **"All"** series was
|
|
112
|
+
dropped alongside STRETCH — with that category retired it tracked "Committed" too closely to
|
|
113
|
+
earn a second line. The legend derives from the `BURNDOWN_SERIES` constant, so it updated
|
|
114
|
+
itself; add or remove a line there rather than editing the legend.
|
|
115
|
+
|
|
83
116
|
### Embed page — `mvc/clickup/react/get.php`
|
|
84
117
|
|
|
85
|
-
A PHP MVC view that `requireAuth`s, then embeds `sprint-dashboard.html` in an
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
A PHP MVC view that `requireAuth`s, then embeds `sprint-dashboard.html` in an iframe
|
|
119
|
+
(cache-busted by `filemtime`). Heading "Clickup Dashboard", subtitle notes the data is
|
|
120
|
+
"…refreshed every 5 min." The frame is `allow="fullscreen; autoplay"` — **autoplay is
|
|
121
|
+
load-bearing**, not decorative: it is what lets the monitor column's outage beeps sound (see
|
|
122
|
+
[the monitor panel doc](./oneuptime-monitor-status-panel.md)).
|
|
88
123
|
|
|
89
124
|
### Nav — `_/app/nav.php`
|
|
90
125
|
|
|
@@ -121,6 +156,16 @@ the React dashboard supersedes it.
|
|
|
121
156
|
`cd tools && ENVIRONMENT=dev-local php -d "include_path=.;C:/www/library" -S localhost:8000 router.php`.
|
|
122
157
|
The `App_` framework + `_.php` bootstrap load from the separate `library` repo via
|
|
123
158
|
`include_path`; `router.php` reproduces the `.htaccess` rewrite for PHP's built-in server.
|
|
159
|
+
The dev server binds to **localhost only**.
|
|
160
|
+
- **Reach the dashboard through `/clickup/react`, never the raw asset.** The `/v2/sprints/*`
|
|
161
|
+
endpoints are same-origin PHP authenticated by the Tools **SSO session cookie**. Opening
|
|
162
|
+
`/assets/clickup/sprint-dashboard.html` directly in an unauthenticated tab makes **every**
|
|
163
|
+
`/v2` call return **HTTP 401** and the page renders empty — the route, not the file, is what
|
|
164
|
+
carries the session.
|
|
165
|
+
- **Expected local-only console noise.** Twelve `ERR_CONNECTION_REFUSED` for
|
|
166
|
+
`http://localhost/resources/*` (the shared 1.0 jquery / fontawesome / `library.css` /
|
|
167
|
+
`library.js` are expected on port 80) and a resulting `preloaderExit is not defined`. Both are
|
|
168
|
+
pre-existing and local-only — not symptoms of anything in this feature.
|
|
124
169
|
|
|
125
170
|
> Credentials note: DB creds and the `dev_mode` / `dev_autologin` flags live in the
|
|
126
171
|
> git-ignored `config.dev-local.ini` — never commit values.
|
|
@@ -138,6 +183,17 @@ the React dashboard supersedes it.
|
|
|
138
183
|
`buildArrayOfRows(App_Database::query($sql,$db), false)` raises "Only variables should be
|
|
139
184
|
passed by reference", which the E_ALL error handler promotes to a fatal 500. Assign first:
|
|
140
185
|
`$res = App_Database::query(...); buildArrayOfRows($res, false);`.
|
|
186
|
+
- **`RETIRED_WORK_TYPES` / `FORMER_DEVS` are client-side and unconditional, so historical
|
|
187
|
+
sprints under-report.** Browsing a past sprint that genuinely had stretch work, or that
|
|
188
|
+
developer's points, silently shows lower numbers than the API returned — the filter does not
|
|
189
|
+
know which sprint is on screen. Acceptable for a wall display pinned to the current sprint;
|
|
190
|
+
the correct long-term fix is to filter in `App_Clickup_Sprint` (server-side) or to scope the
|
|
191
|
+
filter to the current sprint only.
|
|
192
|
+
- **`StatusChart`'s `USE_MOCK` fixture is broken (dev-only, unfixed).** The fixture supplies
|
|
193
|
+
`{label, count}` but the code reads `b.points`, so every value is `undefined`, gets filtered
|
|
194
|
+
out, and the Status panel renders **blank** whenever `USE_MOCK = true`. Production is
|
|
195
|
+
unaffected — the live API returns `points`. One-word fix (`count:` → `points:`) if anyone
|
|
196
|
+
needs the mock; deliberately left alone as out of scope.
|
|
141
197
|
|
|
142
198
|
- **The old Power BI embed page (`mvc/clickup/dashboard/get.php`) keeps ~6 fixed colour
|
|
143
199
|
literals on purpose — do NOT theme them.** Its card/frame colour `#0b1020` is matched to the
|
|
@@ -147,6 +203,14 @@ the React dashboard supersedes it.
|
|
|
147
203
|
[App-Wide Colour Theme](./theme-light-dark.md).
|
|
148
204
|
|
|
149
205
|
## Change history
|
|
206
|
+
- 2026-08-14 — Retired the **STRETCH** work type (KPI tile, colour, Work Type slice) and removed
|
|
207
|
+
the blue **"All"** burndown series, leaving Target + Committed; added the client-side
|
|
208
|
+
`RETIRED_WORK_TYPES` / `FORMER_DEVS` response filters (editing the `USE_MOCK` fixtures does
|
|
209
|
+
nothing — the live API drives the page) and recorded their historical-sprint under-reporting
|
|
210
|
+
caveat. Embed iframe is now `allow="fullscreen; autoplay"` for the new
|
|
211
|
+
[monitor status column](./oneuptime-monitor-status-panel.md), which shares this document.
|
|
212
|
+
Documented the raw-asset **401** trap and expected local console noise, plus the broken
|
|
213
|
+
`StatusChart` mock fixture. (kyalamarthi)
|
|
150
214
|
- 2026-08-04 — Tokenised the `/clickup/dashboard` page-local styles for the app-wide light/dark
|
|
151
215
|
theme, keeping ~6 deliberate fixed literals (incl. the `#0b1020` frame that matches the
|
|
152
216
|
embedded Power BI canvas so the iframe load does not flash white). Not committed. (jcardinal)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: OneUptime Monitor Status Panel & Outage Alerting (tools /clickup/react)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: tools
|
|
5
|
+
project: Tools
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-14
|
|
10
|
+
owners: [kyalamarthi]
|
|
11
|
+
files:
|
|
12
|
+
- tools/assets/clickup/sprint-dashboard.html
|
|
13
|
+
- tools/mvc/clickup/react/get.php
|
|
14
|
+
related:
|
|
15
|
+
- ./clickup-sprint-dashboard.md
|
|
16
|
+
- ../architecture.md
|
|
17
|
+
- ../../worker/features/oneuptime-worker-uptime-monitoring.md
|
|
18
|
+
- ../../../../2.0/apps/worker2/features/oneuptime-worker2-monitoring.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
A live **operational monitor column** on the wall-display dashboard at `/clickup/react`. The
|
|
24
|
+
page is a two-column split — the ClickUp sprint board at 80%, the monitor column filling the
|
|
25
|
+
rest, each a bordered rounded card. The column shows an overall status pill, a **single solid
|
|
26
|
+
status circle** carrying the whole system's state, a per-status legend (count + %), and a
|
|
27
|
+
"Degraded and offline" card listing name / group / status / how long it has been in that state.
|
|
28
|
+
|
|
29
|
+
The display is designed to be read **from across a room**: when a monitor changes to a bad state
|
|
30
|
+
it **beeps, pops up and blinks**, and for as long as anything is still down the **screen edges
|
|
31
|
+
hold a standing colour tint**.
|
|
32
|
+
|
|
33
|
+
It reads the **OneUptime public status-page overview API** directly from the browser. This is
|
|
34
|
+
the **read/consumer** side of OneUptime and is unrelated to the push-heartbeat monitors the
|
|
35
|
+
worker tiers report *into* — see
|
|
36
|
+
[OneUptime push-metric monitors for 2.0 workers](../../../../2.0/apps/worker2/features/oneuptime-worker2-monitoring.md)
|
|
37
|
+
and [OneUptime external uptime monitoring for 1.0 workers](../../worker/features/oneuptime-worker-uptime-monitoring.md)
|
|
38
|
+
for that side. Those docs define what *creates* the statuses this panel renders.
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
### One document, not a nested iframe
|
|
43
|
+
|
|
44
|
+
The panel is implemented as React components **in the same `sprint-dashboard.html` document**
|
|
45
|
+
as the sprint board. It is deliberately **not** a nested iframe: `mvc/clickup/react/get.php`
|
|
46
|
+
already iframes this page, so nesting a second frame would load a **second React runtime** and
|
|
47
|
+
run a **duplicate ~250 KB poll**.
|
|
48
|
+
|
|
49
|
+
The existing sprint board was left byte-for-byte unchanged — its component was renamed
|
|
50
|
+
`SprintBoard` and a two-line `Dashboard` wrapper added around it plus the monitor column. The
|
|
51
|
+
monitor poll is lifted into `Dashboard` and passed **down as props**, so the status panel and
|
|
52
|
+
the alert watcher share **one** fetch loop rather than polling twice.
|
|
53
|
+
|
|
54
|
+
Only the monitor fetch runs at `MONITOR_REFRESH_MS` (5s); sprint data stays on the page's
|
|
55
|
+
existing 5-minute `AUTO_REFRESH_MS`.
|
|
56
|
+
|
|
57
|
+
### Upstream contract — OneUptime public status-page overview API
|
|
58
|
+
|
|
59
|
+
Reusable for any future status display. Endpoint:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
POST https://oneuptime.com/status-page-api/overview/<statusPageId>
|
|
63
|
+
body: {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- **It is a POST, not a GET**, and it returns **raw JSON** — **not** the api2
|
|
67
|
+
`{isSuccess, data, messages}` envelope used everywhere else in TOGA. The payload **is** the
|
|
68
|
+
data. Do not unwrap a `.data` that isn't there.
|
|
69
|
+
- A **public** status page needs **no auth** and answers with `Access-Control-Allow-Origin: *`,
|
|
70
|
+
so the browser can call it cross-origin with **no proxy and no credentials**. This is the one
|
|
71
|
+
cross-origin call on a page whose every other fetch is same-origin `/v2/*`.
|
|
72
|
+
- The response is **~250 KB**.
|
|
73
|
+
- Values arrive as **typed envelopes** — `{_type: "ObjectID" | "DateTime" | "Color", value: …}`
|
|
74
|
+
— so read `.value`, never the object. Dates are ISO-8601 UTC with a trailing `Z`.
|
|
75
|
+
- A monitor's **current** state is `statusPageResources[].monitor.currentMonitorStatusId`,
|
|
76
|
+
resolved against the `monitorStatuses[]` list.
|
|
77
|
+
- In `monitorStatusTimelines[]`, the entry with **`endsAt: null`** is the **open** interval —
|
|
78
|
+
i.e. when the current state began. That is what drives "in this state for X".
|
|
79
|
+
|
|
80
|
+
The status page ID is currently a hardcoded constant (`MONITOR_STATUS_PAGE_ID`) in the HTML;
|
|
81
|
+
moving it to config is part of the recommended next step below. (Identifier location only — no
|
|
82
|
+
value recorded here.)
|
|
83
|
+
|
|
84
|
+
### Status bucketing is derived, never hardcoded
|
|
85
|
+
|
|
86
|
+
Buckets are computed from the status list itself, not from a hardcoded set of status names:
|
|
87
|
+
|
|
88
|
+
- `isOperationalState` → **good**
|
|
89
|
+
- the **worst-priority non-operational** status → **offline / critical**
|
|
90
|
+
- anything in between → **degraded**
|
|
91
|
+
|
|
92
|
+
So a renamed status, or a newly added one, still lands in the right bucket without a code
|
|
93
|
+
change.
|
|
94
|
+
|
|
95
|
+
### The status circle — the colour is the message
|
|
96
|
+
|
|
97
|
+
`MonitorCircle` is **one filled circle** whose colour is the whole system's state: green
|
|
98
|
+
all-clear, amber if anything is degraded, red if anything is offline, **red winning when both**.
|
|
99
|
+
It draws **nothing inside it** — no total, no label.
|
|
100
|
+
|
|
101
|
+
That is deliberate, and it replaced a `MonitorDonut` (a segmented ring showing per-status
|
|
102
|
+
proportions with the total in the centre) which was **deleted**. From across a room the colour is
|
|
103
|
+
what carries; the legend directly beneath still gives the exact per-status counts, so no
|
|
104
|
+
information is lost. The SVG keeps an `aria-label` listing the counts, so screen readers still
|
|
105
|
+
get the numbers that came off the face of the circle.
|
|
106
|
+
|
|
107
|
+
The circle's colour comes from the **same `standingRole()`** that drives the screen-edge tint, so
|
|
108
|
+
the circle and the edges can never disagree about severity.
|
|
109
|
+
|
|
110
|
+
### Alerting — edge-triggered events over a level-triggered state
|
|
111
|
+
|
|
112
|
+
**The distinction to carry to any future alerting surface.** Two separate mechanisms, and mixing
|
|
113
|
+
them up is the bug:
|
|
114
|
+
|
|
115
|
+
| | Trigger | Drives | Why |
|
|
116
|
+
|---|---|---|---|
|
|
117
|
+
| **Event** | **Edge** — fires on the transition | beeps, popup, 5s blink | A level-triggered *event* re-alarms every 5s poll for a monitor that has been offline an hour, and the wall display becomes a siren nobody can silence. |
|
|
118
|
+
| **State** | **Level** — follows current state | standing edge tint, status circle | An edge-triggered *state* would show a clean screen when you open the page during an existing outage. **The board must never look healthy while it isn't.** |
|
|
119
|
+
|
|
120
|
+
**Event — `useMonitorAlerts`** compares each poll's non-operational rows against the previous
|
|
121
|
+
poll's:
|
|
122
|
+
|
|
123
|
+
- The **first successful poll is the baseline**, so opening the page mid-outage is **silent**
|
|
124
|
+
(the standing tint, being level-triggered, still shows immediately).
|
|
125
|
+
- A state that simply persists never re-alarms.
|
|
126
|
+
- A full recovery to operational is **silent** (the monitor drops out of the row set entirely).
|
|
127
|
+
- It fires on **any change of non-operational state** — `r.role !== previous.get(r.key)`, where
|
|
128
|
+
the row set only ever holds non-operational monitors, so good→degraded, good→offline,
|
|
129
|
+
degraded→offline **and offline→degraded** all alert. An earlier version compared severity
|
|
130
|
+
numerically (`SEVERITY[new] > SEVERITY[old]`), which silently suppressed **offline → degraded**
|
|
131
|
+
because that is a severity *decrease*. That transition is news, so it is now announced and the
|
|
132
|
+
now-unused `SEVERITY` map was deleted.
|
|
133
|
+
|
|
134
|
+
The event presentation, held for `ALERT_HOLD_MS` (5s):
|
|
135
|
+
|
|
136
|
+
- **Sound** — Web Audio beeps, synthesised at runtime, so there is **no audio asset to ship**.
|
|
137
|
+
**1 beep @ 720 Hz** degraded, **2 beeps @ 990 Hz** offline. The beep count describes the state
|
|
138
|
+
the monitor is in **now**, so an offline → degraded change beeps **once**. Pitch differs too,
|
|
139
|
+
so severity is recognisable across a room without counting.
|
|
140
|
+
- **Popup** — a centre overlay naming each affected monitor.
|
|
141
|
+
- **Blink** — the tint element gains `.is-blinking` for the 5s pulse, then the colour **holds**.
|
|
142
|
+
|
|
143
|
+
**State — `standingRole(model)`** returns `critical` if any row is offline, else `warning` if any
|
|
144
|
+
is degraded, else `null` (no tint). The tint element only renders while `standingRole` is
|
|
145
|
+
non-null, so a full recovery clears it.
|
|
146
|
+
|
|
147
|
+
Note the two can legitimately show different colours at once: the tint always reflects
|
|
148
|
+
**worst-current** state while the popup reflects **the event**, so a degraded-event popup can sit
|
|
149
|
+
on a red screen because something else is still offline. That is correct, not a bug.
|
|
150
|
+
|
|
151
|
+
Verified across full cycles: beep sequence 720 / 990 990 / 720, silent on unchanged and on
|
|
152
|
+
recovery, popup held 4982 ms and 4955 ms against the 5s spec; amber standing → red when offline
|
|
153
|
+
joined (priority) → amber when offline cleared → no tint on full recovery, with the blink
|
|
154
|
+
stopping after 5s and the colour held. Circle verified against the DOM: `#0ca30c` all-clear,
|
|
155
|
+
`#fab219` degraded only, `#d03b3b` with 1 degraded + 1 offline, and `textNodesInSvg = 0`.
|
|
156
|
+
|
|
157
|
+
### Two colour pairs: meaning vs. legibility
|
|
158
|
+
|
|
159
|
+
`MON_COLOR` is the **validated status palette** and drives everything that **carries meaning** —
|
|
160
|
+
icons, legend, popup border, status text, and the status circle. `MON_COLOR_BRIGHT`
|
|
161
|
+
(`good:#25d825, warning:#ffd633, critical:#ff4d4d`) is used **only** for the full-screen edge rim,
|
|
162
|
+
where nothing depends on its exact value and the only job is legibility from across a room. Do
|
|
163
|
+
not let the bright pair leak into anything semantic.
|
|
164
|
+
|
|
165
|
+
Both reach the overlay as CSS custom properties — `--alert-color` and `--alert-bright`. The rim is
|
|
166
|
+
a **three-layer `box-shadow`**: solid hot rim + tight bright bloom + a deep haze that deliberately
|
|
167
|
+
stays on the **base** hue, so the dashboard underneath stays readable instead of washing out. Each
|
|
168
|
+
bright layer is written `var(--alert-bright, var(--alert-color))` so it **degrades to the base
|
|
169
|
+
colour** if the property never reaches the element.
|
|
170
|
+
|
|
171
|
+
Standing and blinking differ only in intensity, which is what keeps "steady = still broken"
|
|
172
|
+
distinguishable from "pulsing = something just changed":
|
|
173
|
+
|
|
174
|
+
- `.alert-flash` (standing) — 12px rim, `opacity: .85`, no animation. It may sit on screen for
|
|
175
|
+
hours.
|
|
176
|
+
- `.alert-flash.is-blinking` (event) — 20px rim, `opacity: 1`, plus the 0.7s pulse.
|
|
177
|
+
|
|
178
|
+
## Gotchas
|
|
179
|
+
|
|
180
|
+
- **The embedding iframe needs `allow="autoplay"` or the alert sound is silently blocked.**
|
|
181
|
+
Browser autoplay policy is scoped **per-iframe**. `mvc/clickup/react/get.php` embedded the
|
|
182
|
+
dashboard with `allow="fullscreen"`, so Web Audio inside the frame was policy-blocked and the
|
|
183
|
+
beeps would never have sounded in the Tools app — with no error. It is now
|
|
184
|
+
`allow="fullscreen; autoplay"`. Any future iframed page that makes sound needs the same.
|
|
185
|
+
- **Permission is not enough — browsers still require one user gesture per session.** The page
|
|
186
|
+
unlocks the `AudioContext` on the first click/keypress, and if an alert fires while audio is
|
|
187
|
+
still blocked the popup **says so** rather than failing silently. On an **unattended wall
|
|
188
|
+
display nobody ever clicks**, so alerts stay visual-only. For kiosk use, launch Chrome with
|
|
189
|
+
`--autoplay-policy=no-user-gesture-required`.
|
|
190
|
+
- **The `prefers-reduced-motion` override needs the compound selector.** Blinking is a
|
|
191
|
+
vestibular risk, so the reduced-motion rule kills the animation and holds the colour steady.
|
|
192
|
+
Once the blink moved to `.alert-flash.is-blinking` (specificity 0,2,0), a reduced-motion rule
|
|
193
|
+
on `.alert-flash` alone (0,1,0) **could no longer override it** and the screen kept pulsing.
|
|
194
|
+
The rule must list both: `.alert-flash, .alert-flash.is-blinking { animation: none; }`. Any
|
|
195
|
+
future state/modifier CSS split has the same trap.
|
|
196
|
+
- **A parse failure currently looks calmer than an outage** (known issue, not fixed). If the
|
|
197
|
+
OneUptime call returns HTTP 200 with a malformed or empty body, `buildMonitorModel` yields
|
|
198
|
+
total 0, empty buckets and empty rows. The status pill correctly degrades to "Unknown", but
|
|
199
|
+
the affected-list card still reads **"All 0 monitors are operational"**, and any
|
|
200
|
+
previously-degraded monitor silently disappears **with no alert** (recovery is silent by
|
|
201
|
+
design, and an empty row set is indistinguishable from a full recovery). Since the standing
|
|
202
|
+
tint and the status circle are both driven by that same empty row set, a parse failure also
|
|
203
|
+
**clears a standing red screen back to green** — the most reassuring possible display of a
|
|
204
|
+
total loss of visibility. Recommended fix: treat "zero resources parsed" as an **error
|
|
205
|
+
state**, not a healthy one.
|
|
206
|
+
|
|
207
|
+
## Recommended next step (advisory — not built)
|
|
208
|
+
|
|
209
|
+
Replace the direct browser → OneUptime poll with a small **server-side proxy endpoint** in the
|
|
210
|
+
Tools app (e.g. `/v2/monitors/status/`) that fetches upstream, reduces the payload to the
|
|
211
|
+
summary, and caches ~5s. Rationale:
|
|
212
|
+
|
|
213
|
+
- The browser currently pulls **~250 KB every 5s (~3 MB/min per open tab)** to display about
|
|
214
|
+
six numbers; a proxy makes it ~1 KB.
|
|
215
|
+
- One upstream fetch is shared across **all** open displays instead of one per tab.
|
|
216
|
+
- It removes the cross-origin dependency, and therefore the CORS/autoplay coupling above.
|
|
217
|
+
- The status page ID moves into **config** instead of hardcoded HTML.
|
|
218
|
+
- It gives a natural home for **server-side transition history**, which is what edge-triggered
|
|
219
|
+
alerting really wants (today the baseline resets every time a tab reloads).
|
|
220
|
+
|
|
221
|
+
## Change history
|
|
222
|
+
- 2026-08-14 — Built the monitor status column on `/clickup/react` (split layout, solid status
|
|
223
|
+
circle + legend + degraded/offline card) as components in the same document rather than a
|
|
224
|
+
nested iframe, sharing one 5s poll; documented the OneUptime public status-page overview API
|
|
225
|
+
contract (POST, raw JSON not the api2 envelope, CORS-open, typed `{_type,value}` envelopes,
|
|
226
|
+
`endsAt: null` = open interval) and derived status bucketing. Alerting splits **edge-triggered
|
|
227
|
+
events** (beeps / popup / 5s blink, now firing on any non-operational change incl.
|
|
228
|
+
offline → degraded) from a **level-triggered standing tint** driven by `standingRole()`, which
|
|
229
|
+
also colours the circle so the two can never disagree; added the `MON_COLOR_BRIGHT` rim-only
|
|
230
|
+
palette. Fixed the iframe `allow="fullscreen; autoplay"` autoplay block and recorded the
|
|
231
|
+
user-gesture/kiosk caveat, the `prefers-reduced-motion` specificity trap, the malformed-body
|
|
232
|
+
"all 0 monitors operational" gap, and the server-side-proxy recommendation. (kyalamarthi)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -14,7 +14,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
14
14
|
- **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
|
|
15
15
|
- **test** (Test) — 14 doc(s) → [1.0/apps/test/INDEX.md](1.0/apps/test/INDEX.md)
|
|
16
16
|
- **toga** (TOGa) — 3 doc(s) → [1.0/apps/toga/INDEX.md](1.0/apps/toga/INDEX.md)
|
|
17
|
-
- **tools** (Tools) —
|
|
17
|
+
- **tools** (Tools) — 15 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
|
|
18
18
|
|
|
19
19
|
## 2.0 framework
|
|
20
20
|
|
|
@@ -39,7 +39,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
39
39
|
- **togatech** (TOGA Technology Website) — 6 doc(s) → [standalone/apps/togatech/INDEX.md](standalone/apps/togatech/INDEX.md)
|
|
40
40
|
- **websocket** (WebSocket Server) — 2 doc(s) → [standalone/apps/websocket/INDEX.md](standalone/apps/websocket/INDEX.md)
|
|
41
41
|
- **forward** (Forwarder) — 3 doc(s) → [standalone/apps/forward/INDEX.md](standalone/apps/forward/INDEX.md)
|
|
42
|
-
- **claude** (Claude Harness) —
|
|
42
|
+
- **claude** (Claude Harness) — 8 doc(s) → [standalone/apps/claude/INDEX.md](standalone/apps/claude/INDEX.md)
|
|
43
43
|
|
|
44
44
|
## Clients
|
|
45
45
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-github-org
|
|
3
|
+
description: Repoints local git remotes from the old GitHub org (agilantsolutions) to the new org (togatech) across every repo in the developer's workspace, without touching SSH keys, tokens, or repo names. Trigger when the user says "migrate-github-org", "update my github remotes", "switch to the new github org", "point my repos at togatech", or asks how to update their local setup after the org transfer.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate GitHub Org — repoint local remotes after the org transfer
|
|
7
|
+
|
|
8
|
+
TOGA is moving its repos from the `agilantsolutions` GitHub org to `togatech`. The
|
|
9
|
+
org-level transfer (repo Settings → Transfer ownership) is done once by an admin.
|
|
10
|
+
**This skill is the per-developer follow-up** — it updates each developer's local
|
|
11
|
+
git remotes so `git`/GitHub Desktop keep working against the new org.
|
|
12
|
+
|
|
13
|
+
## Before running this
|
|
14
|
+
|
|
15
|
+
Confirm with the developer:
|
|
16
|
+
1. **Has the org transfer already happened?** If repos don't exist at
|
|
17
|
+
`github.com/togatech/<repo>` yet, do not run this — the local remote would point
|
|
18
|
+
at a repo that doesn't resolve. Ask them to check with the admin first.
|
|
19
|
+
2. **Is their GitHub account a member of `togatech`?** If not, pushes/pulls will
|
|
20
|
+
fail with a 403 or "repository not found" regardless of remote URL — this is
|
|
21
|
+
an org-membership issue, not something this script fixes.
|
|
22
|
+
|
|
23
|
+
If either is unconfirmed, tell the developer to check before proceeding, but still
|
|
24
|
+
offer to run the script if they want to prepare ahead of time — it's safe to run
|
|
25
|
+
against repos still on the old org (it just does nothing until the org changes).
|
|
26
|
+
|
|
27
|
+
## Step 1 — Locate the script
|
|
28
|
+
|
|
29
|
+
The script lives next to this SKILL.md in the team repo:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
for d in claude ../claude; do [ -f "$d/skills/migrate-github-org/migrate-github-org.sh" ] && REPO="$d" && break; done
|
|
33
|
+
echo "${REPO:-NOT_FOUND}"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If `NOT_FOUND`, tell the user to run `/sync-team-skills` first (or clone
|
|
37
|
+
`https://github.com/TOGATechnology/claude`), then retry.
|
|
38
|
+
|
|
39
|
+
## Step 2 — Run it against their workspace
|
|
40
|
+
|
|
41
|
+
Run from the developer's actual project/workspace root (the folder containing
|
|
42
|
+
their repo checkouts as subfolders — e.g. `www`, `2.0`, whatever they call it):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bash "$REPO/skills/migrate-github-org/migrate-github-org.sh" .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If the user is running this from inside VS Code with the workspace folder already
|
|
49
|
+
open, `.` is correct — no path argument needed.
|
|
50
|
+
|
|
51
|
+
## Step 3 — Report results
|
|
52
|
+
|
|
53
|
+
Relay the script's own summary output verbatim (updated / skipped / no-origin
|
|
54
|
+
counts and the list of repos changed) — do not re-summarize or drop detail.
|
|
55
|
+
|
|
56
|
+
Then tell the developer:
|
|
57
|
+
- If any repos were **updated**: restart GitHub Desktop (or close/reopen the repo
|
|
58
|
+
in it) so it picks up the new remote URL.
|
|
59
|
+
- The **first push or pull** after this may prompt for re-authentication if their
|
|
60
|
+
GitHub account doesn't yet have access to `togatech` — that's expected, not a
|
|
61
|
+
bug in the script. They should sign in / re-authorize when prompted.
|
|
62
|
+
- No SSH keys or manually-generated tokens are needed for this step — GitHub
|
|
63
|
+
Desktop handles HTTPS auth via its own sign-in. A token only matters for
|
|
64
|
+
someone with a manually configured PAT used outside Desktop (CI scripts,
|
|
65
|
+
`composer.json` VCS repos, deploy hooks) — those need separate re-scoping to
|
|
66
|
+
`togatech` and are out of scope for this skill.
|
|
67
|
+
|
|
68
|
+
## What this does NOT do
|
|
69
|
+
|
|
70
|
+
- Does not transfer repos on GitHub itself (that's the admin's one-time step).
|
|
71
|
+
- Does not touch SSH remotes, deploy keys, CI secrets, or hardcoded org
|
|
72
|
+
references in code/config (ebextensions, composer.json, etc.) — those need
|
|
73
|
+
a separate sweep.
|
|
74
|
+
- Does not grant org membership or repo permissions.
|
|
75
|
+
|
|
76
|
+
## Self-updating anomaly log
|
|
77
|
+
|
|
78
|
+
If you hit an error, permission issue, or unexpected behavior not already
|
|
79
|
+
documented above — even if you worked around it — record it here so the next
|
|
80
|
+
developer doesn't hit it blind.
|
|
81
|
+
|
|
82
|
+
### Known anomalies
|
|
83
|
+
|
|
84
|
+
(none yet)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# migrate-github-org.sh
|
|
4
|
+
#
|
|
5
|
+
# Scans a workspace directory for git repos and repoints any remote that
|
|
6
|
+
# points at OLD_ORG on github.com to NEW_ORG, keeping the repo name and
|
|
7
|
+
# the HTTPS protocol (what GitHub Desktop uses) unchanged.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# ./migrate-github-org.sh [workspace-dir]
|
|
11
|
+
#
|
|
12
|
+
# workspace-dir defaults to the current directory.
|
|
13
|
+
#
|
|
14
|
+
# Safe to re-run: repos already pointing at NEW_ORG, or at any org other
|
|
15
|
+
# than OLD_ORG, are left untouched and reported as skipped.
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
OLD_ORG="agilantsolutions"
|
|
20
|
+
NEW_ORG="togatech"
|
|
21
|
+
|
|
22
|
+
WORKSPACE="${1:-.}"
|
|
23
|
+
|
|
24
|
+
if [ ! -d "$WORKSPACE" ]; then
|
|
25
|
+
echo "Error: workspace directory not found: $WORKSPACE" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
updated=0
|
|
30
|
+
skipped=0
|
|
31
|
+
not_git=0
|
|
32
|
+
|
|
33
|
+
echo "Scanning $WORKSPACE for git repositories..."
|
|
34
|
+
echo "Renaming remotes: github.com/$OLD_ORG/<repo> -> github.com/$NEW_ORG/<repo>"
|
|
35
|
+
echo
|
|
36
|
+
|
|
37
|
+
# Only descend one level into WORKSPACE — each subfolder is treated as a
|
|
38
|
+
# candidate repo. Adjust maxdepth if your repos are nested deeper.
|
|
39
|
+
while IFS= read -r -d '' gitdir; do
|
|
40
|
+
repo_path="$(dirname "$gitdir")"
|
|
41
|
+
repo_name="$(basename "$repo_path")"
|
|
42
|
+
|
|
43
|
+
remote_url="$(git -C "$repo_path" remote get-url origin 2>/dev/null || true)"
|
|
44
|
+
|
|
45
|
+
if [ -z "$remote_url" ]; then
|
|
46
|
+
echo " [no origin] $repo_name"
|
|
47
|
+
not_git=$((not_git + 1))
|
|
48
|
+
continue
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
case "$remote_url" in
|
|
52
|
+
*"github.com/$OLD_ORG/"*|*"github.com:$OLD_ORG/"*)
|
|
53
|
+
new_url="${remote_url/$OLD_ORG/$NEW_ORG}"
|
|
54
|
+
git -C "$repo_path" remote set-url origin "$new_url"
|
|
55
|
+
echo " [updated] $repo_name"
|
|
56
|
+
echo " $remote_url"
|
|
57
|
+
echo " -> $new_url"
|
|
58
|
+
updated=$((updated + 1))
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
echo " [skipped] $repo_name ($remote_url)"
|
|
62
|
+
skipped=$((skipped + 1))
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
done < <(find "$WORKSPACE" -mindepth 2 -maxdepth 2 -type d -name ".git" -print0)
|
|
66
|
+
|
|
67
|
+
echo
|
|
68
|
+
echo "Done. Updated: $updated, skipped (not $OLD_ORG): $skipped, no origin: $not_git"
|
|
69
|
+
|
|
70
|
+
if [ "$updated" -gt 0 ]; then
|
|
71
|
+
echo
|
|
72
|
+
echo "Next steps for each updated repo:"
|
|
73
|
+
echo " - If you use GitHub Desktop, close and reopen the repo (or restart Desktop)"
|
|
74
|
+
echo " so it picks up the new remote URL."
|
|
75
|
+
echo " - The first push/pull against the new org may prompt you to re-authenticate"
|
|
76
|
+
echo " if your GitHub account/token doesn't already have access to $NEW_ORG."
|
|
77
|
+
fi
|