yam-flow 2.8.0 → 2.8.2
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/AGENTS.md +4 -0
- package/CHANGELOG.md +22 -0
- package/COMMANDS.md +17 -2
- package/README.md +5 -1
- package/dist/bin/yam.js +162 -42
- package/dist/lib/design-production.d.ts +6 -6
- package/dist/lib/external-updates.d.ts +6 -1
- package/dist/lib/external-updates.js +93 -6
- package/dist/lib/hook-readiness.d.ts +54 -0
- package/dist/lib/hook-readiness.js +259 -0
- package/dist/lib/memory-records.d.ts +29 -0
- package/dist/lib/memory-records.js +92 -0
- package/dist/lib/security-check.d.ts +98 -0
- package/dist/lib/security-check.js +262 -0
- package/dist/lib/security-integration.d.ts +8 -0
- package/dist/lib/security-integration.js +428 -0
- package/dist/lib/verification-closure.d.ts +1 -1
- package/package.json +10 -3
- package/references/final-report.md +2 -0
- package/references/security-check.md +131 -0
- package/references/study-note.md +6 -0
- package/skills/deep/SKILL.md +4 -0
- package/skills/mission/SKILL.md +4 -0
- package/skills/quick/SKILL.md +4 -0
- package/skills/ueye/SKILL.md +4 -0
- package/src/bin/yam.ts +142 -39
- package/src/lib/external-updates.ts +87 -6
- package/src/lib/hook-readiness.ts +215 -0
- package/src/lib/memory-records.ts +109 -0
- package/src/lib/security-check.ts +184 -0
- package/src/lib/security-integration.ts +299 -0
- package/templates/security-check-note.md +42 -0
- package/templates/security-gate.yml +44 -0
- package/yam.manifest.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
21. When relevant, include architecture hygiene in the Study Note: avoid dumping unrelated logic into `page.tsx`, one-off component CSS into `global.css`, or structured product data into broad DB `jsonb` blobs when existing project boundaries, scoped styles, typed tables, constraints, or indexes fit better.
|
|
24
24
|
22. When an artifact changed, put `Next step` immediately after Study Note. Build it from a quick whole-process scan with current situation, forward outlook, a concrete critical opinion, improvement recommendations, and ordered fix-first then planned actions with evidence and ownership; do not merely rename remaining tasks.
|
|
25
25
|
|
|
26
|
+
## Security check gate
|
|
27
|
+
|
|
28
|
+
Before commit, push, CI approval, or deployment, run the configured `yam security check` gate for the exact stage and record its Security check block. Use `references/security-check.md`; preserve every SEC explanation, evidence reference, and unresolved status. Missing required evidence or a note-write failure blocks the stage. Local hooks are bypassable; enforce protected merge/deployment with a trusted CI policy and required checks. Never present a validated supplied report as an independent vulnerability scan.
|
|
29
|
+
|
|
26
30
|
## Latest Update Trigger
|
|
27
31
|
|
|
28
32
|
When the user says exactly `yam 최신 업데이트 사항 반영해줘` in a chat for this project, treat that phrase as explicit authorization to check and apply reviewed updates for yam, Scrapling, and Insane Search.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to yam-flow are documented here.
|
|
4
4
|
|
|
5
|
+
## v2.8.2 - 2026-10-02
|
|
6
|
+
|
|
7
|
+
### Improved
|
|
8
|
+
|
|
9
|
+
- Hook configuration now uses Codex's required top-level `hooks` wrapper. `yam hook migrate` backs up legacy files and preserves commands and unrelated handlers without automatically approving Codex trust.
|
|
10
|
+
- Hook status can now separate configured health, Codex `hooks/list` discovery, and opt-in local entrypoint observations; Node launcher selection is bound to the running executable identity.
|
|
11
|
+
- External yam update checks distinguish exact-version npm distribution propagation (`pending_distribution`) from network, authorization, or metadata failures.
|
|
12
|
+
- Memory listing and summary preserve the difference between missing, empty, invalid, unreadable, and incomplete record storage; incomplete reads cannot overwrite an existing summary.
|
|
13
|
+
- Added bounded Markdown skill-content checks for frontmatter identity, symlinks, personal absolute paths, download-to-shell patterns, and high-signal secrets.
|
|
14
|
+
|
|
15
|
+
## v2.8.1 - 2026-10-01
|
|
16
|
+
|
|
17
|
+
### Security
|
|
18
|
+
|
|
19
|
+
- Add nine explained SEC areas, exact-stage evidence validation and safe append-only Security check notes. Missing, stale or unresolved evidence blocks the operation.
|
|
20
|
+
- Add project snapshot checks, reviewed source/policy pins, commit/push hooks and required CI security checks. Package lifecycle verification uses the same reviewed revision on Linux, macOS and Windows.
|
|
21
|
+
- Retain sanitized security notes in CI artifacts and require actual environment inspection for deployment. Document operator-run npm publication and its enforcement limits.
|
|
22
|
+
|
|
23
|
+
### Verification
|
|
24
|
+
|
|
25
|
+
- Independent security audit, actual commit/push hooks, hosted security evidence and three-platform packaged lifecycle checks passed for the security implementation.
|
|
26
|
+
|
|
5
27
|
## v2.8.0 - 2026-09-01
|
|
6
28
|
|
|
7
29
|
### Added
|
package/COMMANDS.md
CHANGED
|
@@ -153,6 +153,8 @@ yam memory add /path/to/project --kind repeat_mistake --summary "UI work was dec
|
|
|
153
153
|
yam memory summary /path/to/project
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
`yam memory list --json` keeps the normal complete result as an array and returns a bounded `yam.memory-read.v1` envelope for missing, invalid, unreadable, or incomplete storage. `yam memory summary --json` refuses to overwrite the existing summary unless the record directory was read completely.
|
|
157
|
+
|
|
156
158
|
## Token Budget
|
|
157
159
|
|
|
158
160
|
```bash
|
|
@@ -172,7 +174,7 @@ yam update apply --component yam --json
|
|
|
172
174
|
yam update apply --all --json
|
|
173
175
|
```
|
|
174
176
|
|
|
175
|
-
`yam update check` is read-only. Its component result preserves the registry artifact source receipt: npm integrity/`gitHead` for yam, PyPI release-file SHA-256 values for Scrapling, and the Git-pinned manifest commit for Insane Search. Every `apply` needs explicit authorization, pins the official npm registry or isolated PyPI index, uses a concurrent-run lock, records a component receipt, and stops on failed/manual results. `--all` runs yam last. A yam install verifies the effective executable identity before any yam-side install command and repeats that check during rollback. This identity contract currently supports POSIX symlink layouts; Windows npm `.cmd` shims fail closed as unverified. Insane Search requires a clean tracked local manifest whose bytes match Git and matching pre/post-add commits, is never remove-first, and never edits `.codex/plugins/cache` directly.
|
|
177
|
+
`yam update check` is read-only. Its component result preserves the registry artifact source receipt: npm integrity/`gitHead` for yam, PyPI release-file SHA-256 values for Scrapling, and the Git-pinned manifest commit for Insane Search. Yam also compares `latest` with exact-version metadata and probes the official exact tarball URL; a 404 is `pending_distribution`, while network/auth/metadata mismatch is `check_failed`. The bounded HEAD probe confirms availability only and does not hash tarball bytes. Every `apply` needs explicit authorization, pins the official npm registry or isolated PyPI index, uses a concurrent-run lock, records a component receipt, and stops on failed/manual results. `--all` runs yam last. A yam install verifies the effective executable identity before any yam-side install command and repeats that check during rollback. This identity contract currently supports POSIX symlink layouts; Windows npm `.cmd` shims fail closed as unverified. Insane Search requires a clean tracked local manifest whose bytes match Git and matching pre/post-add commits, is never remove-first, and never edits `.codex/plugins/cache` directly.
|
|
176
178
|
|
|
177
179
|
## Release Supply Chain
|
|
178
180
|
|
|
@@ -327,12 +329,25 @@ Supported report shapes:
|
|
|
327
329
|
|
|
328
330
|
`lite` is advisory-only. `study-note` runs the read-only Study Note Guard against the final assistant message and can request one correction pass; neither profile runs verification or forces routes.
|
|
329
331
|
|
|
332
|
+
`yam hook migrate [--global|--project dir]` wraps legacy top-level events in Codex's `hooks` object without changing commands. It backs up the original, refuses unsafe files, and is a no-op for canonical configs. Review changed definitions in Codex `/hooks` before execution; yam does not approve trust.
|
|
333
|
+
|
|
330
334
|
```bash
|
|
331
335
|
yam hook status --global
|
|
336
|
+
yam hook migrate --global
|
|
332
337
|
yam hook enable lite --global
|
|
333
338
|
yam hook enable study-note --global
|
|
334
339
|
yam hook disable lite --global
|
|
335
340
|
yam hook disable study-note --global
|
|
336
341
|
```
|
|
337
342
|
|
|
338
|
-
`yam hook status` exits nonzero for unreadable configs, stale paths, missing targets, duplicate handlers, or incomplete event coverage. Re-enable the affected profile to back up the file, preserve unrelated hooks, and migrate its command and events.
|
|
343
|
+
`yam hook status` exits nonzero for unreadable configs, stale paths, missing targets, duplicate handlers, or incomplete event coverage. Add `--json` for `yam.hook-readiness.v1`, or `--probe` to query `hooks/list` in a separate bounded Codex app-server. The probe separates host discovery from local configuration and never claims that the active Desktop session loaded the hook. Add `--observe` to `yam hook enable` to record a bounded local entrypoint observation; it contains only hashes and event metadata and remains partial same-user evidence. Re-enable the affected profile to back up the file, preserve unrelated hooks, and migrate its command and events.
|
|
344
|
+
|
|
345
|
+
## Security check
|
|
346
|
+
|
|
347
|
+
- `yam security init`: create a private all-unverified draft and pin a reviewed policy; preserve existing files.
|
|
348
|
+
- `yam security check --stage commit|push|ci|deploy`: validate exact-target evidence and append Security check to Yam note; nonzero exit blocks.
|
|
349
|
+
- `yam security hooks enable`: explicitly install local pre-commit/pre-push hooks, preserving existing hooks.
|
|
350
|
+
- `yam security status`: show local configuration; remote protections remain not measured.
|
|
351
|
+
- `yam template security` / `yam template security-ci`: explained note and CI setup templates.
|
|
352
|
+
|
|
353
|
+
See `references/security-check.md` for stage arguments, trusted policy requirements and limitations. This validates supplied evidence; it does not automatically scan application vulnerabilities.
|
package/README.md
CHANGED
|
@@ -74,6 +74,8 @@ yam memory add . --kind lesson --summary "Keep UI checks visual before declaring
|
|
|
74
74
|
yam memory summary .
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
`yam memory list --json` distinguishes missing, empty, invalid, unreadable, and incomplete record directories. A blocked `yam memory summary --json` exits nonzero and preserves the previous summary instead of treating an access failure as an empty memory set.
|
|
78
|
+
|
|
77
79
|
Memory writes to `.yam/memory/` only when you run the command. Routes should prefer `.yam/memory/summary.md` and should not read every record by default.
|
|
78
80
|
|
|
79
81
|
## Lite Hook
|
|
@@ -91,6 +93,8 @@ It only adds short advisory context. It does not run verification, tmux, browser
|
|
|
91
93
|
|
|
92
94
|
## Study Note Hook
|
|
93
95
|
|
|
96
|
+
Codex hook files use a top-level `hooks` object containing event groups (`{"hooks":{"Stop":[...]}}`). For older yam files with events at the top level, run `yam hook migrate --global`: this creates a backup and changes only the layout, preserving existing commands and unrelated handlers. Review the changed definitions in Codex `/hooks`; discovery alone does not authorize execution, and yam never approves hook trust automatically.
|
|
97
|
+
|
|
94
98
|
Enable this profile when you want Codex to check changed work at final-response time as well as remind the agent at prompt time.
|
|
95
99
|
|
|
96
100
|
```bash
|
|
@@ -102,7 +106,7 @@ The profile installs `UserPromptSubmit` and `Stop` handlers. At `Stop`, yam chec
|
|
|
102
106
|
|
|
103
107
|
Hook stdin is limited to 1 MiB. Malformed JSON or an oversized payload produces a valid fail-open response without echoing the rejected content, deriving hook context from it, or mutating the workspace. Other CLI commands that read piped text use a 4 MiB limit and fail closed when it is exceeded.
|
|
104
108
|
|
|
105
|
-
`yam hook status` reports stale or missing command targets as `broken` and exits nonzero. Run `yam hook enable <profile> --global` again to create a timestamped backup, preserve unrelated hooks, and migrate that profile to the current installed path and event coverage. Restart Codex or open a new task after changing hooks.
|
|
109
|
+
`yam hook status` reports stale or missing command targets as `broken` and exits nonzero. Run `yam hook enable <profile> --global` again to create a timestamped backup, preserve unrelated hooks, and migrate that profile to the current installed path and event coverage. For runtime-oriented diagnosis, use `yam hook status --global --json --probe`; this separates configured hooks, discovery from a new bounded Codex app-server, and local entrypoint observations. The active Desktop session remains `not_measured` unless the host provides independent evidence. `yam hook enable <profile> --global --observe` records only a local hash-bound event observation; it is partial evidence and not host attestation. Restart Codex or open a new task after changing hooks.
|
|
106
110
|
|
|
107
111
|
## Install
|
|
108
112
|
|
package/dist/bin/yam.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { selectHookNode, probeHookDiscovery, inspectHookObservation, recordHookObservation } from '../lib/hook-readiness.js';
|
|
4
|
+
import { readMemoryDirectory } from '../lib/memory-records.js';
|
|
5
|
+
import { runSecurityCommand } from '../lib/security-integration.js';
|
|
3
6
|
import { createHash } from 'node:crypto';
|
|
4
7
|
import fs from 'node:fs';
|
|
5
8
|
import fsp from 'node:fs/promises';
|
|
@@ -70,8 +73,8 @@ const INSTRUCTION_DUPLICATION_LIMITS = {
|
|
|
70
73
|
minDirectiveChars: 40
|
|
71
74
|
};
|
|
72
75
|
const YAM_HOOK_ENTRYPOINT = path.join(ROOT, 'dist', 'bin', 'yam.js');
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
let YAM_LITE_HOOK_COMMAND = `${JSON.stringify(process.execPath)} ${JSON.stringify(YAM_HOOK_ENTRYPOINT)} hook run lite`;
|
|
77
|
+
let YAM_STUDY_NOTE_HOOK_COMMAND = `${JSON.stringify(process.execPath)} ${JSON.stringify(YAM_HOOK_ENTRYPOINT)} hook run study-note`;
|
|
75
78
|
const REQUIRED_PACK_SECTIONS = [
|
|
76
79
|
'Product Direction',
|
|
77
80
|
'UI Direction',
|
|
@@ -145,6 +148,7 @@ Usage:
|
|
|
145
148
|
yam proof [dir|--from file] [--route route] [--truth status] [--command text] [--evidence text]
|
|
146
149
|
yam proof write [dir] [--format json|md] [--out file] [--route route] [--truth status] [--command text]
|
|
147
150
|
yam study-note check [dir] [--report file|--text text] [--json]
|
|
151
|
+
yam security <init|check|hooks|status> [--stage commit|push|ci|deploy] [--json]
|
|
148
152
|
yam next-step <report|verify> [--spec file|--receipt file] [--json]
|
|
149
153
|
yam loop report [--route route] [--intent text] [--stage id:status:note] [--evidence text] [--json]
|
|
150
154
|
yam scout receipt <create|verify> [options]
|
|
@@ -170,7 +174,7 @@ Usage:
|
|
|
170
174
|
yam safety [text...]
|
|
171
175
|
yam memory <init|add|list|summary|resolve> [dir] [options]
|
|
172
176
|
yam hook <status|enable|disable|run> [lite|study-note] [--global|--project dir]
|
|
173
|
-
yam template <project|ueye|mission|proof|tuning>
|
|
177
|
+
yam template <project|ueye|mission|proof|tuning|security|security-ci>
|
|
174
178
|
yam tune-log [dir]
|
|
175
179
|
yam install [--dry-run] [--json] [--replace-user-skill name]
|
|
176
180
|
yam uninstall
|
|
@@ -489,6 +493,7 @@ async function verify({ quiet = false } = {}) {
|
|
|
489
493
|
'context-reuse.md',
|
|
490
494
|
'markdown-management.md',
|
|
491
495
|
'study-note.md',
|
|
496
|
+
'security-check.md',
|
|
492
497
|
'final-report.md',
|
|
493
498
|
'token-budget-reporter.md',
|
|
494
499
|
'memory.md'
|
|
@@ -507,7 +512,7 @@ async function verify({ quiet = false } = {}) {
|
|
|
507
512
|
issues.push(`project template missing section: ${section}`);
|
|
508
513
|
}
|
|
509
514
|
}
|
|
510
|
-
for (const template of ['ueye-review.md', 'ueye-comparison.md', 'mission-plan.md', 'runtime-proof.md', 'tuning-log.md']) {
|
|
515
|
+
for (const template of ['ueye-review.md', 'ueye-comparison.md', 'mission-plan.md', 'runtime-proof.md', 'tuning-log.md', 'security-check-note.md', 'security-gate.yml']) {
|
|
511
516
|
if (!await exists(path.join(ROOT, 'templates', template)))
|
|
512
517
|
issues.push(`missing template: ${template}`);
|
|
513
518
|
}
|
|
@@ -1941,6 +1946,8 @@ async function hook(args = []) {
|
|
|
1941
1946
|
return hookUsage();
|
|
1942
1947
|
if (subcommand === 'status')
|
|
1943
1948
|
return hookStatus(args.slice(1));
|
|
1949
|
+
if (subcommand === 'migrate')
|
|
1950
|
+
return hookMigrate(args.slice(1));
|
|
1944
1951
|
if (subcommand === 'enable')
|
|
1945
1952
|
return hookEnable(args.slice(1));
|
|
1946
1953
|
if (subcommand === 'disable')
|
|
@@ -1954,14 +1961,17 @@ function hookUsage() {
|
|
|
1954
1961
|
console.log(`yam hook
|
|
1955
1962
|
|
|
1956
1963
|
Usage:
|
|
1957
|
-
yam hook status [--global|--project dir]
|
|
1958
|
-
yam hook
|
|
1964
|
+
yam hook status [--global|--project dir] [--probe] [--json]
|
|
1965
|
+
yam hook migrate [--global|--project dir]
|
|
1966
|
+
yam hook enable <lite|study-note> [--global|--project dir] [--observe]
|
|
1959
1967
|
yam hook disable [lite|study-note] [--global|--project dir]
|
|
1960
1968
|
yam hook run <lite|study-note>
|
|
1961
1969
|
|
|
1962
1970
|
Notes:
|
|
1963
1971
|
hooks are opt-in. lite is advisory-only; study-note adds a prompt reminder and a one-pass Stop completion gate.
|
|
1964
1972
|
Hooks do not generate reports, run tmux, start subagents, or execute verification automatically.
|
|
1973
|
+
--probe queries hooks/list in a separate bounded Codex app-server; active session loading stays unknown.
|
|
1974
|
+
--observe opts into private local entrypoint observations without storing prompt content; not host attestation.
|
|
1965
1975
|
`);
|
|
1966
1976
|
}
|
|
1967
1977
|
function parseHookArgs(args = []) {
|
|
@@ -1988,7 +1998,7 @@ function parseHookArgs(args = []) {
|
|
|
1988
1998
|
}
|
|
1989
1999
|
function hookPathFor(parsed) {
|
|
1990
2000
|
if (parsed.mode === 'global')
|
|
1991
|
-
return path.join(os.homedir(), '.codex', 'hooks.json');
|
|
2001
|
+
return path.join(process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), 'hooks.json');
|
|
1992
2002
|
return path.join(path.resolve(parsed.projectDir || process.cwd()), '.codex', 'hooks.json');
|
|
1993
2003
|
}
|
|
1994
2004
|
function isYamLiteHook(handler = {}) {
|
|
@@ -2000,12 +2010,34 @@ function isYamStudyNoteHook(handler = {}) {
|
|
|
2000
2010
|
function isYamHookProfile(handler = {}, profile = 'lite') {
|
|
2001
2011
|
return profile === 'study-note' ? isYamStudyNoteHook(handler) : isYamLiteHook(handler);
|
|
2002
2012
|
}
|
|
2013
|
+
const CODEX_HOOK_EVENTS = new Set(['SessionStart', 'SessionEnd', 'PreToolUse', 'PermissionRequest', 'PostToolUse', 'PreCompact', 'PostCompact', 'UserPromptSubmit', 'SubagentStart', 'SubagentStop', 'Stop', 'Interrupt']);
|
|
2014
|
+
function hookEventMap(config = {}) {
|
|
2015
|
+
const nested = config.hooks && typeof config.hooks === 'object' && !Array.isArray(config.hooks) ? config.hooks : {};
|
|
2016
|
+
const events = { ...nested };
|
|
2017
|
+
for (const [event, entries] of Object.entries(config)) {
|
|
2018
|
+
if (CODEX_HOOK_EVENTS.has(event) && Array.isArray(entries)) {
|
|
2019
|
+
events[event] = [...(Array.isArray(events[event]) ? events[event] : []), ...entries];
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
return events;
|
|
2023
|
+
}
|
|
2024
|
+
function canonicalHookConfig(config = {}) {
|
|
2025
|
+
if (config.hooks != null && (typeof config.hooks !== 'object' || Array.isArray(config.hooks)))
|
|
2026
|
+
throw new Error('hooks must be an event object; existing file preserved');
|
|
2027
|
+
const next = { ...config, hooks: hookEventMap(config) };
|
|
2028
|
+
for (const event of CODEX_HOOK_EVENTS) {
|
|
2029
|
+
if (event in config && !Array.isArray(config[event]))
|
|
2030
|
+
throw new Error('legacy hook event must be an array; existing file preserved');
|
|
2031
|
+
delete next[event];
|
|
2032
|
+
}
|
|
2033
|
+
return next;
|
|
2034
|
+
}
|
|
2003
2035
|
function stripYamHooks(config = {}, profile = 'lite') {
|
|
2004
|
-
const next =
|
|
2005
|
-
for (const event of Object.keys(next)) {
|
|
2006
|
-
if (!Array.isArray(next[event]))
|
|
2036
|
+
const next = canonicalHookConfig(config);
|
|
2037
|
+
for (const event of Object.keys(next.hooks)) {
|
|
2038
|
+
if (!Array.isArray(next.hooks[event]))
|
|
2007
2039
|
continue;
|
|
2008
|
-
const entries = next[event];
|
|
2040
|
+
const entries = next.hooks[event];
|
|
2009
2041
|
const keptEntries = [];
|
|
2010
2042
|
for (const entry of entries) {
|
|
2011
2043
|
const hooks = Array.isArray(entry?.hooks) ? entry.hooks.filter((handler) => !isYamHookProfile(handler, profile)) : [];
|
|
@@ -2014,9 +2046,9 @@ function stripYamHooks(config = {}, profile = 'lite') {
|
|
|
2014
2046
|
keptEntries.push(rest);
|
|
2015
2047
|
}
|
|
2016
2048
|
if (keptEntries.length > 0)
|
|
2017
|
-
next[event] = keptEntries;
|
|
2049
|
+
next.hooks[event] = keptEntries;
|
|
2018
2050
|
else
|
|
2019
|
-
delete next[event];
|
|
2051
|
+
delete next.hooks[event];
|
|
2020
2052
|
}
|
|
2021
2053
|
return next;
|
|
2022
2054
|
}
|
|
@@ -2033,7 +2065,7 @@ function withYamHook(config = {}, profile = 'lite') {
|
|
|
2033
2065
|
}
|
|
2034
2066
|
]
|
|
2035
2067
|
};
|
|
2036
|
-
next[event] = [...(Array.isArray(next[event]) ? next[event] : []), entry];
|
|
2068
|
+
next.hooks[event] = [...(Array.isArray(next.hooks[event]) ? next.hooks[event] : []), entry];
|
|
2037
2069
|
}
|
|
2038
2070
|
return next;
|
|
2039
2071
|
}
|
|
@@ -2042,6 +2074,11 @@ async function hookStatus(args = []) {
|
|
|
2042
2074
|
const target = hookPathFor(parsed);
|
|
2043
2075
|
const loaded = await readHookConfig(target);
|
|
2044
2076
|
if (loaded.error) {
|
|
2077
|
+
if (args.includes('--json')) {
|
|
2078
|
+
console.log(JSON.stringify({ schema: 'yam.hook-readiness.v1', scope: parsed.mode, configuration: 'unreadable', loaded: 'unknown', execution_observed: false, truth_status: 'partial' }, null, 2));
|
|
2079
|
+
process.exitCode = 1;
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2045
2082
|
console.log('yam-lite hook: broken');
|
|
2046
2083
|
console.log('yam-study-note hook: broken');
|
|
2047
2084
|
console.log(` - hook config unreadable: ${loaded.error}`);
|
|
@@ -2052,10 +2089,30 @@ async function hookStatus(args = []) {
|
|
|
2052
2089
|
}
|
|
2053
2090
|
const lite = await inspectHookProfile(loaded.config, 'lite');
|
|
2054
2091
|
const studyNote = await inspectHookProfile(loaded.config, 'study-note');
|
|
2092
|
+
const cwd = path.resolve(parsed.projectDir || process.cwd());
|
|
2093
|
+
const commands = { lite: lite.entries.map((entry) => String(entry.handler.command)), 'study-note': studyNote.entries.map((entry) => String(entry.handler.command)) };
|
|
2094
|
+
const host = args.includes('--probe')
|
|
2095
|
+
? await probeHookDiscovery({ executable: await findExecutable('codex') || 'codex', cwd, commands, configPath: target })
|
|
2096
|
+
: { state: 'not_measured', active_session_loaded: 'not_measured', execution_observed: false, truth_status: 'partial' };
|
|
2097
|
+
const profiles = {};
|
|
2098
|
+
for (const [profile, health] of [['lite', lite], ['study-note', studyNote]]) {
|
|
2099
|
+
profiles[profile] = { configured: health.state, issues: health.issues, loaded: 'unknown',
|
|
2100
|
+
execution: await inspectHookObservation(cwd, profile, YAM_HOOK_ENTRYPOINT) };
|
|
2101
|
+
}
|
|
2102
|
+
if (args.includes('--json')) {
|
|
2103
|
+
console.log(JSON.stringify({ schema: 'yam.hook-readiness.v1', scope: parsed.mode, profiles, host, truth_status: 'partial' }, null, 2));
|
|
2104
|
+
if (lite.state === 'broken' || studyNote.state === 'broken')
|
|
2105
|
+
process.exitCode = 1;
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2055
2108
|
printHookProfileStatus('lite', lite);
|
|
2056
2109
|
printHookProfileStatus('study-note', studyNote);
|
|
2057
2110
|
console.log(`scope: ${parsed.mode}`);
|
|
2058
2111
|
console.log(`file: ${target}`);
|
|
2112
|
+
console.log('active Codex session loaded: unknown (configuration is not runtime evidence)');
|
|
2113
|
+
console.log(`host discovery: ${host.state}`);
|
|
2114
|
+
for (const profile of ['lite', 'study-note'])
|
|
2115
|
+
console.log(`yam-${profile} execution: ${profiles[profile].execution.state} (local entrypoint evidence, not host attestation)`);
|
|
2059
2116
|
if (lite.state === 'broken' || studyNote.state === 'broken')
|
|
2060
2117
|
process.exitCode = 1;
|
|
2061
2118
|
}
|
|
@@ -2063,7 +2120,7 @@ function hookConfigHasYamLite(config = {}) {
|
|
|
2063
2120
|
return hookConfigHasProfile(config, 'lite');
|
|
2064
2121
|
}
|
|
2065
2122
|
function hookConfigHasProfile(config = {}, profile = 'lite') {
|
|
2066
|
-
return Object.values(config).some((entries) => Array.isArray(entries) && entries.some((entry) => {
|
|
2123
|
+
return Object.values(hookEventMap(config)).some((entries) => Array.isArray(entries) && entries.some((entry) => {
|
|
2067
2124
|
return Array.isArray(entry?.hooks) && entry.hooks.some((handler) => isYamHookProfile(handler, profile));
|
|
2068
2125
|
}));
|
|
2069
2126
|
}
|
|
@@ -2075,7 +2132,7 @@ function hookEventsForProfile(profile = 'lite') {
|
|
|
2075
2132
|
}
|
|
2076
2133
|
function hookProfileEntries(config = {}, profile = 'lite') {
|
|
2077
2134
|
const matches = [];
|
|
2078
|
-
for (const [event, entries] of Object.entries(config)) {
|
|
2135
|
+
for (const [event, entries] of Object.entries(hookEventMap(config))) {
|
|
2079
2136
|
if (!Array.isArray(entries))
|
|
2080
2137
|
continue;
|
|
2081
2138
|
for (const entry of entries) {
|
|
@@ -2139,6 +2196,8 @@ function splitHookCommand(command = '') {
|
|
|
2139
2196
|
}
|
|
2140
2197
|
function parseYamHookCommand(command = '', profile = 'lite') {
|
|
2141
2198
|
const words = splitHookCommand(command);
|
|
2199
|
+
if (words.at(-1) === '--observe')
|
|
2200
|
+
words.pop();
|
|
2142
2201
|
if (words.length === 5 && words[2] === 'hook' && words[3] === 'run' && words[4] === profile) {
|
|
2143
2202
|
const nodeName = path.basename(words[0]).toLowerCase();
|
|
2144
2203
|
if (/^node(?:\.exe)?$/.test(nodeName) && path.basename(words[1]).toLowerCase() === 'yam.js') {
|
|
@@ -2182,6 +2241,8 @@ async function inspectHookProfile(config = {}, profile = 'lite') {
|
|
|
2182
2241
|
if (!entries.length)
|
|
2183
2242
|
return { state: 'disabled', issues: [], entries };
|
|
2184
2243
|
const issues = [];
|
|
2244
|
+
if (Object.keys(config).some((event) => CODEX_HOOK_EVENTS.has(event)))
|
|
2245
|
+
issues.push('legacy hook config requires the top-level hooks wrapper; rerun yam hook enable to migrate with backup');
|
|
2185
2246
|
for (const event of hookEventsForProfile(profile)) {
|
|
2186
2247
|
const count = entries.filter((entry) => entry.event === event).length;
|
|
2187
2248
|
if (count === 0)
|
|
@@ -2210,6 +2271,9 @@ async function readHookConfig(target) {
|
|
|
2210
2271
|
if (!value || Array.isArray(value) || typeof value !== 'object') {
|
|
2211
2272
|
return { config: {}, exists: true, error: 'top-level value must be a JSON object' };
|
|
2212
2273
|
}
|
|
2274
|
+
if (value.hooks != null && (typeof value.hooks !== 'object' || Array.isArray(value.hooks))) {
|
|
2275
|
+
return { config: {}, exists: true, error: 'hooks must be an event object' };
|
|
2276
|
+
}
|
|
2213
2277
|
return { config: value, exists: true, error: '' };
|
|
2214
2278
|
}
|
|
2215
2279
|
catch (error) {
|
|
@@ -2230,8 +2294,41 @@ async function writeHookConfig(target, config) {
|
|
|
2230
2294
|
throw error;
|
|
2231
2295
|
}
|
|
2232
2296
|
}
|
|
2297
|
+
async function hookMigrate(args = []) {
|
|
2298
|
+
const parsed = parseHookArgs(args);
|
|
2299
|
+
const target = hookPathFor(parsed);
|
|
2300
|
+
const loaded = await readHookConfig(target);
|
|
2301
|
+
if (loaded.error) {
|
|
2302
|
+
console.error('hook migration blocked: unreadable configuration');
|
|
2303
|
+
process.exitCode = 1;
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
if (!loaded.exists || !Object.keys(loaded.config).some((key) => CODEX_HOOK_EVENTS.has(key))) {
|
|
2307
|
+
console.log('hook migration: no legacy event layout found');
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
2310
|
+
const before = await fsp.lstat(target);
|
|
2311
|
+
if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1)
|
|
2312
|
+
throw new Error('hook migration blocked: unsafe config file');
|
|
2313
|
+
const original = await fsp.readFile(target, 'utf8');
|
|
2314
|
+
if (JSON.stringify(JSON.parse(original)) !== JSON.stringify(loaded.config))
|
|
2315
|
+
throw new Error('hook configuration changed; retry migration');
|
|
2316
|
+
const next = canonicalHookConfig(loaded.config);
|
|
2317
|
+
const backup = `${target}.yam-backup-${timestampId()}`;
|
|
2318
|
+
await fsp.copyFile(target, backup, fs.constants.COPYFILE_EXCL);
|
|
2319
|
+
const after = await fsp.lstat(target);
|
|
2320
|
+
if (after.dev !== before.dev || after.ino !== before.ino || after.mtimeMs !== before.mtimeMs
|
|
2321
|
+
|| await fsp.readFile(target, 'utf8') !== original)
|
|
2322
|
+
throw new Error('hook configuration changed; backup preserved, retry migration');
|
|
2323
|
+
await writeHookConfig(target, next);
|
|
2324
|
+
console.log(`hook migration: wrapped event groups; handlers and metadata preserved\nbackup: ${backup}\nReview changed definitions in Codex /hooks before enabling execution.`);
|
|
2325
|
+
}
|
|
2233
2326
|
async function hookEnable(args = []) {
|
|
2234
2327
|
const parsed = parseHookArgs(args);
|
|
2328
|
+
const node = await selectHookNode();
|
|
2329
|
+
const observe = args.includes('--observe') ? ' --observe' : '';
|
|
2330
|
+
YAM_LITE_HOOK_COMMAND = `${JSON.stringify(node.executable)} ${JSON.stringify(YAM_HOOK_ENTRYPOINT)} hook run lite${observe}`;
|
|
2331
|
+
YAM_STUDY_NOTE_HOOK_COMMAND = `${JSON.stringify(node.executable)} ${JSON.stringify(YAM_HOOK_ENTRYPOINT)} hook run study-note${observe}`;
|
|
2235
2332
|
if (!['lite', 'study-note'].includes(parsed.profile)) {
|
|
2236
2333
|
console.error('Only lite and study-note hooks are supported: yam hook enable <lite|study-note>');
|
|
2237
2334
|
process.exitCode = 1;
|
|
@@ -2260,6 +2357,7 @@ async function hookEnable(args = []) {
|
|
|
2260
2357
|
}
|
|
2261
2358
|
await writeHookConfig(target, next);
|
|
2262
2359
|
console.log(`yam-${parsed.profile} hook enabled (${parsed.mode}): ${target}`);
|
|
2360
|
+
console.log(`node launcher: ${node.selection}; alias identity matched the current runtime (no PATH candidate executed)`);
|
|
2263
2361
|
if (needsMigration)
|
|
2264
2362
|
console.log(`migrated: ${existing.length} existing yam-${parsed.profile} handler(s) to the current command and event coverage`);
|
|
2265
2363
|
console.log('Restart Codex or start a new thread if the app does not pick up hook changes immediately.');
|
|
@@ -2280,7 +2378,7 @@ async function hookDisable(args = []) {
|
|
|
2280
2378
|
return;
|
|
2281
2379
|
}
|
|
2282
2380
|
const next = stripYamHooks(current, parsed.profile);
|
|
2283
|
-
if (Object.keys(next).length === 0) {
|
|
2381
|
+
if (Object.keys(next).length === 1 && Object.keys(next.hooks).length === 0) {
|
|
2284
2382
|
await rmrf(target);
|
|
2285
2383
|
}
|
|
2286
2384
|
else {
|
|
@@ -2310,6 +2408,8 @@ async function hookRun(args = []) {
|
|
|
2310
2408
|
}
|
|
2311
2409
|
const event = input?.hook_event_name || input?.hookEventName || input?.event || 'UserPromptSubmit';
|
|
2312
2410
|
const cwd = String(input?.cwd || process.cwd());
|
|
2411
|
+
if (args.includes('--observe'))
|
|
2412
|
+
await recordHookObservation(cwd, profile, String(event), YAM_HOOK_ENTRYPOINT).catch(() => { });
|
|
2313
2413
|
if (profile === 'study-note' && event === 'Stop') {
|
|
2314
2414
|
console.log(JSON.stringify(await buildStudyNoteStopOutput(input, cwd)));
|
|
2315
2415
|
return;
|
|
@@ -6038,11 +6138,13 @@ async function printTemplate(name = '') {
|
|
|
6038
6138
|
mission: 'mission-plan.md',
|
|
6039
6139
|
proof: 'runtime-proof.md',
|
|
6040
6140
|
runtime: 'runtime-proof.md',
|
|
6041
|
-
tuning: 'tuning-log.md'
|
|
6141
|
+
tuning: 'tuning-log.md',
|
|
6142
|
+
security: 'security-check-note.md',
|
|
6143
|
+
'security-ci': 'security-gate.yml'
|
|
6042
6144
|
};
|
|
6043
6145
|
const file = map[key];
|
|
6044
6146
|
if (!file) {
|
|
6045
|
-
console.error('usage: yam template <project|ueye|ueye-comparison|mission|proof|tuning>');
|
|
6147
|
+
console.error('usage: yam template <project|ueye|ueye-comparison|mission|proof|tuning|security|security-ci>');
|
|
6046
6148
|
process.exitCode = 1;
|
|
6047
6149
|
return;
|
|
6048
6150
|
}
|
|
@@ -6074,7 +6176,7 @@ async function memory(args = []) {
|
|
|
6074
6176
|
}
|
|
6075
6177
|
if (subcommand === 'summary' || subcommand === 'summarize') {
|
|
6076
6178
|
const parsed = parseMemoryArgs(args.slice(1));
|
|
6077
|
-
return memorySummary(parsed.dir);
|
|
6179
|
+
return memorySummary(parsed.dir, { json: args.includes('--json') });
|
|
6078
6180
|
}
|
|
6079
6181
|
if (subcommand === 'resolve')
|
|
6080
6182
|
return memoryResolve(args.slice(1));
|
|
@@ -6088,7 +6190,7 @@ Usage:
|
|
|
6088
6190
|
yam memory init [dir]
|
|
6089
6191
|
yam memory add [dir] --kind <kind> --summary <text> [--evidence <text>] [--action <text>] [--source <text>]
|
|
6090
6192
|
yam memory list [dir] [--json]
|
|
6091
|
-
yam memory summary [dir]
|
|
6193
|
+
yam memory summary [dir] [--json]
|
|
6092
6194
|
yam memory resolve [dir] <id> [--note <text>]
|
|
6093
6195
|
|
|
6094
6196
|
Kinds:
|
|
@@ -6158,7 +6260,17 @@ async function memoryAdd(args = []) {
|
|
|
6158
6260
|
console.log(`memory added: ${id}`);
|
|
6159
6261
|
}
|
|
6160
6262
|
async function memoryList(targetDir = process.cwd(), { json = false } = {}) {
|
|
6161
|
-
const
|
|
6263
|
+
const report = await readMemoryRecords(targetDir);
|
|
6264
|
+
const records = report.records;
|
|
6265
|
+
if (!report.complete) {
|
|
6266
|
+
if (report.state !== 'missing')
|
|
6267
|
+
process.exitCode = 1;
|
|
6268
|
+
if (json)
|
|
6269
|
+
console.log(JSON.stringify(report, null, 2));
|
|
6270
|
+
else
|
|
6271
|
+
console.error(`memory read ${report.state}: ${JSON.stringify(report.diagnostics)}${report.diagnostics_truncated ? ' (diagnostics truncated)' : ''}`);
|
|
6272
|
+
return;
|
|
6273
|
+
}
|
|
6162
6274
|
if (json) {
|
|
6163
6275
|
console.log(JSON.stringify(records, null, 2));
|
|
6164
6276
|
return;
|
|
@@ -6173,9 +6285,18 @@ async function memoryList(targetDir = process.cwd(), { json = false } = {}) {
|
|
|
6173
6285
|
console.log(` action: ${record.action}`);
|
|
6174
6286
|
}
|
|
6175
6287
|
}
|
|
6176
|
-
async function memorySummary(targetDir = process.cwd()) {
|
|
6288
|
+
async function memorySummary(targetDir = process.cwd(), { json = false } = {}) {
|
|
6177
6289
|
const dir = memoryDir(targetDir);
|
|
6178
|
-
const
|
|
6290
|
+
const report = await readMemoryRecords(targetDir);
|
|
6291
|
+
if (!report.complete) {
|
|
6292
|
+
process.exitCode = 1;
|
|
6293
|
+
if (json)
|
|
6294
|
+
console.log(JSON.stringify({ ...report, summary_written: false }, null, 2));
|
|
6295
|
+
else
|
|
6296
|
+
console.error(`memory summary blocked (${report.state}); existing summary preserved: ${JSON.stringify(report.diagnostics)}${report.diagnostics_truncated ? ' (diagnostics truncated)' : ''}`);
|
|
6297
|
+
return;
|
|
6298
|
+
}
|
|
6299
|
+
const records = report.records;
|
|
6179
6300
|
await fsp.mkdir(dir, { recursive: true });
|
|
6180
6301
|
const active = records.filter((record) => record.status !== 'resolved');
|
|
6181
6302
|
const resolved = records.filter((record) => record.status === 'resolved');
|
|
@@ -6207,7 +6328,10 @@ async function memorySummary(targetDir = process.cwd()) {
|
|
|
6207
6328
|
}
|
|
6208
6329
|
const target = path.join(dir, 'summary.md');
|
|
6209
6330
|
await fsp.writeFile(target, `${lines.join('\n').trim()}\n`);
|
|
6210
|
-
|
|
6331
|
+
if (json)
|
|
6332
|
+
console.log(JSON.stringify({ ...report, summary_written: true, path: target }, null, 2));
|
|
6333
|
+
else
|
|
6334
|
+
console.log(`memory summary written: ${target}`);
|
|
6211
6335
|
}
|
|
6212
6336
|
async function memoryResolve(args = []) {
|
|
6213
6337
|
const parsed = parseMemoryArgs(args);
|
|
@@ -6262,23 +6386,7 @@ function memoryDir(targetDir = process.cwd()) {
|
|
|
6262
6386
|
}
|
|
6263
6387
|
async function readMemoryRecords(targetDir = process.cwd()) {
|
|
6264
6388
|
const recordsDir = path.join(memoryDir(targetDir), 'records');
|
|
6265
|
-
|
|
6266
|
-
return [];
|
|
6267
|
-
const entries = await fsp.readdir(recordsDir, { withFileTypes: true });
|
|
6268
|
-
const records = [];
|
|
6269
|
-
for (const entry of entries) {
|
|
6270
|
-
if (!entry.isFile() || !entry.name.endsWith('.json'))
|
|
6271
|
-
continue;
|
|
6272
|
-
const file = path.join(recordsDir, entry.name);
|
|
6273
|
-
try {
|
|
6274
|
-
const record = await readJson(file);
|
|
6275
|
-
records.push(record);
|
|
6276
|
-
}
|
|
6277
|
-
catch (error) {
|
|
6278
|
-
records.push({ id: entry.name.replace(/\.json$/, ''), kind: 'invalid', status: 'invalid', summary: `invalid JSON: ${errorMessage(error)}` });
|
|
6279
|
-
}
|
|
6280
|
-
}
|
|
6281
|
-
return records.sort((a, b) => String(a.createdAt || '').localeCompare(String(b.createdAt || '')));
|
|
6389
|
+
return readMemoryDirectory(recordsDir);
|
|
6282
6390
|
}
|
|
6283
6391
|
function timestampId() {
|
|
6284
6392
|
const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.(\d{3})Z$/, '$1z');
|
|
@@ -6309,6 +6417,7 @@ function showRequestedHelp(args) {
|
|
|
6309
6417
|
return true;
|
|
6310
6418
|
}
|
|
6311
6419
|
const commandUsage = {
|
|
6420
|
+
security: () => console.log('yam security <init|check|hooks enable|status> [--stage commit|push|ci|deploy] [--policy file --policy-digest sha256 --evidence file --note file]\nSee references/security-check.md for exact bindings and CI/deploy trust configuration.'),
|
|
6312
6421
|
context: contextUsage,
|
|
6313
6422
|
cleanup: cleanupUsage,
|
|
6314
6423
|
'study-note': studyNoteUsage,
|
|
@@ -6336,6 +6445,17 @@ async function main() {
|
|
|
6336
6445
|
return;
|
|
6337
6446
|
if (command === 'help')
|
|
6338
6447
|
return usage();
|
|
6448
|
+
if (command === 'security') {
|
|
6449
|
+
if (args.length === 1 || ['help', '--help', '-h'].includes(args[1])) {
|
|
6450
|
+
console.log('yam security <init|check|hooks enable|status> [--stage commit|push|ci|deploy] [--policy file --policy-digest sha256 --evidence file --note file]\nSee references/security-check.md for exact bindings and CI/deploy trust configuration.');
|
|
6451
|
+
return;
|
|
6452
|
+
}
|
|
6453
|
+
const result = await runSecurityCommand(args.slice(1), { cwd: process.cwd(), cliPath: fileURLToPath(import.meta.url) });
|
|
6454
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6455
|
+
if (!result.ok)
|
|
6456
|
+
process.exitCode = 1;
|
|
6457
|
+
return;
|
|
6458
|
+
}
|
|
6339
6459
|
if (command === 'install')
|
|
6340
6460
|
return install(args.slice(1));
|
|
6341
6461
|
if (command === 'uninstall')
|
|
@@ -129,7 +129,7 @@ export declare function createPlanReviewCanvas(input: {
|
|
|
129
129
|
visual_correctness: string;
|
|
130
130
|
implementation_correctness: string;
|
|
131
131
|
};
|
|
132
|
-
truth_status: "
|
|
132
|
+
truth_status: "partial" | "verified";
|
|
133
133
|
}>;
|
|
134
134
|
export declare function addPlanReviewComment(input: {
|
|
135
135
|
root: string;
|
|
@@ -147,7 +147,7 @@ export declare function addPlanReviewComment(input: {
|
|
|
147
147
|
visual_correctness: string;
|
|
148
148
|
implementation_correctness: string;
|
|
149
149
|
};
|
|
150
|
-
truth_status: "
|
|
150
|
+
truth_status: "partial" | "verified";
|
|
151
151
|
}>;
|
|
152
152
|
export declare function closePlanReviewCanvas(input: {
|
|
153
153
|
root: string;
|
|
@@ -165,7 +165,7 @@ export declare function closePlanReviewCanvas(input: {
|
|
|
165
165
|
visual_correctness: string;
|
|
166
166
|
implementation_correctness: string;
|
|
167
167
|
};
|
|
168
|
-
truth_status: "
|
|
168
|
+
truth_status: "partial" | "verified";
|
|
169
169
|
}>;
|
|
170
170
|
export declare function readPlanReviewSession(file: string): Promise<PlanReviewSession>;
|
|
171
171
|
export declare function createDesignRevisionState(input: {
|
|
@@ -228,7 +228,7 @@ export declare function verifyFinalGalleryManifest(input: {
|
|
|
228
228
|
implementation_correctness: string;
|
|
229
229
|
};
|
|
230
230
|
next_action: string;
|
|
231
|
-
truth_status: "
|
|
231
|
+
truth_status: "partial" | "blocked";
|
|
232
232
|
}>;
|
|
233
233
|
export declare function finalizeDesignProductionPhase(input: {
|
|
234
234
|
root: string;
|
|
@@ -283,7 +283,7 @@ export declare function finalizeDesignProductionPhase(input: {
|
|
|
283
283
|
server: false;
|
|
284
284
|
background_service: false;
|
|
285
285
|
};
|
|
286
|
-
phase_evidence_status: "complete" | "
|
|
286
|
+
phase_evidence_status: "complete" | "incomplete" | "bounded_stop";
|
|
287
287
|
ready: boolean;
|
|
288
288
|
ready_to_claim_correctness: boolean;
|
|
289
289
|
next_action: string;
|
|
@@ -301,6 +301,6 @@ export declare function verifyDesignProductionPhaseReceipt(input: {
|
|
|
301
301
|
receipt_digest: string;
|
|
302
302
|
ready_to_claim_correctness: boolean;
|
|
303
303
|
next_action: string;
|
|
304
|
-
truth_status: "
|
|
304
|
+
truth_status: "partial" | "blocked";
|
|
305
305
|
}>;
|
|
306
306
|
export {};
|
|
@@ -22,6 +22,7 @@ export interface ExternalUpdatePaths {
|
|
|
22
22
|
export interface ExternalUpdateDependencies {
|
|
23
23
|
run?: (command: string, args: string[], options?: ExternalCommandOptions) => Promise<ExternalCommandResult> | ExternalCommandResult;
|
|
24
24
|
fetchJson?: (url: string) => Promise<any>;
|
|
25
|
+
probeArtifact?: (url: string) => Promise<number>;
|
|
25
26
|
now?: () => Date;
|
|
26
27
|
homeDir?: string;
|
|
27
28
|
env?: NodeJS.ProcessEnv;
|
|
@@ -33,7 +34,7 @@ export interface ExternalComponentCheck {
|
|
|
33
34
|
installed_version: string;
|
|
34
35
|
latest_version: string;
|
|
35
36
|
update_available: boolean;
|
|
36
|
-
status: 'up_to_date' | 'update_available' | 'not_installed' | 'check_failed';
|
|
37
|
+
status: 'up_to_date' | 'update_available' | 'not_installed' | 'pending_distribution' | 'check_failed';
|
|
37
38
|
source: string;
|
|
38
39
|
source_revision?: {
|
|
39
40
|
local: string;
|
|
@@ -132,4 +133,8 @@ export declare function applyExternalUpdates(currentYamVersion: string, selectio
|
|
|
132
133
|
truth_status: string;
|
|
133
134
|
next_action: string;
|
|
134
135
|
}>;
|
|
136
|
+
export declare class RegistryHttpError extends Error {
|
|
137
|
+
readonly status: number;
|
|
138
|
+
constructor(status: number, url: string);
|
|
139
|
+
}
|
|
135
140
|
export {};
|