leerness 1.9.212 β 1.9.213
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 +75 -0
- package/README.md +3 -3
- package/bin/harness.js +265 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.213 β 2026-05-22
|
|
4
|
+
|
|
5
|
+
**π― intent inference + scope expansion κ²μ΄νΈ (μ¬μ©μ λͺ
μ) β λ§μ§λ§ pending task μμ±.**
|
|
6
|
+
|
|
7
|
+
### μ¬μ©μ λͺ
μ
|
|
8
|
+
> *"μ¬μ©μκ° λ§ν λ΄μ©λ§ μμ ν΄μΌνλ κ²½μ°λ μμ§λ§, κ΄λ ¨μλκ²μ΄λ 보κ°νλ©΄ μ’μ λΆλΆμ νμ
νμ¬ μ§ν / κ²μ κ°λ°μμ λ§΅+μΊλ¦ν°+κΈ°λ³ΈκΈ°λ₯ μμ² μ μλ νμ
"*
|
|
9
|
+
|
|
10
|
+
### 1. 3μμΉ μμ μ€κ³
|
|
11
|
+
1. **Always-Off, Opt-In** β κΈ°λ³Έ λΉνμ±, λͺ
μμ νΈμΆ (`leerness intent expand`) λλ review-request ν΅ν© μλ§ μλ
|
|
12
|
+
2. **Dry-run κΈ°λ³Έ** β μ€μ task add **μ λ X**, λͺ¨λ μΆλ ₯μ ν보 λ³΄κ³ λ§
|
|
13
|
+
3. **λͺ
μ vs μΆλ‘ λΆλ¦¬ λΌλ²¨λ§** β `π€ μ¬μ©μ λͺ
μ` vs `π€ AI μΆλ‘ νμ₯` νμ ꡬλΆ
|
|
14
|
+
|
|
15
|
+
### 2. `_classifyIntent(text)` β 3λ¨κ³ λΆλ₯
|
|
16
|
+
- **precise** ("μ νν", "κ·Έκ²λ§", "κ·Έλλ‘", "λ§νλλ‘", "only") β AI μΆλ‘ νμ₯ **λΉνμ±**
|
|
17
|
+
- **broad** ("κΈ°λ³Έ", "ν¬κ΄μ ", "λ±λ±", "λ€μν", "μ 체", "νμν") β νμ₯ ν보 N건 dry-run μ μ
|
|
18
|
+
- **default** (λͺ
μ μμ) β λͺ
μ μ°μ , νμ₯ ν보 κ²ν μ©μΌλ‘ νμ
|
|
19
|
+
|
|
20
|
+
### 3. `.harness/domain-catalog.json` β 5 default + user νΈμ§ κ°λ₯
|
|
21
|
+
- **game** (10 μ»΄ν¬λνΈ): map, character, gameLoop, collision, camera, hud, audio, save, menu, input
|
|
22
|
+
- **web** (8 μ»΄ν¬λνΈ): routing, state, auth, api, db, ui, test, deploy
|
|
23
|
+
- **api** (7 μ»΄ν¬λνΈ): endpoint, auth, rate-limit, validation, error, logging, docs
|
|
24
|
+
- **cli** (6 μ»΄ν¬λνΈ): argParser, help, config, output, error, completion
|
|
25
|
+
- **data** (6 μ»΄ν¬λνΈ): ingest, transform, storage, query, validation, lineage
|
|
26
|
+
|
|
27
|
+
### 4. `_inferScopeExpansion(text, root)` β νμ₯ ν보 dry-run
|
|
28
|
+
- λλ©μΈ μλ νμ§ (alias λ§€μΉ)
|
|
29
|
+
- μ¬μ©μ λͺ
μ mention μΆμΆ
|
|
30
|
+
- λλ¨Έμ§ β AI μΆλ‘ νμ₯ ν보
|
|
31
|
+
- **mode: 'dry-run' κ°μ ** (μ€ν X)
|
|
32
|
+
|
|
33
|
+
### 5. `leerness intent <classify|expand|domains>` CLI
|
|
34
|
+
- `classify "<req>"` β μλ λΆλ₯ + μ νΈ
|
|
35
|
+
- `expand "<req>"` β λλ©μΈ νμ§ + νμ₯ ν보 dry-run
|
|
36
|
+
- `domains` β catalog μΆλ ₯
|
|
37
|
+
- λͺ¨λ `--json` μ§μ
|
|
38
|
+
|
|
39
|
+
### 6. μ¬μ©μ κ²μ μμ κ²μ¦
|
|
40
|
+
```
|
|
41
|
+
$ leerness intent expand "λ§΅κ³Ό μΊλ¦ν° + κΈ°λ³Έ κ²μ κΈ°λ₯ ν¬κ΄μ μΌλ‘ λ§λ€μ΄μ€"
|
|
42
|
+
π intent: broad π¦ domain: game (matched: "κ²μ")
|
|
43
|
+
|
|
44
|
+
## π€ μ¬μ©μ λͺ
μ (2)
|
|
45
|
+
β’ character β μΊλ¦ν°/μ€νλΌμ΄νΈ + μ λλ©μ΄μ
μνλ¨Έμ
|
|
46
|
+
β’ gameLoop β κ²μ 루ν (tick/render/update)
|
|
47
|
+
|
|
48
|
+
## π€ AI μΆλ‘ νμ₯ ν보 (8, dry-run)
|
|
49
|
+
[1] map / [2] collision / [3] camera / [4] hud / [5] audio / [6] save / [7] menu / [8] input
|
|
50
|
+
|
|
51
|
+
β μ§ν μ λͺ
μ μΉμΈ νμ: leerness task add "<μ νν ν보 μμ²>"
|
|
52
|
+
β μ λΆ λ¬΄μνλ €λ©΄ μΆκ° task add μμ΄ λͺ
μ μμ²λ§ μ§ν
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 7. precise μλ λ³΄νΈ κ²μ¦
|
|
56
|
+
```
|
|
57
|
+
$ leerness intent expand "μ νν κ²μμ λ§΅λ§ μμ ν΄μ€ κ·Έκ²λ§"
|
|
58
|
+
π‘ intent: precise β AI μΆλ‘ νμ₯ λΉνμ± (μ¬μ©μ μλ 보νΈ)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 8. λμ νκ· (1.9.200~212) β λͺ¨λ μ μ§
|
|
62
|
+
|
|
63
|
+
### 9. stress-v158 β 19/19 PASS
|
|
64
|
+
- 1.9.213 (10) + μ±λ₯ (2) + λμ νκ· (7)
|
|
65
|
+
- κ²μ μμ broad β 8 νμ₯ ν보 / precise β 0 νμ₯ (μλ 보νΈ) / web λλ©μΈ νμ§
|
|
66
|
+
- μ±λ₯: --version cold start avg 388ms Β· MCP 54 λꡬ 434ms
|
|
67
|
+
|
|
68
|
+
### 10. μλ release (75 λΌμ΄λ main-push streak Β· 36 λΌμ΄λ npm publish streak)
|
|
69
|
+
|
|
70
|
+
### 11. π μ¬μ©μ λͺ
μ task λ°±λ‘κ·Έ **μμ μμ§** (#307κΉμ§ λͺ¨λ completed)
|
|
71
|
+
- 1.9.207~213 7 λΌμ΄λ μ°μ μ¬μ©μ λͺ
μ μμ² μ²λ¦¬:
|
|
72
|
+
- 207 user-requests audit / 208 platform constraints / 209 pre-wake audit
|
|
73
|
+
- 210 adaptive wakeup / 211 .harnessβ.leerness migration / 212 idempotency dedup
|
|
74
|
+
- 213 intent inference + scope expansion κ²μ΄νΈ
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
3
78
|
## 1.9.212 β 2026-05-22
|
|
4
79
|
|
|
5
80
|
**π λ©±λ±μ± κ°μ¬ + ruleAdd/taskAdd dedup λ³΄κ° (μ¬μ©μ λͺ
μ).**
|
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.213 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β π― intent inference + scope expansion 5λλ©μΈ (μ¬μ©μ λͺ
μ) β
|
|
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.213';
|
|
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 μ²λ¦¬).
|
|
@@ -2526,6 +2526,175 @@ function _buildWorkspaceReferenceGuide(root, dirName) {
|
|
|
2526
2526
|
return lines.join('\n');
|
|
2527
2527
|
}
|
|
2528
2528
|
|
|
2529
|
+
// 1.9.213: intent inference + scope expansion κ²μ΄νΈ (μ¬μ©μ λͺ
μ)
|
|
2530
|
+
// "μ¬μ©μκ° λ§ν λ΄μ©λ§ μμ ν΄μΌνλ κ²½μ°λ μμ§λ§, κ΄λ ¨μλκ²μ΄λ 보κ°νλ©΄ μ’μ λΆλΆμ νμ
νμ¬ μ§ν"
|
|
2531
|
+
// "κ²μ κ°λ°μμ λ§΅+μΊλ¦ν°+κΈ°λ³ΈκΈ°λ₯ μμ² μ μλ νμ
"
|
|
2532
|
+
// 3μμΉ: (1) Always-Off Opt-In, (2) Dry-run κΈ°λ³Έ (μ€ν X), (3) λͺ
μ vs μΆλ‘ λΆλ¦¬ λΌλ²¨λ§
|
|
2533
|
+
// .harness/domain-catalog.json μ¬μ©μ νΈμ§ κ°λ₯ + default catalog 5μ’
(game/web/api/cli/data)
|
|
2534
|
+
function _domainCatalogPath(root) { return path.join(root, '.harness', 'domain-catalog.json'); }
|
|
2535
|
+
const _DEFAULT_DOMAIN_CATALOG = {
|
|
2536
|
+
version: '1.9.213',
|
|
2537
|
+
domains: {
|
|
2538
|
+
game: {
|
|
2539
|
+
aliases: ['κ²μ', 'game', 'unity', 'unreal', 'godot', 'phaser', 'gamedev'],
|
|
2540
|
+
components: [
|
|
2541
|
+
{ key: 'map', desc: 'λ§΅/νμΌ μμ€ν
+ μμ/μ€ν°' },
|
|
2542
|
+
{ key: 'character', desc: 'μΊλ¦ν°/μ€νλΌμ΄νΈ + μ λλ©μ΄μ
μνλ¨Έμ ' },
|
|
2543
|
+
{ key: 'gameLoop', desc: 'κ²μ 루ν (tick/render/update)' },
|
|
2544
|
+
{ key: 'collision', desc: 'μΆ©λ κ°μ§ (AABB/SAT/grid)' },
|
|
2545
|
+
{ key: 'camera', desc: 'μΉ΄λ©λΌ follow + μμ μ ν' },
|
|
2546
|
+
{ key: 'hud', desc: 'HUD/UI (HP/score/inventory)' },
|
|
2547
|
+
{ key: 'audio', desc: 'μ¬μ΄λ λ§€λμ (BGM/SFX)' },
|
|
2548
|
+
{ key: 'save', desc: 'μ μ₯/λ‘λ (slot μμ€ν
)' },
|
|
2549
|
+
{ key: 'menu', desc: 'λ©λ΄ (λ©μΈ/μΌμμ μ§/μ€μ )' },
|
|
2550
|
+
{ key: 'input', desc: 'μ
λ ₯ νΈλ€λ¬ (ν€λ³΄λ/ν¨λ/ν°μΉ)' }
|
|
2551
|
+
]
|
|
2552
|
+
},
|
|
2553
|
+
web: {
|
|
2554
|
+
aliases: ['μΉ', 'web', 'website', 'webapp', 'nextjs', 'react', 'vue', 'svelte', 'frontend'],
|
|
2555
|
+
components: [
|
|
2556
|
+
{ key: 'routing', desc: 'λΌμ°ν
(path/dynamic/nested)' },
|
|
2557
|
+
{ key: 'state', desc: 'μν κ΄λ¦¬ (context/redux/zustand)' },
|
|
2558
|
+
{ key: 'auth', desc: 'μΈμ¦ (OAuth/JWT/session)' },
|
|
2559
|
+
{ key: 'api', desc: 'API ν΄λΌμ΄μΈνΈ (fetch/axios/tanstack-query)' },
|
|
2560
|
+
{ key: 'db', desc: 'DB μ°λ (ORM/migration/seed)' },
|
|
2561
|
+
{ key: 'ui', desc: 'UI μ»΄ν¬λνΈ λΌμ΄λΈλ¬λ¦¬' },
|
|
2562
|
+
{ key: 'test', desc: 'ν
μ€νΈ (unit/e2e/visual)' },
|
|
2563
|
+
{ key: 'deploy', desc: 'λ°°ν¬ (Vercel/Netlify/Cloudflare)' }
|
|
2564
|
+
]
|
|
2565
|
+
},
|
|
2566
|
+
api: {
|
|
2567
|
+
aliases: ['api', 'rest', 'graphql', 'endpoint', 'backend', 'server'],
|
|
2568
|
+
components: [
|
|
2569
|
+
{ key: 'endpoint', desc: 'μλν¬μΈνΈ λΌμ°ν
+ HTTP method' },
|
|
2570
|
+
{ key: 'auth', desc: 'μΈμ¦/μΈκ° (API key/OAuth/JWT)' },
|
|
2571
|
+
{ key: 'rate-limit', desc: 'rate limit (RPS/RPM/token bucket)' },
|
|
2572
|
+
{ key: 'validation', desc: 'μ
λ ₯ κ²μ¦ (zod/joi/yup)' },
|
|
2573
|
+
{ key: 'error', desc: 'μλ¬ νΈλ€λ§ + μλ΅ νμ' },
|
|
2574
|
+
{ key: 'logging', desc: 'λ‘κΉ
+ λͺ¨λν°λ§ (structured logs)' },
|
|
2575
|
+
{ key: 'docs', desc: 'API λ¬Έμ (OpenAPI/Swagger)' }
|
|
2576
|
+
]
|
|
2577
|
+
},
|
|
2578
|
+
cli: {
|
|
2579
|
+
aliases: ['cli', 'command-line', 'tool', 'utility', 'shell'],
|
|
2580
|
+
components: [
|
|
2581
|
+
{ key: 'argParser', desc: 'μΈμ νμ± (yargs/commander/clipanion)' },
|
|
2582
|
+
{ key: 'help', desc: 'help / man / examples ν
μ€νΈ' },
|
|
2583
|
+
{ key: 'config', desc: 'μ€μ νμΌ + env λ³μ' },
|
|
2584
|
+
{ key: 'output', desc: 'μΆλ ₯ (TTY μμ/JSON/quiet)' },
|
|
2585
|
+
{ key: 'error', desc: 'μλ¬ μ²λ¦¬ + exit code κ·μ½' },
|
|
2586
|
+
{ key: 'completion', desc: 'shell completion (bash/zsh/fish)' }
|
|
2587
|
+
]
|
|
2588
|
+
},
|
|
2589
|
+
data: {
|
|
2590
|
+
aliases: ['data', 'pipeline', 'etl', 'analytics', 'ingest'],
|
|
2591
|
+
components: [
|
|
2592
|
+
{ key: 'ingest', desc: 'λ°μ΄ν° μμ§ (file/API/stream)' },
|
|
2593
|
+
{ key: 'transform', desc: 'λ³ν (cleaning/normalization/joining)' },
|
|
2594
|
+
{ key: 'storage', desc: 'μ μ₯μ (parquet/db/blob)' },
|
|
2595
|
+
{ key: 'query', desc: '쿼리/λΆμ (SQL/aggregations)' },
|
|
2596
|
+
{ key: 'validation', desc: 'λ°μ΄ν° κ²μ¦ (schema/contracts)' },
|
|
2597
|
+
{ key: 'lineage', desc: 'λ°μ΄ν° lineage μΆμ ' }
|
|
2598
|
+
]
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
};
|
|
2602
|
+
function _loadDomainCatalog(root) {
|
|
2603
|
+
try {
|
|
2604
|
+
const fp = _domainCatalogPath(root);
|
|
2605
|
+
if (!exists(fp)) return _DEFAULT_DOMAIN_CATALOG;
|
|
2606
|
+
const j = JSON.parse(read(fp));
|
|
2607
|
+
// user catalog merge β user override μ°μ
|
|
2608
|
+
const merged = JSON.parse(JSON.stringify(_DEFAULT_DOMAIN_CATALOG));
|
|
2609
|
+
if (j.domains) {
|
|
2610
|
+
for (const k of Object.keys(j.domains)) merged.domains[k] = j.domains[k];
|
|
2611
|
+
}
|
|
2612
|
+
return merged;
|
|
2613
|
+
} catch { return _DEFAULT_DOMAIN_CATALOG; }
|
|
2614
|
+
}
|
|
2615
|
+
function _writeDomainCatalog(root, catalog) {
|
|
2616
|
+
try {
|
|
2617
|
+
mkdirp(path.join(root, '.harness'));
|
|
2618
|
+
writeUtf8(_domainCatalogPath(root), JSON.stringify({ ...catalog, updatedAt: new Date().toISOString() }, null, 2));
|
|
2619
|
+
return true;
|
|
2620
|
+
} catch { return false; }
|
|
2621
|
+
}
|
|
2622
|
+
// intent λΆλ₯: precise / broad / default
|
|
2623
|
+
function _classifyIntent(text) {
|
|
2624
|
+
if (!text || typeof text !== 'string') return { intent: 'default', signals: [] };
|
|
2625
|
+
const signals = [];
|
|
2626
|
+
// precise μ νΈ: "μ νν / κ·Έκ²λ§ / κ·Έλλ‘ / only / just / λ§"
|
|
2627
|
+
const preciseKws = ['μ νν', 'κ·Έκ²λ§', 'κ·Έλλ‘', 'only', 'just only', 'λ§νλλ‘', 'λ§ν κ·Έλλ‘'];
|
|
2628
|
+
for (const kw of preciseKws) {
|
|
2629
|
+
if (text.toLowerCase().includes(kw.toLowerCase())) signals.push({ kind: 'precise', match: kw });
|
|
2630
|
+
}
|
|
2631
|
+
// broad μ νΈ: "κΈ°λ³Έ / ν¬κ΄μ / λ±λ± / λ€μν / μ 체 / κΈ°λ³Έμ μΈ / etc / overall"
|
|
2632
|
+
const broadKws = ['κΈ°λ³Έ', 'ν¬κ΄μ ', 'λ±λ±', 'λ€μν', 'μ 체', 'κΈ°λ³Έμ μΈ', 'etc', 'overall', 'νμν', 'κ΄λ ¨', 'comprehensive', 'including'];
|
|
2633
|
+
for (const kw of broadKws) {
|
|
2634
|
+
if (text.toLowerCase().includes(kw.toLowerCase())) signals.push({ kind: 'broad', match: kw });
|
|
2635
|
+
}
|
|
2636
|
+
// κ²°μ
|
|
2637
|
+
const preciseCount = signals.filter(s => s.kind === 'precise').length;
|
|
2638
|
+
const broadCount = signals.filter(s => s.kind === 'broad').length;
|
|
2639
|
+
let intent;
|
|
2640
|
+
if (preciseCount > broadCount && preciseCount >= 1) intent = 'precise';
|
|
2641
|
+
else if (broadCount >= 1) intent = 'broad';
|
|
2642
|
+
else intent = 'default';
|
|
2643
|
+
return { intent, signals, preciseCount, broadCount };
|
|
2644
|
+
}
|
|
2645
|
+
function _detectDomain(text, root) {
|
|
2646
|
+
if (!text) return { domain: null, alias: null };
|
|
2647
|
+
const lower = text.toLowerCase();
|
|
2648
|
+
const catalog = _loadDomainCatalog(root);
|
|
2649
|
+
for (const [domain, info] of Object.entries(catalog.domains)) {
|
|
2650
|
+
for (const a of info.aliases || []) {
|
|
2651
|
+
if (lower.includes(a.toLowerCase())) {
|
|
2652
|
+
return { domain, alias: a, components: info.components };
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
return { domain: null, alias: null };
|
|
2657
|
+
}
|
|
2658
|
+
function _inferScopeExpansion(text, root) {
|
|
2659
|
+
const classify = _classifyIntent(text);
|
|
2660
|
+
const det = _detectDomain(text, root);
|
|
2661
|
+
const result = {
|
|
2662
|
+
text,
|
|
2663
|
+
intent: classify.intent,
|
|
2664
|
+
intentSignals: classify.signals,
|
|
2665
|
+
domain: det.domain,
|
|
2666
|
+
matchedAlias: det.alias,
|
|
2667
|
+
explicitMentions: [],
|
|
2668
|
+
expansionCandidates: [],
|
|
2669
|
+
mode: 'dry-run' // νμ dry-run β μ€ν X
|
|
2670
|
+
};
|
|
2671
|
+
if (!det.domain || !det.components) {
|
|
2672
|
+
result.note = 'λλ©μΈ λ―Ένμ§ β λͺ
μ μμ²λ§ μ§ν (νμ₯ ν보 μμ)';
|
|
2673
|
+
return result;
|
|
2674
|
+
}
|
|
2675
|
+
// μ¬μ©μ ν
μ€νΈμμ component key μ§μ μΈκΈ μΆμΆ
|
|
2676
|
+
const lowerText = text.toLowerCase();
|
|
2677
|
+
for (const c of det.components) {
|
|
2678
|
+
const mentionPatterns = [c.key.toLowerCase(), ...(c.desc.split(/[\s/()]/).filter(w => w.length >= 2).map(w => w.toLowerCase()))];
|
|
2679
|
+
const mentioned = mentionPatterns.some(p => lowerText.includes(p));
|
|
2680
|
+
if (mentioned) {
|
|
2681
|
+
result.explicitMentions.push({ key: c.key, desc: c.desc, source: 'user-explicit' });
|
|
2682
|
+
} else {
|
|
2683
|
+
result.expansionCandidates.push({ key: c.key, desc: c.desc, source: 'ai-inference' });
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
// intent === precise λ©΄ expansion λΉμ΄μκ² (μλ 보νΈ)
|
|
2687
|
+
if (classify.intent === 'precise') {
|
|
2688
|
+
result.expansionCandidates = [];
|
|
2689
|
+
result.note = `intent: precise β λͺ
μ μμ²λ§ μ§ν, AI μΆλ‘ νμ₯ λΉνμ± (μ¬μ©μ μλ 보νΈ)`;
|
|
2690
|
+
} else if (classify.intent === 'broad') {
|
|
2691
|
+
result.note = `intent: broad β ${result.expansionCandidates.length} νμ₯ ν보 μ μ (--expand-all λλ --select N μΌλ‘ λͺ
μ μΉμΈ νμ)`;
|
|
2692
|
+
} else {
|
|
2693
|
+
result.note = `intent: default β λͺ
μ ${result.explicitMentions.length}κ±΄λ§ μ°μ , νμ₯ ν보 ${result.expansionCandidates.length}건 κ²ν μ©`;
|
|
2694
|
+
}
|
|
2695
|
+
return result;
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2529
2698
|
// 1.9.203: μλ λΌμ΄λ plan μ 리 β μ¬μ©μ λͺ
μ
|
|
2530
2699
|
// "λ°±κ·ΈλΌμ΄λμ λ€μ μμ
μ΄ μμκ°λ₯ν μμ μκ° + μΌμ΄λ¬μλ ν΄μΌνλ μΌμ μ 리"
|
|
2531
2700
|
// λΌμ΄λ λ§λ¬΄λ¦¬ μ .harness/auto-resume-plan.json μλ μ μ₯ β λ€μ wakeup μ μ¦μ μ€ν κ°λ₯
|
|
@@ -3317,6 +3486,99 @@ function idempotencyCmd(root, sub) {
|
|
|
3317
3486
|
process.exit(1);
|
|
3318
3487
|
}
|
|
3319
3488
|
|
|
3489
|
+
// 1.9.213: leerness intent <classify|expand|domains> CLI β intent inference + scope expansion (μ¬μ©μ λͺ
μ)
|
|
3490
|
+
function intentCmd(root, sub, ...rest) {
|
|
3491
|
+
root = absRoot(root);
|
|
3492
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
3493
|
+
const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
3494
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
3495
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
3496
|
+
const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
3497
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
3498
|
+
|
|
3499
|
+
if (!sub || sub === 'help' || sub === '--help') {
|
|
3500
|
+
log(`# leerness intent (1.9.213) β μ¬μ©μ μλ νμ
+ scope expansion κ²μ΄νΈ`);
|
|
3501
|
+
log('');
|
|
3502
|
+
log(` classify "<request>" β intent λΆλ₯ (precise/broad/default) + μ νΈ (--json κ°λ₯)`);
|
|
3503
|
+
log(` expand "<request>" β λλ©μΈ νμ§ + νμ₯ ν보 dry-run (--json κ°λ₯)`);
|
|
3504
|
+
log(` domains β λ±λ‘λ λλ©μΈ catalog μΆλ ₯ (game/web/api/cli/data)`);
|
|
3505
|
+
log('');
|
|
3506
|
+
log(dim(` 3μμΉ: (1) Always-Off Opt-In (2) Dry-run κΈ°λ³Έ (μ€ν X) (3) λͺ
μ vs μΆλ‘ λΆλ¦¬ λΌλ²¨λ§`));
|
|
3507
|
+
log(dim(` μ: leerness intent expand "λ§΅κ³Ό μΊλ¦ν° + κΈ°λ³Έ κ²μ κΈ°λ₯ λ§λ€μ΄μ€"`));
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
if (sub === 'classify') {
|
|
3512
|
+
const text = rest.filter(x => !x.startsWith('-')).join(' ');
|
|
3513
|
+
if (!text) { console.error('Usage: leerness intent classify "<request text>"'); process.exit(1); }
|
|
3514
|
+
const result = _classifyIntent(text);
|
|
3515
|
+
if (has('--json')) { log(JSON.stringify({ text, ...result }, null, 2)); return; }
|
|
3516
|
+
log(cyan(`# leerness intent classify (1.9.213)`));
|
|
3517
|
+
log(` text: ${text.slice(0, 100)}${text.length > 100 ? 'β¦' : ''}`);
|
|
3518
|
+
log('');
|
|
3519
|
+
const icon = result.intent === 'precise' ? 'π―' : (result.intent === 'broad' ? 'π' : 'π');
|
|
3520
|
+
log(` ${icon} intent: ${grn(result.intent)} (precise=${result.preciseCount} / broad=${result.broadCount})`);
|
|
3521
|
+
if (result.signals.length) {
|
|
3522
|
+
log('');
|
|
3523
|
+
log(` π‘ μ νΈ:`);
|
|
3524
|
+
result.signals.forEach(s => log(dim(` β’ [${s.kind}] "${s.match}"`)));
|
|
3525
|
+
}
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
if (sub === 'expand') {
|
|
3530
|
+
const text = rest.filter(x => !x.startsWith('-')).join(' ');
|
|
3531
|
+
if (!text) { console.error('Usage: leerness intent expand "<request text>"'); process.exit(1); }
|
|
3532
|
+
const result = _inferScopeExpansion(text, root);
|
|
3533
|
+
if (has('--json')) { log(JSON.stringify(result, null, 2)); return; }
|
|
3534
|
+
log(cyan(`# leerness intent expand (1.9.213) [DRY-RUN]`));
|
|
3535
|
+
log(` text: ${text.slice(0, 100)}${text.length > 100 ? 'β¦' : ''}`);
|
|
3536
|
+
log('');
|
|
3537
|
+
const iIcon = result.intent === 'precise' ? 'π―' : (result.intent === 'broad' ? 'π' : 'π');
|
|
3538
|
+
log(` ${iIcon} intent: ${grn(result.intent)}` + (result.domain ? ` π¦ domain: ${grn(result.domain)}` + (result.matchedAlias ? dim(` (matched: "${result.matchedAlias}")`) : '') : ` ${dim('domain λ―Ένμ§')}`));
|
|
3539
|
+
log('');
|
|
3540
|
+
if (result.explicitMentions.length) {
|
|
3541
|
+
log(grn(`## π€ μ¬μ©μ λͺ
μ (${result.explicitMentions.length})`));
|
|
3542
|
+
result.explicitMentions.forEach(m => log(` β’ ${m.key} β ${m.desc}`));
|
|
3543
|
+
log('');
|
|
3544
|
+
}
|
|
3545
|
+
if (result.expansionCandidates.length) {
|
|
3546
|
+
log(yel(`## π€ AI μΆλ‘ νμ₯ ν보 (${result.expansionCandidates.length}, dry-run)`));
|
|
3547
|
+
result.expansionCandidates.forEach((c, i) => log(` [${i + 1}] ${c.key} β ${c.desc}`));
|
|
3548
|
+
log('');
|
|
3549
|
+
log(dim(` β μ§ν μ λͺ
μ μΉμΈ νμ: leerness task add "<μ νν ν보 μμ²>"`));
|
|
3550
|
+
log(dim(` β μ λΆ λ¬΄μνλ €λ©΄ μΆκ° task add μμ΄ λͺ
μ μμ²λ§ μ§ν`));
|
|
3551
|
+
} else if (result.domain && result.intent === 'precise') {
|
|
3552
|
+
log(red(` π‘ intent: precise β AI μΆλ‘ νμ₯ λΉνμ± (μ¬μ©μ μλ 보νΈ)`));
|
|
3553
|
+
}
|
|
3554
|
+
if (result.note) {
|
|
3555
|
+
log('');
|
|
3556
|
+
log(dim(` βΉ ${result.note}`));
|
|
3557
|
+
}
|
|
3558
|
+
return;
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
if (sub === 'domains') {
|
|
3562
|
+
const catalog = _loadDomainCatalog(root);
|
|
3563
|
+
if (has('--json')) { log(JSON.stringify(catalog, null, 2)); return; }
|
|
3564
|
+
log(cyan(`# leerness intent domains (1.9.213)`));
|
|
3565
|
+
log(` total domains: ${Object.keys(catalog.domains).length}`);
|
|
3566
|
+
log('');
|
|
3567
|
+
for (const [name, info] of Object.entries(catalog.domains)) {
|
|
3568
|
+
log(grn(` π¦ ${name}`) + dim(` aliases: ${(info.aliases || []).join(', ')}`));
|
|
3569
|
+
for (const c of info.components || []) {
|
|
3570
|
+
log(` β’ ${c.key.padEnd(12)} ${dim(c.desc)}`);
|
|
3571
|
+
}
|
|
3572
|
+
log('');
|
|
3573
|
+
}
|
|
3574
|
+
return;
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3577
|
+
console.error(`Unknown subcommand: ${sub}`);
|
|
3578
|
+
console.error(`Run: leerness intent help`);
|
|
3579
|
+
process.exit(1);
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3320
3582
|
// 1.9.199: wakeup miss μλ ν볡 κ°ν β last-handoff timestamp κΈ°λ‘ + 25min κΈ°λ interval μ λ° μΈ‘μ
|
|
3321
3583
|
// μ¬μ©μ λͺ
μ (1.9.198 νμ): "22:01μ λΌμ΄λμ μλμ§μ
λμ§μμμ΄"
|
|
3322
3584
|
// 1.9.196 task-log mtime κΈ°λ° detector λ task-log κ° μμ£Ό μ μ
λ°μ΄νΈλλ©΄ false positive.
|
|
@@ -16760,6 +17022,8 @@ async function main() {
|
|
|
16760
17022
|
if (cmd === 'migrate-workspace-dir') return migrateWorkspaceDirCmd(arg('--path', process.cwd()));
|
|
16761
17023
|
// 1.9.212: leerness idempotency audit β λ©±λ±μ± μλ° νμ§ (μ¬μ©μ λͺ
μ)
|
|
16762
17024
|
if (cmd === 'idempotency') return idempotencyCmd(arg('--path', process.cwd()), args[1]);
|
|
17025
|
+
// 1.9.213: leerness intent <classify|expand|domains> β intent inference + scope expansion (μ¬μ©μ λͺ
μ)
|
|
17026
|
+
if (cmd === 'intent') return intentCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
16763
17027
|
if (cmd === 'rule' && args[1] === 'add') return ruleAdd(arg('--path', process.cwd()), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
|
|
16764
17028
|
if (cmd === 'rule' && args[1] === 'list') return ruleList(arg('--path', process.cwd()));
|
|
16765
17029
|
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.213",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|