leerness 1.9.207 β 1.9.208
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 +44 -0
- package/README.md +3 -3
- package/bin/harness.js +229 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.208 β 2026-05-22
|
|
4
|
+
|
|
5
|
+
**π¦ νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ).**
|
|
6
|
+
|
|
7
|
+
### μ¬μ©μ λͺ
μ
|
|
8
|
+
> *"μ¬μ©μμ λͺ
λ Ήμ λ°μΌλ©΄, κ³ λ €ν΄μΌνλ λΆλΆμ λ¨Όμ νμΈνκ³ μ§ννκ² νλ©΄ μ΄λ¨μ§ / νΉμ νλ«νΌμ API ... νΈμΆμλκ° μ΄λΉ 5ν μ΄νλ‘λ§ ν΄μΌνλ€λ κ·μ μ λ¨Όμ νμΈ"*
|
|
9
|
+
|
|
10
|
+
### 1. `.harness/platform-constraints.json` + κΈ°λ³Έ catalog 6μ’
|
|
11
|
+
- **stripe** (rate: 100 req/s, idempotency key, webhook signing)
|
|
12
|
+
- **openai** (tier-based RPM, TPM, cost per 1M tokens)
|
|
13
|
+
- **anthropic** (claude tier, context-window, cost)
|
|
14
|
+
- **github** (5K req/hr auth, search 30 req/min, secondary)
|
|
15
|
+
- **discord** (50 req/s global, invalid ban)
|
|
16
|
+
- **twitter** (tier-based, OAuth 2.0 PKCE)
|
|
17
|
+
- κ° alias array λ§€μΉ + docs URL λλ΄
|
|
18
|
+
|
|
19
|
+
### 2. ν¬νΌ ν¨μ
|
|
20
|
+
- `_loadPlatformConstraints(root)` β default merge user override
|
|
21
|
+
- `_writePlatformConstraints(root, catalog)` β μ¬μ©μ catalog μ μ₯
|
|
22
|
+
- `_checkRequestConstraints(root, text)` β ν
μ€νΈ β λ§€μΉ νλ«νΌ + μ μ½ + suggestions
|
|
23
|
+
|
|
24
|
+
### 3. `leerness constraints <list|check|add>` CLI
|
|
25
|
+
- `list` β λ±λ‘ catalog μΆλ ₯ (--json)
|
|
26
|
+
- `check "<req>"` β μ¬μ©μ μμ² λ§€μΉ β μ μ½ λ³΄κ³ (--json)
|
|
27
|
+
- `add <id> --alias name --constraint "kind:detail"` β μ¬μ©μ μ μ
|
|
28
|
+
|
|
29
|
+
### 4. review-request μλ ν΅ν©
|
|
30
|
+
- `_checkRequestConstraints()` review-request λ΄λΆμμ μλ νΈμΆ
|
|
31
|
+
- JSON μΆλ ₯μ `platformConstraints` + `constraintSuggestions` νλ μΆκ°
|
|
32
|
+
- human μΆλ ₯μ `## π¦ νλ«νΌ/API μ μ½ μ¬μ 체ν¬` μΉμ
|
|
33
|
+
- efficiencyHints μ λ§€μΉ N건 μλ¦Ό
|
|
34
|
+
|
|
35
|
+
### 5. λμ νκ· (1.9.200~207) β λͺ¨λ μ μ§
|
|
36
|
+
|
|
37
|
+
### 6. stress-v153 β 18/18 PASS
|
|
38
|
+
- 1.9.208 (9) + μ±λ₯ (2) + λμ νκ· (7)
|
|
39
|
+
- κΈ°λ³Έ 6 catalog + μ¬μ©μ μ μ add + review-request ν΅ν© κ²μ¦
|
|
40
|
+
- μ±λ₯: --version cold start avg 483ms Β· MCP 54 λꡬ 431ms
|
|
41
|
+
|
|
42
|
+
### 7. μλ release (70 λΌμ΄λ main-push streak Β· 31 λΌμ΄λ npm publish streak)
|
|
43
|
+
- `release sync-main` μλ β main merge + npm publish leerness@1.9.208
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
3
47
|
## 1.9.207 β 2026-05-22
|
|
4
48
|
|
|
5
49
|
**π₯ μ¬μ©μ μμ² λλ½ νμΈ μ μ°¨ 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.208 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β π¦ νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ 6μ’
(μ¬μ©μ λͺ
μ) β
|
|
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.208';
|
|
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,111 @@ 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
|
+
|
|
2009
2114
|
// 1.9.203: μλ λΌμ΄λ plan μ 리 β μ¬μ©μ λͺ
μ
|
|
2010
2115
|
// "λ°±κ·ΈλΌμ΄λμ λ€μ μμ
μ΄ μμκ°λ₯ν μμ μκ° + μΌμ΄λ¬μλ ν΄μΌνλ μΌμ μ 리"
|
|
2011
2116
|
// λΌμ΄λ λ§λ¬΄λ¦¬ μ .harness/auto-resume-plan.json μλ μ μ₯ β λ€μ wakeup μ μ¦μ μ€ν κ°λ₯
|
|
@@ -2231,6 +2336,104 @@ function requestsCmd(root, sub, ...rest) {
|
|
|
2231
2336
|
process.exit(1);
|
|
2232
2337
|
}
|
|
2233
2338
|
|
|
2339
|
+
// 1.9.208: leerness constraints <list|check|add> β νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ CLI (μ¬μ©μ λͺ
μ)
|
|
2340
|
+
// "νΉμ νλ«νΌμ API ... νΈμΆμλκ° μ΄λΉ 5ν μ΄νλ‘λ§ ν΄μΌνλ€λ κ·μ μ λ¨Όμ νμΈ"
|
|
2341
|
+
// list β λ±λ‘λ λͺ¨λ νλ«νΌ catalog μΆλ ₯
|
|
2342
|
+
// check "<req>" β μ¬μ©μ μμ² ν
μ€νΈμμ νλ«νΌ λ§€μΉ β μ μ½ λ³΄κ³ (--json κ°λ₯)
|
|
2343
|
+
// add <id> --aliases ... --constraint "kind:detail" β μ¬μ©μ μ μ νλ«νΌ μΆκ°
|
|
2344
|
+
function constraintsCmd(root, sub, ...rest) {
|
|
2345
|
+
root = absRoot(root);
|
|
2346
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
2347
|
+
const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
2348
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
2349
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
2350
|
+
const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
2351
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
2352
|
+
|
|
2353
|
+
if (!sub || sub === 'help' || sub === '--help') {
|
|
2354
|
+
log(`# leerness constraints (1.9.208) β νλ«νΌ/API μ μ½ μ¬μ 체ν¬`);
|
|
2355
|
+
log('');
|
|
2356
|
+
log(` list β λ±λ‘λ λͺ¨λ νλ«νΌ catalog μΆλ ₯ (--json κ°λ₯)`);
|
|
2357
|
+
log(` check "<request>" β μ¬μ©μ μμ²μμ νλ«νΌ λ§€μΉ β μ μ½ λ³΄κ³ (--json κ°λ₯)`);
|
|
2358
|
+
log(` add <id> --constraint "kind:detail" --alias name`);
|
|
2359
|
+
log('');
|
|
2360
|
+
log(dim(` μ: leerness constraints check "Stripe API μ°λ κ²°μ λͺ¨λ"`));
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
if (sub === 'list') {
|
|
2365
|
+
const catalog = _loadPlatformConstraints(root);
|
|
2366
|
+
if (has('--json')) { log(JSON.stringify(catalog, null, 2)); return; }
|
|
2367
|
+
log(cyan(`# leerness constraints list (1.9.208)`));
|
|
2368
|
+
log(` total platforms: ${Object.keys(catalog.platforms).length}`);
|
|
2369
|
+
log('');
|
|
2370
|
+
for (const [pid, plat] of Object.entries(catalog.platforms)) {
|
|
2371
|
+
log(grn(` π¦ ${pid}`) + dim(` aliases: ${(plat.aliases || []).join(', ')}`));
|
|
2372
|
+
log(dim(` docs: ${plat.docs || '-'}`));
|
|
2373
|
+
for (const c of plat.constraints || []) {
|
|
2374
|
+
const icon = c.kind === 'rate-limit' ? 'π¦' : (c.kind === 'cost' ? 'π°' : (c.kind === 'auth' ? 'π' : 'π'));
|
|
2375
|
+
log(` ${icon} [${c.kind}] ${c.detail}`);
|
|
2376
|
+
}
|
|
2377
|
+
log('');
|
|
2378
|
+
}
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
if (sub === 'check') {
|
|
2383
|
+
const text = rest.filter(x => !x.startsWith('-')).join(' ');
|
|
2384
|
+
if (!text) { console.error('Usage: leerness constraints check "<request text>"'); process.exit(1); }
|
|
2385
|
+
const result = _checkRequestConstraints(root, text);
|
|
2386
|
+
if (has('--json')) { log(JSON.stringify({ query: text, ...result }, null, 2)); return; }
|
|
2387
|
+
log(cyan(`# leerness constraints check (1.9.208)`));
|
|
2388
|
+
log(` query: ${text.slice(0, 80)}${text.length > 80 ? 'β¦' : ''}`);
|
|
2389
|
+
log('');
|
|
2390
|
+
if (result.matched.length === 0) {
|
|
2391
|
+
log(grn(` β λ§€μΉλ νλ«νΌ μμ (catalog ${result.totalPlatforms}μ’
κ²ν μλ£)`));
|
|
2392
|
+
if (result.suggestions.length) {
|
|
2393
|
+
log('');
|
|
2394
|
+
log(yel(` π‘ μ μ:`));
|
|
2395
|
+
result.suggestions.forEach(s => log(` β’ ${s}`));
|
|
2396
|
+
}
|
|
2397
|
+
return;
|
|
2398
|
+
}
|
|
2399
|
+
log(red(` β ${result.matched.length}κ° νλ«νΌ λ§€μΉ β μ μ½ μ¬μ νμΈ νμ:`));
|
|
2400
|
+
log('');
|
|
2401
|
+
for (const m of result.matched) {
|
|
2402
|
+
log(grn(` π¦ ${m.platform}`) + dim(` (matched: "${m.matchedAlias}")`));
|
|
2403
|
+
log(dim(` docs: ${m.docs || '-'}`));
|
|
2404
|
+
for (const c of m.constraints || []) {
|
|
2405
|
+
const icon = c.kind === 'rate-limit' ? 'π¦' : (c.kind === 'cost' ? 'π°' : (c.kind === 'auth' ? 'π' : 'π'));
|
|
2406
|
+
log(` ${icon} [${c.kind}] ${c.detail}`);
|
|
2407
|
+
}
|
|
2408
|
+
log('');
|
|
2409
|
+
}
|
|
2410
|
+
log(dim(` β ꡬν μ μ μ μ½μ λ°μν μ€κ³ κΆμ₯ (rate limiter / idempotency key / λΉμ© μΆμ )`));
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
if (sub === 'add') {
|
|
2415
|
+
const id = rest[0];
|
|
2416
|
+
if (!id) { console.error('Usage: leerness constraints add <platform-id> --constraint "kind:detail"'); process.exit(1); }
|
|
2417
|
+
const catalog = _loadPlatformConstraints(root);
|
|
2418
|
+
const aliases = (arg('--alias', '') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
2419
|
+
const detailRaw = arg('--constraint', '');
|
|
2420
|
+
if (!detailRaw) { console.error('--constraint "kind:detail" required'); process.exit(1); }
|
|
2421
|
+
const [kind, ...rest2] = detailRaw.split(':');
|
|
2422
|
+
const detail = rest2.join(':').trim();
|
|
2423
|
+
if (!catalog.platforms[id]) catalog.platforms[id] = { aliases: [], constraints: [] };
|
|
2424
|
+
if (aliases.length) catalog.platforms[id].aliases = [...new Set([...(catalog.platforms[id].aliases || []), ...aliases])];
|
|
2425
|
+
if (kind && detail) catalog.platforms[id].constraints.push({ kind: kind.trim(), detail });
|
|
2426
|
+
_writePlatformConstraints(root, catalog);
|
|
2427
|
+
if (has('--json')) { log(JSON.stringify(catalog.platforms[id], null, 2)); return; }
|
|
2428
|
+
log(grn(`β platform "${id}" κ°±μ β constraints: ${catalog.platforms[id].constraints.length}`));
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
console.error(`Unknown subcommand: ${sub}`);
|
|
2433
|
+
console.error(`Run: leerness constraints help`);
|
|
2434
|
+
process.exit(1);
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2234
2437
|
// 1.9.199: wakeup miss μλ ν볡 κ°ν β last-handoff timestamp κΈ°λ‘ + 25min κΈ°λ interval μ λ° μΈ‘μ
|
|
2235
2438
|
// μ¬μ©μ λͺ
μ (1.9.198 νμ): "22:01μ λΌμ΄λμ μλμ§μ
λμ§μμμ΄"
|
|
2236
2439
|
// 1.9.196 task-log mtime κΈ°λ° detector λ task-log κ° μμ£Ό μ μ
λ°μ΄νΈλλ©΄ false positive.
|
|
@@ -15238,6 +15441,15 @@ function reviewRequestCmd(root, request) {
|
|
|
15238
15441
|
efficiencyHints.push('β¨ μΆ©λ μ νΈ μμ β μ¦μ μ§ν μμ ');
|
|
15239
15442
|
}
|
|
15240
15443
|
|
|
15444
|
+
// 6.5) 1.9.208: νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ β μ¬μ©μ λͺ
μ ("νΈμΆμλ μ΄λΉ 5ν" κ°μ κ·μ μ¬μ νμΈ)
|
|
15445
|
+
let constraintsCheck = { matched: [], suggestions: [] };
|
|
15446
|
+
try {
|
|
15447
|
+
constraintsCheck = _checkRequestConstraints(root, text);
|
|
15448
|
+
if (constraintsCheck.matched.length > 0) {
|
|
15449
|
+
efficiencyHints.push(`β νλ«νΌ μ μ½ ${constraintsCheck.matched.length}건 β leerness constraints check λ‘ μμΈ νμΈ`);
|
|
15450
|
+
}
|
|
15451
|
+
} catch {}
|
|
15452
|
+
|
|
15241
15453
|
// 7) proceed κΆμ₯ (μΆ©λ critical μ false)
|
|
15242
15454
|
const proceed = conflictHints.length < 3 && planConflicts.length === 0;
|
|
15243
15455
|
|
|
@@ -15252,6 +15464,8 @@ function reviewRequestCmd(root, request) {
|
|
|
15252
15464
|
featureConflicts,
|
|
15253
15465
|
recommendedSteps,
|
|
15254
15466
|
efficiencyHints,
|
|
15467
|
+
platformConstraints: constraintsCheck.matched,
|
|
15468
|
+
constraintSuggestions: constraintsCheck.suggestions,
|
|
15255
15469
|
proceed,
|
|
15256
15470
|
proceedReason: proceed ? 'μμ β μΆ©λ μ νΈ < 3 + plan μΆ©λ 0' : 'β μΆ©λ critical β μ¬μ©μ νμΈ ν μ§ν',
|
|
15257
15471
|
durationMs: dt
|
|
@@ -15295,6 +15509,18 @@ function reviewRequestCmd(root, request) {
|
|
|
15295
15509
|
log(`## π‘ ν¨μ¨ μ μ`);
|
|
15296
15510
|
efficiencyHints.forEach(h => log(` ${h}`));
|
|
15297
15511
|
log('');
|
|
15512
|
+
// 1.9.208: νλ«νΌ/API μ μ½ μ¬μ λ
ΈμΆ (μ¬μ©μ λͺ
μ)
|
|
15513
|
+
if (constraintsCheck.matched.length > 0) {
|
|
15514
|
+
log(`## π¦ νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (${constraintsCheck.matched.length})`);
|
|
15515
|
+
for (const m of constraintsCheck.matched) {
|
|
15516
|
+
log(` - π¦ ${m.platform} (docs: ${m.docs || '-'})`);
|
|
15517
|
+
for (const c of (m.constraints || []).slice(0, 3)) {
|
|
15518
|
+
log(` β’ [${c.kind}] ${c.detail}`);
|
|
15519
|
+
}
|
|
15520
|
+
}
|
|
15521
|
+
log(` β leerness constraints check "${text.slice(0, 40)}β¦" λ‘ μμΈ νμΈ`);
|
|
15522
|
+
log('');
|
|
15523
|
+
}
|
|
15298
15524
|
if (recommendedSteps.length) {
|
|
15299
15525
|
log(`## π κΆμ₯ λ¨κ³ (${estimatedType})`);
|
|
15300
15526
|
recommendedSteps.forEach(s => log(` ${s}`));
|
|
@@ -15568,6 +15794,8 @@ async function main() {
|
|
|
15568
15794
|
if (cmd === 'resume') return resumeCmd(arg('--path', process.cwd()));
|
|
15569
15795
|
// 1.9.207: leerness requests <audit|add|list|complete|drop> β μ¬μ©μ μμ² λλ½ νμΈ μ μ°¨ (μ¬μ©μ λͺ
μ)
|
|
15570
15796
|
if (cmd === 'requests') return requestsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
15797
|
+
// 1.9.208: leerness constraints <list|check|add> β νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ)
|
|
15798
|
+
if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
15571
15799
|
if (cmd === 'rule' && args[1] === 'add') return ruleAdd(arg('--path', process.cwd()), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
|
|
15572
15800
|
if (cmd === 'rule' && args[1] === 'list') return ruleList(arg('--path', process.cwd()));
|
|
15573
15801
|
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.208",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|