toga-ai 1.0.80 → 1.0.82

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.
@@ -1,6 +1,27 @@
1
1
  {
2
2
  "hooks": {
3
+ "UserPromptSubmit": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \".claude/hooks/toga/kickoff-gate.js\"",
9
+ "timeout": 3000
10
+ }
11
+ ]
12
+ }
13
+ ],
3
14
  "PreToolUse": [
15
+ {
16
+ "matcher": "Bash|Read|Grep|Glob|Edit|Write|MultiEdit|NotebookEdit|Task|WebFetch|WebSearch",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "node \".claude/hooks/toga/kickoff-gate.js\"",
21
+ "timeout": 3000
22
+ }
23
+ ]
24
+ },
4
25
  {
5
26
  "matcher": "Bash",
6
27
  "hooks": [
@@ -1,6 +1,6 @@
1
- # toga2-hub (TOGA Hub) — 2.0 knowledge
1
+ # toga2-hub (TOGa Hub) — 2.0 knowledge
2
2
 
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
- | [TOGA Hub Architecture](architecture.md) | toga2-hub (TOGA Hub) is a React + TypeScript single-page admin portal for the TOGA platform. | toga2-hub/src/main.tsx, toga2-hub/src/routes.tsx, toga2-hub/src/App.tsx, toga2-hub/src/api/axiosInstance.ts, toga2-hub/src/api/apiFunctions.ts, toga2-hub/src/utils/queryHelpers.ts, toga2-hub/src/contexts/AuthContext.tsx, toga2-hub/src/stores/useUserStore.ts |
6
- | [ACL Record Permissions — Rendering Semantics (Permissions Page)](features/acl-permissions-rendering.md) | How the TOGA Hub Permissions page must interpret the api2 endpoint `GET /v2/acl-record-permissions/getAclRecordPermissionsByRecordAndRole` and turn its response | toga2-hub/src/pages/Permissions/api/permissionsApi.ts, toga2-hub/src/pages/Permissions/utils/permissionsUtils.ts, toga2-hub/src/pages/Permissions/viewModel/useRolesViewModel.ts, toga2-hub/src/hooks/useAclPermissionsByRoleQuery.ts, toga2-hub/src/pages/Permissions/view/RolesView/RoleDetailView/LogicGroupView.tsx, toga2-hub/src/pages/Permissions/view/RecordsView/RecordDetailView/RecordDetailView.tsx, toga2-hub/src/hooks/useQueryData.ts |
5
+ | [TOGa Hub Architecture](architecture.md) | toga2-hub (TOGa Hub) is a React + TypeScript single-page admin portal for the TOGA platform. | toga2-hub/src/main.tsx, toga2-hub/src/routes.tsx, toga2-hub/src/App.tsx, toga2-hub/src/api/axiosInstance.ts, toga2-hub/src/api/apiFunctions.ts, toga2-hub/src/utils/queryHelpers.ts, toga2-hub/src/contexts/AuthContext.tsx, toga2-hub/src/stores/useUserStore.ts |
6
+ | [ACL Record Permissions — Rendering Semantics (Permissions Page)](features/acl-permissions-rendering.md) | How the TOGa Hub Permissions page must interpret the api2 endpoint `GET /v2/acl-record-permissions/getAclRecordPermissionsByRecordAndRole` and turn its response | toga2-hub/src/pages/Permissions/api/permissionsApi.ts, toga2-hub/src/pages/Permissions/utils/permissionsUtils.ts, toga2-hub/src/pages/Permissions/viewModel/useRolesViewModel.ts, toga2-hub/src/hooks/useAclPermissionsByRoleQuery.ts, toga2-hub/src/pages/Permissions/view/RolesView/RoleDetailView/LogicGroupView.tsx, toga2-hub/src/pages/Permissions/view/RecordsView/RecordDetailView/RecordDetailView.tsx, toga2-hub/src/hooks/useQueryData.ts |
@@ -1,8 +1,8 @@
1
1
  ---
2
- title: TOGA Hub Architecture
2
+ title: TOGa Hub Architecture
3
3
  framework: "2.0"
4
4
  repo: toga2-hub
5
- project: TOGA Hub
5
+ project: TOGa Hub
6
6
  client: shared
7
7
  type: architecture
8
8
  status: active
@@ -23,7 +23,7 @@ related:
23
23
 
24
24
  ## Summary
25
25
 
26
- toga2-hub (TOGA Hub) is a React + TypeScript single-page admin portal for the TOGA
26
+ toga2-hub (TOGa Hub) is a React + TypeScript single-page admin portal for the TOGA
27
27
  platform. It is a pure frontend client — all business logic and persistence live in the
28
28
  `api2` backend (framework 2.0), which Hub talks to exclusively over REST. The portal is
29
29
  multi-tenant: it selects both its API endpoint and theme from the hostname it is served
@@ -2,7 +2,7 @@
2
2
  title: ACL Record Permissions — Rendering Semantics (Permissions Page)
3
3
  framework: "2.0"
4
4
  repo: toga2-hub
5
- project: TOGA Hub
5
+ project: TOGa Hub
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
@@ -21,7 +21,7 @@ related: []
21
21
 
22
22
  ## Summary
23
23
 
24
- How the TOGA Hub Permissions page must interpret the api2 endpoint
24
+ How the TOGa Hub Permissions page must interpret the api2 endpoint
25
25
  `GET /v2/acl-record-permissions/getAclRecordPermissionsByRecordAndRole` and turn its
26
26
  response into the green-check / red-X permissions grid. Semantics confirmed in a design
27
27
  review with jcardinal (Naperville, 2026-06-09); an earlier implementation over-thought
@@ -18,7 +18,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
18
18
  - **toga2-supply** (TOGa Supply) — 2 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
19
19
  - **saml** (SAML SSO Gateway) — 2 doc(s) → [2.0/apps/saml/INDEX.md](2.0/apps/saml/INDEX.md)
20
20
  - **toga2-view** (TOGa View Frontend) — 0 doc(s) → [2.0/apps/toga2-view/INDEX.md](2.0/apps/toga2-view/INDEX.md)
21
- - **toga2-hub** (TOGA Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
21
+ - **toga2-hub** (TOGa Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
22
22
 
23
23
  ## Clients
24
24
 
@@ -10,6 +10,6 @@
10
10
  { "repo": "toga2-view", "project": "TOGa View Frontend", "framework": "2.0", "role": "app", "dependsOn": ["api2"] },
11
11
  { "repo": "togadesk", "project": "TOGa Desk", "framework": "1.0", "role": "app", "dependsOn": [] },
12
12
  { "repo": "togaview", "project": "TOGa View", "framework": "1.0", "role": "app", "dependsOn": [] },
13
- { "repo": "toga2-hub", "project": "TOGA Hub", "framework": "2.0", "role": "app", "dependsOn": ["api2"] }
13
+ { "repo": "toga2-hub", "project": "TOGa Hub", "framework": "2.0", "role": "app", "dependsOn": ["api2"] }
14
14
 
15
15
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.80",
3
+ "version": "1.0.82",
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",
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * kickoff-gate.js — DETERMINISTIC enforcement of the /kickoff priming gate.
6
+ *
7
+ * Why this exists: the kickoff SKILL.md states a "hard gate" — when /kickoff is
8
+ * invoked you MUST complete priming (Steps 0–6) BEFORE touching the task with any
9
+ * Read/Grep/Glob/Edit/Write/Task call. Prose alone did not stop the model from
10
+ * jumping straight to investigation when /kickoff was followed by a long, specific
11
+ * task description. This hook makes the gate mechanical, not advisory.
12
+ *
13
+ * It registers for TWO events from a single file:
14
+ *
15
+ * UserPromptSubmit → if the submitted prompt invokes /kickoff, ARM the gate:
16
+ * write a session-scoped lock and inject a forceful reminder.
17
+ *
18
+ * PreToolUse → while the gate is armed for THIS session, ALLOW only the
19
+ * read-only priming steps (the priming Bash commands + the
20
+ * interview via AskUserQuestion/Skill, which don't match the
21
+ * PreToolUse matcher) and BLOCK every task tool
22
+ * (Read/Grep/Glob/Edit/Write/MultiEdit/NotebookEdit/Task/
23
+ * WebFetch/WebSearch and any non-priming Bash). The lock
24
+ * AUTO-CLEARS the moment `knowledge.js kickoff-preflight`
25
+ * runs — the definitive priming step that precedes Step 4's
26
+ * first Read. So the model literally cannot investigate or
27
+ * edit the task until it has actually primed.
28
+ *
29
+ * Fail-open: any internal/parse error allows the tool (a crashing gate must never
30
+ * brick every session). The SKILL.md prose remains the backup.
31
+ *
32
+ * Escape hatch: set KICKOFF_GATE_DISABLED=1 to disable enforcement entirely.
33
+ */
34
+
35
+ const fs = require('fs');
36
+ const path = require('path');
37
+
38
+ /* ---------- input: read stdin JSON (CC standard), fall back to env ---------- */
39
+ function readPayload() {
40
+ let raw = '';
41
+ try { raw = fs.readFileSync(0, 'utf8'); } catch (e) { /* no stdin */ }
42
+ let data = {};
43
+ if (raw && raw.trim()) {
44
+ try { data = JSON.parse(raw); } catch (e) { data = {}; }
45
+ }
46
+ // env fallbacks used by this harness's other hooks
47
+ if (!data.tool_name && process.env.CLAUDE_TOOL_NAME) data.tool_name = process.env.CLAUDE_TOOL_NAME;
48
+ if (!data.tool_input && process.env.CLAUDE_TOOL_INPUT) {
49
+ try { data.tool_input = JSON.parse(process.env.CLAUDE_TOOL_INPUT); } catch (e) {}
50
+ }
51
+ if (!data.prompt && process.env.CLAUDE_USER_PROMPT) data.prompt = process.env.CLAUDE_USER_PROMPT;
52
+ if (!data.session_id && process.env.CLAUDE_SESSION_ID) data.session_id = process.env.CLAUDE_SESSION_ID;
53
+ return data;
54
+ }
55
+
56
+ function lockPath() {
57
+ return path.join(process.cwd(), '.claude', '.kickoff-gate.json');
58
+ }
59
+
60
+ function readLock() {
61
+ try { return JSON.parse(fs.readFileSync(lockPath(), 'utf8')); } catch (e) { return null; }
62
+ }
63
+
64
+ function writeLock(sessionId) {
65
+ try {
66
+ fs.mkdirSync(path.dirname(lockPath()), { recursive: true });
67
+ fs.writeFileSync(lockPath(), JSON.stringify({ session: sessionId || null, ts: Date.now() }) + '\n');
68
+ } catch (e) { /* non-fatal */ }
69
+ }
70
+
71
+ function clearLock() {
72
+ try { fs.unlinkSync(lockPath()); } catch (e) { /* already gone */ }
73
+ }
74
+
75
+ /* A prompt invokes /kickoff if it carries any of these signals (covers the literal
76
+ * "/kickoff ...", the expanded skill command form, and the rendered skill header). */
77
+ function invokesKickoff(prompt) {
78
+ if (typeof prompt !== 'string' || !prompt) return false;
79
+ return (
80
+ /(^|\s)\/kickoff(\s|$)/.test(prompt) ||
81
+ /command-name>\s*\/?kickoff\s*<\/command-name>/i.test(prompt) ||
82
+ /Kickoff\s+—\s+prime a coding session/i.test(prompt)
83
+ );
84
+ }
85
+
86
+ /* Bash commands that ARE the read-only priming steps (Steps 0–3). Everything else
87
+ * is task work and stays blocked until preflight clears the gate. */
88
+ function isPrimingBash(command) {
89
+ if (typeof command !== 'string') return false;
90
+ return /knowledge\.js|kickoff-preflight|toga-ai\.version|npm\s+view\s+toga-ai|npx\s+toga-ai|registry\.json|rev-parse/i.test(command);
91
+ }
92
+
93
+ function isPreflightBash(command) {
94
+ return typeof command === 'string' && /kickoff-preflight/i.test(command);
95
+ }
96
+
97
+ /* Tools that constitute touching the task — blocked while the gate is armed. */
98
+ const BLOCKED_TOOLS = new Set([
99
+ 'Read', 'Grep', 'Glob', 'Edit', 'Write', 'MultiEdit',
100
+ 'NotebookEdit', 'Task', 'Agent', 'WebFetch', 'WebSearch',
101
+ ]);
102
+
103
+ function blockMessage() {
104
+ return [
105
+ '🛑 KICKOFF GATE — priming is not complete.',
106
+ '',
107
+ '/kickoff was invoked this session. You MUST finish priming BEFORE touching the task',
108
+ 'with any Read/Grep/Glob/Edit/Write/Task call — no matter how detailed the request after',
109
+ '/kickoff looks. That trailing text is the Step 2 task description, NOT permission to start.',
110
+ '',
111
+ 'Do this now, in order (these are allowed while the gate is armed):',
112
+ ' • Step 0 version check (cat .claude/toga-ai.version ; npm view toga-ai version)',
113
+ ' • Step 1 resolve the team repo (probe for knowledge/registry.json)',
114
+ ' • Step 2 interview the developer (framework / layer / repo(s) / client / task)',
115
+ ' • Step 3 node "<TEAM_REPO>/knowledge.js" kickoff-preflight ... ← this AUTO-CLEARS the gate',
116
+ ' • Step 4+ THEN read the knowledge docs and start the task',
117
+ '',
118
+ 'The gate releases automatically the instant kickoff-preflight runs.',
119
+ '(Emergency override only: set KICKOFF_GATE_DISABLED=1.)',
120
+ ].join('\n');
121
+ }
122
+
123
+ function main() {
124
+ if (process.env.KICKOFF_GATE_DISABLED === '1') process.exit(0);
125
+
126
+ const data = readPayload();
127
+
128
+ // ---- UserPromptSubmit: arm the gate when /kickoff is invoked ----
129
+ // Identify by the presence of a prompt and absence of a tool call.
130
+ const isPromptEvent =
131
+ data.hook_event_name === 'UserPromptSubmit' ||
132
+ (typeof data.prompt === 'string' && !data.tool_name);
133
+
134
+ if (isPromptEvent) {
135
+ if (invokesKickoff(data.prompt)) {
136
+ writeLock(data.session_id);
137
+ // stdout from UserPromptSubmit is injected into the model's context.
138
+ console.log(
139
+ '<system-reminder>KICKOFF GATE ARMED. Before ANY other tool call, complete priming ' +
140
+ 'Steps 0–6 of the kickoff skill — version check, resolve team repo, interview, then ' +
141
+ 'run `knowledge.js kickoff-preflight` (which releases the gate), THEN read docs and work. ' +
142
+ 'The trailing task description is Step 2 input, not permission to start. ' +
143
+ 'A hook will block Read/Grep/Edit/Write/Task until preflight runs.</system-reminder>'
144
+ );
145
+ }
146
+ process.exit(0);
147
+ }
148
+
149
+ // ---- PreToolUse: enforce while armed for THIS session ----
150
+ const lock = readLock();
151
+ if (!lock) process.exit(0);
152
+
153
+ // Cross-session safety: only enforce for the session that armed the gate.
154
+ // If we can't match sessions, fall back to a 3-hour staleness window.
155
+ const sameSession = lock.session && data.session_id && lock.session === data.session_id;
156
+ const fresh = lock.ts && (Date.now() - lock.ts) < 3 * 60 * 60 * 1000;
157
+ if (!sameSession && !fresh) { clearLock(); process.exit(0); }
158
+ if (data.session_id && lock.session && !sameSession) process.exit(0);
159
+
160
+ const tool = data.tool_name || '';
161
+ const command = (data.tool_input && data.tool_input.command) || '';
162
+
163
+ if (tool === 'Bash') {
164
+ if (isPreflightBash(command)) { clearLock(); process.exit(0); } // priming reached — release
165
+ if (isPrimingBash(command)) process.exit(0); // other read-only priming step
166
+ console.log(blockMessage());
167
+ process.exit(2);
168
+ }
169
+
170
+ if (BLOCKED_TOOLS.has(tool)) {
171
+ console.log(blockMessage());
172
+ process.exit(2);
173
+ }
174
+
175
+ // Anything else (AskUserQuestion, Skill, TodoWrite, ExitPlanMode, …) is part of
176
+ // priming/interview — allow.
177
+ process.exit(0);
178
+ }
179
+
180
+ try { main(); } catch (e) { process.exit(0); } // fail-open: never brick a session
@@ -22,6 +22,16 @@ description: Start-of-session context loader for TOGA Technology projects. Run t
22
22
  >
23
23
  > Only after Step 5's "primed and ready" summary (and Step 6's plan, for non-trivial work)
24
24
  > may you touch the task itself.
25
+ >
26
+ > **This gate is mechanically enforced — it is not just prose.** A hook
27
+ > (`hooks/toga/kickoff-gate.js`, wired on `UserPromptSubmit` + `PreToolUse`) arms the
28
+ > instant `/kickoff` is invoked and will **hard-block** `Read`, `Grep`, `Glob`, `Edit`,
29
+ > `Write`, `Task`, and any non-priming `Bash` until you actually prime. The only calls it
30
+ > permits while armed are the read-only priming steps (the version check, team-repo probe,
31
+ > `knowledge.js manifest`, the developer interview) and `knowledge.js kickoff-preflight` —
32
+ > **running preflight (Step 3) is what releases the gate.** So the correct response to a
33
+ > block message is never to fight it: run Steps 0–3, and the moment preflight executes you
34
+ > are free to read docs and work. (Emergency override only: `KICKOFF_GATE_DISABLED=1`.)
25
35
 
26
36
  ## Arguments — text passed after `/kickoff` never skips any step
27
37