leerness 1.9.207 β 1.9.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/README.md +3 -3
- package/bin/harness.js +498 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,94 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.209 β 2026-05-22
|
|
4
|
+
|
|
5
|
+
**π pre-wake sub-agent audit + κΉ¨μ΄λ¨ μ§ν μλ λ
ΈμΆ (μ¬μ©μ λͺ
μ).**
|
|
6
|
+
|
|
7
|
+
### μ¬μ©μ λͺ
μ
|
|
8
|
+
> *"λ©μΈ μμ΄μ νΈκ° μ¬λ¦½μ μ μλΈμμ΄μ νΈλ₯Ό νΈμΆν΄μ λ―ΈλΉλ λΆλΆμ΄ μλμ§, μΆ©λλλ λΆλΆμ΄ μλμ§, μ΄μ μ λλ½λ μμ
μ΄ μλμ§ λ±λ± μ¬λ¬λΆλΆμ νμνλ©΄μ νμν λ΄μ©μ μ 리νκ³ λ©μΈ μμ΄μ νΈκ° κΉ¨μ΄λ¬μλ, μλΈμμ΄μ νΈκ° μ 리ν λ΄μ©μ νμΈν΄λ³΄κ±°λ νλ κΈ°λ₯"*
|
|
9
|
+
|
|
10
|
+
### 1. `.harness/pre-wake-report.json` β sleep μ audit λμ
|
|
11
|
+
- `_preWakeReportPath/_loadPreWakeReport/_writePreWakeReport` νμΌ I/O ν¬νΌ
|
|
12
|
+
- μ΅κ·Ό 10κ°λ§ μ μ§ (rotate)
|
|
13
|
+
- ꡬ쑰: `{ auditedAt, auditVersion, findings: {critical/warning/info}, summary }`
|
|
14
|
+
|
|
15
|
+
### 2. `_runPreWakeAudit(root)` β sub-agent audit 6μμ
|
|
16
|
+
- **missing-user-requests** (1.9.207 ν΅ν©) β task-log/plan/decisions λ§€μΉ μ λ μμ²
|
|
17
|
+
- **stale-user-requests** β 7μΌ+ open μμ²
|
|
18
|
+
- **stale-in-progress** β 24h+ μ§μ² μλ task
|
|
19
|
+
- **drift-handoff-stale** β session-handoff.md 5μΌ+ stale
|
|
20
|
+
- **wakeup-missed** β wakeup miss κ°μ§ (1.9.205)
|
|
21
|
+
- **next-action-pending** β next-action queue λκΈ°
|
|
22
|
+
- **auto-resume-plan-ready/stale** β 1.9.203 plan μν
|
|
23
|
+
|
|
24
|
+
### 3. `leerness pre-wake-audit` CLI
|
|
25
|
+
- κΈ°λ³Έ: μ audit μ€ν + μ μ₯
|
|
26
|
+
- `--last` / `show` / `review` β κ°μ₯ μ΅κ·Ό μ μ₯λ audit νμ
|
|
27
|
+
- `--json` β JSON μΆλ ₯
|
|
28
|
+
|
|
29
|
+
### 4. handoff μλ λ
ΈμΆ (μ¬μ©μ λͺ
μ "κΉ¨μ΄λ¬μλ νμΈ")
|
|
30
|
+
- ν€λλΌμΈ 14λ²μ§Έ μμ: `π pre-wake NC/MW (ageMin)` β critical N건 + warning M건
|
|
31
|
+
- λ³Έλ¬Έ μλ μΉμ
: `## π μ§μ sleep pre-wake-audit (1.9.209, NλΆ μ )`
|
|
32
|
+
Β· critical/warning μ΅λ 3κ°μ© λ
ΈμΆ
|
|
33
|
+
Β· 4μκ° μ΄λ΄ λ³΄κ³ μλ§ (stale μλ hide)
|
|
34
|
+
- ν€λλΌμΈ λΌλ²¨: `1.9.81/93/113/152/162/192/197/204/207/209`
|
|
35
|
+
|
|
36
|
+
### 5. λμ νκ· (1.9.200~208) β λͺ¨λ μ μ§
|
|
37
|
+
|
|
38
|
+
### 6. stress-v154 β 18/18 PASS
|
|
39
|
+
- 1.9.209 (9) + μ±λ₯ (2) + λμ νκ· (7)
|
|
40
|
+
- 격리 tmp dir λΌμ΄νμ¬μ΄ν΄ κ²μ¦ (μ€ν β μ μ₯ β --last β rotate to 10)
|
|
41
|
+
- 6 findings kind ν€μλ κ²μ¦
|
|
42
|
+
- μ±λ₯: --version cold start avg 517ms Β· MCP 54 λꡬ 574ms
|
|
43
|
+
|
|
44
|
+
### 7. μλ release (71 λΌμ΄λ main-push streak Β· 32 λΌμ΄λ npm publish streak)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 1.9.208 β 2026-05-22
|
|
49
|
+
|
|
50
|
+
**π¦ νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ).**
|
|
51
|
+
|
|
52
|
+
### μ¬μ©μ λͺ
μ
|
|
53
|
+
> *"μ¬μ©μμ λͺ
λ Ήμ λ°μΌλ©΄, κ³ λ €ν΄μΌνλ λΆλΆμ λ¨Όμ νμΈνκ³ μ§ννκ² νλ©΄ μ΄λ¨μ§ / νΉμ νλ«νΌμ API ... νΈμΆμλκ° μ΄λΉ 5ν μ΄νλ‘λ§ ν΄μΌνλ€λ κ·μ μ λ¨Όμ νμΈ"*
|
|
54
|
+
|
|
55
|
+
### 1. `.harness/platform-constraints.json` + κΈ°λ³Έ catalog 6μ’
|
|
56
|
+
- **stripe** (rate: 100 req/s, idempotency key, webhook signing)
|
|
57
|
+
- **openai** (tier-based RPM, TPM, cost per 1M tokens)
|
|
58
|
+
- **anthropic** (claude tier, context-window, cost)
|
|
59
|
+
- **github** (5K req/hr auth, search 30 req/min, secondary)
|
|
60
|
+
- **discord** (50 req/s global, invalid ban)
|
|
61
|
+
- **twitter** (tier-based, OAuth 2.0 PKCE)
|
|
62
|
+
- κ° alias array λ§€μΉ + docs URL λλ΄
|
|
63
|
+
|
|
64
|
+
### 2. ν¬νΌ ν¨μ
|
|
65
|
+
- `_loadPlatformConstraints(root)` β default merge user override
|
|
66
|
+
- `_writePlatformConstraints(root, catalog)` β μ¬μ©μ catalog μ μ₯
|
|
67
|
+
- `_checkRequestConstraints(root, text)` β ν
μ€νΈ β λ§€μΉ νλ«νΌ + μ μ½ + suggestions
|
|
68
|
+
|
|
69
|
+
### 3. `leerness constraints <list|check|add>` CLI
|
|
70
|
+
- `list` β λ±λ‘ catalog μΆλ ₯ (--json)
|
|
71
|
+
- `check "<req>"` β μ¬μ©μ μμ² λ§€μΉ β μ μ½ λ³΄κ³ (--json)
|
|
72
|
+
- `add <id> --alias name --constraint "kind:detail"` β μ¬μ©μ μ μ
|
|
73
|
+
|
|
74
|
+
### 4. review-request μλ ν΅ν©
|
|
75
|
+
- `_checkRequestConstraints()` review-request λ΄λΆμμ μλ νΈμΆ
|
|
76
|
+
- JSON μΆλ ₯μ `platformConstraints` + `constraintSuggestions` νλ μΆκ°
|
|
77
|
+
- human μΆλ ₯μ `## π¦ νλ«νΌ/API μ μ½ μ¬μ 체ν¬` μΉμ
|
|
78
|
+
- efficiencyHints μ λ§€μΉ N건 μλ¦Ό
|
|
79
|
+
|
|
80
|
+
### 5. λμ νκ· (1.9.200~207) β λͺ¨λ μ μ§
|
|
81
|
+
|
|
82
|
+
### 6. stress-v153 β 18/18 PASS
|
|
83
|
+
- 1.9.208 (9) + μ±λ₯ (2) + λμ νκ· (7)
|
|
84
|
+
- κΈ°λ³Έ 6 catalog + μ¬μ©μ μ μ add + review-request ν΅ν© κ²μ¦
|
|
85
|
+
- μ±λ₯: --version cold start avg 483ms Β· MCP 54 λꡬ 431ms
|
|
86
|
+
|
|
87
|
+
### 7. μλ release (70 λΌμ΄λ main-push streak Β· 31 λΌμ΄λ npm publish streak)
|
|
88
|
+
- `release sync-main` μλ β main merge + npm publish leerness@1.9.208
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
3
92
|
## 1.9.207 β 2026-05-22
|
|
4
93
|
|
|
5
94
|
**π₯ μ¬μ©μ μμ² λλ½ νμΈ μ μ°¨ MVP (μ¬μ©μ λͺ
μ).**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI μ½λ© μμ΄μ νΈμ κ±°μ§ μλ£Β·μ€λ³΅Β·λ§κ°Β·μΆ©λμ λ§μμ£Όλ κ²μΒ·κΈ°μ΅Β·νμ
CLI νλ€μ€.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() [-brightgreen)]() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
β βββ ββββββ ββββββ ββββββββββββββββββββββββ ββββββββ β
|
|
13
13
|
β βββββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββ β
|
|
14
14
|
β βββββββββββββββββββββββββββ ββββββ βββββββββββββββββββββ β
|
|
15
|
-
β v1.9.
|
|
15
|
+
β v1.9.209 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β π pre-wake sub-agent audit (sleep μ μ κ²) (μ¬μ©μ λͺ
μ) β
|
|
18
18
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
19
19
|
```
|
|
20
20
|
|
package/bin/harness.js
CHANGED
|
@@ -7,7 +7,7 @@ const cp = require('child_process');
|
|
|
7
7
|
const os = require('os'); // 1.9.178: _publishToNpm μμ os.tmpdir() μ¬μ© (μ μ import)
|
|
8
8
|
const readline = require('readline');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.9.
|
|
10
|
+
const VERSION = '1.9.209';
|
|
11
11
|
|
|
12
12
|
// 1.9.184: DEP0190 (child_process shell: true) deprecation warning μ΅μ (μ¬μ©μ λͺ
μ).
|
|
13
13
|
// leerness λ cross-platform PATH resolution μ μν΄ shell: true λ₯Ό μλμ μΌλ‘ μ¬μ© (claude.cmd / ollama.cmd λ± Windows .cmd μ²λ¦¬).
|
|
@@ -2006,6 +2006,251 @@ function _auditUserRequests(root) {
|
|
|
2006
2006
|
};
|
|
2007
2007
|
}
|
|
2008
2008
|
|
|
2009
|
+
// 1.9.208: νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ)
|
|
2010
|
+
// "μ¬μ©μμ λͺ
λ Ήμ λ°μΌλ©΄, κ³ λ €ν΄μΌνλ λΆλΆμ λ¨Όμ νμΈνκ³ μ§ννκ² νλ©΄ μ΄λ¨μ§"
|
|
2011
|
+
// "νΉμ νλ«νΌμ API ... νΈμΆμλκ° μ΄λΉ 5ν μ΄νλ‘λ§ ν΄μΌνλ€λ κ·μ μ λ¨Όμ νμΈ"
|
|
2012
|
+
// .harness/platform-constraints.json μ νλ«νΌλ³ μ μ½ catalog μ μ₯ β μμ² ν
μ€νΈ ν€μλ λ§€μΉ β μ μ© κ°λ₯ν μ μ½ λ³΄κ³
|
|
2013
|
+
// κΈ°λ³Έ catalog 6μ’
: Stripe / OpenAI / Anthropic / GitHub / Discord / Twitter
|
|
2014
|
+
function _platformConstraintsPath(root) { return path.join(root, '.harness', 'platform-constraints.json'); }
|
|
2015
|
+
const _DEFAULT_PLATFORM_CONSTRAINTS = {
|
|
2016
|
+
version: '1.9.208',
|
|
2017
|
+
platforms: {
|
|
2018
|
+
stripe: {
|
|
2019
|
+
aliases: ['stripe', 'stripe api', 'payment', 'κ²°μ '],
|
|
2020
|
+
docs: 'https://stripe.com/docs/rate-limits',
|
|
2021
|
+
constraints: [
|
|
2022
|
+
{ kind: 'rate-limit', detail: 'read: 100 req/s, write: 100 req/s (live mode), test mode: 25 req/s' },
|
|
2023
|
+
{ kind: 'idempotency', detail: 'Idempotency-Key ν€λ 24h μ μ§ β μ€λ³΅ κ²°μ λ°©μ§ νμ' },
|
|
2024
|
+
{ kind: 'webhook', detail: 'webhook μλͺ
κ²μ¦ νμ (Stripe-Signature header + endpoint secret)' }
|
|
2025
|
+
]
|
|
2026
|
+
},
|
|
2027
|
+
openai: {
|
|
2028
|
+
aliases: ['openai', 'gpt', 'chatgpt', 'gpt-4', 'gpt-3'],
|
|
2029
|
+
docs: 'https://platform.openai.com/docs/guides/rate-limits',
|
|
2030
|
+
constraints: [
|
|
2031
|
+
{ kind: 'rate-limit', detail: 'tier-based: Free 3 RPM / Tier 1 500 RPM / Tier 5 10,000 RPM' },
|
|
2032
|
+
{ kind: 'token-limit', detail: 'TPM (tokens/min) λ³λ β ν° μ
λ ₯ μ RPM λλ¬ μ μ°¨λ¨ κ°λ₯' },
|
|
2033
|
+
{ kind: 'cost', detail: 'gpt-4: $30/$60 per 1M input/output tokens β λλ νΈμΆ μ λΉμ© μΆμ νμ' }
|
|
2034
|
+
]
|
|
2035
|
+
},
|
|
2036
|
+
anthropic: {
|
|
2037
|
+
aliases: ['anthropic', 'claude', 'claude api', 'sonnet', 'opus', 'haiku'],
|
|
2038
|
+
docs: 'https://docs.anthropic.com/claude/reference/rate-limits',
|
|
2039
|
+
constraints: [
|
|
2040
|
+
{ kind: 'rate-limit', detail: 'tier-based: Free 5 RPM / Tier 1 50 RPM / Tier 4 4,000 RPM' },
|
|
2041
|
+
{ kind: 'context-window', detail: 'claude-sonnet 200K context, claude-opus 200K, 1M tier λ³λ' },
|
|
2042
|
+
{ kind: 'cost', detail: 'sonnet: $3/$15 per 1M tokens (1M context tier 2x)' }
|
|
2043
|
+
]
|
|
2044
|
+
},
|
|
2045
|
+
github: {
|
|
2046
|
+
aliases: ['github', 'github api', 'gh api', 'octokit'],
|
|
2047
|
+
docs: 'https://docs.github.com/en/rest/rate-limit',
|
|
2048
|
+
constraints: [
|
|
2049
|
+
{ kind: 'rate-limit', detail: 'authenticated: 5,000 req/hr, unauthenticated: 60 req/hr' },
|
|
2050
|
+
{ kind: 'rate-limit', detail: 'search API: 30 req/min (authenticated)' },
|
|
2051
|
+
{ kind: 'secondary', detail: 'secondary rate limit β concurrent + content creation λ³λ κ°λ' }
|
|
2052
|
+
]
|
|
2053
|
+
},
|
|
2054
|
+
discord: {
|
|
2055
|
+
aliases: ['discord', 'discord api', 'discord bot'],
|
|
2056
|
+
docs: 'https://discord.com/developers/docs/topics/rate-limits',
|
|
2057
|
+
constraints: [
|
|
2058
|
+
{ kind: 'rate-limit', detail: 'global: 50 req/s, per-route λ³λ' },
|
|
2059
|
+
{ kind: 'invalid', detail: '10,000 invalid req/10min β 1h ban μν' }
|
|
2060
|
+
]
|
|
2061
|
+
},
|
|
2062
|
+
twitter: {
|
|
2063
|
+
aliases: ['twitter', 'twitter api', 'x api', 'x.com api'],
|
|
2064
|
+
docs: 'https://developer.twitter.com/en/docs/twitter-api/rate-limits',
|
|
2065
|
+
constraints: [
|
|
2066
|
+
{ kind: 'rate-limit', detail: 'tier-based: Free 1,500 posts/month, Basic 50,000 posts/month' },
|
|
2067
|
+
{ kind: 'auth', detail: 'OAuth 2.0 PKCE νμ (user context), App-onlyλ λ³λ endpoint' }
|
|
2068
|
+
]
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
function _loadPlatformConstraints(root) {
|
|
2073
|
+
try {
|
|
2074
|
+
const fp = _platformConstraintsPath(root);
|
|
2075
|
+
if (!exists(fp)) return _DEFAULT_PLATFORM_CONSTRAINTS;
|
|
2076
|
+
const j = JSON.parse(read(fp));
|
|
2077
|
+
// user catalog μ default merge β user override μ°μ
|
|
2078
|
+
const merged = { ...JSON.parse(JSON.stringify(_DEFAULT_PLATFORM_CONSTRAINTS)) };
|
|
2079
|
+
if (j.platforms) {
|
|
2080
|
+
for (const k of Object.keys(j.platforms)) {
|
|
2081
|
+
merged.platforms[k] = j.platforms[k];
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return merged;
|
|
2085
|
+
} catch { return _DEFAULT_PLATFORM_CONSTRAINTS; }
|
|
2086
|
+
}
|
|
2087
|
+
function _writePlatformConstraints(root, catalog) {
|
|
2088
|
+
try {
|
|
2089
|
+
mkdirp(path.join(root, '.harness'));
|
|
2090
|
+
writeUtf8(_platformConstraintsPath(root), JSON.stringify({ ...catalog, updatedAt: new Date().toISOString() }, null, 2));
|
|
2091
|
+
return true;
|
|
2092
|
+
} catch { return false; }
|
|
2093
|
+
}
|
|
2094
|
+
// μ¬μ©μ μμ² ν
μ€νΈμμ νλ«νΌ alias λ§€μΉ β μ μ© μ μ½ λͺ©λ‘ λ°ν
|
|
2095
|
+
function _checkRequestConstraints(root, text) {
|
|
2096
|
+
if (!text || typeof text !== 'string') return { matched: [], suggestions: [] };
|
|
2097
|
+
const catalog = _loadPlatformConstraints(root);
|
|
2098
|
+
const lower = text.toLowerCase();
|
|
2099
|
+
const matched = [];
|
|
2100
|
+
for (const [pid, plat] of Object.entries(catalog.platforms)) {
|
|
2101
|
+
const aliases = plat.aliases || [];
|
|
2102
|
+
const hit = aliases.find(a => lower.includes(a.toLowerCase()));
|
|
2103
|
+
if (hit) matched.push({ platform: pid, matchedAlias: hit, docs: plat.docs, constraints: plat.constraints });
|
|
2104
|
+
}
|
|
2105
|
+
// suggestions β λ³΄νΈ ν€μλ (api/rate/limit/integration) μ catalog κ²ν κΆμ₯
|
|
2106
|
+
const suggestions = [];
|
|
2107
|
+
const generic = /\bapi\b|μ°λ|integration|νΈμΆ|rate|limit|quota|webhook/i.test(text);
|
|
2108
|
+
if (generic && matched.length === 0) {
|
|
2109
|
+
suggestions.push('μΌλ°μ API μ°λ ν€μλ κ°μ§ β leerness constraints list λ‘ μ¬μ λ±λ‘λ νλ«νΌ catalog νμΈ κΆμ₯');
|
|
2110
|
+
}
|
|
2111
|
+
return { matched, suggestions, totalPlatforms: Object.keys(catalog.platforms).length };
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
// 1.9.209: pre-wake sub-agent audit (μ¬μ©μ λͺ
μ)
|
|
2115
|
+
// "λ©μΈ μμ΄μ νΈκ° μ¬λ¦½μ μ μλΈμμ΄μ νΈλ₯Ό νΈμΆν΄μ λ―ΈλΉλ λΆλΆμ΄ μλμ§, μΆ©λλλ λΆλΆμ΄ μλμ§,
|
|
2116
|
+
// μ΄μ μ λλ½λ μμ
μ΄ μλμ§ λ±λ± μ¬λ¬λΆλΆμ νμνλ©΄μ νμν λ΄μ©μ μ 리νκ³
|
|
2117
|
+
// λ©μΈ μμ΄μ νΈκ° κΉ¨μ΄λ¬μλ, μλΈμμ΄μ νΈκ° μ 리ν λ΄μ©μ νμΈν΄λ³΄κ±°λ νλ κΈ°λ₯"
|
|
2118
|
+
// .harness/pre-wake-report.json μ sleep μ audit κ²°κ³Ό λμ (μ΅κ·Ό 10κ° μ μ§) β
|
|
2119
|
+
// λ€μ handoff μμ μλ λ
ΈμΆ β κΉ¨μ΄λ¨ μ§ν λ©μΈ μμ΄μ νΈκ° κ²ν κ°λ₯
|
|
2120
|
+
// audit μμ: λ―Έλ΅ μμ² / 24h+ 무μ§μ² task / drift μ νΈ / feature_graph μΆ©λ / νλ«νΌ μ μ½ λλ½
|
|
2121
|
+
function _preWakeReportPath(root) { return path.join(root, '.harness', 'pre-wake-report.json'); }
|
|
2122
|
+
function _loadPreWakeReport(root) {
|
|
2123
|
+
try {
|
|
2124
|
+
const fp = _preWakeReportPath(root);
|
|
2125
|
+
if (!exists(fp)) return { reports: [] };
|
|
2126
|
+
const j = JSON.parse(read(fp));
|
|
2127
|
+
return { reports: Array.isArray(j.reports) ? j.reports : [] };
|
|
2128
|
+
} catch { return { reports: [] }; }
|
|
2129
|
+
}
|
|
2130
|
+
function _writePreWakeReport(root, reports) {
|
|
2131
|
+
try {
|
|
2132
|
+
mkdirp(path.join(root, '.harness'));
|
|
2133
|
+
writeUtf8(_preWakeReportPath(root), JSON.stringify({ reports, updatedAt: new Date().toISOString() }, null, 2));
|
|
2134
|
+
return true;
|
|
2135
|
+
} catch { return false; }
|
|
2136
|
+
}
|
|
2137
|
+
// μ€μ audit μ€ν β sub-agent μν (λ¨μΌ νλ‘μΈμ€μμ syncλ‘ λ€μν μ νΈ μμ§)
|
|
2138
|
+
function _runPreWakeAudit(root) {
|
|
2139
|
+
const audit = {
|
|
2140
|
+
auditedAt: new Date().toISOString(),
|
|
2141
|
+
auditVersion: VERSION,
|
|
2142
|
+
findings: { critical: [], warning: [], info: [] }
|
|
2143
|
+
};
|
|
2144
|
+
// 1) λ―Έλ΅ μ¬μ©μ μμ² (1.9.207)
|
|
2145
|
+
try {
|
|
2146
|
+
const reqAudit = _auditUserRequests(root);
|
|
2147
|
+
if (reqAudit.missing && reqAudit.missing.length > 0) {
|
|
2148
|
+
audit.findings.critical.push({
|
|
2149
|
+
kind: 'missing-user-requests',
|
|
2150
|
+
count: reqAudit.missing.length,
|
|
2151
|
+
detail: `${reqAudit.missing.length}건 μ¬μ©μ μμ²μ΄ task-log/plan/decisions μ λ§€μΉ μ λ¨`,
|
|
2152
|
+
items: reqAudit.missing.slice(0, 5).map(r => ({ id: r.id, text: r.text.slice(0, 80) }))
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
if (reqAudit.stale && reqAudit.stale.length > 0) {
|
|
2156
|
+
audit.findings.warning.push({
|
|
2157
|
+
kind: 'stale-user-requests',
|
|
2158
|
+
count: reqAudit.stale.length,
|
|
2159
|
+
detail: `${reqAudit.stale.length}건 μ¬μ©μ μμ²μ΄ 7μΌ+ open μν`
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
} catch (e) { audit.findings.info.push({ kind: 'audit-error', area: 'user-requests', error: String(e.message || e) }); }
|
|
2163
|
+
|
|
2164
|
+
// 2) 24h+ 무μ§μ² task β progress-tracker κ²μ¬
|
|
2165
|
+
try {
|
|
2166
|
+
const ptPath = path.join(root, '.harness', 'progress-tracker.md');
|
|
2167
|
+
if (exists(ptPath)) {
|
|
2168
|
+
const content = read(ptPath);
|
|
2169
|
+
const stat = fs.statSync(ptPath);
|
|
2170
|
+
const ageMin = Math.floor((Date.now() - stat.mtimeMs) / 60000);
|
|
2171
|
+
// in-progress νκ·Έκ° μλλ° 24h+ κ°±μ μμ
|
|
2172
|
+
const inProgressCount = (content.match(/status:\s*in-progress/gi) || []).length;
|
|
2173
|
+
if (inProgressCount > 0 && ageMin > 24 * 60) {
|
|
2174
|
+
audit.findings.warning.push({
|
|
2175
|
+
kind: 'stale-in-progress',
|
|
2176
|
+
count: inProgressCount,
|
|
2177
|
+
detail: `${inProgressCount}건 in-progress task, ${Math.floor(ageMin/60)}h κ°±μ μμ`,
|
|
2178
|
+
ageMin
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
} catch {}
|
|
2183
|
+
|
|
2184
|
+
// 3) drift μ νΈ β session-handoff/progress-tracker stale κ²μ¬
|
|
2185
|
+
try {
|
|
2186
|
+
const handoffPath = path.join(root, '.harness', 'session-handoff.md');
|
|
2187
|
+
if (exists(handoffPath)) {
|
|
2188
|
+
const stat = fs.statSync(handoffPath);
|
|
2189
|
+
const ageDay = (Date.now() - stat.mtimeMs) / 86400000;
|
|
2190
|
+
if (ageDay > 5) {
|
|
2191
|
+
audit.findings.warning.push({
|
|
2192
|
+
kind: 'drift-handoff-stale',
|
|
2193
|
+
ageDay: Math.round(ageDay * 10) / 10,
|
|
2194
|
+
detail: `session-handoff.md ${ageDay.toFixed(1)}μΌ stale β drift μν`
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
} catch {}
|
|
2199
|
+
|
|
2200
|
+
// 4) λ€μ λΌμ΄λ plan μ μ© κ°λ₯ μ¬λΆ (1.9.203)
|
|
2201
|
+
try {
|
|
2202
|
+
const plan = _loadAutoResumePlan(root);
|
|
2203
|
+
if (!plan) {
|
|
2204
|
+
audit.findings.info.push({ kind: 'no-auto-resume-plan', detail: 'auto-resume-plan.json μμ β λ€μ λΌμ΄λ μ§μ
μ manual context' });
|
|
2205
|
+
} else if (plan.ageMin > 12 * 60) {
|
|
2206
|
+
audit.findings.warning.push({ kind: 'auto-resume-plan-stale', detail: `plan ${plan.ageMin}λΆ μ μμ± β outdated κ°λ₯` });
|
|
2207
|
+
} else {
|
|
2208
|
+
audit.findings.info.push({ kind: 'auto-resume-plan-ready', detail: `nextRoundVersion=${plan.nextRoundVersion}, focus=${(plan.focus||'').slice(0,50)}` });
|
|
2209
|
+
}
|
|
2210
|
+
} catch {}
|
|
2211
|
+
|
|
2212
|
+
// 5) Active wakeup μν (1.9.205)
|
|
2213
|
+
try {
|
|
2214
|
+
const wkStat = _analyzeWakeupStatus(root);
|
|
2215
|
+
if (wkStat.hasWakeup && wkStat.kind === 'missed') {
|
|
2216
|
+
audit.findings.critical.push({
|
|
2217
|
+
kind: 'wakeup-missed',
|
|
2218
|
+
deltaMin: wkStat.deltaMin,
|
|
2219
|
+
detail: `wakeup ${wkStat.deltaMin}λΆ μ§λ¨ β λ€μ λΌμ΄λ μ§μ
λ¦μ`
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
} catch {}
|
|
2223
|
+
|
|
2224
|
+
// 6) next-action queue μμ¬ (1.9.201)
|
|
2225
|
+
try {
|
|
2226
|
+
const q = _loadNextActionQueue(root);
|
|
2227
|
+
if (q && q.pending && q.pending.length > 0) {
|
|
2228
|
+
audit.findings.info.push({
|
|
2229
|
+
kind: 'next-action-pending',
|
|
2230
|
+
count: q.pending.length,
|
|
2231
|
+
detail: `${q.pending.length}건 next-action λκΈ° β leerness next-action take λ‘ μ¦μ μ²λ¦¬`
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
} catch {}
|
|
2235
|
+
|
|
2236
|
+
// 7) ν΅ν© μμ½
|
|
2237
|
+
audit.summary = {
|
|
2238
|
+
criticalCount: audit.findings.critical.length,
|
|
2239
|
+
warningCount: audit.findings.warning.length,
|
|
2240
|
+
infoCount: audit.findings.info.length,
|
|
2241
|
+
needsAttention: audit.findings.critical.length > 0 || audit.findings.warning.length >= 2
|
|
2242
|
+
};
|
|
2243
|
+
return audit;
|
|
2244
|
+
}
|
|
2245
|
+
function _saveAndAppendPreWakeReport(root, audit) {
|
|
2246
|
+
const state = _loadPreWakeReport(root);
|
|
2247
|
+
state.reports.push(audit);
|
|
2248
|
+
// μ΅κ·Ό 10κ°λ§ μ μ§
|
|
2249
|
+
if (state.reports.length > 10) state.reports = state.reports.slice(-10);
|
|
2250
|
+
_writePreWakeReport(root, state.reports);
|
|
2251
|
+
return audit;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2009
2254
|
// 1.9.203: μλ λΌμ΄λ plan μ 리 β μ¬μ©μ λͺ
μ
|
|
2010
2255
|
// "λ°±κ·ΈλΌμ΄λμ λ€μ μμ
μ΄ μμκ°λ₯ν μμ μκ° + μΌμ΄λ¬μλ ν΄μΌνλ μΌμ μ 리"
|
|
2011
2256
|
// λΌμ΄λ λ§λ¬΄λ¦¬ μ .harness/auto-resume-plan.json μλ μ μ₯ β λ€μ wakeup μ μ¦μ μ€ν κ°λ₯
|
|
@@ -2231,6 +2476,191 @@ function requestsCmd(root, sub, ...rest) {
|
|
|
2231
2476
|
process.exit(1);
|
|
2232
2477
|
}
|
|
2233
2478
|
|
|
2479
|
+
// 1.9.208: leerness constraints <list|check|add> β νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ CLI (μ¬μ©μ λͺ
μ)
|
|
2480
|
+
// "νΉμ νλ«νΌμ API ... νΈμΆμλκ° μ΄λΉ 5ν μ΄νλ‘λ§ ν΄μΌνλ€λ κ·μ μ λ¨Όμ νμΈ"
|
|
2481
|
+
// list β λ±λ‘λ λͺ¨λ νλ«νΌ catalog μΆλ ₯
|
|
2482
|
+
// check "<req>" β μ¬μ©μ μμ² ν
μ€νΈμμ νλ«νΌ λ§€μΉ β μ μ½ λ³΄κ³ (--json κ°λ₯)
|
|
2483
|
+
// add <id> --aliases ... --constraint "kind:detail" β μ¬μ©μ μ μ νλ«νΌ μΆκ°
|
|
2484
|
+
function constraintsCmd(root, sub, ...rest) {
|
|
2485
|
+
root = absRoot(root);
|
|
2486
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
2487
|
+
const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
2488
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
2489
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
2490
|
+
const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
2491
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
2492
|
+
|
|
2493
|
+
if (!sub || sub === 'help' || sub === '--help') {
|
|
2494
|
+
log(`# leerness constraints (1.9.208) β νλ«νΌ/API μ μ½ μ¬μ 체ν¬`);
|
|
2495
|
+
log('');
|
|
2496
|
+
log(` list β λ±λ‘λ λͺ¨λ νλ«νΌ catalog μΆλ ₯ (--json κ°λ₯)`);
|
|
2497
|
+
log(` check "<request>" β μ¬μ©μ μμ²μμ νλ«νΌ λ§€μΉ β μ μ½ λ³΄κ³ (--json κ°λ₯)`);
|
|
2498
|
+
log(` add <id> --constraint "kind:detail" --alias name`);
|
|
2499
|
+
log('');
|
|
2500
|
+
log(dim(` μ: leerness constraints check "Stripe API μ°λ κ²°μ λͺ¨λ"`));
|
|
2501
|
+
return;
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
if (sub === 'list') {
|
|
2505
|
+
const catalog = _loadPlatformConstraints(root);
|
|
2506
|
+
if (has('--json')) { log(JSON.stringify(catalog, null, 2)); return; }
|
|
2507
|
+
log(cyan(`# leerness constraints list (1.9.208)`));
|
|
2508
|
+
log(` total platforms: ${Object.keys(catalog.platforms).length}`);
|
|
2509
|
+
log('');
|
|
2510
|
+
for (const [pid, plat] of Object.entries(catalog.platforms)) {
|
|
2511
|
+
log(grn(` π¦ ${pid}`) + dim(` aliases: ${(plat.aliases || []).join(', ')}`));
|
|
2512
|
+
log(dim(` docs: ${plat.docs || '-'}`));
|
|
2513
|
+
for (const c of plat.constraints || []) {
|
|
2514
|
+
const icon = c.kind === 'rate-limit' ? 'π¦' : (c.kind === 'cost' ? 'π°' : (c.kind === 'auth' ? 'π' : 'π'));
|
|
2515
|
+
log(` ${icon} [${c.kind}] ${c.detail}`);
|
|
2516
|
+
}
|
|
2517
|
+
log('');
|
|
2518
|
+
}
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
if (sub === 'check') {
|
|
2523
|
+
const text = rest.filter(x => !x.startsWith('-')).join(' ');
|
|
2524
|
+
if (!text) { console.error('Usage: leerness constraints check "<request text>"'); process.exit(1); }
|
|
2525
|
+
const result = _checkRequestConstraints(root, text);
|
|
2526
|
+
if (has('--json')) { log(JSON.stringify({ query: text, ...result }, null, 2)); return; }
|
|
2527
|
+
log(cyan(`# leerness constraints check (1.9.208)`));
|
|
2528
|
+
log(` query: ${text.slice(0, 80)}${text.length > 80 ? 'β¦' : ''}`);
|
|
2529
|
+
log('');
|
|
2530
|
+
if (result.matched.length === 0) {
|
|
2531
|
+
log(grn(` β λ§€μΉλ νλ«νΌ μμ (catalog ${result.totalPlatforms}μ’
κ²ν μλ£)`));
|
|
2532
|
+
if (result.suggestions.length) {
|
|
2533
|
+
log('');
|
|
2534
|
+
log(yel(` π‘ μ μ:`));
|
|
2535
|
+
result.suggestions.forEach(s => log(` β’ ${s}`));
|
|
2536
|
+
}
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
log(red(` β ${result.matched.length}κ° νλ«νΌ λ§€μΉ β μ μ½ μ¬μ νμΈ νμ:`));
|
|
2540
|
+
log('');
|
|
2541
|
+
for (const m of result.matched) {
|
|
2542
|
+
log(grn(` π¦ ${m.platform}`) + dim(` (matched: "${m.matchedAlias}")`));
|
|
2543
|
+
log(dim(` docs: ${m.docs || '-'}`));
|
|
2544
|
+
for (const c of m.constraints || []) {
|
|
2545
|
+
const icon = c.kind === 'rate-limit' ? 'π¦' : (c.kind === 'cost' ? 'π°' : (c.kind === 'auth' ? 'π' : 'π'));
|
|
2546
|
+
log(` ${icon} [${c.kind}] ${c.detail}`);
|
|
2547
|
+
}
|
|
2548
|
+
log('');
|
|
2549
|
+
}
|
|
2550
|
+
log(dim(` β ꡬν μ μ μ μ½μ λ°μν μ€κ³ κΆμ₯ (rate limiter / idempotency key / λΉμ© μΆμ )`));
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
if (sub === 'add') {
|
|
2555
|
+
const id = rest[0];
|
|
2556
|
+
if (!id) { console.error('Usage: leerness constraints add <platform-id> --constraint "kind:detail"'); process.exit(1); }
|
|
2557
|
+
const catalog = _loadPlatformConstraints(root);
|
|
2558
|
+
const aliases = (arg('--alias', '') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
2559
|
+
const detailRaw = arg('--constraint', '');
|
|
2560
|
+
if (!detailRaw) { console.error('--constraint "kind:detail" required'); process.exit(1); }
|
|
2561
|
+
const [kind, ...rest2] = detailRaw.split(':');
|
|
2562
|
+
const detail = rest2.join(':').trim();
|
|
2563
|
+
if (!catalog.platforms[id]) catalog.platforms[id] = { aliases: [], constraints: [] };
|
|
2564
|
+
if (aliases.length) catalog.platforms[id].aliases = [...new Set([...(catalog.platforms[id].aliases || []), ...aliases])];
|
|
2565
|
+
if (kind && detail) catalog.platforms[id].constraints.push({ kind: kind.trim(), detail });
|
|
2566
|
+
_writePlatformConstraints(root, catalog);
|
|
2567
|
+
if (has('--json')) { log(JSON.stringify(catalog.platforms[id], null, 2)); return; }
|
|
2568
|
+
log(grn(`β platform "${id}" κ°±μ β constraints: ${catalog.platforms[id].constraints.length}`));
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
console.error(`Unknown subcommand: ${sub}`);
|
|
2573
|
+
console.error(`Run: leerness constraints help`);
|
|
2574
|
+
process.exit(1);
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
// 1.9.209: leerness pre-wake-audit β sleep μ sub-agent audit CLI (μ¬μ©μ λͺ
μ)
|
|
2578
|
+
// "λ©μΈ μμ΄μ νΈκ° μ¬λ¦½μ μ μλΈμμ΄μ νΈλ₯Ό νΈμΆν΄μ λ―ΈλΉλ λΆλΆμ΄ μλμ§, μΆ©λλλ λΆλΆμ΄ μλμ§,
|
|
2579
|
+
// μ΄μ μ λλ½λ μμ
μ΄ μλμ§ λ±λ± μ¬λ¬λΆλΆμ νμνλ©΄μ νμν λ΄μ©μ μ 리"
|
|
2580
|
+
// κΈ°λ³Έ: μ audit μ€ν + μ μ₯ + μΆλ ₯
|
|
2581
|
+
// --last: μ΅κ·Ό μ μ₯λ audit νμ (μ¬μ©μ κΉ¨μ΄λ¬μ λ κ²ν μ©)
|
|
2582
|
+
// --json: JSON μΆλ ₯
|
|
2583
|
+
function preWakeAuditCmd(root, sub) {
|
|
2584
|
+
root = absRoot(root);
|
|
2585
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
2586
|
+
const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
2587
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
2588
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
2589
|
+
const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
2590
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
2591
|
+
|
|
2592
|
+
// --last λλ review/show β κ°μ₯ μ΅κ·Ό audit νμ (μ€ν μ ν¨)
|
|
2593
|
+
if (has('--last') || sub === 'show' || sub === 'review') {
|
|
2594
|
+
const state = _loadPreWakeReport(root);
|
|
2595
|
+
if (state.reports.length === 0) {
|
|
2596
|
+
log(cyan(`# leerness pre-wake-audit (1.9.209) β review`));
|
|
2597
|
+
log(dim(` (μ μ₯λ audit μμ β leerness pre-wake-audit μΌλ‘ μ μ€ν)`));
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
2600
|
+
const latest = state.reports[state.reports.length - 1];
|
|
2601
|
+
if (has('--json')) { log(JSON.stringify(latest, null, 2)); return; }
|
|
2602
|
+
log(cyan(`# leerness pre-wake-audit (1.9.209) β review (latest)`));
|
|
2603
|
+
log(dim(` audited at: ${latest.auditedAt} (version ${latest.auditVersion})`));
|
|
2604
|
+
log('');
|
|
2605
|
+
const sum = latest.summary || {};
|
|
2606
|
+
log(` π ${red(`critical ${sum.criticalCount || 0}`)} Β· ${yel(`warning ${sum.warningCount || 0}`)} Β· info ${sum.infoCount || 0}`);
|
|
2607
|
+
if (sum.needsAttention) log(yel(` β needsAttention=true β λ©μΈ μμ΄μ νΈ κ²ν νμ`));
|
|
2608
|
+
log('');
|
|
2609
|
+
if (latest.findings.critical && latest.findings.critical.length) {
|
|
2610
|
+
log(red(`## π¨ critical (${latest.findings.critical.length})`));
|
|
2611
|
+
latest.findings.critical.forEach(f => log(` - [${f.kind}] ${f.detail}`));
|
|
2612
|
+
log('');
|
|
2613
|
+
}
|
|
2614
|
+
if (latest.findings.warning && latest.findings.warning.length) {
|
|
2615
|
+
log(yel(`## β warning (${latest.findings.warning.length})`));
|
|
2616
|
+
latest.findings.warning.forEach(f => log(` - [${f.kind}] ${f.detail}`));
|
|
2617
|
+
log('');
|
|
2618
|
+
}
|
|
2619
|
+
if (latest.findings.info && latest.findings.info.length) {
|
|
2620
|
+
log(dim(`## βΉ info (${latest.findings.info.length})`));
|
|
2621
|
+
latest.findings.info.forEach(f => log(dim(` - [${f.kind}] ${f.detail}`)));
|
|
2622
|
+
}
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
// κΈ°λ³Έ: μ audit μ€ν + μ μ₯
|
|
2627
|
+
const audit = _runPreWakeAudit(root);
|
|
2628
|
+
_saveAndAppendPreWakeReport(root, audit);
|
|
2629
|
+
|
|
2630
|
+
if (has('--json')) { log(JSON.stringify(audit, null, 2)); return; }
|
|
2631
|
+
log(cyan(`# leerness pre-wake-audit (1.9.209) β sleep μ sub-agent audit`));
|
|
2632
|
+
log(dim(` audited at: ${audit.auditedAt}`));
|
|
2633
|
+
log('');
|
|
2634
|
+
const sum = audit.summary;
|
|
2635
|
+
log(` π ${red(`critical ${sum.criticalCount}`)} Β· ${yel(`warning ${sum.warningCount}`)} Β· info ${sum.infoCount}`);
|
|
2636
|
+
if (sum.needsAttention) {
|
|
2637
|
+
log(yel(` β needsAttention=true β κΉ¨μ΄λ ν λ©μΈ μμ΄μ νΈ κ²ν νμ`));
|
|
2638
|
+
} else {
|
|
2639
|
+
log(grn(` β μ μ¬ μ΄μ μμ β sleep μμ `));
|
|
2640
|
+
}
|
|
2641
|
+
log('');
|
|
2642
|
+
if (audit.findings.critical.length) {
|
|
2643
|
+
log(red(`## π¨ critical (${audit.findings.critical.length})`));
|
|
2644
|
+
audit.findings.critical.forEach(f => {
|
|
2645
|
+
log(` - [${f.kind}] ${f.detail}`);
|
|
2646
|
+
if (f.items) f.items.forEach(i => log(dim(` β’ ${i.id}: ${i.text}`)));
|
|
2647
|
+
});
|
|
2648
|
+
log('');
|
|
2649
|
+
}
|
|
2650
|
+
if (audit.findings.warning.length) {
|
|
2651
|
+
log(yel(`## β warning (${audit.findings.warning.length})`));
|
|
2652
|
+
audit.findings.warning.forEach(f => log(` - [${f.kind}] ${f.detail}`));
|
|
2653
|
+
log('');
|
|
2654
|
+
}
|
|
2655
|
+
if (audit.findings.info.length) {
|
|
2656
|
+
log(dim(`## βΉ info (${audit.findings.info.length})`));
|
|
2657
|
+
audit.findings.info.forEach(f => log(dim(` - [${f.kind}] ${f.detail}`)));
|
|
2658
|
+
log('');
|
|
2659
|
+
}
|
|
2660
|
+
log(dim(` β μ μ₯: .harness/pre-wake-report.json (μ΅κ·Ό 10κ° μ μ§)`));
|
|
2661
|
+
log(dim(` β κΉ¨μ΄λ ν: leerness pre-wake-audit --last`));
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2234
2664
|
// 1.9.199: wakeup miss μλ ν볡 κ°ν β last-handoff timestamp κΈ°λ‘ + 25min κΈ°λ interval μ λ° μΈ‘μ
|
|
2235
2665
|
// μ¬μ©μ λͺ
μ (1.9.198 νμ): "22:01μ λΌμ΄λμ μλμ§μ
λμ§μμμ΄"
|
|
2236
2666
|
// 1.9.196 task-log mtime κΈ°λ° detector λ task-log κ° μμ£Ό μ μ
λ°μ΄νΈλλ©΄ false positive.
|
|
@@ -4274,13 +4704,52 @@ function handoff(root) {
|
|
|
4274
4704
|
parts.push(`π₯ μμ² ${audit.open} (tracked)`);
|
|
4275
4705
|
}
|
|
4276
4706
|
} catch {}
|
|
4707
|
+
// 14) 1.9.209: pre-wake-audit μ΅κ·Ό λ³΄κ³ μ (μ¬μ©μ λͺ
μ) β κΉ¨μ΄λ¨ μ§ν μλ λ
ΈμΆ
|
|
4708
|
+
try {
|
|
4709
|
+
const pwState = _loadPreWakeReport(root);
|
|
4710
|
+
if (pwState.reports.length > 0) {
|
|
4711
|
+
const latest = pwState.reports[pwState.reports.length - 1];
|
|
4712
|
+
const sum = latest.summary || {};
|
|
4713
|
+
if (sum.criticalCount > 0 || sum.warningCount > 0) {
|
|
4714
|
+
const ageMin = Math.floor((Date.now() - new Date(latest.auditedAt).getTime()) / 60000);
|
|
4715
|
+
parts.push(`π pre-wake ${sum.criticalCount}C/${sum.warningCount}W (${ageMin}m)`);
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
} catch {}
|
|
4277
4719
|
if (parts.length) {
|
|
4278
4720
|
const isTty = process.stdout && process.stdout.isTTY;
|
|
4279
4721
|
const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
4280
|
-
log(cy(`π ν€λλΌμΈ (1.9.81/93/113/152/162/192/197/204/207): ${parts.join(' Β· ')}`));
|
|
4722
|
+
log(cy(`π ν€λλΌμΈ (1.9.81/93/113/152/162/192/197/204/207/209): ${parts.join(' Β· ')}`));
|
|
4281
4723
|
}
|
|
4282
4724
|
} catch {}
|
|
4283
4725
|
}
|
|
4726
|
+
|
|
4727
|
+
// 1.9.209: pre-wake-audit λ³Έλ¬Έ μλ λ
ΈμΆ (handoff λ§μ§λ§ λΆλΆ, μ¬μ©μ λͺ
μ)
|
|
4728
|
+
// "λ©μΈ μμ΄μ νΈκ° κΉ¨μ΄λ¬μλ, μλΈμμ΄μ νΈκ° μ 리ν λ΄μ©μ νμΈ"
|
|
4729
|
+
try {
|
|
4730
|
+
const pwState = _loadPreWakeReport(root);
|
|
4731
|
+
if (pwState.reports.length > 0) {
|
|
4732
|
+
const latest = pwState.reports[pwState.reports.length - 1];
|
|
4733
|
+
const ageMin = Math.floor((Date.now() - new Date(latest.auditedAt).getTime()) / 60000);
|
|
4734
|
+
// 4μκ° μ΄λ΄ λ³΄κ³ μλ§ μλ λ
ΈμΆ (μ€λλ 건 stale)
|
|
4735
|
+
if (ageMin < 240 && (latest.summary.criticalCount > 0 || latest.summary.warningCount > 0)) {
|
|
4736
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
4737
|
+
const cy2 = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
4738
|
+
const rd2 = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
4739
|
+
const yl2 = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
4740
|
+
const dm2 = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
4741
|
+
log('');
|
|
4742
|
+
log(cy2(`## π μ§μ sleep pre-wake-audit (1.9.209, ${ageMin}λΆ μ )`));
|
|
4743
|
+
if (latest.findings.critical && latest.findings.critical.length) {
|
|
4744
|
+
latest.findings.critical.slice(0, 3).forEach(f => log(rd2(` π¨ [${f.kind}] ${f.detail}`)));
|
|
4745
|
+
}
|
|
4746
|
+
if (latest.findings.warning && latest.findings.warning.length) {
|
|
4747
|
+
latest.findings.warning.slice(0, 3).forEach(f => log(yl2(` β [${f.kind}] ${f.detail}`)));
|
|
4748
|
+
}
|
|
4749
|
+
log(dm2(` β μμΈ: leerness pre-wake-audit --last`));
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
} catch {}
|
|
4284
4753
|
// 1.9.8: active rules μλ λ
ΈμΆ (λ§€ μΈμ
μμ μ AIμκ² λ³΄μ)
|
|
4285
4754
|
const activeRules = readRules(root).filter(r => r.status === 'active');
|
|
4286
4755
|
if (activeRules.length) {
|
|
@@ -15238,6 +15707,15 @@ function reviewRequestCmd(root, request) {
|
|
|
15238
15707
|
efficiencyHints.push('β¨ μΆ©λ μ νΈ μμ β μ¦μ μ§ν μμ ');
|
|
15239
15708
|
}
|
|
15240
15709
|
|
|
15710
|
+
// 6.5) 1.9.208: νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ β μ¬μ©μ λͺ
μ ("νΈμΆμλ μ΄λΉ 5ν" κ°μ κ·μ μ¬μ νμΈ)
|
|
15711
|
+
let constraintsCheck = { matched: [], suggestions: [] };
|
|
15712
|
+
try {
|
|
15713
|
+
constraintsCheck = _checkRequestConstraints(root, text);
|
|
15714
|
+
if (constraintsCheck.matched.length > 0) {
|
|
15715
|
+
efficiencyHints.push(`β νλ«νΌ μ μ½ ${constraintsCheck.matched.length}건 β leerness constraints check λ‘ μμΈ νμΈ`);
|
|
15716
|
+
}
|
|
15717
|
+
} catch {}
|
|
15718
|
+
|
|
15241
15719
|
// 7) proceed κΆμ₯ (μΆ©λ critical μ false)
|
|
15242
15720
|
const proceed = conflictHints.length < 3 && planConflicts.length === 0;
|
|
15243
15721
|
|
|
@@ -15252,6 +15730,8 @@ function reviewRequestCmd(root, request) {
|
|
|
15252
15730
|
featureConflicts,
|
|
15253
15731
|
recommendedSteps,
|
|
15254
15732
|
efficiencyHints,
|
|
15733
|
+
platformConstraints: constraintsCheck.matched,
|
|
15734
|
+
constraintSuggestions: constraintsCheck.suggestions,
|
|
15255
15735
|
proceed,
|
|
15256
15736
|
proceedReason: proceed ? 'μμ β μΆ©λ μ νΈ < 3 + plan μΆ©λ 0' : 'β μΆ©λ critical β μ¬μ©μ νμΈ ν μ§ν',
|
|
15257
15737
|
durationMs: dt
|
|
@@ -15295,6 +15775,18 @@ function reviewRequestCmd(root, request) {
|
|
|
15295
15775
|
log(`## π‘ ν¨μ¨ μ μ`);
|
|
15296
15776
|
efficiencyHints.forEach(h => log(` ${h}`));
|
|
15297
15777
|
log('');
|
|
15778
|
+
// 1.9.208: νλ«νΌ/API μ μ½ μ¬μ λ
ΈμΆ (μ¬μ©μ λͺ
μ)
|
|
15779
|
+
if (constraintsCheck.matched.length > 0) {
|
|
15780
|
+
log(`## π¦ νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (${constraintsCheck.matched.length})`);
|
|
15781
|
+
for (const m of constraintsCheck.matched) {
|
|
15782
|
+
log(` - π¦ ${m.platform} (docs: ${m.docs || '-'})`);
|
|
15783
|
+
for (const c of (m.constraints || []).slice(0, 3)) {
|
|
15784
|
+
log(` β’ [${c.kind}] ${c.detail}`);
|
|
15785
|
+
}
|
|
15786
|
+
}
|
|
15787
|
+
log(` β leerness constraints check "${text.slice(0, 40)}β¦" λ‘ μμΈ νμΈ`);
|
|
15788
|
+
log('');
|
|
15789
|
+
}
|
|
15298
15790
|
if (recommendedSteps.length) {
|
|
15299
15791
|
log(`## π κΆμ₯ λ¨κ³ (${estimatedType})`);
|
|
15300
15792
|
recommendedSteps.forEach(s => log(` ${s}`));
|
|
@@ -15568,6 +16060,10 @@ async function main() {
|
|
|
15568
16060
|
if (cmd === 'resume') return resumeCmd(arg('--path', process.cwd()));
|
|
15569
16061
|
// 1.9.207: leerness requests <audit|add|list|complete|drop> β μ¬μ©μ μμ² λλ½ νμΈ μ μ°¨ (μ¬μ©μ λͺ
μ)
|
|
15570
16062
|
if (cmd === 'requests') return requestsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
16063
|
+
// 1.9.208: leerness constraints <list|check|add> β νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ)
|
|
16064
|
+
if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
16065
|
+
// 1.9.209: leerness pre-wake-audit β sleep μ sub-agent audit (μ¬μ©μ λͺ
μ)
|
|
16066
|
+
if (cmd === 'pre-wake-audit') return preWakeAuditCmd(arg('--path', process.cwd()), args[1]);
|
|
15571
16067
|
if (cmd === 'rule' && args[1] === 'add') return ruleAdd(arg('--path', process.cwd()), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
|
|
15572
16068
|
if (cmd === 'rule' && args[1] === 'list') return ruleList(arg('--path', process.cwd()));
|
|
15573
16069
|
if (cmd === 'rule' && args[1] === 'remove') return ruleRemove(arg('--path', process.cwd()), args[2]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.209",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|