@ulpi/cli 0.1.6 → 0.1.8
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/README.md +143 -214
- package/dist/{chunk-KYYI23AQ.js → chunk-BV5UYMYQ.js} +1 -1
- package/dist/{chunk-V2H5D6Y3.js → chunk-PO4NUZUU.js} +2 -1
- package/dist/{chunk-VXH5Y4FO.js → chunk-WVOZE25N.js} +6 -10
- package/dist/{chunk-VVEDXI7E.js → chunk-XKF4DPUM.js} +6 -6
- package/dist/{ci-X3U2W4HC.js → ci-ZKXPTYOS.js} +2 -2
- package/dist/{doctor-SI4LLLDZ.js → doctor-OHAU2ZOF.js} +1 -1
- package/dist/{history-5NE46ZAH.js → history-INYAXMBQ.js} +1 -1
- package/dist/{hooks-installer-UN5JZLDQ.js → hooks-installer-YEYTYA6Q.js} +1 -1
- package/dist/index.js +16 -16
- package/dist/{init-5FK3VKRT.js → init-TJYW5ROZ.js} +4 -4
- package/dist/{launchd-6AWT54HR.js → launchd-U3MSWBRH.js} +1 -1
- package/dist/{review-integration-5WHEJU2A.js → review-integration-RQE4KMAV.js} +1 -1
- package/dist/{server-KKSETHDV-XSSLEENT.js → server-U7PQ6FTS-MG4MJPTS.js} +1 -1
- package/dist/skills/ulpi-generate-guards/SKILL.md +750 -0
- package/dist/skills/ulpi-generate-guards/references/framework-rules.md +849 -0
- package/dist/skills/ulpi-generate-guards/references/language-rules.md +591 -0
- package/dist/{start-JYOEL7AJ.js → start-SQRNELKC.js} +3 -3
- package/dist/{uninstall-ICUV6DDV.js → uninstall-BX6FOV77.js} +2 -2
- package/dist/{update-7ZMAYRBH.js → update-V4LET4UD.js} +2 -2
- package/dist/{version-checker-4ZFMZA7Y.js → version-checker-AUAHP4P2.js} +1 -1
- package/package.json +39 -38
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# ULPI
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Your Autonomous Engineering Fleet.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Dynamic hooks that govern any AI coding agent in real time. Centralized one-click MCP servers per project. Semantic code search, persistent memory, and a full visual dashboard — locally or in the cloud. Upload a sprint and watch your fleet execute dozens of tasks in parallel.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@ulpi/cli)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -10,309 +10,238 @@ ULPI sits between you and Claude Code, automatically approving safe operations,
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## Why ULPI?
|
|
14
|
-
|
|
15
|
-
Without ULPI, every Claude Code session is a stream of permission prompts. You click "Allow" for `npm test`. Allow for `git status`. Allow for reading a file. Over and over.
|
|
16
|
-
|
|
17
|
-
With ULPI:
|
|
18
|
-
|
|
19
|
-
- `npm test` runs automatically — you defined it as safe
|
|
20
|
-
- `rm -rf /` gets blocked — before Claude can execute it
|
|
21
|
-
- Editing a file requires reading it first — because you set that rule
|
|
22
|
-
- Your session history is preserved — decisions, patterns, and context carry over
|
|
23
|
-
|
|
24
|
-
You write the rules once. ULPI enforces them every session.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
13
|
## Install
|
|
29
14
|
|
|
30
15
|
```bash
|
|
31
16
|
npm install -g @ulpi/cli
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Requires **Node.js 20** or later.
|
|
35
|
-
|
|
36
|
-
## Get Started
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
cd your-project
|
|
40
17
|
ulpi init
|
|
41
18
|
```
|
|
42
19
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Next time you start a Claude Code session, ULPI is active.
|
|
46
|
-
|
|
47
|
-
### Try it without installing
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
npx @ulpi/cli init
|
|
51
|
-
```
|
|
20
|
+
Requires **Node.js 20+**. `init` detects your stack, generates rules with AI, installs hooks, starts the daemon, and registers your project. Use `--no-ai` for template-only generation, or `--model=<id>` to pick a specific model.
|
|
52
21
|
|
|
53
22
|
---
|
|
54
23
|
|
|
55
|
-
##
|
|
56
|
-
|
|
57
|
-
### Automatic Permissions
|
|
58
|
-
|
|
59
|
-
Stop clicking "Allow" for every safe command. Define what's safe once, and ULPI handles the rest.
|
|
60
|
-
|
|
61
|
-
```yaml
|
|
62
|
-
permissions:
|
|
63
|
-
auto-approve-tests:
|
|
64
|
-
trigger: PermissionRequest
|
|
65
|
-
matcher: Bash
|
|
66
|
-
command_pattern: "npm test|pnpm test|yarn test"
|
|
67
|
-
decision: allow
|
|
68
|
-
|
|
69
|
-
auto-approve-git-read:
|
|
70
|
-
trigger: PermissionRequest
|
|
71
|
-
matcher: Bash
|
|
72
|
-
command_pattern: "git (status|log|diff|branch)"
|
|
73
|
-
decision: allow
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Guardrails
|
|
77
|
-
|
|
78
|
-
Block destructive operations before they execute. ULPI ships with built-in protection against `rm -rf`, `git push --force`, `DROP TABLE`, and more — plus you can add your own.
|
|
79
|
-
|
|
80
|
-
### Preconditions
|
|
81
|
-
|
|
82
|
-
Enforce good practices automatically. Require files to be read before editing. Require tests to pass before committing. Require linting before pushing.
|
|
83
|
-
|
|
84
|
-
```yaml
|
|
85
|
-
preconditions:
|
|
86
|
-
read-before-edit:
|
|
87
|
-
trigger: PreToolUse
|
|
88
|
-
matcher: "Write|Edit"
|
|
89
|
-
message: "Read the file before editing it."
|
|
90
|
-
requires_read: true
|
|
91
|
-
|
|
92
|
-
test-before-commit:
|
|
93
|
-
trigger: PreToolUse
|
|
94
|
-
matcher: Bash
|
|
95
|
-
command_pattern: "git commit"
|
|
96
|
-
message: "Run tests before committing."
|
|
97
|
-
requires:
|
|
98
|
-
tests_run: true
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Pipelines
|
|
24
|
+
## Commands
|
|
102
25
|
|
|
103
|
-
|
|
26
|
+
### Core
|
|
104
27
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
command_pattern: "git commit"
|
|
111
|
-
steps:
|
|
112
|
-
- name: build
|
|
113
|
-
command: "pnpm -r build"
|
|
114
|
-
- name: test
|
|
115
|
-
command: "pnpm test"
|
|
116
|
-
block_on_failure: true
|
|
117
|
-
```
|
|
28
|
+
| Command | What it does |
|
|
29
|
+
|---------|-------------|
|
|
30
|
+
| `ulpi init` | Detect stack, generate guards, install hooks |
|
|
31
|
+
| `ulpi start` | Start ULPI daemon (API server + codemap watcher + portal) |
|
|
32
|
+
| `ulpi run` | Start execution engine loop (`--prd`, `--agent`, `--tasks`) |
|
|
118
33
|
|
|
119
|
-
###
|
|
34
|
+
### Management
|
|
120
35
|
|
|
121
|
-
|
|
36
|
+
| Command | What it does |
|
|
37
|
+
|---------|-------------|
|
|
38
|
+
| `ulpi repos` | Manage registered repos (list/add/remove/default) |
|
|
39
|
+
| `ulpi rules` | List, add, enable, disable, or validate rules |
|
|
40
|
+
| `ulpi templates` | Browse, apply, save, export, or import templates |
|
|
41
|
+
| `ulpi skills` | List, add, get, or attach skills |
|
|
42
|
+
| `ulpi config` | Manage settings and API keys |
|
|
43
|
+
| `ulpi prd` | PRD management (create/convert/show) |
|
|
44
|
+
| `ulpi job` | Manage execution jobs (create/list/status/cancel/logs) |
|
|
122
45
|
|
|
123
|
-
|
|
46
|
+
### Monitoring
|
|
124
47
|
|
|
125
|
-
|
|
48
|
+
| Command | What it does |
|
|
49
|
+
|---------|-------------|
|
|
50
|
+
| `ulpi status` | Show current session state |
|
|
51
|
+
| `ulpi log` | View activity log |
|
|
52
|
+
| `ulpi history` | Shadow branch history (init/capture/list/show/enrich/backfill) |
|
|
53
|
+
| `ulpi tui` | Terminal UI client (connects to daemon) |
|
|
54
|
+
| `ulpi portal` | Start Portal dashboard in local mode |
|
|
55
|
+
| `ulpi doctor` | System health check (agents, MCP, hooks, intelligence) |
|
|
126
56
|
|
|
127
|
-
|
|
57
|
+
### Data & Intelligence
|
|
128
58
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
59
|
+
| Command | What it does |
|
|
60
|
+
|---------|-------------|
|
|
61
|
+
| `ulpi codemap` | Semantic code indexing (init/search/status/reindex/watch) |
|
|
62
|
+
| `ulpi memory` | Agent memory (init/search/remember/status/export/import) |
|
|
63
|
+
| `ulpi mcp` | MCP management (gateway/list/add/remove/enable/disable/catalog/setup) |
|
|
64
|
+
| `ulpi cloud` | Connect to Cloud MCP Gateway (connect/status/disconnect) |
|
|
132
65
|
|
|
133
|
-
|
|
66
|
+
### Agent Integrations
|
|
134
67
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
- **Memory** — Memory count, classified sessions, importance breakdown
|
|
140
|
-
- **History** — Captured entries with AI enrichment status
|
|
141
|
-
- **Skills** — Available bundled, project, and global skills
|
|
142
|
-
- **Responses** — Notification channel configuration
|
|
68
|
+
| Command | What it does |
|
|
69
|
+
|---------|-------------|
|
|
70
|
+
| `ulpi kiro` | Manage Kiro CLI integration (install/convert/uninstall/status) |
|
|
71
|
+
| `ulpi codex` | Manage Codex CLI integration (install/convert/uninstall/status) |
|
|
143
72
|
|
|
144
|
-
###
|
|
73
|
+
### Utility
|
|
145
74
|
|
|
146
|
-
|
|
75
|
+
| Command | What it does |
|
|
76
|
+
|---------|-------------|
|
|
77
|
+
| `ulpi export` | Export rules configuration |
|
|
78
|
+
| `ulpi import` | Import rules configuration |
|
|
79
|
+
| `ulpi update` | Check for and install updates |
|
|
80
|
+
| `ulpi ci` | Run in CI/PR worker mode (used inside worker containers) |
|
|
81
|
+
| `ulpi auth` | Manage AI agent credentials for CI workers |
|
|
82
|
+
| `ulpi uninstall` | Remove hooks and ULPI from a project |
|
|
147
83
|
|
|
148
|
-
|
|
84
|
+
Run `ulpi --help` for the full list, or use `-p <project>` to target a specific registered project.
|
|
149
85
|
|
|
150
|
-
|
|
86
|
+
---
|
|
151
87
|
|
|
152
|
-
|
|
88
|
+
## Five Pillars
|
|
153
89
|
|
|
154
|
-
###
|
|
90
|
+
### Govern
|
|
155
91
|
|
|
156
|
-
|
|
92
|
+
Define what your AI agent can and cannot do. Four rule types — preconditions, permissions, postconditions, and pipelines — work together for layered enforcement. 28 bundled templates auto-selected for your detected stack. Auto-approve safe operations, block dangerous commands, enforce read-before-write. Session-aware — tracks reads, writes, tests, and lints across the entire session. Fail-open — if ULPI errors, your agent continues unblocked.
|
|
157
93
|
|
|
158
|
-
|
|
159
|
-
- **Symbol extraction** identifies functions, classes, interfaces, and types
|
|
160
|
-
- **Hybrid ranking** fuses vector similarity (60%), keyword matching (25%), symbol boost (10%), and path relevance (5%)
|
|
161
|
-
- **Incremental indexing** — only re-indexes changed files
|
|
162
|
-
- **Per-branch indexes** — each git branch gets its own index
|
|
163
|
-
- **Shadow branch export** — share indexes across machines via git
|
|
94
|
+
### Understand
|
|
164
95
|
|
|
165
|
-
|
|
96
|
+
Your agent understands your entire codebase. CodeMap provides hybrid vector + BM25 semantic search with AST-aware chunking. DepGraph uses tree-sitter entity mapping across 35 languages to build dependency graphs with PageRank importance ranking, cycle detection, and coupling metrics. 18 MCP tools exposed directly to your agent. Stack detection with 10 detectors: runtime, language, framework, package manager, formatter, linter, test runner, ORM, git workflow, features.
|
|
166
97
|
|
|
167
|
-
|
|
168
|
-
ulpi codemap init # Index your codebase
|
|
169
|
-
ulpi codemap search "authentication middleware"
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Agent Memory
|
|
98
|
+
### Remember
|
|
173
99
|
|
|
174
|
-
Your
|
|
100
|
+
Your agent learns from every session instead of starting fresh. ULPI captures session events, classifies them with an LLM into 8 memory types — decisions, patterns, bug root causes, preferences, constraints, context, lessons, and relationships — then stores them with vector embeddings for semantic search. Relevant memories are surfaced automatically at the start of each new session. Deduplication, importance-weighted ranking, and redaction of secrets.
|
|
175
101
|
|
|
176
|
-
|
|
102
|
+
### Record
|
|
177
103
|
|
|
178
|
-
|
|
104
|
+
Complete audit trail of every AI action. Per-user shadow git branches (`ulpi/history-<user>`) store structured records without touching your working tree. Commit diffs, session analytics, metadata, full transcripts, and AI enrichment (summary, intent, challenges, learnings, recommendations). No database — everything lives in git and travels with your repo.
|
|
179
105
|
|
|
180
|
-
|
|
181
|
-
- **Importance-weighted ranking** — critical memories never decay; low-importance ones fade over time
|
|
182
|
-
- **Redaction** — API keys, tokens, and secrets are stripped before storage
|
|
183
|
-
- **Soft delete** — memories can be superseded rather than permanently removed
|
|
106
|
+
### Orchestrate
|
|
184
107
|
|
|
185
|
-
|
|
108
|
+
From PRD to production. The execution engine (`ulpi run`) parses a PRD into structured tasks, builds a dependency graph, schedules parallel work across multiple agents, and auto-commits results. 6 agent adapters, 5 task trackers, configurable retries, branch management, and team delegation.
|
|
186
109
|
|
|
187
110
|
```bash
|
|
188
|
-
ulpi
|
|
189
|
-
ulpi
|
|
111
|
+
ulpi run --prd feature.md --agent claude --auto-commit
|
|
112
|
+
ulpi run --tracker jira --agent gemini --branch feat/new-feature
|
|
113
|
+
ulpi run --tasks tasks.json --agent claude --parallel
|
|
190
114
|
```
|
|
191
115
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
Every coding session is recorded on a per-user orphan git branch (`ulpi/history-<username>`) — separate from your code, never touching your working tree.
|
|
116
|
+
---
|
|
195
117
|
|
|
196
|
-
|
|
118
|
+
## Supported Agents
|
|
197
119
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
120
|
+
| Agent | Hook Support | MCP Support | Execution Engine |
|
|
121
|
+
|-------|-------------|-------------|-----------------|
|
|
122
|
+
| Claude Code | Full (7 hooks) | Full (18 tools) | `--agent claude` |
|
|
123
|
+
| Gemini CLI | Full (7 hooks) | Full (18 tools) | `--agent gemini` |
|
|
124
|
+
| OpenCode | Full (7 hooks) | Full (18 tools) | `--agent opencode` |
|
|
125
|
+
| Kiro CLI | Full (4 hooks) | Full (18 tools) | `--agent kiro` |
|
|
126
|
+
| Codex | Prompt governance | Full (18 tools) | `--agent codex` |
|
|
127
|
+
| Factory Droid | MCP only | Full (18 tools) | `--agent factory-droid` |
|
|
204
128
|
|
|
205
129
|
```bash
|
|
206
|
-
ulpi
|
|
207
|
-
ulpi
|
|
208
|
-
ulpi
|
|
130
|
+
ulpi kiro install # Install ULPI governance for Kiro CLI
|
|
131
|
+
ulpi codex install # Install ULPI governance for Codex CLI
|
|
132
|
+
ulpi doctor # Check which agents are installed and configured
|
|
209
133
|
```
|
|
210
134
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
Route events to desktop notifications, webhooks, terminal bells, or log files based on classification rules. Built-in deduplication prevents notification storms.
|
|
214
|
-
|
|
215
|
-
### Templates & Skills
|
|
135
|
+
---
|
|
216
136
|
|
|
217
|
-
|
|
137
|
+
## MCP Integration
|
|
218
138
|
|
|
219
|
-
**
|
|
139
|
+
- **18 MCP tools** — CodeMap (12 tools) and Memory (6 tools) exposed via stdio transport
|
|
140
|
+
- **MCP gateway** — multiplexing proxy that aggregates third-party MCP backends through a single connection
|
|
141
|
+
- **MCP catalog** — curated registry of MCP server definitions installable with one command
|
|
142
|
+
- **Per-repo MCP** — enable or disable specific MCP servers per repository
|
|
143
|
+
- **Hot reload** — automatic tool list updates when MCP configuration changes
|
|
144
|
+
- **Crash recovery** — automatic backend restart on failure
|
|
220
145
|
|
|
221
146
|
```bash
|
|
222
|
-
ulpi
|
|
223
|
-
ulpi
|
|
147
|
+
ulpi mcp catalog # Browse available MCP servers
|
|
148
|
+
ulpi mcp add <server> # Add an MCP server
|
|
149
|
+
ulpi mcp setup # Auto-configure MCP connections
|
|
150
|
+
ulpi mcp gateway # Start MCP gateway
|
|
224
151
|
```
|
|
225
152
|
|
|
226
153
|
---
|
|
227
154
|
|
|
228
155
|
## Configuration
|
|
229
156
|
|
|
230
|
-
Rules live in `.ulpi/guards.yml`
|
|
157
|
+
Rules live in `.ulpi/guards.yml` — plain YAML, auto-generated based on your stack:
|
|
231
158
|
|
|
232
159
|
```yaml
|
|
233
|
-
project:
|
|
234
|
-
name: my-app
|
|
235
|
-
runtime: node
|
|
236
|
-
package_manager: pnpm
|
|
237
|
-
test_command: pnpm test
|
|
238
|
-
|
|
239
160
|
preconditions:
|
|
240
|
-
read-before-
|
|
241
|
-
trigger: PreToolUse
|
|
161
|
+
read-before-write:
|
|
242
162
|
matcher: "Write|Edit"
|
|
243
|
-
message: "Read the file before editing it."
|
|
244
163
|
requires_read: true
|
|
164
|
+
message: "Read the file before editing it."
|
|
245
165
|
|
|
246
166
|
permissions:
|
|
247
167
|
auto-approve-tests:
|
|
248
|
-
trigger: PermissionRequest
|
|
249
168
|
matcher: Bash
|
|
250
169
|
command_pattern: "pnpm test"
|
|
251
170
|
decision: allow
|
|
252
171
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
matcher:
|
|
256
|
-
|
|
257
|
-
|
|
172
|
+
postconditions:
|
|
173
|
+
run-tests-after-edit:
|
|
174
|
+
matcher: "Write|Edit"
|
|
175
|
+
file_pattern: "src/**/*.ts"
|
|
176
|
+
command: "pnpm test"
|
|
258
177
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
178
|
+
pipelines:
|
|
179
|
+
pre-commit-checks:
|
|
180
|
+
matcher: Bash
|
|
181
|
+
command_pattern: "git commit"
|
|
182
|
+
steps:
|
|
183
|
+
- name: build
|
|
184
|
+
command: "pnpm -r build"
|
|
185
|
+
- name: test
|
|
186
|
+
command: "pnpm test"
|
|
264
187
|
```
|
|
265
188
|
|
|
266
189
|
---
|
|
267
190
|
|
|
268
|
-
##
|
|
191
|
+
## Interfaces
|
|
269
192
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
| `ulpi templates` | Browse and apply rule templates |
|
|
275
|
-
| `ulpi skills` | Manage injectable skills |
|
|
276
|
-
| `ulpi status` | Show current session state |
|
|
277
|
-
| `ulpi log` | View activity log |
|
|
278
|
-
| `ulpi ui` | Launch web dashboard |
|
|
279
|
-
| `ulpi projects` | Manage multiple projects |
|
|
280
|
-
| `ulpi history` | Browse session history |
|
|
281
|
-
| `ulpi review` | Plan and code review management |
|
|
282
|
-
| `ulpi codemap` | Semantic code search and indexing |
|
|
283
|
-
| `ulpi memory` | Agent memory management |
|
|
284
|
-
| `ulpi config` | View and update settings |
|
|
285
|
-
| `ulpi update` | Check for and install updates |
|
|
286
|
-
| `ulpi export` | Export your rules configuration |
|
|
287
|
-
| `ulpi import` | Import a rules configuration |
|
|
288
|
-
| `ulpi uninstall` | Remove ULPI hooks from project |
|
|
193
|
+
- **Portal** — Next.js dashboard for rules, sessions, code search, memory, history, review, and execution monitoring (`ulpi start` or `ulpi portal`)
|
|
194
|
+
- **Terminal UI** — ink-based TUI client for live session monitoring (`ulpi tui`)
|
|
195
|
+
- **REST API** — modular HTTP server with WebSocket for live updates and SSE for event streaming
|
|
196
|
+
- **macOS LaunchAgent** — automatic background startup for daemon and codemap watcher
|
|
289
197
|
|
|
290
198
|
---
|
|
291
199
|
|
|
292
200
|
## How It Works
|
|
293
201
|
|
|
294
|
-
ULPI uses
|
|
295
|
-
|
|
296
|
-
Seven hooks intercept the full session lifecycle:
|
|
202
|
+
ULPI uses hook protocols — lifecycle events that fire before and after every tool execution in your AI agent.
|
|
297
203
|
|
|
298
204
|
| Hook | When | What ULPI Does |
|
|
299
205
|
|------|------|----------------|
|
|
300
|
-
| **SessionStart** |
|
|
301
|
-
| **PreToolUse** | Before any tool runs | Evaluate preconditions, block dangerous commands
|
|
302
|
-
| **PostToolUse** | After a tool completes | Track files/commands, run postconditions, capture history on new commits
|
|
303
|
-
| **PermissionRequest** | Tool needs approval | Auto-approve or deny based on rules,
|
|
206
|
+
| **SessionStart** | Agent session begins | Detect stack, capture branch/HEAD, surface memories, import CodeMap index |
|
|
207
|
+
| **PreToolUse** | Before any tool runs | Evaluate preconditions, block dangerous commands |
|
|
208
|
+
| **PostToolUse** | After a tool completes | Track files/commands, run postconditions, capture history on new commits |
|
|
209
|
+
| **PermissionRequest** | Tool needs approval | Auto-approve or deny based on rules, plan review on ExitPlanMode |
|
|
304
210
|
| **Notification** | Event notification | Classify and route to desktop, webhook, terminal, or log channels |
|
|
305
211
|
| **Stop** | Session stopping | Final checks (warn about missing tests/lint) |
|
|
306
212
|
| **SessionEnd** | Session complete | Persist summary, capture commits to history, classify memories, export indexes |
|
|
307
213
|
|
|
308
|
-
If ULPI ever encounters an error, it fails open —
|
|
214
|
+
If ULPI ever encounters an error, it fails open — your AI agent continues normally.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Embedding Providers
|
|
219
|
+
|
|
220
|
+
| Provider | Setup | Cost | Data |
|
|
221
|
+
|----------|-------|------|------|
|
|
222
|
+
| **ULPI Cloud** (recommended) | No setup, use `ULPI_API_KEY` | Free tier included | Sent to ULPI servers |
|
|
223
|
+
| **Ollama** | Install Ollama locally | Free | Stays on your machine |
|
|
224
|
+
| **OpenAI** | Use your `OPENAI_API_KEY` | Per-token pricing | Sent to OpenAI |
|
|
225
|
+
|
|
226
|
+
Configure via `ulpi config set embedding.provider <ulpi|ollama|openai>`.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Cloud
|
|
231
|
+
|
|
232
|
+
Upload a sprint with dozens of tasks — or import directly from Jira. ULPI Cloud spawns isolated Docker workers, each with a full AI agent, to execute them in parallel. GitHub webhooks trigger automated code review on PRs. Per-org quotas, member roles, API keys, and audit logs.
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
ulpi cloud connect # Connect to ULPI Cloud
|
|
236
|
+
ulpi cloud status # Check connection status
|
|
237
|
+
```
|
|
309
238
|
|
|
310
239
|
---
|
|
311
240
|
|
|
312
241
|
## Requirements
|
|
313
242
|
|
|
314
243
|
- **Node.js** >= 20
|
|
315
|
-
-
|
|
244
|
+
- An AI coding agent: Claude Code, Gemini CLI, OpenCode, Kiro, Codex, or Factory Droid
|
|
316
245
|
|
|
317
246
|
## License
|
|
318
247
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
REVIEW_FLAGS_DIR,
|
|
3
|
+
getPortalPort,
|
|
3
4
|
loadUlpiSettings
|
|
4
5
|
} from "./chunk-C7CLUQI6.js";
|
|
5
6
|
|
|
@@ -69,7 +70,7 @@ async function runPlanReviewSession(plan, projectDir, sessionId) {
|
|
|
69
70
|
if (!registration?.success) return null;
|
|
70
71
|
const reviewSessionId = registration.sessionId;
|
|
71
72
|
if (settings.review.auto_open_browser) {
|
|
72
|
-
const url = `http://
|
|
73
|
+
const url = `http://localhost:${getPortalPort()}/review/plan?session=${reviewSessionId}`;
|
|
73
74
|
try {
|
|
74
75
|
execFileSync("open", [url], { timeout: 5e3 });
|
|
75
76
|
} catch {
|
|
@@ -100,6 +100,7 @@ import {
|
|
|
100
100
|
getCodemapBranch,
|
|
101
101
|
getCurrentBranch,
|
|
102
102
|
getHistoryBranch,
|
|
103
|
+
getPortalPort,
|
|
103
104
|
globalGuardsFile,
|
|
104
105
|
loadTomlConfig,
|
|
105
106
|
loadUlpiSettings,
|
|
@@ -112,7 +113,7 @@ import {
|
|
|
112
113
|
saveUlpiSettings
|
|
113
114
|
} from "./chunk-C7CLUQI6.js";
|
|
114
115
|
|
|
115
|
-
// ../api/dist/chunk-
|
|
116
|
+
// ../api/dist/chunk-5JUK7LNP.js
|
|
116
117
|
import * as http from "http";
|
|
117
118
|
import * as fs14 from "fs";
|
|
118
119
|
import * as path11 from "path";
|
|
@@ -310,7 +311,7 @@ var EventBus = class {
|
|
|
310
311
|
}
|
|
311
312
|
};
|
|
312
313
|
|
|
313
|
-
// ../api/dist/chunk-
|
|
314
|
+
// ../api/dist/chunk-5JUK7LNP.js
|
|
314
315
|
import * as crypto from "crypto";
|
|
315
316
|
import * as fs12 from "fs";
|
|
316
317
|
import * as path9 from "path";
|
|
@@ -490,7 +491,7 @@ function formatScalar(v) {
|
|
|
490
491
|
function writeRulesConfig(rulesPath, config) {
|
|
491
492
|
const lines = [
|
|
492
493
|
"# ULPI \u2014 Rules Configuration",
|
|
493
|
-
"# Generated via
|
|
494
|
+
"# Generated via Portal",
|
|
494
495
|
"",
|
|
495
496
|
"project:",
|
|
496
497
|
` name: "${yamlEscapeString(config.project.name)}"`,
|
|
@@ -1130,7 +1131,7 @@ async function generateHandler(ctx) {
|
|
|
1130
1131
|
"text",
|
|
1131
1132
|
"--permission-mode",
|
|
1132
1133
|
"bypassPermissions",
|
|
1133
|
-
`/ulpi-generate-
|
|
1134
|
+
`/ulpi-generate-guards ${projectDir}`
|
|
1134
1135
|
],
|
|
1135
1136
|
{
|
|
1136
1137
|
cwd: projectDir,
|
|
@@ -5053,10 +5054,6 @@ var reviewSSE = new SSEBroadcaster();
|
|
|
5053
5054
|
function broadcastReviewSSE(eventName, data) {
|
|
5054
5055
|
reviewSSE.broadcast(eventName, data);
|
|
5055
5056
|
}
|
|
5056
|
-
var _uiServerPort = 9800;
|
|
5057
|
-
function getUiServerPort() {
|
|
5058
|
-
return _uiServerPort;
|
|
5059
|
-
}
|
|
5060
5057
|
async function getReviewConfig(ctx) {
|
|
5061
5058
|
const settings = loadUlpiSettings();
|
|
5062
5059
|
jsonResponse2(ctx.res, settings.review, 200, ctx.req);
|
|
@@ -5163,9 +5160,8 @@ async function hubRegister(ctx) {
|
|
|
5163
5160
|
if (reviewSSE.size === 0 && reviewSettings.auto_open_browser) {
|
|
5164
5161
|
try {
|
|
5165
5162
|
const { exec } = await import("child_process");
|
|
5166
|
-
const port = getUiServerPort();
|
|
5167
5163
|
exec(
|
|
5168
|
-
`open "http://localhost:${
|
|
5164
|
+
`open "http://localhost:${getPortalPort()}/review/plan?session=${result.sessionId}&token=${result.token}"`
|
|
5169
5165
|
);
|
|
5170
5166
|
} catch {
|
|
5171
5167
|
}
|
|
@@ -51,14 +51,14 @@ function installHooks(projectDir) {
|
|
|
51
51
|
function findSkillSource() {
|
|
52
52
|
if (process.argv[1]) {
|
|
53
53
|
const entryDir = path.dirname(path.resolve(process.argv[1]));
|
|
54
|
-
const bundled = path.join(entryDir, "skills", "ulpi-generate-
|
|
54
|
+
const bundled = path.join(entryDir, "skills", "ulpi-generate-guards");
|
|
55
55
|
if (fs.existsSync(bundled)) return bundled;
|
|
56
56
|
}
|
|
57
57
|
if (process.argv[1]) {
|
|
58
58
|
let dir = path.dirname(path.resolve(process.argv[1]));
|
|
59
59
|
for (let i = 0; i < 5; i++) {
|
|
60
60
|
dir = path.dirname(dir);
|
|
61
|
-
const candidate = path.join(dir, ".claude", "skills", "ulpi-generate-
|
|
61
|
+
const candidate = path.join(dir, ".claude", "skills", "ulpi-generate-guards");
|
|
62
62
|
if (fs.existsSync(candidate)) return candidate;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -66,7 +66,7 @@ function findSkillSource() {
|
|
|
66
66
|
}
|
|
67
67
|
function installGlobalSkill() {
|
|
68
68
|
const homeDir = os.homedir();
|
|
69
|
-
const globalSkillsDir = path.join(homeDir, ".claude", "skills", "ulpi-generate-
|
|
69
|
+
const globalSkillsDir = path.join(homeDir, ".claude", "skills", "ulpi-generate-guards");
|
|
70
70
|
if (fs.existsSync(globalSkillsDir)) {
|
|
71
71
|
return { installed: false, message: "Skill already installed globally" };
|
|
72
72
|
}
|
|
@@ -77,13 +77,13 @@ function installGlobalSkill() {
|
|
|
77
77
|
try {
|
|
78
78
|
fs.mkdirSync(path.dirname(globalSkillsDir), { recursive: true });
|
|
79
79
|
copyDirRecursive(skillSource, globalSkillsDir);
|
|
80
|
-
return { installed: true, message: `Installed /ulpi-generate-
|
|
80
|
+
return { installed: true, message: `Installed /ulpi-generate-guards skill globally to ${globalSkillsDir}` };
|
|
81
81
|
} catch (err) {
|
|
82
82
|
return { installed: false, message: `Failed to install skill: ${err instanceof Error ? err.message : String(err)}` };
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
function installLocalSkill(projectDir) {
|
|
86
|
-
const localSkillsDir = path.join(projectDir, ".claude", "skills", "ulpi-generate-
|
|
86
|
+
const localSkillsDir = path.join(projectDir, ".claude", "skills", "ulpi-generate-guards");
|
|
87
87
|
if (fs.existsSync(localSkillsDir)) {
|
|
88
88
|
return { installed: false, message: "Skill already installed locally" };
|
|
89
89
|
}
|
|
@@ -94,7 +94,7 @@ function installLocalSkill(projectDir) {
|
|
|
94
94
|
try {
|
|
95
95
|
fs.mkdirSync(path.dirname(localSkillsDir), { recursive: true });
|
|
96
96
|
copyDirRecursive(skillSource, localSkillsDir);
|
|
97
|
-
return { installed: true, message: `Installed /ulpi-generate-
|
|
97
|
+
return { installed: true, message: `Installed /ulpi-generate-guards skill locally` };
|
|
98
98
|
} catch (err) {
|
|
99
99
|
return { installed: false, message: `Failed to install skill: ${err instanceof Error ? err.message : String(err)}` };
|
|
100
100
|
}
|
|
@@ -392,7 +392,7 @@ async function initUlpiSubsystems(projectDir) {
|
|
|
392
392
|
console.log(chalk.yellow(`[ulpi-ci] Warning: Could not detect stack/generate guards.yml: ${err instanceof Error ? err.message : String(err)}`));
|
|
393
393
|
}
|
|
394
394
|
try {
|
|
395
|
-
const { installHooks } = await import("./hooks-installer-
|
|
395
|
+
const { installHooks } = await import("./hooks-installer-YEYTYA6Q.js");
|
|
396
396
|
installHooks(projectDir);
|
|
397
397
|
console.log(chalk.blue("[ulpi-ci] Hooks installed"));
|
|
398
398
|
} catch (err) {
|
|
@@ -415,7 +415,7 @@ async function initUlpiSubsystems(projectDir) {
|
|
|
415
415
|
const { historyBranchExists, initHistoryBranch } = await import("./dist-YCNWHSLN.js");
|
|
416
416
|
if (!historyBranchExists(projectDir)) {
|
|
417
417
|
const projectName = path.basename(projectDir);
|
|
418
|
-
const version = true ? "0.1.
|
|
418
|
+
const version = true ? "0.1.8" : "0.0.0";
|
|
419
419
|
initHistoryBranch(projectDir, projectName, version);
|
|
420
420
|
console.log(chalk.blue("[ulpi-ci] History branch initialized"));
|
|
421
421
|
} else {
|
|
@@ -164,7 +164,7 @@ function checkHooksInstalled(configPath) {
|
|
|
164
164
|
function checkCore(projectDir) {
|
|
165
165
|
section("Core");
|
|
166
166
|
try {
|
|
167
|
-
const version = "0.1.
|
|
167
|
+
const version = "0.1.8";
|
|
168
168
|
pass(`ULPI CLI version: ${version}`);
|
|
169
169
|
} catch {
|
|
170
170
|
pass("ULPI CLI: installed");
|
|
@@ -416,7 +416,7 @@ async function initSubcommand(projectDir) {
|
|
|
416
416
|
}
|
|
417
417
|
const projectName = path2.basename(projectDir);
|
|
418
418
|
try {
|
|
419
|
-
initHistoryBranch(projectDir, projectName, "0.1.
|
|
419
|
+
initHistoryBranch(projectDir, projectName, "0.1.8");
|
|
420
420
|
} catch (err) {
|
|
421
421
|
const message = err instanceof Error ? err.message : String(err);
|
|
422
422
|
console.log(chalk.red(`Error: ${message}`));
|