qfai 2.1.1 → 2.2.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/README.md +56 -36
- package/assets/defaults/agent-routing/qfai-implement.yml +9 -0
- package/assets/defaults/agent-routing/qfai-triage.yml +18 -0
- package/assets/defaults/workflows/answer-in-session.yml +8 -0
- package/assets/defaults/workflows/quarantine-flaky.yml +3 -0
- package/assets/defaults/workflows/repair-consistency.yml +1 -0
- package/assets/defaults/workflows/run-operation.yml +11 -0
- package/assets/defaults/workflows/run-owned-cleanup.yml +12 -0
- package/assets/defaults/workflows/write-procedure.yml +18 -0
- package/assets/graph/codegraph-native.mjs +174 -0
- package/assets/graph/graphify-native.py +72 -0
- package/assets/init/.claude/settings.json +9 -9
- package/assets/init/.codex/hooks.json +8 -8
- package/assets/init/.qfai/assistant/agent/frontend-engineer.md +5 -0
- package/assets/init/.qfai/assistant/agent/product-experience-architect.md +4 -0
- package/assets/init/.qfai/assistant/agent/product-surface-reviewer.md +7 -0
- package/assets/init/.qfai/assistant/agent/requirements-analyst.md +8 -0
- package/assets/init/.qfai/assistant/rule/communication.md +18 -8
- package/assets/init/.qfai/assistant/rule/constitution.md +31 -15
- package/assets/init/.qfai/assistant/rule/drift-protocol.md +119 -2
- package/assets/init/.qfai/assistant/rule/references/asset-authoring.md +6 -4
- package/assets/init/.qfai/assistant/rule/references/codex-delegation.md +27 -0
- package/assets/init/.qfai/assistant/rule/references/griller-recommendations.md +21 -9
- package/assets/init/.qfai/assistant/rule/references/worker-edit-boundary.md +48 -0
- package/assets/init/.qfai/assistant/rule/review-convergence.md +25 -12
- package/assets/init/.qfai/assistant/rule/shared-skill-delegation-baseline.md +16 -25
- package/assets/init/.qfai/assistant/rule/shared-skill-operating-baseline.md +16 -11
- package/assets/init/.qfai/assistant/rule/ui-definition-protocol.md +6 -1
- package/assets/init/.qfai/assistant/rule/workflow.md +2 -1
- package/assets/init/.qfai/assistant/skill/qfai-configure/SKILL.md +3 -3
- package/assets/init/.qfai/assistant/skill/qfai-discussion/SKILL.md +6 -0
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/discussion-completion-matrix.md +20 -15
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui-bearing-playbook.md +2 -4
- package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui_ux_best_practices.md +1 -6
- package/assets/init/.qfai/assistant/skill/qfai-discussion/templates/uiux/00_index.md +0 -16
- package/assets/init/.qfai/assistant/skill/qfai-grilling/SKILL.md +30 -20
- package/assets/init/.qfai/assistant/skill/qfai-grilling/references/delegated-session.md +4 -3
- package/assets/init/.qfai/assistant/skill/qfai-grilling/references/session-record.md +8 -2
- package/assets/init/.qfai/assistant/skill/qfai-implement/SKILL.md +16 -3
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/parallelization-policy.md +9 -1
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/red-admissibility.md +46 -0
- package/assets/init/.qfai/assistant/skill/qfai-implement/references/ui-affecting.md +5 -2
- package/assets/init/.qfai/assistant/skill/qfai-maintain/SKILL.md +3 -3
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/SKILL.md +12 -6
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-guide.md +1 -265
- package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-placement.md +273 -0
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/SKILL.md +4 -3
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/review-payload-schema.md +2 -3
- package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/reviewer-prompt.md +17 -1
- package/assets/init/.qfai/assistant/skill/qfai-run/SKILL.md +52 -37
- package/assets/init/.qfai/assistant/skill/qfai-run/references/codex-cloud-install.md +80 -0
- package/assets/init/.qfai/assistant/skill/qfai-run/references/evidence-delivery.md +322 -0
- package/assets/init/.qfai/assistant/skill/qfai-run/references/extraction.md +83 -49
- package/assets/init/.qfai/assistant/skill/qfai-run/references/operator-screens.md +226 -11
- package/assets/init/.qfai/assistant/skill/qfai-run/references/plan.md +6 -3
- package/assets/init/.qfai/assistant/skill/qfai-run/references/reached-step-observations.md +132 -0
- package/assets/init/.qfai/assistant/skill/qfai-run/references/stage-points.md +14 -0
- package/assets/init/.qfai/assistant/skill/qfai-run/scripts/codex-cloud-install.mjs +117 -0
- package/assets/init/.qfai/assistant/skill/qfai-sdd/SKILL.md +4 -3
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/contract-artifact-rules.md +1 -0
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-anti-patterns.md +23 -5
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-md-authoring.md +20 -7
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/requirements-decomposition.md +8 -0
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-execution-playbook.md +29 -4
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-phase-checklists.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-pre-draft-grilling.md +4 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-quality-gate.md +1 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-triage.md +159 -4
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/spec-traceability-rules.md +14 -2
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-contract-guide.md +146 -0
- package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-design-contract-normalization.md +4 -29
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/change-request.md +38 -1
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/contracts/ui-contract.sample.yaml +52 -5
- package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/decisions.md +12 -0
- package/assets/init/.qfai/assistant/skill/qfai-triage/SKILL.md +34 -21
- package/assets/init/.qfai/assistant/skill/qfai-verify/SKILL.md +5 -4
- package/assets/init/.qfai/assistant/skill/qfai-verify/references/context-load.md +9 -6
- package/assets/init/.qfai/assistant/skill/qfai-verify/references/verify-output-contract.md +80 -15
- package/assets/init/.qfai/assistant/skill/web-research/SKILL.md +35 -21
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/config.toml +2 -4
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/mcp-config.json +9 -5
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/.mcp.json +1 -2
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/config.toml +3 -3
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/mcp-config.json +11 -8
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/config.toml +1 -1
- package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/mcp-config.json +7 -3
- package/assets/init/.qfai/assistant/step/common-design-md/STEP.md +33 -20
- package/assets/init/.qfai/assistant/step/common-gate-run/STEP.md +124 -8
- package/assets/init/.qfai/assistant/step/common-grilling-record/STEP.md +10 -2
- package/assets/init/.qfai/assistant/step/common-policy-check/STEP.md +1 -0
- package/assets/init/.qfai/assistant/step/common-review-cycle/STEP.md +26 -9
- package/assets/init/.qfai/assistant/step/discussion-interview/STEP.md +15 -8
- package/assets/init/.qfai/assistant/step/discussion-oq/STEP.md +5 -1
- package/assets/init/.qfai/assistant/step/discussion-pack/STEP.md +6 -1
- package/assets/init/.qfai/assistant/step/discussion-research/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/discussion-uiux/STEP.md +6 -4
- package/assets/init/.qfai/assistant/step/implement-backport/STEP.md +1 -1
- package/assets/init/.qfai/assistant/step/implement-benchmark/STEP.md +7 -4
- package/assets/init/.qfai/assistant/step/implement-dep-bump/STEP.md +11 -2
- package/assets/init/.qfai/assistant/step/implement-diagnose/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/implement-oracle-parity/STEP.md +2 -2
- package/assets/init/.qfai/assistant/step/implement-procedure/STEP.md +69 -0
- package/assets/init/.qfai/assistant/step/implement-quarantine/STEP.md +24 -7
- package/assets/init/.qfai/assistant/step/implement-refactor/STEP.md +2 -2
- package/assets/init/.qfai/assistant/step/implement-regression-fix/STEP.md +7 -6
- package/assets/init/.qfai/assistant/step/implement-retire/STEP.md +6 -3
- package/assets/init/.qfai/assistant/step/implement-revert/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/implement-seam/STEP.md +6 -5
- package/assets/init/.qfai/assistant/step/implement-stress-harness/STEP.md +34 -3
- package/assets/init/.qfai/assistant/step/implement-sweep/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/implement-tdd/STEP.md +39 -5
- package/assets/init/.qfai/assistant/step/implement-tooling/STEP.md +22 -2
- package/assets/init/.qfai/assistant/step/maintain-edit/STEP.md +18 -14
- package/assets/init/.qfai/assistant/step/prototyping-grill/STEP.md +4 -3
- package/assets/init/.qfai/assistant/step/prototyping-loop/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/prototyping-preflight/STEP.md +9 -3
- package/assets/init/.qfai/assistant/step/sdd-contract/STEP.md +11 -0
- package/assets/init/.qfai/assistant/step/sdd-flow/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/sdd-story/STEP.md +10 -0
- package/assets/init/.qfai/assistant/step/sdd-triage/STEP.md +34 -10
- package/assets/init/.qfai/assistant/step/triage-answer/STEP.md +7 -6
- package/assets/init/.qfai/assistant/step/triage-close/STEP.md +33 -23
- package/assets/init/.qfai/assistant/step/triage-cluster/STEP.md +5 -3
- package/assets/init/.qfai/assistant/step/triage-decompose/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/triage-dedupe/STEP.md +4 -0
- package/assets/init/.qfai/assistant/step/triage-handoff/STEP.md +13 -4
- package/assets/init/.qfai/assistant/step/triage-investigate/STEP.md +8 -5
- package/assets/init/.qfai/assistant/step/triage-operate/STEP.md +50 -0
- package/assets/init/.qfai/assistant/step/triage-owned-cleanup/STEP.md +86 -0
- package/assets/init/.qfai/assistant/step/triage-request-info/STEP.md +2 -0
- package/assets/init/.qfai/assistant/step/triage-security-intake/STEP.md +6 -3
- package/assets/init/.qfai/assistant/step/verify-change-note/STEP.md +1 -0
- package/assets/init/.qfai/assistant/step/verify-commit/STEP.md +37 -9
- package/assets/init/.qfai/assistant/step/verify-external/STEP.md +5 -2
- package/assets/init/.qfai/assistant/step/verify-qfai-gate/STEP.md +14 -16
- package/assets/init/.qfai/assistant/step/verify-release-notes/STEP.md +1 -0
- package/assets/init/.qfai/assistant/step/verify-repeat-run/STEP.md +46 -4
- package/assets/init/.qfai/assistant/step/verify-repo-gate/STEP.md +133 -30
- package/assets/init/root/.agents/rules/ai-readable-markdown.md +2 -2
- package/assets/init/root/.agents/rules/api-budget.md +187 -8
- package/assets/init/root/.agents/rules/document-schema.md +17 -0
- package/assets/init/root/.agents/rules/documentation-clarity.md +163 -34
- package/assets/init/root/.agents/rules/graph-exploration.md +150 -0
- package/assets/init/root/.agents/rules/grilling.md +100 -43
- package/assets/init/root/.agents/rules/minimal-implementation.md +3 -3
- package/assets/init/root/.agents/rules/reminders.json +27 -18
- package/assets/init/root/.agents/rules/session-feedback.md +131 -0
- package/assets/init/root/.agents/rules/temporary-files.md +33 -0
- package/assets/init/root/.agents/rules/untrusted-content.md +2 -2
- package/assets/init/root/.agents/rules/user-questions.md +51 -40
- package/assets/init/root/.github/workflows/qfai-docs.yml +3 -3
- package/assets/init/root/.github/workflows/qfai-tests.yml +88 -35
- package/assets/init/root/.github/workflows/qfai-validate.yml +2 -2
- package/assets/init/root/AGENTS.md +24 -22
- package/assets/sandbox-templates/default-deny.yaml +9 -3
- package/assets/schemas/workflow/extraction.schema.json +89 -5
- package/assets/scripts/check-mdschema.mjs +77 -8
- package/assets/uix-rev/comparison-review.md +1 -1
- package/assets/uix-rev/contracts-review.md +1 -2
- package/dist/cli/index.cjs +9444 -10071
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +9421 -10041
- package/dist/cli/index.mjs.map +1 -1
- package/dist/graph/cli.cjs +1568 -0
- package/dist/graph/cli.cjs.map +1 -0
- package/dist/graph/cli.d.cts +9 -0
- package/dist/graph/cli.d.ts +9 -0
- package/dist/graph/cli.mjs +1541 -0
- package/dist/graph/cli.mjs.map +1 -0
- package/dist/graph/hook.cjs +817 -0
- package/dist/graph/hook.cjs.map +1 -0
- package/dist/graph/hook.d.cts +9 -0
- package/dist/graph/hook.d.ts +9 -0
- package/dist/graph/hook.mjs +792 -0
- package/dist/graph/hook.mjs.map +1 -0
- package/dist/index.cjs +7634 -8517
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +146 -658
- package/dist/index.d.ts +146 -658
- package/dist/index.mjs +7462 -8318
- package/dist/index.mjs.map +1 -1
- package/dist/process-C21nTvkT.d.cts +12 -0
- package/dist/process-C21nTvkT.d.ts +12 -0
- package/package.json +4 -6
- package/assets/init/root/CLAUDE.md +0 -46
package/README.md
CHANGED
|
@@ -79,11 +79,21 @@ Then open your AI coding agent in the repository and describe the change in your
|
|
|
79
79
|
|
|
80
80
|
> Let each customer register up to five notification addresses, with no duplicates.
|
|
81
81
|
|
|
82
|
+
If you only have an idea, say so: the run starts with a discussion that structures scope and open questions.
|
|
83
|
+
|
|
82
84
|
The agent announces the goal, the stages it will run and the files it may change, then runs them.
|
|
83
85
|
It asks you only what it cannot decide for you, such as whether to create a new story.
|
|
86
|
+
Answer its questions, or say `stop` to end the run.
|
|
84
87
|
The stages fill the seeded story tree and follow the project's Standard commands in
|
|
85
88
|
`<paths.contractsDir>/tech.md` (by default `.qfai/spec/03_contract/tech.md`) for its quality gates.
|
|
86
89
|
|
|
90
|
+
When the run ends, check the result:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx qfai validate
|
|
94
|
+
npx qfai report
|
|
95
|
+
```
|
|
96
|
+
|
|
87
97
|
To drive the stages yourself instead:
|
|
88
98
|
Run `/qfai-discussion` and `/qfai-sdd` to fill the seeded story tree.
|
|
89
99
|
See [Invoking a stage directly](#invoking-a-stage-directly-expert-path).
|
|
@@ -313,27 +323,22 @@ flowchart LR
|
|
|
313
323
|
(`assistant/rule/`, `skill/`, `agent/` and `prompt/`), plus `qfai.config.yaml`.
|
|
314
324
|
- Options:
|
|
315
325
|
|
|
316
|
-
| Flag
|
|
317
|
-
|
|
|
318
|
-
| `--dir <path>`
|
|
319
|
-
| `--root <path>`
|
|
320
|
-
| `--force`
|
|
321
|
-
| `--dry-run`
|
|
322
|
-
| `--
|
|
323
|
-
| `--
|
|
324
|
-
| `--
|
|
325
|
-
| `--
|
|
326
|
-
| `--version`, `-V` | Print the installed QFAI version to stdout and exit 0. Accepted by every command, `init` included, and handled before the command runs, so it works outside a project too. |
|
|
327
|
-
|
|
328
|
-
- `QFAI-DEPRECATED-001` means the legacy assistant layout remains past its
|
|
329
|
-
supported window. Run `npx qfai init --upgrade-assistant-tree` to copy
|
|
330
|
-
recognized files into the current tree without deleting their sources.
|
|
326
|
+
| Flag | Effect |
|
|
327
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
328
|
+
| `--dir <path>` | Output directory (default: the current directory). Wins over `--root` when both are given. |
|
|
329
|
+
| `--root <path>` | Every other command reads this as the target directory; `init` reads it as the output directory too, but only when `--dir` is omitted. |
|
|
330
|
+
| `--force` | Overwrite the shipped skills, steps, agents and rules, the rule masters under `.agents/rules/`, their host wrappers, and generated Copilot instructions, whether or not you edited them. Project content, `qfai.config.yaml`, `DESIGN.md`, `AGENTS.md` and routing overrides are preserved. The managed `.gitignore` block and `core.symlinks` setting are repaired on every non-dry-run. |
|
|
331
|
+
| `--dry-run` | Report what would change and write nothing. |
|
|
332
|
+
| `--yes` | Reserved for a future interactive mode; no behavioural difference today. |
|
|
333
|
+
| `--verbose` | Expand the run report's `skipped` list to the full path listing. Off by default, so a no-op re-run prints the skip count and a pointer to this flag instead of every shipped asset path. It does not gate the written or removed listings: those are printed whenever they have entries, with or without this flag. |
|
|
334
|
+
| `--help`, `-h` | Print the CLI usage banner and exit without writing anything. Accepted by every command, `init` included, and handled before the command runs. |
|
|
335
|
+
| `--version`, `-V` | Print the installed QFAI version to stdout and exit 0. Accepted by every command, `init` included, and handled before the command runs, so it works outside a project too. |
|
|
331
336
|
|
|
332
337
|
- `npx qfai validate`
|
|
333
338
|
- Validates the story tree, contracts and test obligations, writes `.qfai/report/validate.json`,
|
|
334
339
|
and appends run logs to `.qfai/report/run-*/`; use `--fail-on error` (or `--fail-on warning`) to turn it into a CI gate,
|
|
335
340
|
and `--format github` to emit GitHub-friendly annotations.
|
|
336
|
-
Use `--flow BF-0001` to scope a run to one business flow.
|
|
341
|
+
Use `--flow BF-0001` to scope a run to one business flow.
|
|
337
342
|
Use `--profile discussion|sdd|prototyping|atdd|tdd|verify` for local skill-owned checks; CI should use default/full validation (or `verify` / `tdd` for the dedicated CI gates).
|
|
338
343
|
- `npx qfai report`
|
|
339
344
|
- Produces a human-readable report (`report.md` by default) or an internal JSON export (`report.json`) from `validate.json`; use `--base-url` to link file paths in Markdown to your repository viewer.
|
|
@@ -426,15 +431,29 @@ Notes.
|
|
|
426
431
|
issue order are not stable; match on `issues[].code`.
|
|
427
432
|
- `report.json`, `doctor.json`, and `run-*` JSON logs are internal exports and are not a stable external contract; prefer `report.md` for integrations that must survive tool upgrades.
|
|
428
433
|
|
|
429
|
-
##
|
|
434
|
+
## Dependency security
|
|
430
435
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
+
The glob-matching dependency `braces` has an unresolved
|
|
437
|
+
[stack-exhaustion denial-of-service advisory](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm).
|
|
438
|
+
QFAI accepts this residual risk only for reviewed project patterns and paths,
|
|
439
|
+
trusted configuration and trusted SDK callers. This is risk acceptance, not a
|
|
440
|
+
clean audit or proof that QFAI is unaffected. Reproduction and exploitation in
|
|
441
|
+
QFAI remain unverified.
|
|
436
442
|
|
|
437
|
-
|
|
443
|
+
Review include, ignore and negative patterns, constructed paths and SDK inputs.
|
|
444
|
+
`validateProject` accepts a caller-supplied `ConfigLoadResult` without invoking
|
|
445
|
+
the configuration loader; the caller must review those values too. Catching
|
|
446
|
+
errors and limiting results after glob expansion do not defend against stack
|
|
447
|
+
exhaustion during expansion.
|
|
448
|
+
|
|
449
|
+
Untrusted pull requests, externally supplied configuration and service request
|
|
450
|
+
inputs are outside this acceptance. Review those inputs and restrict access;
|
|
451
|
+
do not expose glob processing to them until your mitigation and security review
|
|
452
|
+
cover them.
|
|
453
|
+
|
|
454
|
+
Reassess the risk when a compatible patch becomes available or untrusted input
|
|
455
|
+
is needed. A forced downgrade to `qfai@0.4.0` is not a compatible fix for the
|
|
456
|
+
current major API; do not apply it through `npm audit fix --force`.
|
|
438
457
|
|
|
439
458
|
## FAQ
|
|
440
459
|
|
|
@@ -607,6 +626,17 @@ Waiver policy.
|
|
|
607
626
|
- Expired waivers are reported as warnings (`QFAI-WAIVER-003`) and must be renewed or removed with evidence.
|
|
608
627
|
- Suppressed findings remain visible in reports as `suppressed=true`; waivers do not erase findings.
|
|
609
628
|
|
|
629
|
+
When upgrading a project with `.qfai/waivers.yml`, back up that file. Check the
|
|
630
|
+
current public finding codes and the release notes for confirmed removals or
|
|
631
|
+
renames. Update a `rule:` value only when the documented rename preserves the
|
|
632
|
+
finding's meaning and scope. Remove confirmed retired or inapplicable waivers,
|
|
633
|
+
keeping the backup and recording each removal's reason for the operator. Do not
|
|
634
|
+
rename whole code prefixes or automatically delete an unknown rule.
|
|
635
|
+
|
|
636
|
+
Rerun full validation and require zero errors. An unknown waiver rule produces
|
|
637
|
+
`QFAI-WAIVER-004` at `warning` and is not applied in that run; investigate it
|
|
638
|
+
against the current diagnostics and release notes.
|
|
639
|
+
|
|
610
640
|
Typical customizations.
|
|
611
641
|
|
|
612
642
|
- Add a `doctor` step before validate if you want to fail fast on path/glob/config issues.
|
|
@@ -929,7 +959,6 @@ commit that bumps the package, and to keep the two from being merged separately.
|
|
|
929
959
|
│ │ └── open-questions.md
|
|
930
960
|
│ └── waivers.yml
|
|
931
961
|
├── AGENTS.md
|
|
932
|
-
├── CLAUDE.md
|
|
933
962
|
└── qfai.config.yaml
|
|
934
963
|
```
|
|
935
964
|
|
|
@@ -966,17 +995,6 @@ provide those defaults to the agent.
|
|
|
966
995
|
The `.claude` / `.github` agent wrappers are symlinks and follow the canonical document
|
|
967
996
|
automatically; the Codex profiles are generated files, so rerun `npx qfai init --force`
|
|
968
997
|
to refresh them (and any other wrapper asset that has drifted).
|
|
969
|
-
`--force` deletes as well as overwrites: it removes the command and prompt wrappers
|
|
970
|
-
under `.claude/commands/` and `.github/prompts/`, and the skill wrappers under
|
|
971
|
-
`.claude/skills/`, `.agents/skills/`, `.codex/skills/` and `.github/skills/` for skills that are
|
|
972
|
-
not in the current release, whether those wrappers are directories or symlinks.
|
|
973
|
-
Files it did not write — a project's own slash command, prompt file or skill,
|
|
974
|
-
including one published from a project-authored `.qfai/assistant/skill/` entry — are left in place,
|
|
975
|
-
whatever they are named. Ownership is read from the file, not the name: a wrapper is removed only when
|
|
976
|
-
it carries the delegation line to the canonical document of the same name, or is a symlink into
|
|
977
|
-
`.qfai/assistant/skill/`. One consequence of that: a symlink has no content to prove who wrote it, so
|
|
978
|
-
if you publish a canonical skill of your own under a name QFAI itself once shipped, `--force` removes
|
|
979
|
-
that link. Your `.qfai/assistant/skill/` entry is untouched; re-create the link to publish it again.
|
|
980
998
|
|
|
981
999
|
### Supported hosts
|
|
982
1000
|
|
|
@@ -986,7 +1004,9 @@ No host is declared supported in this release.
|
|
|
986
1004
|
### Cross-AI rules and the writing reminder
|
|
987
1005
|
|
|
988
1006
|
`npx qfai init` seeds `.agents/rules/**`, the rule set every AI coding agent in
|
|
989
|
-
the project shares, and points `AGENTS.md`
|
|
1007
|
+
the project shares, and points `AGENTS.md` at it, with a line for each rule that says when
|
|
1008
|
+
to read it. Claude Code reads `AGENTS.md` when the project has no `CLAUDE.md` (Claude Code
|
|
1009
|
+
2.1.277 or later). One of those
|
|
990
1010
|
rules, `documentation-clarity.md`, sets the writing standard for pull requests,
|
|
991
1011
|
issues, code comments and Markdown: no project-local identifiers, no account of
|
|
992
1012
|
how the work went, cut to what a reader outside the team can follow.
|
|
@@ -216,6 +216,15 @@ routing:
|
|
|
216
216
|
rerun_policy: changed-scope-dependents
|
|
217
217
|
review_profile: default
|
|
218
218
|
|
|
219
|
+
- step: implement-procedure
|
|
220
|
+
phases:
|
|
221
|
+
- id: documentation
|
|
222
|
+
mandatory_agents: [doc-steward]
|
|
223
|
+
conditional_agents: []
|
|
224
|
+
parallel_groups: []
|
|
225
|
+
rerun_policy: changed-scope-dependents
|
|
226
|
+
review_profile: default
|
|
227
|
+
|
|
219
228
|
# Writes the bodies of empty acceptance tests, keeping each annotation.
|
|
220
229
|
- step: implement-acceptance
|
|
221
230
|
phases:
|
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
routing:
|
|
5
5
|
# The triage steps change no tracked file, so each has one author and no
|
|
6
6
|
# build or test phase.
|
|
7
|
+
- step: triage-operate
|
|
8
|
+
phases:
|
|
9
|
+
- id: operate
|
|
10
|
+
mandatory_agents: [devops-ci-engineer]
|
|
11
|
+
conditional_agents: []
|
|
12
|
+
parallel_groups: []
|
|
13
|
+
rerun_policy: changed-scope-dependents
|
|
14
|
+
review_profile: default
|
|
15
|
+
|
|
16
|
+
- step: triage-owned-cleanup
|
|
17
|
+
phases:
|
|
18
|
+
- id: cleanup
|
|
19
|
+
mandatory_agents: [devops-ci-engineer]
|
|
20
|
+
conditional_agents: []
|
|
21
|
+
parallel_groups: []
|
|
22
|
+
rerun_policy: changed-scope-dependents
|
|
23
|
+
review_profile: default
|
|
24
|
+
|
|
7
25
|
- step: triage-close
|
|
8
26
|
phases:
|
|
9
27
|
- id: record
|
|
@@ -29,6 +29,9 @@ stages:
|
|
|
29
29
|
after: [note]
|
|
30
30
|
decisionPoints: []
|
|
31
31
|
branchPoints:
|
|
32
|
+
- step: implement-quarantine
|
|
33
|
+
outcomes:
|
|
34
|
+
- { outcome: failing-consistently, routes: decision-table }
|
|
32
35
|
- step: implement-diagnose
|
|
33
36
|
outcomes:
|
|
34
37
|
- { outcome: product-race, routes: [fix-intermittent] }
|
|
@@ -11,6 +11,7 @@ stages:
|
|
|
11
11
|
- { step: sdd-flow, passThrough: true }
|
|
12
12
|
- { step: sdd-story, passThrough: true }
|
|
13
13
|
- { step: sdd-contract, passThrough: true }
|
|
14
|
+
- { step: common-design-md, passThrough: true }
|
|
14
15
|
- { step: sdd-cycle, passThrough: true }
|
|
15
16
|
after: [diagnose]
|
|
16
17
|
review: spec
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
route: write-procedure
|
|
2
|
+
family: change
|
|
3
|
+
stages:
|
|
4
|
+
- id: documentation
|
|
5
|
+
kind: documentation
|
|
6
|
+
steps: [implement-procedure]
|
|
7
|
+
- id: note
|
|
8
|
+
kind: verify
|
|
9
|
+
steps:
|
|
10
|
+
- { step: verify-change-note, passThrough: true }
|
|
11
|
+
after: [documentation]
|
|
12
|
+
review: code
|
|
13
|
+
- id: verify
|
|
14
|
+
kind: verify
|
|
15
|
+
steps: [verify-qfai-gate, verify-repo-gate, verify-commit]
|
|
16
|
+
after: [note]
|
|
17
|
+
decisionPoints: []
|
|
18
|
+
branchPoints: []
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
const sdk = await import(pathToFileURL(process.argv[2]).href);
|
|
8
|
+
const { default: CodeGraph, setLogger, silentLogger } = sdk.default;
|
|
9
|
+
setLogger(silentLogger);
|
|
10
|
+
const mode = process.argv[4];
|
|
11
|
+
const corpus = process.argv[3];
|
|
12
|
+
const graph = mode
|
|
13
|
+
? await CodeGraph.open(process.argv[3], { readOnly: true })
|
|
14
|
+
: await CodeGraph.init(process.argv[3], { index: false });
|
|
15
|
+
try {
|
|
16
|
+
if (mode === "inventory") {
|
|
17
|
+
process.stdout.write(
|
|
18
|
+
JSON.stringify({ files: graph.getFiles().map((file) => file.path) }) + "\n",
|
|
19
|
+
);
|
|
20
|
+
} else if (mode === "coverage") {
|
|
21
|
+
process.stdout.write(JSON.stringify(await coverage(graph, corpus)) + "\n");
|
|
22
|
+
} else if (mode === undefined) {
|
|
23
|
+
const result = await graph.indexAll();
|
|
24
|
+
const build = graph.getIndexBuildInfo();
|
|
25
|
+
await writeFile(
|
|
26
|
+
path.join(corpus, ".codegraph", "qfai-native-evidence.json"),
|
|
27
|
+
JSON.stringify({
|
|
28
|
+
engineVersion: build.version,
|
|
29
|
+
extractionVersion: build.extractionVersion,
|
|
30
|
+
lastIndexedAt: graph.getLastIndexedAt(),
|
|
31
|
+
result: {
|
|
32
|
+
success: result.success,
|
|
33
|
+
filesDiscovered: result.filesDiscovered ?? null,
|
|
34
|
+
filesIndexed: result.filesIndexed,
|
|
35
|
+
filesSkipped: result.filesSkipped,
|
|
36
|
+
filesErrored: result.filesErrored,
|
|
37
|
+
filesSkippedUnsupported: result.filesSkippedUnsupported ?? 0,
|
|
38
|
+
topUnsupportedExtensions: result.topUnsupportedExtensions ?? [],
|
|
39
|
+
errors: result.errors.map((error) => ({
|
|
40
|
+
code: error.code ?? "unclassified",
|
|
41
|
+
severity: error.severity,
|
|
42
|
+
filePath: safeRelativeInput(corpus, error.filePath),
|
|
43
|
+
})),
|
|
44
|
+
},
|
|
45
|
+
}) + "\n",
|
|
46
|
+
);
|
|
47
|
+
process.stdout.write("CodeGraph native indexing completed.\n");
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error("Unsupported native operation");
|
|
50
|
+
}
|
|
51
|
+
} finally {
|
|
52
|
+
graph.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function safeRelativeInput(corpus, file) {
|
|
57
|
+
if (typeof file !== "string" || !file) return "Unidentified native input";
|
|
58
|
+
const relative = (path.isAbsolute(file) ? path.relative(corpus, file) : file).replaceAll(
|
|
59
|
+
"\\",
|
|
60
|
+
"/",
|
|
61
|
+
);
|
|
62
|
+
if (
|
|
63
|
+
path.posix.isAbsolute(relative) ||
|
|
64
|
+
path.win32.isAbsolute(relative) ||
|
|
65
|
+
relative.split("/").some((part) => !part || part === "." || part === "..") ||
|
|
66
|
+
/(?:^|\/)(?:\.env(?:\.|$)|\.npmrc$|\.pypirc$|\.netrc$|credentials?(?:\.|$)|secrets?(?:\.|$))|\.(?:pem|key|p12|pfx)$/i.test(
|
|
67
|
+
relative,
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
return "Unidentified native input";
|
|
71
|
+
return relative;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function coverage(graph, corpus) {
|
|
75
|
+
const unknown = { complete: false, unsupported: [], unreadable: [], unparsed: [] };
|
|
76
|
+
let evidence;
|
|
77
|
+
try {
|
|
78
|
+
evidence = JSON.parse(
|
|
79
|
+
await readFile(path.join(corpus, ".codegraph", "qfai-native-evidence.json"), "utf8"),
|
|
80
|
+
);
|
|
81
|
+
} catch {
|
|
82
|
+
return unknown;
|
|
83
|
+
}
|
|
84
|
+
const build = graph.getIndexBuildInfo();
|
|
85
|
+
const result = evidence?.result;
|
|
86
|
+
const counts = [
|
|
87
|
+
"filesDiscovered",
|
|
88
|
+
"filesIndexed",
|
|
89
|
+
"filesSkipped",
|
|
90
|
+
"filesErrored",
|
|
91
|
+
"filesSkippedUnsupported",
|
|
92
|
+
];
|
|
93
|
+
if (
|
|
94
|
+
!record(evidence) ||
|
|
95
|
+
Object.keys(evidence).length !== 4 ||
|
|
96
|
+
evidence.engineVersion !== build.version ||
|
|
97
|
+
evidence.extractionVersion !== build.extractionVersion ||
|
|
98
|
+
!Number.isSafeInteger(evidence.lastIndexedAt) ||
|
|
99
|
+
evidence.lastIndexedAt !== graph.getLastIndexedAt() ||
|
|
100
|
+
!record(result) ||
|
|
101
|
+
Object.keys(result).length !== 8 ||
|
|
102
|
+
typeof result.success !== "boolean" ||
|
|
103
|
+
counts.some((key) => !Number.isSafeInteger(result[key]) || result[key] < 0) ||
|
|
104
|
+
!Array.isArray(result.errors) ||
|
|
105
|
+
!Array.isArray(result.topUnsupportedExtensions)
|
|
106
|
+
)
|
|
107
|
+
return unknown;
|
|
108
|
+
const unsupported = [];
|
|
109
|
+
const unreadable = [];
|
|
110
|
+
const unparsed = [];
|
|
111
|
+
let documentedInputs = 0;
|
|
112
|
+
for (const group of result.topUnsupportedExtensions) {
|
|
113
|
+
if (
|
|
114
|
+
!record(group) ||
|
|
115
|
+
typeof group.ext !== "string" ||
|
|
116
|
+
!Number.isSafeInteger(group.count) ||
|
|
117
|
+
group.count < 0
|
|
118
|
+
)
|
|
119
|
+
return unknown;
|
|
120
|
+
if (
|
|
121
|
+
/^\.(?:md|mdx|txt|rst|adoc|pdf|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|mp[34]|wav)$/i.test(
|
|
122
|
+
group.ext,
|
|
123
|
+
)
|
|
124
|
+
) {
|
|
125
|
+
documentedInputs += group.count;
|
|
126
|
+
} else {
|
|
127
|
+
unsupported.push(`${group.ext} (${group.count} inputs)`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const namedUnsupported = result.topUnsupportedExtensions.reduce(
|
|
131
|
+
(count, group) => count + group.count,
|
|
132
|
+
0,
|
|
133
|
+
);
|
|
134
|
+
if (namedUnsupported < result.filesSkippedUnsupported)
|
|
135
|
+
unsupported.push("Other unsupported native inputs");
|
|
136
|
+
if (
|
|
137
|
+
namedUnsupported > result.filesSkippedUnsupported ||
|
|
138
|
+
documentedInputs > result.filesSkippedUnsupported
|
|
139
|
+
)
|
|
140
|
+
return unknown;
|
|
141
|
+
for (const error of [
|
|
142
|
+
...result.errors,
|
|
143
|
+
...graph.getFiles().flatMap((file) => file.errors ?? []),
|
|
144
|
+
]) {
|
|
145
|
+
if (!record(error) || !["error", "warning"].includes(error.severity)) return unknown;
|
|
146
|
+
const file = safeRelativeInput(corpus, error.filePath);
|
|
147
|
+
if (error.code === "read_error") unreadable.push(file);
|
|
148
|
+
else unparsed.push(file);
|
|
149
|
+
}
|
|
150
|
+
if (result.filesErrored > 0 && unreadable.length === 0 && unparsed.length === 0)
|
|
151
|
+
unparsed.push("Unidentified native extraction errors");
|
|
152
|
+
const complete =
|
|
153
|
+
result.success &&
|
|
154
|
+
result.filesIndexed + result.filesSkipped + result.filesErrored >= result.filesDiscovered &&
|
|
155
|
+
result.filesErrored === 0 &&
|
|
156
|
+
unsupported.length === 0 &&
|
|
157
|
+
unreadable.length === 0 &&
|
|
158
|
+
unparsed.length === 0;
|
|
159
|
+
return {
|
|
160
|
+
complete,
|
|
161
|
+
unsupported,
|
|
162
|
+
unreadable: [...new Set(unreadable)],
|
|
163
|
+
unparsed: [...new Set(unparsed)],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function record(value) {
|
|
168
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
main().catch(() => {
|
|
172
|
+
process.stderr.write("CodeGraph native indexing failed.\n");
|
|
173
|
+
process.exitCode = 1;
|
|
174
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Inspect the managed corpus with Graphify's native freshness operation."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from graphify.detect import detect_incremental
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def input_inventory(output, graph):
|
|
11
|
+
manifest = json.loads((output / "manifest.json").read_text(encoding="utf-8"))
|
|
12
|
+
if not isinstance(manifest, dict):
|
|
13
|
+
raise ValueError("Invalid native manifest")
|
|
14
|
+
files = set(manifest.keys())
|
|
15
|
+
groups = [graph["nodes"]]
|
|
16
|
+
for name in ("edges", "links", "hyperedges"):
|
|
17
|
+
if name in graph:
|
|
18
|
+
groups.append(graph[name])
|
|
19
|
+
nested = graph.get("graph", {})
|
|
20
|
+
if not isinstance(nested, dict):
|
|
21
|
+
raise ValueError("Invalid native graph attributes")
|
|
22
|
+
if "hyperedges" in nested:
|
|
23
|
+
groups.append(nested["hyperedges"])
|
|
24
|
+
for group in groups:
|
|
25
|
+
if not isinstance(group, list):
|
|
26
|
+
raise ValueError("Invalid native graph references")
|
|
27
|
+
for item in group:
|
|
28
|
+
if not isinstance(item, dict):
|
|
29
|
+
raise ValueError("Invalid native graph reference")
|
|
30
|
+
for field in ("source_file", "definition_file", "path"):
|
|
31
|
+
value = item.get(field)
|
|
32
|
+
if value is None or value == "":
|
|
33
|
+
continue
|
|
34
|
+
if not isinstance(value, str):
|
|
35
|
+
raise ValueError("Invalid native input path")
|
|
36
|
+
files.add(value)
|
|
37
|
+
return sorted(files)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def main():
|
|
41
|
+
root = Path(sys.argv[1])
|
|
42
|
+
kind = sys.argv[2]
|
|
43
|
+
output = root / "graphify-out"
|
|
44
|
+
graph = json.loads((output / "graph.json").read_text(encoding="utf-8"))
|
|
45
|
+
if not isinstance(graph, dict) or not isinstance(graph.get("nodes"), list):
|
|
46
|
+
raise ValueError("Invalid native graph")
|
|
47
|
+
if kind == "inventory":
|
|
48
|
+
print(json.dumps({"files": input_inventory(output, graph)}))
|
|
49
|
+
return
|
|
50
|
+
if kind not in ("semantic", "ast"):
|
|
51
|
+
raise ValueError("Unsupported native inspection")
|
|
52
|
+
state = detect_incremental(
|
|
53
|
+
root,
|
|
54
|
+
manifest_path=str(output / "manifest.json"),
|
|
55
|
+
kind=kind,
|
|
56
|
+
cache_root=output,
|
|
57
|
+
)
|
|
58
|
+
print(json.dumps({
|
|
59
|
+
"current": state["new_total"] == 0
|
|
60
|
+
and not state["deleted_files"]
|
|
61
|
+
and not state["excluded_files"],
|
|
62
|
+
"unsupported": state.get("unclassified", []),
|
|
63
|
+
"unreadable": state.get("unreadable", []),
|
|
64
|
+
}))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
try:
|
|
69
|
+
main()
|
|
70
|
+
except Exception:
|
|
71
|
+
sys.stderr.write("Graphify freshness inspection failed.\n")
|
|
72
|
+
sys.exit(1)
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"command": "node",
|
|
31
31
|
"args": [
|
|
32
32
|
"-e",
|
|
33
|
-
"try{let
|
|
33
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}const p=i.prompt;if(!(typeof p==='string'&&/^[ \\t]*(<(task-notification|wake|ci-monitor-event)[\\s>]|\\[SYSTEM NOTIFICATION)/m.test(p))){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}}catch{}",
|
|
34
34
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
35
35
|
"structured-question"
|
|
36
36
|
]
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"command": "node",
|
|
47
47
|
"args": [
|
|
48
48
|
"-e",
|
|
49
|
-
"try{let
|
|
49
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}const p=i.prompt;if(!(typeof p==='string'&&/^[ \\t]*(<(task-notification|wake|ci-monitor-event)[\\s>]|\\[SYSTEM NOTIFICATION)/m.test(p))){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}}catch{}",
|
|
50
50
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
51
51
|
"free-text-entry"
|
|
52
52
|
]
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"command": "node",
|
|
97
97
|
"args": [
|
|
98
98
|
"-e",
|
|
99
|
-
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
99
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}catch{}",
|
|
100
100
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
101
101
|
"grilling-design-artifact"
|
|
102
102
|
]
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"command": "node",
|
|
113
113
|
"args": [
|
|
114
114
|
"-e",
|
|
115
|
-
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
115
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}catch{}",
|
|
116
116
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
117
117
|
"grilling-delegation"
|
|
118
118
|
]
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"command": "node",
|
|
129
129
|
"args": [
|
|
130
130
|
"-e",
|
|
131
|
-
"try{const
|
|
131
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}catch{}",
|
|
132
132
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
133
133
|
"grilling-plan"
|
|
134
134
|
]
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"command": "node",
|
|
145
145
|
"args": [
|
|
146
146
|
"-e",
|
|
147
|
-
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}const c=i.tool_input&&i.tool_input.command;if(typeof c==='string'&&/(^|[^\\w.-])gh([^\\w.-]|$)|api\\.github\\.com/.test(c)){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
147
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))||{}}catch{}const c=i.tool_input&&i.tool_input.command;if(typeof c==='string'&&/(^|[^\\w.-])gh([^\\w.-]|$)|api\\.github\\.com/.test(c)){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}}catch{}",
|
|
148
148
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
149
149
|
"api-budget"
|
|
150
150
|
]
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
"command": "node",
|
|
164
164
|
"args": [
|
|
165
165
|
"-e",
|
|
166
|
-
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
166
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}catch{}",
|
|
167
167
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
168
168
|
"documentation-clarity-after-write"
|
|
169
169
|
]
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"command": "node",
|
|
176
176
|
"args": [
|
|
177
177
|
"-e",
|
|
178
|
-
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
178
|
+
"try{const f=require('fs');let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}catch{}",
|
|
179
179
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
180
180
|
"documentation-clarity-after-edit"
|
|
181
181
|
]
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"command": "node",
|
|
192
192
|
"args": [
|
|
193
193
|
"-e",
|
|
194
|
-
"try{const f=require('fs'),p=require('path'),R=p.dirname(p.dirname(p.dirname(process.argv[1])));let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}const u=i.tool_input&&i.tool_input.file_path;let src=true;if(typeof u==='string'&&(x=>{const s=x.split(p.sep),b=s.pop();return p.isAbsolute(x)||s[0]==='..'||s.some(y=>['tmp','test','tests','__tests__','node_modules','.qfai','.agents'].includes(y))||b[0]==='.'||/\\.(test|spec)\\./.test(b)||['.md','.mdx','.markdown','.txt','.rst','.yml','.yaml','.json','.jsonc','.json5','.toml','.ini','.csv','.tsv','.lock','.svg','.png','.jpg','.jpeg','.gif'].includes(p.extname(b).toLowerCase())})(p.relative(R,p.resolve(R,u))))src=false;if(src){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}
|
|
194
|
+
"try{const f=require('fs'),p=require('path'),R=p.dirname(p.dirname(p.dirname(process.argv[1])));let i={};try{i=JSON.parse(f.readFileSync(0,'utf8'))}catch{}const u=i.tool_input&&i.tool_input.file_path;let src=true;if(typeof u==='string'&&(x=>{const s=x.split(p.sep),b=s.pop();return p.isAbsolute(x)||s[0]==='..'||s.some(y=>['tmp','test','tests','__tests__','node_modules','.qfai','.agents'].includes(y))||b[0]==='.'||/\\.(test|spec)\\./.test(b)||['.md','.mdx','.markdown','.txt','.rst','.yml','.yaml','.json','.jsonc','.json5','.toml','.ini','.csv','.tsv','.lock','.svg','.png','.jpg','.jpeg','.gif'].includes(p.extname(b).toLowerCase())})(p.relative(R,p.resolve(R,u))))src=false;if(src){let n=1;if(typeof i.session_id==='string'){try{const t=require('path').join(require('os').tmpdir(),['qfai-reminder',i.session_id,i.agent_id||'main',process.argv[2]].join('-').replace(/[^\\w.-]/g,'_'));f.appendFileSync(t,'.');n=f.statSync(t).size}catch{}}const e=JSON.parse(f.readFileSync(process.argv[1],'utf8'))[process.argv[2]];if(e!==undefined){const {briefContext,...m}=e;if(n>1&&typeof briefContext==='string')m.hookSpecificOutput.additionalContext=briefContext;console.log(JSON.stringify(m))}}}catch{}",
|
|
195
195
|
"${CLAUDE_PROJECT_DIR}/.agents/rules/reminders.json",
|
|
196
196
|
"minimal-implementation"
|
|
197
197
|
]
|