@besales/ops-framework 0.1.0
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/CHANGELOG.md +10 -0
- package/README.md +328 -0
- package/bin/build-check-context.mjs +67 -0
- package/bin/build-execution-ledger.mjs +54 -0
- package/bin/estimate-llm-input.mjs +160 -0
- package/bin/guard-task.mjs +384 -0
- package/bin/hash-task-artifacts.mjs +44 -0
- package/bin/init-project.mjs +49 -0
- package/bin/intake-execution-feedback.mjs +207 -0
- package/bin/intake-feedback.test.mjs +73 -0
- package/bin/learning-loop.mjs +658 -0
- package/bin/learning-loop.test.mjs +175 -0
- package/bin/lib/bootstrap-utils.mjs +542 -0
- package/bin/lib/bootstrap-utils.test.mjs +156 -0
- package/bin/lib/check-context-utils.mjs +1448 -0
- package/bin/lib/check-context-utils.test.mjs +497 -0
- package/bin/lib/execution-ledger-utils.mjs +162 -0
- package/bin/lib/execution-ledger-utils.test.mjs +74 -0
- package/bin/lib/llm-input-pack-utils.mjs +663 -0
- package/bin/lib/llm-input-pack-utils.test.mjs +262 -0
- package/bin/lib/project-config.mjs +229 -0
- package/bin/lib/project-config.test.mjs +102 -0
- package/bin/lib/task-manifest-utils.mjs +512 -0
- package/bin/lib/task-manifest-utils.test.mjs +218 -0
- package/bin/lib/task-metrics-utils.mjs +63 -0
- package/bin/lib/task-metrics-utils.test.mjs +40 -0
- package/bin/lib/test-setup.mjs +37 -0
- package/bin/new-task.mjs +42 -0
- package/bin/ops-agent.mjs +81 -0
- package/bin/preflight.mjs +56 -0
- package/bin/providers/external-cli-checker.mjs +190 -0
- package/bin/providers/openai-checker.mjs +62 -0
- package/bin/quality-gates.mjs +92 -0
- package/bin/run-check.mjs +559 -0
- package/bin/run-plan-check-loop.mjs +392 -0
- package/bin/run-verify.mjs +627 -0
- package/bin/self-lint.mjs +88 -0
- package/bin/supervisor-turn.mjs +146 -0
- package/bin/supervisor-turn.test.mjs +72 -0
- package/bin/task-manifest.mjs +57 -0
- package/bin/task-metrics.mjs +48 -0
- package/bin/transition.mjs +94 -0
- package/bin/validate-check-artifacts.mjs +418 -0
- package/config/default-agents.json +100 -0
- package/package.json +28 -0
- package/playbooks/checker-context.md +9 -0
- package/playbooks/complexity-performance.md +13 -0
- package/playbooks/production-rollout.md +9 -0
- package/playbooks/source-sync-provider.md +9 -0
- package/playbooks/ui-acceptance.md +9 -0
- package/prompts/checker.md +170 -0
- package/prompts/executor.md +54 -0
- package/prompts/planner.md +128 -0
- package/prompts/researcher.md +44 -0
- package/prompts/supervisor.md +337 -0
- package/prompts/verifier.md +128 -0
- package/templates/brief.md +15 -0
- package/templates/check-resolution.md +69 -0
- package/templates/check-result.json +32 -0
- package/templates/check.md +46 -0
- package/templates/execution-feedback.md +25 -0
- package/templates/execution.md +101 -0
- package/templates/human-gate-summary.md +49 -0
- package/templates/orchestration-log.md +8 -0
- package/templates/plan.md +86 -0
- package/templates/research.md +13 -0
- package/templates/retrospective.md +48 -0
- package/templates/status.md +53 -0
- package/templates/verify-result.json +19 -0
- package/templates/verify.md +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Created the first local shared Ops Framework package boundary.
|
|
6
|
+
- Added `ops-agent` command dispatch for the current agent command surface.
|
|
7
|
+
- Added project config resolution through `ops/project.ops.yaml`.
|
|
8
|
+
- Kept task, memory, cache and project-specific provider overrides outside shared defaults.
|
|
9
|
+
- Added `ops-agent init` and `ops-agent new-task` for project bootstrap and task scaffolding.
|
|
10
|
+
- Added bootstrap tests for idempotent project setup, portable generated config and fixture lifecycle smoke.
|
package/README.md
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# Ops Framework
|
|
2
|
+
|
|
3
|
+
Reusable human-in-the-loop delivery framework for planning, checking, executing and verifying software tasks across separate project repositories.
|
|
4
|
+
|
|
5
|
+
The package owns the process engine and reusable assets. Each project owns its task history, memory, cache, project playbook overlays and local provider overrides.
|
|
6
|
+
|
|
7
|
+
## What Lives In The Package
|
|
8
|
+
|
|
9
|
+
- `bin/`: CLI commands and shared implementation utilities.
|
|
10
|
+
- `prompts/`: reusable agent prompts for supervisor, researcher, planner, checker, executor and verifier.
|
|
11
|
+
- `templates/`: task artifact templates.
|
|
12
|
+
- `playbooks/`: shared reusable procedures for UI acceptance, complexity, rollout, provider/source-sync and checker context.
|
|
13
|
+
- `config/default-agents.json`: portable defaults with environment placeholders, not local machine paths.
|
|
14
|
+
|
|
15
|
+
## What Stays In Each Project
|
|
16
|
+
|
|
17
|
+
- `ops/project.ops.yaml`: project binding file.
|
|
18
|
+
- `ops/agent-pipeline/tasks/`: task artifacts and history.
|
|
19
|
+
- `ops/agent-pipeline/memory/`: project memory.
|
|
20
|
+
- `ops/agent-pipeline/playbooks/`: project playbook overlays with project-specific routes, commands, services, environments and provider quirks.
|
|
21
|
+
- `ops/agent-pipeline/cache/`: project-local generated cache.
|
|
22
|
+
- `ops/agent-pipeline/config/agents.json`: optional project/user provider override.
|
|
23
|
+
- Project-specific deferred work, SQL, runtime notes and learning candidates.
|
|
24
|
+
|
|
25
|
+
Do not put project memory, task history, secrets, project-specific paths, project service names, routes, provider names or local absolute provider paths into this shared package unless they are explicitly marked as generic examples.
|
|
26
|
+
|
|
27
|
+
## Layer Model
|
|
28
|
+
|
|
29
|
+
Ops Framework has three layers:
|
|
30
|
+
|
|
31
|
+
- Shared framework core: CLI, lifecycle, prompts, templates, config defaults and generic gates.
|
|
32
|
+
- Shared playbooks: reusable procedures that apply across projects.
|
|
33
|
+
- Project overlays: project memory, project playbooks, tasks, cache, local providers and runtime commands.
|
|
34
|
+
|
|
35
|
+
When a task has relevant risk triggers, checker/verifier context can include both layers:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
Shared Playbook: UI Acceptance
|
|
39
|
+
Project Overlay: UI Acceptance
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Shared playbooks stay portable. Project overlays add concrete routes, commands, services, environments and known project quirks.
|
|
43
|
+
|
|
44
|
+
## Project Config
|
|
45
|
+
|
|
46
|
+
The recommended setup is:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
corepack yarn dlx @besales/ops-framework@latest init --project-name ExampleProject --install-scripts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This creates the project-owned `ops/**` structure, including `ops/project.ops.yaml`, task roots, cache, memory files and project-local agent config. With `--install-scripts`, it also writes package-manager scripts that call the pinned framework package through `corepack yarn dlx`; it does not add the framework as a dependency, so production installs do not need access to a local framework checkout.
|
|
53
|
+
|
|
54
|
+
The generated scripts look like:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"scripts": {
|
|
59
|
+
"ops": "corepack yarn dlx @besales/ops-framework@0.1.0",
|
|
60
|
+
"agent:run-check": "corepack yarn dlx @besales/ops-framework@0.1.0 run-check",
|
|
61
|
+
"agent:run-verify": "corepack yarn dlx @besales/ops-framework@0.1.0 run-verify"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use `--framework-version 0.1.0` to pin a specific version, or `--framework-package @scope/name` for a different registry package name.
|
|
67
|
+
|
|
68
|
+
The generated `ops/project.ops.yaml` shape is:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
name: ExampleProject
|
|
72
|
+
ops:
|
|
73
|
+
legacyPipelineDir: ops/agent-pipeline
|
|
74
|
+
tasksDir: ops/agent-pipeline/tasks
|
|
75
|
+
memoryDir: ops/agent-pipeline/memory
|
|
76
|
+
playbooksDir: ops/agent-pipeline/playbooks
|
|
77
|
+
cacheDir: ops/agent-pipeline/cache
|
|
78
|
+
agents:
|
|
79
|
+
configFile: ops/agent-pipeline/config/agents.json
|
|
80
|
+
risk:
|
|
81
|
+
uiRoots:
|
|
82
|
+
- apps/web
|
|
83
|
+
backendRoots:
|
|
84
|
+
- apps/api
|
|
85
|
+
workerRoots:
|
|
86
|
+
- apps/workers
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`ops-agent` walks upward from the current working directory until it finds `ops/project.ops.yaml`.
|
|
90
|
+
|
|
91
|
+
It then resolves:
|
|
92
|
+
|
|
93
|
+
- project artifacts from the configured project paths;
|
|
94
|
+
- framework prompts/templates/config from this package;
|
|
95
|
+
- shared playbooks from the package and project playbook overlays from `ops.playbooksDir`;
|
|
96
|
+
- project provider overrides from `agents.configFile`, if present.
|
|
97
|
+
|
|
98
|
+
Risk roots are project-owned. They decide when generic triggers such as UI, user-visible API, worker, production or performance gates apply. Do not hardcode one project's app layout into shared playbooks or shared risk classification.
|
|
99
|
+
|
|
100
|
+
Fresh bootstrap projects start with commented placeholder root examples. Until a project fills them, `build-check-context` and `preflight` warn that path-based UI/API/worker detection is disabled or limited.
|
|
101
|
+
|
|
102
|
+
If no project config exists, the resolver falls back to a legacy `ops/agent-pipeline` layout when it can find one.
|
|
103
|
+
|
|
104
|
+
## Optimization Gate
|
|
105
|
+
|
|
106
|
+
Optimization is built into the normal Plan -> Check -> Execute -> Verify flow, but it is bounded by risk tier so delivery stays fast:
|
|
107
|
+
|
|
108
|
+
- `O0`: no dedicated optimization section.
|
|
109
|
+
- `O1`: normal implementation checklist.
|
|
110
|
+
- `O2`: one focused review for touched UI/API/read-model hot paths.
|
|
111
|
+
- `O3`: one focused review plus one representative measurement for workers, materializers, source-sync/provider or production-runtime hot paths.
|
|
112
|
+
|
|
113
|
+
For O2/O3 work, `plan.md` must include `## Optimization Strategy` with tier, hot paths, expected data size, chosen efficient approach, avoided anti-patterns and a stop rule. `execution.md` must then include `## Optimization Review Evidence` before Verify can pass.
|
|
114
|
+
|
|
115
|
+
The framework blocks obvious inefficiency early, but speculative or broad optimization ideas should be deferred instead of expanding the task.
|
|
116
|
+
|
|
117
|
+
## CLI
|
|
118
|
+
|
|
119
|
+
From a project root, run commands through the package entry point:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 init --project-name ExampleProject --install-scripts
|
|
123
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 new-task TASK-001-example --title "Example task"
|
|
124
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 manifest TASK-001-example
|
|
125
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 preflight TASK-001-example --target execute
|
|
126
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 build-check-context TASK-001-example
|
|
127
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 run-check TASK-001-example
|
|
128
|
+
corepack yarn dlx @besales/ops-framework@0.1.0 run-verify TASK-001-example
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
When installed as a package, the intended command is:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
ops-agent init --project-name ExampleProject
|
|
135
|
+
ops-agent new-task TASK-001-example --title "Example task"
|
|
136
|
+
ops-agent manifest TASK-001-example
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For local package development in another project, use a `file:` dependency:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"devDependencies": {
|
|
144
|
+
"@besales/ops-framework": "file:../shared-platform/packages/ops-framework"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Do not commit that `file:` dependency to production projects. It is only for package development because production builders usually do not have a sibling `../shared-platform` checkout.
|
|
150
|
+
|
|
151
|
+
## Supported Commands
|
|
152
|
+
|
|
153
|
+
- `init`
|
|
154
|
+
- `new-task`
|
|
155
|
+
- `manifest`
|
|
156
|
+
- `preflight`
|
|
157
|
+
- `transition`
|
|
158
|
+
- `build-check-context`
|
|
159
|
+
- `validate-check-artifacts`
|
|
160
|
+
- `estimate-llm-input`
|
|
161
|
+
- `quality-gates`
|
|
162
|
+
- `run-check`
|
|
163
|
+
- `run-verify`
|
|
164
|
+
- `hash-task-artifacts`
|
|
165
|
+
- `build-execution-ledger`
|
|
166
|
+
- `task-metrics`
|
|
167
|
+
- `run-plan-check-loop`
|
|
168
|
+
- `supervisor-turn`
|
|
169
|
+
- `intake-feedback`
|
|
170
|
+
- `intake-execution-feedback`
|
|
171
|
+
- `guard-task`
|
|
172
|
+
- `memory-candidates`
|
|
173
|
+
- `learning-index`
|
|
174
|
+
- `learning-review`
|
|
175
|
+
- `update-memory`
|
|
176
|
+
- `learning-audit`
|
|
177
|
+
- `learning-report`
|
|
178
|
+
- `test/self-test`
|
|
179
|
+
|
|
180
|
+
## Learning Loop
|
|
181
|
+
|
|
182
|
+
Learning is controlled and human-approved:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
retrospective/feedback/check/verify artifacts
|
|
186
|
+
-> memory/playbook candidates
|
|
187
|
+
-> learning index
|
|
188
|
+
-> human promote/defer/reject
|
|
189
|
+
-> update memory/playbooks
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Use:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
ops-agent memory-candidates
|
|
196
|
+
ops-agent learning-index
|
|
197
|
+
ops-agent learning-review
|
|
198
|
+
ops-agent learning-audit
|
|
199
|
+
ops-agent update-memory --apply-approved
|
|
200
|
+
ops-agent learning-report
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`memory-candidates` creates structured learning cards with source, reason hash, learning layer, confidence, problem, lesson, repeat risk, proposed wording and suggested target. `learning-index` turns those cards into human-reviewable decisions. `update-memory` only writes approved entries when `--apply-approved` is passed.
|
|
204
|
+
|
|
205
|
+
`learning-review` writes `ops/agent-pipeline/memory/learning-review.md`, a human approval pack with each pending candidate and the allowed decisions: `promote`, `defer`, `reject` or `rewrite`.
|
|
206
|
+
|
|
207
|
+
`learning-report` writes `ops/agent-pipeline/memory/learning-report.md`. Show the review pack before approval and the report during closeout so the human can see what the framework learned, what is still pending, and which approved entries were written to project memory or project playbooks.
|
|
208
|
+
|
|
209
|
+
Shared playbook candidates are intentionally manual-review only. Promote them through a separate reviewed framework task, not by auto-writing project-specific observations into the shared package.
|
|
210
|
+
|
|
211
|
+
## Feedback Intake
|
|
212
|
+
|
|
213
|
+
Feedback is stage-agnostic. Any user question, correction, review note or learning observation during an active task should be captured before it is acted on:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
ops-agent intake-feedback TASK-001-example "Feedback text"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This appends a classified event to `feedback.md`, updates `status.md`, appends `orchestration-log.md` and makes the event available to checker/verifier context and learning candidates.
|
|
220
|
+
|
|
221
|
+
Use `learning_capture` for process/memory/playbook observations that should feed retrospective without invalidating the current implementation scope.
|
|
222
|
+
|
|
223
|
+
For active task conversations, prefer the turn router:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
ops-agent supervisor-turn TASK-001-example "User message"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
It records the message, appends a `supervisor_turn` log event and prints the mandatory response contract:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
TASK: ...
|
|
233
|
+
STAGE: ...
|
|
234
|
+
SUPERVISOR: active
|
|
235
|
+
FEEDBACK INTAKE: recorded (...)
|
|
236
|
+
ALLOWED NOW: ...
|
|
237
|
+
NOT ALLOWED NOW: ...
|
|
238
|
+
Следующий шаг: ...
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Provider Config
|
|
242
|
+
|
|
243
|
+
Shared defaults use environment placeholders:
|
|
244
|
+
|
|
245
|
+
- `CODEX_CLI_COMMAND`
|
|
246
|
+
- `CLAUDE_CLI_COMMAND`
|
|
247
|
+
- `CLOUD_CLI_COMMAND`
|
|
248
|
+
- `CHECKER_CLI_COMMAND`
|
|
249
|
+
|
|
250
|
+
Project-local overrides may point to real local binaries in the project or user environment. Keep those overrides out of shared defaults.
|
|
251
|
+
|
|
252
|
+
## Verification Model
|
|
253
|
+
|
|
254
|
+
The normal lifecycle is:
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
Brief -> Research -> Plan -> Check -> Human Gate -> Execute -> Verify
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`Check` reviews the plan before implementation. `Verify` reviews the result after execution evidence exists.
|
|
261
|
+
|
|
262
|
+
Internal supervisor verify is acceptable for ordinary local engineering slices. External CLI verify should be used for production readiness, destructive or security-sensitive work, material data migrations/backfills, broad ambiguous refactors or explicit human request.
|
|
263
|
+
|
|
264
|
+
## Release
|
|
265
|
+
|
|
266
|
+
`@besales/ops-framework` is published as a public scoped npm package through GitHub Actions trusted publishing.
|
|
267
|
+
|
|
268
|
+
The release workflow is `.github/workflows/publish-ops-framework.yml`.
|
|
269
|
+
|
|
270
|
+
Required npm trusted publisher configuration:
|
|
271
|
+
|
|
272
|
+
- Package: `@besales/ops-framework`
|
|
273
|
+
- Provider: GitHub Actions
|
|
274
|
+
- Organization / user: `be-sales`
|
|
275
|
+
- Repository: `shared-platform`
|
|
276
|
+
- Workflow filename: `publish-ops-framework.yml`
|
|
277
|
+
- Environment: leave empty
|
|
278
|
+
- Allowed action: `npm publish`
|
|
279
|
+
|
|
280
|
+
The workflow uses GitHub OIDC (`id-token: write`) and does not require an `NPM_TOKEN` secret.
|
|
281
|
+
|
|
282
|
+
For first-time package creation, npm requires the package to exist before a trusted publisher can be attached. Bootstrap the first version with a short-lived manual publish path, configure the trusted publisher, then use the workflow for all future versions.
|
|
283
|
+
|
|
284
|
+
Manual workflow release:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
gh workflow run publish-ops-framework.yml --repo be-sales/shared-platform -f version=0.1.0
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Tag workflow release:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
git tag ops-framework-v0.1.0
|
|
294
|
+
git push origin ops-framework-v0.1.0
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Validation
|
|
298
|
+
|
|
299
|
+
Run package tests:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
yarn workspace @besales/ops-framework test
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Run package lint:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
node bin/self-lint.mjs
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Auto-fix supported whitespace issues:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
node bin/self-lint.mjs --fix
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The lint script checks:
|
|
318
|
+
|
|
319
|
+
- no `.DS_Store` files;
|
|
320
|
+
- no open-work markers in package files;
|
|
321
|
+
- no local home-directory or application-bundle absolute paths in shared files;
|
|
322
|
+
- no known project-specific paths or project names in shared files;
|
|
323
|
+
- no trailing whitespace;
|
|
324
|
+
- text files end with a newline.
|
|
325
|
+
|
|
326
|
+
## Pilot Status
|
|
327
|
+
|
|
328
|
+
This package was first extracted from a project-local Ops Framework. Pilot task history, memory and provider paths remain project-owned and are connected through that project's `ops/project.ops.yaml`.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
buildCheckerContextPack,
|
|
5
|
+
buildCheckContext,
|
|
6
|
+
buildEvidenceMarkdown,
|
|
7
|
+
computeTaskContextInputs,
|
|
8
|
+
riskRootWarnings,
|
|
9
|
+
resolveTaskDir,
|
|
10
|
+
} from './lib/check-context-utils.mjs';
|
|
11
|
+
|
|
12
|
+
function main() {
|
|
13
|
+
const taskArg = process.argv[2];
|
|
14
|
+
if (!taskArg) {
|
|
15
|
+
fail('Usage: node ops/agent-pipeline/bin/build-check-context.mjs <TASK-id-or-task-path>');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const taskDir = resolveTaskDir(taskArg);
|
|
20
|
+
const taskId = path.basename(taskDir);
|
|
21
|
+
const inputs = computeTaskContextInputs(taskDir);
|
|
22
|
+
const checkContext = buildCheckContext({
|
|
23
|
+
taskId,
|
|
24
|
+
inputs,
|
|
25
|
+
});
|
|
26
|
+
const evidence = buildEvidenceMarkdown({
|
|
27
|
+
taskId,
|
|
28
|
+
risk: inputs.risk,
|
|
29
|
+
qualityGates: inputs.qualityGates,
|
|
30
|
+
referencedFiles: inputs.referencedFiles,
|
|
31
|
+
structuralLines: inputs.structuralLines,
|
|
32
|
+
planFingerprint: inputs.planFingerprint,
|
|
33
|
+
memorySha: inputs.memorySha,
|
|
34
|
+
taskArtifacts: inputs.taskArtifacts,
|
|
35
|
+
});
|
|
36
|
+
const checkerContextPack = buildCheckerContextPack({
|
|
37
|
+
taskId,
|
|
38
|
+
risk: inputs.risk,
|
|
39
|
+
qualityGates: inputs.qualityGates,
|
|
40
|
+
referencedFiles: inputs.referencedFiles,
|
|
41
|
+
structuralLines: inputs.structuralLines,
|
|
42
|
+
taskArtifacts: inputs.taskArtifacts,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
fs.writeFileSync(path.join(taskDir, 'check-context.json'), `${JSON.stringify(checkContext, null, 2)}\n`);
|
|
46
|
+
fs.writeFileSync(path.join(taskDir, 'check-evidence.md'), evidence);
|
|
47
|
+
fs.writeFileSync(path.join(taskDir, checkContext.checkerContextPackFile), checkerContextPack);
|
|
48
|
+
|
|
49
|
+
console.log(`Built check context for ${taskId}`);
|
|
50
|
+
console.log(`- riskProfile: ${inputs.risk.riskProfile}`);
|
|
51
|
+
console.log(`- riskTriggers: ${inputs.risk.riskTriggers.join(', ') || 'none'}`);
|
|
52
|
+
for (const warning of riskRootWarnings()) {
|
|
53
|
+
console.log(`- warning: ${warning}`);
|
|
54
|
+
}
|
|
55
|
+
console.log(`- referencedFiles: ${inputs.referencedFiles.length}`);
|
|
56
|
+
console.log(`- checkerContextPack: ${checkContext.checkerContextPackFile}`);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
fail(error.message);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function fail(message) {
|
|
63
|
+
console.error(`Error: ${message}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
main();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
normalizeMarkdownBody,
|
|
5
|
+
parseCliArgs,
|
|
6
|
+
readTaskFile,
|
|
7
|
+
repoRoot,
|
|
8
|
+
resolveTaskDir,
|
|
9
|
+
sha256,
|
|
10
|
+
writeTaskFile,
|
|
11
|
+
} from './lib/check-context-utils.mjs';
|
|
12
|
+
import { buildExecutionLedger } from './lib/execution-ledger-utils.mjs';
|
|
13
|
+
|
|
14
|
+
function main() {
|
|
15
|
+
const args = parseCliArgs(process.argv.slice(2));
|
|
16
|
+
const taskArg = args.positional[0];
|
|
17
|
+
if (!taskArg) {
|
|
18
|
+
fail('Usage: node ops/agent-pipeline/bin/build-execution-ledger.mjs <TASK-id-or-task-path>');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const taskDir = resolveTaskDir(taskArg);
|
|
23
|
+
const taskId = path.basename(taskDir);
|
|
24
|
+
const ledger = buildExecutionLedger({
|
|
25
|
+
taskId,
|
|
26
|
+
taskDir,
|
|
27
|
+
repoRoot,
|
|
28
|
+
planSha: hashTaskMarkdown(taskDir, 'plan.md'),
|
|
29
|
+
executionSha: hashTaskMarkdown(taskDir, 'execution.md'),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
writeTaskFile(taskDir, 'execution-ledger.json', JSON.stringify(ledger, null, 2));
|
|
33
|
+
console.log(`Built execution ledger for ${taskId}`);
|
|
34
|
+
console.log(`- changedFiles: ${ledger.git.changedFiles.length}`);
|
|
35
|
+
console.log(`- unrelatedDirtyFiles: ${ledger.git.unrelatedDirtyFiles.length}`);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
fail(error.message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hashTaskMarkdown(taskDir, fileName) {
|
|
42
|
+
const content = readTaskFile(taskDir, fileName);
|
|
43
|
+
if (!content) {
|
|
44
|
+
throw new Error(`Task artifact is missing or empty: ${fileName}`);
|
|
45
|
+
}
|
|
46
|
+
return sha256(normalizeMarkdownBody(content));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function fail(message) {
|
|
50
|
+
console.error(`Error: ${message}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
main();
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {
|
|
3
|
+
buildCheckerContextPack,
|
|
4
|
+
buildCheckContext,
|
|
5
|
+
buildEvidenceMarkdown,
|
|
6
|
+
computePromptSha,
|
|
7
|
+
computeTaskContextInputs,
|
|
8
|
+
getFlag,
|
|
9
|
+
normalizeMarkdownBody,
|
|
10
|
+
parseCliArgs,
|
|
11
|
+
readMemorySnapshot,
|
|
12
|
+
readPrompt,
|
|
13
|
+
readTaskFile,
|
|
14
|
+
resolveTaskDir,
|
|
15
|
+
sha256,
|
|
16
|
+
} from './lib/check-context-utils.mjs';
|
|
17
|
+
import {
|
|
18
|
+
buildCheckerLlmInputPack,
|
|
19
|
+
buildVerifierLlmInputPack,
|
|
20
|
+
estimatePayload,
|
|
21
|
+
resolveLlmContextMode,
|
|
22
|
+
summarizePackForConsole,
|
|
23
|
+
} from './lib/llm-input-pack-utils.mjs';
|
|
24
|
+
|
|
25
|
+
function main() {
|
|
26
|
+
const args = parseCliArgs(process.argv.slice(2));
|
|
27
|
+
const taskArg = args.positional[0];
|
|
28
|
+
if (!taskArg) {
|
|
29
|
+
fail('Usage: node ops/agent-pipeline/bin/estimate-llm-input.mjs <TASK-id-or-task-path> --stage check|verify [--mode fast|standard|strict] [--json]');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const taskDir = resolveTaskDir(taskArg);
|
|
34
|
+
const taskId = path.basename(taskDir);
|
|
35
|
+
const stage = String(getFlag(args, 'stage') || args.positional[1] || 'check').toLowerCase();
|
|
36
|
+
const pack = stage === 'verify'
|
|
37
|
+
? buildVerifyEstimatePack({ taskDir, taskId, args })
|
|
38
|
+
: buildCheckEstimatePack({ taskDir, taskId, args });
|
|
39
|
+
const promptName = stage === 'verify' ? 'verifier.md' : 'checker.md';
|
|
40
|
+
const fullPromptEstimate = estimatePayload([
|
|
41
|
+
readPrompt(promptName),
|
|
42
|
+
'',
|
|
43
|
+
JSON.stringify(pack.input, null, 2),
|
|
44
|
+
].join('\n'));
|
|
45
|
+
const result = {
|
|
46
|
+
taskId,
|
|
47
|
+
stage,
|
|
48
|
+
mode: pack.meta.mode,
|
|
49
|
+
capTokens: pack.meta.capTokens,
|
|
50
|
+
packBytes: pack.meta.bytes,
|
|
51
|
+
packEstimatedTokens: pack.meta.estimatedTokens,
|
|
52
|
+
fullPromptBytes: fullPromptEstimate.bytes,
|
|
53
|
+
fullPromptEstimatedTokens: fullPromptEstimate.estimatedTokens,
|
|
54
|
+
overCap: pack.meta.overCap,
|
|
55
|
+
compactedArtifacts: pack.meta.compactedArtifacts,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (args.flags.has('json')) {
|
|
59
|
+
console.log(JSON.stringify(result, null, 2));
|
|
60
|
+
} else {
|
|
61
|
+
console.log(`LLM input estimate for ${taskId} (${stage})`);
|
|
62
|
+
for (const line of summarizePackForConsole(pack)) {
|
|
63
|
+
console.log(line);
|
|
64
|
+
}
|
|
65
|
+
console.log(`- fullPromptEstimatedTokens: ${result.fullPromptEstimatedTokens}`);
|
|
66
|
+
console.log(`- overCap: ${result.overCap ? 'yes' : 'no'}`);
|
|
67
|
+
}
|
|
68
|
+
process.exit(result.overCap ? 1 : 0);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
fail(error.message);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function buildCheckEstimatePack({ taskDir, taskId, args }) {
|
|
75
|
+
const inputs = computeTaskContextInputs(taskDir);
|
|
76
|
+
const checkContext = buildCheckContext({ taskId, inputs });
|
|
77
|
+
const checkerContextPack = buildCheckerContextPack({
|
|
78
|
+
taskId,
|
|
79
|
+
risk: inputs.risk,
|
|
80
|
+
qualityGates: inputs.qualityGates,
|
|
81
|
+
referencedFiles: inputs.referencedFiles,
|
|
82
|
+
structuralLines: inputs.structuralLines,
|
|
83
|
+
taskArtifacts: inputs.taskArtifacts,
|
|
84
|
+
});
|
|
85
|
+
const checkEvidence = buildEvidenceMarkdown({
|
|
86
|
+
taskId,
|
|
87
|
+
risk: inputs.risk,
|
|
88
|
+
qualityGates: inputs.qualityGates,
|
|
89
|
+
referencedFiles: inputs.referencedFiles,
|
|
90
|
+
structuralLines: inputs.structuralLines,
|
|
91
|
+
planFingerprint: inputs.planFingerprint,
|
|
92
|
+
memorySha: inputs.memorySha,
|
|
93
|
+
taskArtifacts: inputs.taskArtifacts,
|
|
94
|
+
});
|
|
95
|
+
const memorySnapshot = readMemorySnapshot(checkContext.memoryFiles);
|
|
96
|
+
const mode = resolveLlmContextMode({
|
|
97
|
+
requestedMode: getFlag(args, 'mode') || getFlag(args, 'context-mode'),
|
|
98
|
+
riskTriggers: checkContext.riskTriggers,
|
|
99
|
+
});
|
|
100
|
+
return buildCheckerLlmInputPack({
|
|
101
|
+
taskDir,
|
|
102
|
+
taskId,
|
|
103
|
+
checkerPromptSha: computePromptSha('checker.md'),
|
|
104
|
+
cacheKey: { taskId, estimate: true, contextMode: mode },
|
|
105
|
+
checkContext,
|
|
106
|
+
checkEvidence,
|
|
107
|
+
checkerContextPack,
|
|
108
|
+
taskManifest: readTaskFile(taskDir, 'task-manifest.json'),
|
|
109
|
+
projectMemory: memorySnapshot.map((item) => ({
|
|
110
|
+
path: item.path,
|
|
111
|
+
sha: item.sha,
|
|
112
|
+
content: item.content,
|
|
113
|
+
})),
|
|
114
|
+
mode,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function buildVerifyEstimatePack({ taskDir, taskId, args }) {
|
|
119
|
+
const manifest = readOptionalJson(taskDir, 'task-manifest.json');
|
|
120
|
+
const mode = resolveLlmContextMode({
|
|
121
|
+
requestedMode: getFlag(args, 'mode') || getFlag(args, 'context-mode'),
|
|
122
|
+
riskTriggers: manifest?.context?.riskTriggers || [],
|
|
123
|
+
});
|
|
124
|
+
return buildVerifierLlmInputPack({
|
|
125
|
+
taskDir,
|
|
126
|
+
taskId,
|
|
127
|
+
planSha: hashTaskMarkdown(taskDir, 'plan.md'),
|
|
128
|
+
executionSha: hashTaskMarkdown(taskDir, 'execution.md'),
|
|
129
|
+
verifier: {
|
|
130
|
+
provider: 'estimate',
|
|
131
|
+
model: 'estimate',
|
|
132
|
+
reasoningEffort: 'none',
|
|
133
|
+
runId: 'estimate',
|
|
134
|
+
},
|
|
135
|
+
mode,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function hashTaskMarkdown(taskDir, fileName) {
|
|
140
|
+
return sha256(normalizeMarkdownBody(readTaskFile(taskDir, fileName)));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function readOptionalJson(taskDir, fileName) {
|
|
144
|
+
const raw = readTaskFile(taskDir, fileName);
|
|
145
|
+
if (!raw) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
return JSON.parse(raw);
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function fail(message) {
|
|
156
|
+
console.error(`Error: ${message}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
main();
|