toga-ai 1.0.225 → 1.0.227
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/knowledge/2.0/apps/worker2/INDEX.md +1 -0
- package/knowledge/2.0/apps/worker2/features/clickup-github-autolink.md +44 -0
- package/knowledge/2.0/apps/worker2/workflows/ticket-to-pseudocode-planning.md +30 -1
- package/knowledge/INDEX.md +1 -1
- package/knowledge/clients/tow-foundation/features/receipt-processing.md +24 -3
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Worker (worker2) Architecture](architecture.md) | Worker (repo `worker2`) is an AWS Elastic Beanstalk **Worker Tier** application that processes background jobs. | worker2/Controller/Index.php, worker2/Worker/, worker2/LambdaFunctions/, _underscore/Worker.php |
|
|
6
6
|
| [ClickUp Connectivity Watchdog](features/clickup-connectivity-watchdog.md) | A cron watchdog that emails when the ClickUp integration looks disconnected during business hours. | worker2/Worker/Clickup/Health.php, worker2/Database/ClickupHealthWatchdog.sql |
|
|
7
|
+
| [ClickUp GitHub-tab Auto-linking & Ticket-id Branch Naming](features/clickup-github-autolink.md) | How ClickUp surfaces branches/PRs/commits in a ticket's **GitHub tab**, and the branch / PR-title naming convention that triggers it. | |
|
|
7
8
|
| [ClickUp Project & Opportunity Multi-List Routing](features/clickup-project-routing.md) | Routes ClickUp tasks into the correct **secondary multi-list memberships** based on their custom-field values, via the `clickup` webhook. | worker2/Worker/Clickup/Project.php, worker2/Worker/Clickup.php |
|
|
8
9
|
| [ClickUp Rich-Text Custom Fields via Quill Delta (API)](features/clickup-richtext-api.md) | ClickUp custom text fields (type `text` and long-text) support rich formatting only through a **Quill Delta** written to the undocumented `value_richtext` key o | test/@dave/clickup_md2delta.js, .claude/skills/plan-ticket/scripts/clickup.js |
|
|
9
10
|
| [ClickUp Work Type Automation (Committed / Conditional / Stretch)](features/clickup-work-type-automation.md) | The ClickUp webhook handler (`_Worker_Clickup`) automatically maintains each task's **Work Type** custom field — `Committed`, `Conditional`, or `Stretch` — base | worker2/Worker/Clickup.php, worker2/Tests/Worker/ClickupWorkTypeTest.php |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: ClickUp GitHub-tab Auto-linking & Ticket-id Branch Naming
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: worker2
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-29
|
|
10
|
+
owners: [dfranks]
|
|
11
|
+
files: []
|
|
12
|
+
related:
|
|
13
|
+
- ../workflows/ticket-to-pseudocode-planning.md
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
How ClickUp surfaces branches/PRs/commits in a ticket's **GitHub tab**, and the branch /
|
|
19
|
+
PR-title naming convention that triggers it. This is the linkage the `/work-ticket` skill
|
|
20
|
+
depends on when it ships PRs for a planned ticket.
|
|
21
|
+
|
|
22
|
+
## How it works
|
|
23
|
+
|
|
24
|
+
- ClickUp's **native GitHub integration** automatically surfaces a branch, PR, or commit in a
|
|
25
|
+
ticket's GitHub tab **whenever the ticket id appears in the branch name and/or the PR
|
|
26
|
+
title/body**. The match is on the textual ticket id (e.g. `TRUE-79868`).
|
|
27
|
+
- **There is no ClickUp API call to create this link.** The `plan-ticket/scripts/clickup.js`
|
|
28
|
+
helper exposes only `get` and `push` (the latter writes the `📝 Pseudocode` field). Linking
|
|
29
|
+
is purely a side effect of the ticket id appearing in Git metadata.
|
|
30
|
+
- Therefore the durable rule for ticket work: name the **git branch as the BARE ticket id**
|
|
31
|
+
(e.g. `TRUE-79868`), **one branch per repo**, and include the ticket id in the PR body.
|
|
32
|
+
PRs default to base branch **`_main`**.
|
|
33
|
+
|
|
34
|
+
## Branch naming overrides the generic git-workflow rule
|
|
35
|
+
|
|
36
|
+
⚠ This intentionally **overrides** the generic `feature/<short-description>` type-prefix rule
|
|
37
|
+
in `.claude/rules/toga/common/git-workflow.md` **for ticket-driven work**. The bare ticket-id
|
|
38
|
+
branch name is exactly what ClickUp's native GitHub integration auto-links on, so a
|
|
39
|
+
`feature/…` prefix would break the auto-link. Confirmed against live repos already on
|
|
40
|
+
`TRUE-79142` (worker) and `TRUE-77219` (api2).
|
|
41
|
+
|
|
42
|
+
## Change history
|
|
43
|
+
|
|
44
|
+
- 2026-06-29 — Initial doc: ClickUp native GitHub integration auto-links any branch/PR carrying the ticket id (no API call; clickup.js exposes only get/push); convention is bare-ticket-id branch name (one per repo) + ticket id in PR body, base `_main`. Bare-id naming intentionally overrides git-workflow.md's feature/ prefix for ticket work, confirmed from live TRUE-79142 (worker) and TRUE-77219 (api2) branches (dfranks)
|
|
@@ -6,13 +6,14 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-29
|
|
10
10
|
owners: [dfranks]
|
|
11
11
|
files:
|
|
12
12
|
- test/@dave/clickup_md2delta.js
|
|
13
13
|
related:
|
|
14
14
|
- ../features/clickup-richtext-api.md
|
|
15
15
|
- ../features/talos-meeting-notes-integration.md
|
|
16
|
+
- ../features/clickup-github-autolink.md
|
|
16
17
|
---
|
|
17
18
|
|
|
18
19
|
## Summary
|
|
@@ -55,6 +56,34 @@ under `test/@dave/approach/`):
|
|
|
55
56
|
**Architecture decision** · **Phases** (each with file paths + pseudocode) · **Testing** ·
|
|
56
57
|
**Risks** · **Owners / open questions** · **Key files**.
|
|
57
58
|
|
|
59
|
+
## Downstream: plan → work pipeline
|
|
60
|
+
|
|
61
|
+
Planning is the **first half** of a two-skill pipeline. Once the plan is approved and pushed
|
|
62
|
+
to the ticket's `📝 Pseudocode` field, the **downstream `/work-ticket <TICKET-ID>` skill**
|
|
63
|
+
(also a local skill, not in the team repo) implements it:
|
|
64
|
+
|
|
65
|
+
1. **Loads the approved plan FROM the ticket's `📝 Pseudocode` field** — the field is the
|
|
66
|
+
source of truth, not the local `approach/<TICKET>.md`. It reads via
|
|
67
|
+
`plan-ticket/scripts/clickup.js get <TICKET>`, which returns JSON
|
|
68
|
+
`{id, custom_id, name, status, description, pseudocodeFieldId, url, fields:{…}}` where
|
|
69
|
+
`fields` is the non-empty custom fields keyed by display name. The plan is the `fields`
|
|
70
|
+
entry whose key contains "Pseudocode" (case-insensitive), as plain text. **Stops if empty.**
|
|
71
|
+
2. **Primes framework context** (self-answered `/kickoff`) from the plan's
|
|
72
|
+
**Repos / Framework / Client** header line.
|
|
73
|
+
3. **Implements phase-by-phase** with implementer subagents (worktree-isolated for independent
|
|
74
|
+
repos) + TOGA reviewers (php-reviewer / sql-reviewer) looping until clean.
|
|
75
|
+
4. **Per repo in the plan's Repos header:** branch → commit → push, then opens **one PR per
|
|
76
|
+
repo** with `gh` (default base branch `_main`).
|
|
77
|
+
5. **Reports and STOPS.**
|
|
78
|
+
|
|
79
|
+
**Autonomy boundary (decided):** `/work-ticket` runs autonomously through PR creation, then
|
|
80
|
+
stops. It **never changes the ClickUp ticket status** — advancing the ticket for approval is
|
|
81
|
+
always a manual developer action, because the developer must review the PR(s) first.
|
|
82
|
+
|
|
83
|
+
See [ClickUp GitHub-tab auto-linking & ticket-id branch naming](../features/clickup-github-autolink.md)
|
|
84
|
+
for the branch/PR naming convention `/work-ticket` relies on.
|
|
85
|
+
|
|
58
86
|
## Change history
|
|
59
87
|
|
|
88
|
+
- 2026-06-29 — Added the downstream half: `/plan-ticket` → `/work-ticket` pipeline. Records how `/work-ticket` loads the approved plan from the `📝 Pseudocode` field (clickup.js `get` JSON shape, "Pseudocode"-keyed plain-text value), implements phase-by-phase with reviewer loops, branches/commits/PRs per repo, and STOPS at PR creation — never touching ClickUp status (manual gate) (dfranks)
|
|
60
89
|
- 2026-06-26 — Initial doc: ticket→pseudocode planning procedure (ClickUp read → codebase investigation → Talos DevCore grounding → phased plan → approval gate → guarded richtext push); records the shape, not the local skill source (dfranks)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -17,7 +17,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
17
17
|
## 2.0 framework
|
|
18
18
|
|
|
19
19
|
- **_underscore** (_Underscore) _(framework core)_ — 17 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
20
|
-
- **worker2** (Worker) —
|
|
20
|
+
- **worker2** (Worker) — 21 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
21
21
|
- **api2** (API) — 7 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
22
22
|
- **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
23
23
|
- **toga2-supply** (TOGa Supply) — 3 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
|
@@ -5,7 +5,7 @@ project: Worker
|
|
|
5
5
|
client: tow-foundation
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
8
|
+
updated: 2026-06-29
|
|
9
9
|
owners: ["rgirish"]
|
|
10
10
|
files:
|
|
11
11
|
- worker2/Worker/Client/TowFoundation.php
|
|
@@ -60,7 +60,7 @@ Credit Card Receipts/
|
|
|
60
60
|
- **`.docx` files bypass Talos** and route to `extractDocxData()` (Talos returns HTTP 500 on a `.docx` MIME type — it only accepts PDF/image). That method opens the docx as a ZIP, extracts `word/document.xml`, strips tags, and regex-parses `MM/DD/YY: description` lines into `line_items[]`
|
|
61
61
|
- All other types POST to Talos AI `/api/ai/generate` → structured `{vendor_name, invoice_date, total, payment_memo, category, ...}`
|
|
62
62
|
- **Year guard on AI dates** — if Talos returns an `invoice_date` whose year is more than 1 year from the current year (AI hallucination on two-digit year inputs, e.g. `5/13/76` → 1976, `5/28/28` → 2028), the year is clamped to the current year while month/day are preserved
|
|
63
|
-
- Cross-verify amount ± $0.01 against parsed statement; if matched, override `payment_memo` with statement description
|
|
63
|
+
- Cross-verify amount ± $0.01 against parsed statement; if matched, override `payment_memo` with the statement description. The statement memo is the **authoritative source for activity-purpose headings** (Grantee meeting, Peer meeting, Grantee event, etc.); the AI memo is good for location/detail but defaults to a bare `"Transportation:"` heading on ride-share/taxi receipts even when the receipt has handwritten activity notes. The override now fires when **either** the AI `payment_memo` is empty **or** it is a bare transportation memo — `isBareTranportationMemo()` returns true when the memo (left-trimmed) starts with `"Transportation:"`. Previously the override only fired on an empty AI memo, so a wrong `"Transportation:"` heading was never corrected.
|
|
64
64
|
- **Zero-total fallback** — if the extracted/docx total is 0, `lookupStatementTotalByVendor()` derives the amount from the billing statement (see *Statement structure* below)
|
|
65
65
|
- Build base filename (no suffix yet) and store in `$pendingRenames`
|
|
66
66
|
- On extract failure → move to `Archive/exception/` immediately
|
|
@@ -157,6 +157,25 @@ the valid category names; keep them in sync with the map keys.
|
|
|
157
157
|
to their QuickBooks Class and Payment Account strings. Ryan Farrell uses Bank of America
|
|
158
158
|
Mastercard; all others use AMEX Open Credit Card.
|
|
159
159
|
|
|
160
|
+
### MoveBack action (restore archived receipts for reprocessing)
|
|
161
|
+
`MoveBack(string $person, string $billingCycle, ?string $year = null): string` is a public
|
|
162
|
+
static action that walks the `Archive/` folder under a person's year directory and moves all
|
|
163
|
+
receipt files (**excluding** `.xlsx`/`.xls`) back into the specified billing-cycle folder,
|
|
164
|
+
creating the target folder if it does not exist. It is the supported way to restore receipts
|
|
165
|
+
after a bad run (wrong memos, duplicate rows, etc.) so they can be reprocessed — it replaces
|
|
166
|
+
the old one-shot `/tmp/tow_restore_archives.php` CLI script.
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"action": "Client/TowFoundation/ProcessReceipts/MoveBack",
|
|
171
|
+
"parameters": { "person": "Emily Tow", "billingCycle": "Amex ending in 06-03-2026" }
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`collectFilesRecursiveRaw(string $accessToken, string $driveId, string $parentId, array &$accumulator): void`
|
|
176
|
+
walks all subfolders of `Archive/` (both the processed root and `exception/`) and collects
|
|
177
|
+
every non-folder item into a flat accumulator array.
|
|
178
|
+
|
|
160
179
|
## Email routing
|
|
161
180
|
|
|
162
181
|
Defined as constants in `TowFoundation.php`:
|
|
@@ -212,10 +231,12 @@ Fatal errors send only to `NOTIFY_EMAIL_DEV` (no CC/BCC).
|
|
|
212
231
|
- **Duplicate detection is within-run only** — if the same receipt was processed in a prior run and archived, it won't be caught. The dedup only covers receipts present in the current run's `$pendingRenames`.
|
|
213
232
|
- **Unmapped AI categories pass through** — if the AI returns a category string not in `TowFoundationCategories.php`, `mapCategory()` logs a warning and writes the raw AI string to the Excel. Check error logs after a run if the Category column looks odd; add the new value to the map file to fix it.
|
|
214
233
|
- **Short vendor acronyms (< 4 chars) require whole-word match** — the substring pass uses a word-boundary regex for needles under 4 chars to avoid false positives (e.g. `"UPS"` inside `"USPS"`). If a short vendor name is not matching, check that the QB vendor list entry starts or ends with the acronym as a whole word.
|
|
215
|
-
- **
|
|
234
|
+
- **Restoring archived receipts** — use the committed `MoveBack` action (see *MoveBack action* above), not a one-shot CLI script. It moves all non-Excel receipt files from a person's `Archive/` back into the named billing-cycle folder. (The earlier throwaway `/tmp/tow_restore_archives.php` script is obsolete.)
|
|
235
|
+
- **Mixed-cycle receipts can collect in Archive** — receipts from a prior run can linger in a person's `Archive/` under a different billing cycle (e.g. January receipts found alongside May during an Emily Tow restore). `MoveBack` moves **everything** in `Archive/` back, so after a restore, verify the receipts belong to the cycle you intend to reprocess; stray off-cycle files should be moved (via Graph API) to their own billing-cycle folder so they are not reprocessed with the wrong cycle.
|
|
216
236
|
|
|
217
237
|
## Change history
|
|
218
238
|
|
|
239
|
+
- 2026-06-29 — `payment_memo` override now also fires on a **bare** `"Transportation:"` AI memo, not just an empty one: new `isBareTranportationMemo()` lets the cardholder's statement Excel (the authoritative source for activity-purpose headings like "Peer meeting:", "Grantee event:") override the AI's generic transportation heading. Fixes wrong headings on Emily Tow May 2026 transit rows. Added the committed `MoveBack` action (+ `collectFilesRecursiveRaw()`) to restore a person's archived receipts into a billing-cycle folder for reprocessing, replacing the throwaway `/tmp/tow_restore_archives.php` script. (rgirish)
|
|
219
240
|
- 2026-06-25 — Statement parsing hardened for Emily Tow's May 2026 Amex xlsx: `loadStatementExcel()` now iterates `getAllSheets()` (4 weekly-period sheets) instead of `getActiveSheet()` and captures the `Receipt` column; `lookupStatementTotalByVendor()` now **sums** all receipt-label-matched rows (14 × $3.00 "Subway Rides" = $42.00) before falling back to description-keyword match — fixes subway totals reading $0/$9.00. Added `extractDocxData()` so `.docx` receipts bypass Talos (Talos 500s on docx), parsing `MM/DD/YY: description` line items into per-entry Excel rows. Added a year guard clamping AI-hallucinated `invoice_date` years (e.g. 1976, 2028) to the current year. Fixed archive-path bug: SharePoint move now uses the actual folder name (`"Emily Tow CC receipts"`) not the normalized name, fixing 404 on archive moves. 5 more vendors found missing from the QB vendor list (client action). (rgirish)
|
|
220
241
|
- 2026-06-23 — `TowFoundationCategories.php` added: AI category values now mapped to exact QB account strings via `mapCategory()`; `"Transportation"` → `"6610 Travel expense"` etc. (19 mappings). QB vendor substring match minimum lowered from 4 to 3 chars with whole-word boundary guard for short needles — fixes `"CVS"` → `"CVS Pharmacy"`, `"MTA"` → `"MTA Metro card"`, prevents `"UPS"` → `"USPS"` false positive. (rgirish)
|
|
221
242
|
- 2026-06-18 — QB vendor matching via local fuzzy match against `TowFoundationVendors.php` (2,994 vendors); AI category prompt updated to return specific types (Dining, Travel, etc.); duplicate receipt detection added (person+date+vendor+amount dedup); `billingCycle` filter parameter added (suffix-match — card-type agnostic); person folder ` CC receipts` suffix stripped so CLASS_MAP/PAYMENT_ACCOUNT_MAP resolve correctly (rgirish)
|
package/package.json
CHANGED