leerness 1.9.128 β 1.9.130
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 +55 -0
- package/README.md +2 -2
- package/bin/harness.js +105 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.130 β 2026-05-20 π **60 λΌμ΄λ μμ¨ λͺ¨λ λ§μΌμ€ν€**
|
|
4
|
+
|
|
5
|
+
**JSON 4μ’
ν΅ν©μ `memorySurface.archive` νλ μΆκ°** + 60 λΌμ΄λ μμ¨ λμ λ³΄κ³ μ.
|
|
6
|
+
|
|
7
|
+
### Added β archive νλ (JSON 4μ’
)
|
|
8
|
+
- `handoff --json` / `memory status --json` / `session close --json` / `health --json` λͺ¨λ `memorySurface.archive: { decisions, lessons, plan, total }` λ
ΈμΆ
|
|
9
|
+
- `memory status` ν
μ€νΈ λͺ¨λ: `π Archive: D1/L1/P0 (2건)` λΌμΈ μΆκ°
|
|
10
|
+
- μΈλΆ AI κ° ν JSON νΈμΆλ‘ λͺ¨λ λ©λͺ¨λ¦¬ μν (active + archive) λμ νμ
|
|
11
|
+
|
|
12
|
+
### 60 λΌμ΄λ λ§μΌμ€ν€
|
|
13
|
+
- λΌμ΄λ: 60 (1.9.70 β 1.9.130)
|
|
14
|
+
- MCP λꡬ: 11 β **40 π** (1.9.128 λ§μΌμ€ν€)
|
|
15
|
+
- --json λͺ
λ Ή: 6 β **19**
|
|
16
|
+
- handoff μλ νμ: 1 β **7**
|
|
17
|
+
- Memory Surface: WRITE 5 + READ 5 + DELETE 5 + RESTORE 3 + Archive 3
|
|
18
|
+
- stress μλ리μ€: v16 β v74 (58 μΆκ°)
|
|
19
|
+
- e2e: μμ 219/219
|
|
20
|
+
|
|
21
|
+
μμΈ: `_reports/AUTONOMOUS_ROUNDS_60_MILESTONE.md` (λΉκ³΅κ°)
|
|
22
|
+
|
|
23
|
+
## 1.9.129 β 2026-05-20
|
|
24
|
+
|
|
25
|
+
**handoff 7λ²μ§Έ μλ νμ β π μ΅κ·Ό 24h archive μλ¦Ό** β DELETE 5μ’
archive νλμ λ§€ μΈμ
μμ μ μλ λ
ΈμΆ.
|
|
26
|
+
|
|
27
|
+
### Added β handoff archive μλ¦Ό
|
|
28
|
+
- handoff μΆλ ₯μ archive νλ λΌμΈ μΆκ°:
|
|
29
|
+
```
|
|
30
|
+
π μ΅κ·Ό 24h archive (1.9.129): D2/L1/P0 (3건 archived) β 볡μ ν보
|
|
31
|
+
β νμ: leerness memory archive list --json
|
|
32
|
+
β 볡μ: leerness memory restore <surface> <target>
|
|
33
|
+
```
|
|
34
|
+
- 3 archive νμΌ (`decisions.archive.md`, `lessons.archive.md`, `plan.archive.md`) μ mtime 24h λ΄ + entry date 24h λ΄λ§ μΉ΄μ΄νΈ
|
|
35
|
+
- `--no-mem-delta` / `--compact` / `--quiet` / `LEERNESS_NO_MEM_DELTA=1` λ‘ λκΈ°
|
|
36
|
+
|
|
37
|
+
### 7κ° handoff μλ νμ
|
|
38
|
+
| # | λΌμ΄λ | μλ νμ |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| 1 | (κΈ°μ‘΄) | lessons matching |
|
|
41
|
+
| 2 | 1.9.45 | skill match μΆμ² |
|
|
42
|
+
| 3 | 1.9.69 | history hit |
|
|
43
|
+
| 4 | 1.9.88 | brainstorm hits |
|
|
44
|
+
| 5 | 1.9.81 | ν΅ν© ν€λλΌμΈ |
|
|
45
|
+
| 6 | 1.9.121 | π 24h λ©λͺ¨λ¦¬ λ³λ |
|
|
46
|
+
| **7** | **1.9.129** | **π 24h archive μλ¦Ό** |
|
|
47
|
+
|
|
48
|
+
### μ¬μ© μλ리μ€
|
|
49
|
+
μΈμ
μμ μ handoff:
|
|
50
|
+
```
|
|
51
|
+
π μ΅κ·Ό 24h λ©λͺ¨λ¦¬ λ³λ (1.9.121): task +3 Β· decision +1 Β· plan: λ³κ²½λ¨
|
|
52
|
+
π μ΅κ·Ό 24h archive (1.9.129): D1/L0/P1 (2건 archived) β 볡μ ν보
|
|
53
|
+
β νμ: leerness memory archive list --json
|
|
54
|
+
β 볡μ: leerness memory restore <surface> <target>
|
|
55
|
+
```
|
|
56
|
+
AI κ° μ¦μ "μ΄μ PostgreSQL κ²°μ μ·¨μνμλ€ β λ€μ κ²ν ν΄μΌ ν κΉ?" νλ¨ κ°λ₯.
|
|
57
|
+
|
|
3
58
|
## 1.9.128 β 2026-05-20
|
|
4
59
|
|
|
5
60
|
**`leerness memory restore` CLI + MCP 40λ²μ§Έ λꡬ `leerness_memory_restore`** π **MCP 40 λꡬ λ§μΌμ€ν€** β DELETEβRESTORE cycle μμ±.
|
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) []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
β βββ ββββββ ββββββ ββββββββββββββββββββββββ ββββββββ β
|
|
13
13
|
β βββββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββ β
|
|
14
14
|
β βββββββββββββββββββββββββββ ββββββ βββββββββββββββββββββ β
|
|
15
|
-
β v1.9.
|
|
15
|
+
β v1.9.130 AI Agent Reliability Harness β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· prevent drift β
|
|
17
17
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
18
18
|
```
|
package/bin/harness.js
CHANGED
|
@@ -6,7 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
|
|
9
|
-
const VERSION = '1.9.
|
|
9
|
+
const VERSION = '1.9.130';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -329,6 +329,8 @@ leerness audit . --fix # λλ½ λ©ν μλ 보κ°
|
|
|
329
329
|
- 1.9.126+ \`leerness plan remove <M-XXXX|title>\` + MCP **38 λꡬ** (\`leerness_plan_remove\`) β milestone μꡬ μ κ±° (archive 보쑴). **Memory Surface DELETE 5μ’
μμ μμ±** π.
|
|
330
330
|
- 1.9.127+ \`leerness memory archive list [--surface decisions|lessons|plan] [--json]\` + MCP **39 λꡬ** (\`leerness_memory_archive_list\`) β DELETE 5μ’
archive ν΅ν© μ‘°ν (볡μ ν보 νμ).
|
|
331
331
|
- 1.9.128+ \`leerness memory restore <surface> <target>\` + MCP **40 λꡬ π** (\`leerness_memory_restore\`) β archive β active λ³΅κ· (DELETEβRESTORE cycle μμ±). **MCP 40 λꡬ λ§μΌμ€ν€**.
|
|
332
|
+
- 1.9.129+ handoff **7λ²μ§Έ μλ νμ** β \`π μ΅κ·Ό 24h archive\` (D/L/P μΉ΄μ΄νΈ + 볡μ ν보 μλ΄). DELETE νλ μλ μΈμ§.
|
|
333
|
+
- 1.9.130+ π **60 λΌμ΄λ μμ¨ λͺ¨λ λ§μΌμ€ν€** β JSON 4μ’
(handoff/memory status/session close/health) \`memorySurface.archive\` νλ ν΅ν©. MCP 40 / handoff auto-recovery 7 / DELETE-RESTORE cycle μμ±.
|
|
332
334
|
|
|
333
335
|
---
|
|
334
336
|
|
|
@@ -1424,6 +1426,19 @@ function memoryStatusCmd(root, opts = {}) {
|
|
|
1424
1426
|
const lm = exists(lessonsPath(root)) ? read(lessonsPath(root)) : '';
|
|
1425
1427
|
const lessonHeaders = lm.match(/^### \d{4}-\d{2}-\d{2}[^\n]*/gm) || [];
|
|
1426
1428
|
const lessonsLatest = lessonHeaders.length ? (lm.split('\n').filter(l => /- Lesson:/.test(l)).pop() || '').replace(/^- Lesson:\s*/, '').slice(0, 100) : null;
|
|
1429
|
+
// 1.9.130: DELETE 5μ’
archive entry counts
|
|
1430
|
+
const archiveCounts = { decisions: 0, lessons: 0, plan: 0, total: 0 };
|
|
1431
|
+
try {
|
|
1432
|
+
const hd = path.join(root, '.harness');
|
|
1433
|
+
for (const [key, file] of [['decisions', 'decisions.archive.md'], ['lessons', 'lessons.archive.md'], ['plan', 'plan.archive.md']]) {
|
|
1434
|
+
const fp = path.join(hd, file);
|
|
1435
|
+
if (exists(fp)) {
|
|
1436
|
+
const entries = _parseArchiveBlocks(read(fp));
|
|
1437
|
+
archiveCounts[key] = entries.length;
|
|
1438
|
+
archiveCounts.total += entries.length;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
} catch {}
|
|
1427
1442
|
|
|
1428
1443
|
const payload = {
|
|
1429
1444
|
version: VERSION,
|
|
@@ -1433,6 +1448,7 @@ function memoryStatusCmd(root, opts = {}) {
|
|
|
1433
1448
|
rules: { active: rulesActive, paused: rulesPaused, total: rules.length },
|
|
1434
1449
|
plan: { milestones, inProgress: planInProgress },
|
|
1435
1450
|
lessons: { count: lessonHeaders.length, latest: lessonsLatest },
|
|
1451
|
+
archive: archiveCounts, // 1.9.130
|
|
1436
1452
|
summary: `T${tasksInProgress}/D${decisionHeaders.length}/R${rulesActive}/P${milestones}/L${lessonHeaders.length}`,
|
|
1437
1453
|
};
|
|
1438
1454
|
if (jsonMode) {
|
|
@@ -1449,6 +1465,7 @@ function memoryStatusCmd(root, opts = {}) {
|
|
|
1449
1465
|
log(`πΊ Plan: ${milestones} milestones (${planInProgress} in-progress)`);
|
|
1450
1466
|
log(`π‘ Lessons: ${lessonHeaders.length} entries`);
|
|
1451
1467
|
if (lessonsLatest) log(` - μ΅κ·Ό: ${lessonsLatest}`);
|
|
1468
|
+
if (archiveCounts.total > 0) log(`π Archive: D${archiveCounts.decisions}/L${archiveCounts.lessons}/P${archiveCounts.plan} (${archiveCounts.total}건)`);
|
|
1452
1469
|
log(`\nπ Summary: ${payload.summary}`);
|
|
1453
1470
|
}
|
|
1454
1471
|
|
|
@@ -2483,12 +2500,26 @@ function handoff(root) {
|
|
|
2483
2500
|
const milestones = (planText.match(/^### M-\d{4}\./gm) || []).length;
|
|
2484
2501
|
const lm = exists(lessonsPath(root)) ? read(lessonsPath(root)) : '';
|
|
2485
2502
|
const lessonsCount = (lm.match(/^### \d{4}-\d{2}-\d{2}[^\n]*/gm) || []).length;
|
|
2503
|
+
// 1.9.130: archive μΉ΄μ΄νΈ ν΅ν©
|
|
2504
|
+
const archiveCountsH = { decisions: 0, lessons: 0, plan: 0, total: 0 };
|
|
2505
|
+
try {
|
|
2506
|
+
const hdH = path.join(root, '.harness');
|
|
2507
|
+
for (const [key, file] of [['decisions', 'decisions.archive.md'], ['lessons', 'lessons.archive.md'], ['plan', 'plan.archive.md']]) {
|
|
2508
|
+
const fpH = path.join(hdH, file);
|
|
2509
|
+
if (exists(fpH)) {
|
|
2510
|
+
const entries = _parseArchiveBlocks(read(fpH));
|
|
2511
|
+
archiveCountsH[key] = entries.length;
|
|
2512
|
+
archiveCountsH.total += entries.length;
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
} catch {}
|
|
2486
2516
|
result.memorySurface = {
|
|
2487
2517
|
tasks: { inProgress: tasksInProgress, total: rows.length, byStatus: tasksByStatus },
|
|
2488
2518
|
decisions: { count: decisionsCount },
|
|
2489
2519
|
rules: { active: rulesActive, total: rules.length },
|
|
2490
2520
|
plan: { milestones },
|
|
2491
2521
|
lessons: { count: lessonsCount },
|
|
2522
|
+
archive: archiveCountsH, // 1.9.130
|
|
2492
2523
|
summary: `T${tasksInProgress}/D${decisionsCount}/R${rulesActive}/P${milestones}/L${lessonsCount}`,
|
|
2493
2524
|
};
|
|
2494
2525
|
} catch {}
|
|
@@ -2791,6 +2822,48 @@ function handoff(root) {
|
|
|
2791
2822
|
}
|
|
2792
2823
|
} catch {}
|
|
2793
2824
|
}
|
|
2825
|
+
// 1.9.129: handoff 7λ²μ§Έ μλ νμ β π μ΅κ·Ό 24h archive μλ¦Ό
|
|
2826
|
+
// DELETE 5μ’
archive νμΌ (.harness/decisions.archive.md, lessons.archive.md, plan.archive.md)
|
|
2827
|
+
// μ μ΅κ·Ό 24h λ΄ μΆκ°λ entry μΉ΄μ΄νΈλ₯Ό λ
ΈμΆ. AIκ° μλͺ» μ κ±°ν νλͺ©μ μ¦μ μΈμ§ + restore ν보 νμ.
|
|
2828
|
+
// `leerness memory archive list` / `leerness memory restore <surface> <target>` μλ΄ ν¬ν¨.
|
|
2829
|
+
if (!has('--no-mem-delta') && !has('--compact') && !has('--quiet') && process.env.LEERNESS_NO_MEM_DELTA !== '1') {
|
|
2830
|
+
try {
|
|
2831
|
+
const isTtyArc = process.stdout && process.stdout.isTTY;
|
|
2832
|
+
const arcCy = s => isTtyArc ? `\x1b[36m${s}\x1b[0m` : s;
|
|
2833
|
+
const arcDim = s => isTtyArc ? `\x1b[2m${s}\x1b[0m` : s;
|
|
2834
|
+
const hd = path.join(root, '.harness');
|
|
2835
|
+
const cutoffArchive = Date.now() - 24 * 60 * 60 * 1000;
|
|
2836
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
2837
|
+
const yest = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
2838
|
+
const surfaces = [
|
|
2839
|
+
{ key: 'D', label: 'decisions', file: 'decisions.archive.md' },
|
|
2840
|
+
{ key: 'L', label: 'lessons', file: 'lessons.archive.md' },
|
|
2841
|
+
{ key: 'P', label: 'plan', file: 'plan.archive.md' }
|
|
2842
|
+
];
|
|
2843
|
+
const archiveDeltas = [];
|
|
2844
|
+
let totalRecent = 0;
|
|
2845
|
+
for (const s of surfaces) {
|
|
2846
|
+
const fp = path.join(hd, s.file);
|
|
2847
|
+
if (!exists(fp)) continue;
|
|
2848
|
+
try {
|
|
2849
|
+
const stat = fs.statSync(fp);
|
|
2850
|
+
if (stat.mtimeMs < cutoffArchive) continue; // νμΌ μμ²΄κ° 24h μΈλ©΄ skip
|
|
2851
|
+
const entries = _parseArchiveBlocks(read(fp));
|
|
2852
|
+
const recent = entries.filter(e => e.date === today || e.date === yest).length;
|
|
2853
|
+
if (recent > 0) {
|
|
2854
|
+
archiveDeltas.push(`${s.key}${recent}`);
|
|
2855
|
+
totalRecent += recent;
|
|
2856
|
+
}
|
|
2857
|
+
} catch {}
|
|
2858
|
+
}
|
|
2859
|
+
if (totalRecent > 0) {
|
|
2860
|
+
log(arcCy(`π μ΅κ·Ό 24h archive (1.9.129): ${archiveDeltas.join('/')} (${totalRecent}건 archived) β 볡μ ν보`));
|
|
2861
|
+
log(arcDim(` β νμ: leerness memory archive list --json`));
|
|
2862
|
+
log(arcDim(` β 볡μ: leerness memory restore <surface> <target>`));
|
|
2863
|
+
log('');
|
|
2864
|
+
}
|
|
2865
|
+
} catch {}
|
|
2866
|
+
}
|
|
2794
2867
|
// 1.9.76: handoff 보μ μν μμ½ β .env vs .env.example + .gitignore μν¬λ¦Ώ ν¨ν΄ 1μ€ μμ½
|
|
2795
2868
|
// λ§€ μΈμ
μμ μ AIκ° λ³΄μ μνμ μ¦μ μΈμ§. --no-security-summary λλ --compactλ‘ λκΈ°
|
|
2796
2869
|
if (!has('--no-security-summary') && !has('--compact') && !has('--quiet')) {
|
|
@@ -4195,7 +4268,7 @@ function _banner(opts = {}) {
|
|
|
4195
4268
|
lines.push('');
|
|
4196
4269
|
for (const ln of lines) log(ln);
|
|
4197
4270
|
if (opts.quickStart) {
|
|
4198
|
-
log(C.bold(C.cyan(' β¨ λΉ λ₯Έ μμ (1.9.
|
|
4271
|
+
log(C.bold(C.cyan(' β¨ λΉ λ₯Έ μμ (1.9.130+ π 60 λΌμ΄λ λ§μΌμ€ν€ archive νλ ν΅ν© β 60 λΌμ΄λ μμ¨ λμ )')));
|
|
4199
4272
|
log(' ' + C.green('npx leerness@latest init .') + C.dim(' # μ κ· νλ‘μ νΈ + μΈλΆ AI CLI μ€μ '));
|
|
4200
4273
|
log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨ν
μ€νΈ + lessons + λ§€μΉ skill + history hit + brainstorm hits + ν€λλΌμΈ'));
|
|
4201
4274
|
log(' ' + C.green('npx leerness handoff . --quiet') + C.dim(' # μλν/CI λͺ¨λ (1.9.99) β μλ νμ λΌμΈ λΉνμ±'));
|
|
@@ -5117,12 +5190,26 @@ function sessionClose(root, opts = {}) {
|
|
|
5117
5190
|
const milestones0 = (planText0.match(/^### M-\d{4}\./gm) || []).length;
|
|
5118
5191
|
const lm0 = exists(lessonsPath(root)) ? read(lessonsPath(root)) : '';
|
|
5119
5192
|
const lessonsCount0 = (lm0.match(/^### \d{4}-\d{2}-\d{2}[^\n]*/gm) || []).length;
|
|
5193
|
+
// 1.9.130: archive μΉ΄μ΄νΈ ν΅ν©
|
|
5194
|
+
const archiveCountsS = { decisions: 0, lessons: 0, plan: 0, total: 0 };
|
|
5195
|
+
try {
|
|
5196
|
+
const hdS = path.join(root, '.harness');
|
|
5197
|
+
for (const [key, file] of [['decisions', 'decisions.archive.md'], ['lessons', 'lessons.archive.md'], ['plan', 'plan.archive.md']]) {
|
|
5198
|
+
const fpS = path.join(hdS, file);
|
|
5199
|
+
if (exists(fpS)) {
|
|
5200
|
+
const entries = _parseArchiveBlocks(read(fpS));
|
|
5201
|
+
archiveCountsS[key] = entries.length;
|
|
5202
|
+
archiveCountsS.total += entries.length;
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
} catch {}
|
|
5120
5206
|
jsonResult.memorySurface = {
|
|
5121
5207
|
tasks: { inProgress: tasksInProgress0, total: rows0.length, byStatus: tasksByStatus0 },
|
|
5122
5208
|
decisions: { count: decisionsCount0 },
|
|
5123
5209
|
rules: { active: rulesActive0, total: rules0.length },
|
|
5124
5210
|
plan: { milestones: milestones0 },
|
|
5125
5211
|
lessons: { count: lessonsCount0 },
|
|
5212
|
+
archive: archiveCountsS, // 1.9.130
|
|
5126
5213
|
summary: `T${tasksInProgress0}/D${decisionsCount0}/R${rulesActive0}/P${milestones0}/L${lessonsCount0}`,
|
|
5127
5214
|
};
|
|
5128
5215
|
} catch {}
|
|
@@ -8734,6 +8821,22 @@ function healthCmd(root) {
|
|
|
8734
8821
|
rules: { active: rulesActive, total: rules.length },
|
|
8735
8822
|
plan: { milestones },
|
|
8736
8823
|
lessons: { count: lessonsCount },
|
|
8824
|
+
archive: (() => {
|
|
8825
|
+
// 1.9.130: archive μΉ΄μ΄νΈ ν΅ν©
|
|
8826
|
+
const a = { decisions: 0, lessons: 0, plan: 0, total: 0 };
|
|
8827
|
+
try {
|
|
8828
|
+
const hdHe = path.join(root, '.harness');
|
|
8829
|
+
for (const [key, file] of [['decisions', 'decisions.archive.md'], ['lessons', 'lessons.archive.md'], ['plan', 'plan.archive.md']]) {
|
|
8830
|
+
const fpHe = path.join(hdHe, file);
|
|
8831
|
+
if (exists(fpHe)) {
|
|
8832
|
+
const entries = _parseArchiveBlocks(read(fpHe));
|
|
8833
|
+
a[key] = entries.length;
|
|
8834
|
+
a.total += entries.length;
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
} catch {}
|
|
8838
|
+
return a;
|
|
8839
|
+
})(),
|
|
8737
8840
|
summary: `T${tasksInProgress}/D${decisionsCount}/R${rulesActive}/P${milestones}/L${lessonsCount}`,
|
|
8738
8841
|
};
|
|
8739
8842
|
} catch { out.memorySurface = { error: 'memorySurface μ κ² μ€ν¨' }; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.130",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|